# Interfaces

Import these from `@grafloria/engine`.

## Interfaces

### `ChangeEntry`

```ts
interface ChangeEntry
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `timestamp` | `number` |  |  |
| `property` | `string` |  |  |
| `oldValue` | `any` |  |  |
| `newValue` | `any` |  |  |

### `CollapsedState`

The reversible snapshot captured when a group collapses. Stored (serialized) on the group so a collapsed diagram round-trips and can
be expanded losslessly after a save/load — not just within one session.

```ts
interface CollapsedState
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `proxyNodeId` | `string` |  | The hidden placeholder node that presents the group as a node endpoint. |
| `savedGeometry?` | `{ position: { x: number; y: number }; size?: { width: number; height: number; depth: number }; bounds?: GroupRect; }` |  | The group's exact geometry before it shrank (restored verbatim on expand). |
| `savedPositions` | `Record<string, { x: number; y: number }>` |  | Member (node) world positions at collapse time (restored on expand). |
| `hiddenNodes` | `Array<{ nodeId: string; prevVisible: boolean }>` |  | Members whose visibility we toggled, with their prior `visible` value. |
| `removedLinks` | `any[]` |  | Serialized links removed at collapse time (internal links + the parallel boundary links that were aggregated away). Re-created verbatim on expand. |
| `proxyLinks` | `Array<{ linkId: string; end: 'source' \| 'target'; originalPortId: string; originalNodeId?: string; aggregatedCount: number; }>` |  | Boundary links that SURVIVED as proxy links: one per (external endpoint) bundle, re-pointed to the placeholder node. Records the original endpoint so expand can restore it, plus how many raw edges it now represents. |

### `DiagramLoadOptions`

```ts
interface DiagramLoadOptions
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `validate?` | `'off' \| 'warn' \| 'strict'` |  | Structural integrity policy for the incoming document: - 'off' (default) skip validation - 'warn' validate and console.warn a one-line summary with the report - 'strict' validate and throw DiagramValidationError on any error |

### `FitToContentsOptions`

Options for {@link GroupModel.fitToContents}.

```ts
interface FitToContentsOptions
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `mode?` | `GroupFitMode` |  | Override the group's stored {@link GroupModel.fitMode} for this call. |
| `deepRecursive?` | `boolean` |  | Deep-recursive fit: fit every descendant group first (deepest first) so a parent fits around already-fitted children. Requires a diagram. |

### `GroupRect`

A resolved rectangle (all four sides present).

```ts
interface GroupRect
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `x` | `number` |  |  |
| `y` | `number` |  |  |
| `width` | `number` |  |  |
| `height` | `number` |  |  |

### `LaneConfig`

Swimlanes & pools as a GENERIC banded group (not BPMN-named). A `pool` group tiles its child `lane` groups into bands along one axis; each
`lane` is an ordinary group (so drop-to-assign, membership, constraints all
reuse the existing machinery). This is intrinsic band config that round-trips.

```ts
interface LaneConfig
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `role` | `'pool' \| 'lane'` |  | 'pool' owns the band grid; 'lane' is one band inside a pool. |
| `orientation` | `'horizontal' \| 'vertical'` |  | Band axis. 'horizontal' → lanes are rows stacked along Y (each spans the pool width). 'vertical' → lanes are columns along X (each spans the height). Set on the pool; lanes carry a copy for convenience. |
| `laneOrder?` | `string[]` |  | Pool only: ordered child lane group ids (band order). |
| `headerSize?` | `number` |  | Pool only: title-band thickness reserved along the main axis start (left for horizontal pools, top for vertical pools). |
| `weight?` | `number` |  | Lane only: relative cross-axis size when not fixed (default 1). |
| `fixedSize?` | `number` |  | Lane only: absolute cross-axis size (pins the band, overrides weight). |

### `MembershipLeaf`

```ts
interface MembershipLeaf
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `field` | `string` |  | Dot-free key looked up on the node's `data` map. |
| `op` | `'eq' \| 'ne' \| 'in' \| 'nin' \| 'gt' \| 'gte' \| 'lt' \| 'lte' \| 'exists' \| 'matches'` |  |  |
| `value?` | `unknown` |  | Comparison operand (array for in/nin; regex source string for matches). |

### `NearestPortHit`

What {@link DiagramModel.findNearestPort} found.

```ts
interface NearestPortHit
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `port` | `PortModel` |  |  |
| `node` | `NodeModel` |  |  |
| `distance` | `number` |  | Distance from the query point to the port, in world units. |

### `NearestPortOptions`

Options for {@link DiagramModel.findNearestPort}.

```ts
interface NearestPortOptions
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `radius?` | `number` |  | Maximum distance, in world units (default {@link DEFAULT_PORT_SNAP_RADIUS}). |
| `filter?` | `(port: PortModel, node: NodeModel) => boolean` |  | Consider only the ports this accepts (e.g. valid targets for the dragged link). |
| `portPosition?` | `(port: PortModel, node: NodeModel) => Point` |  | Where a port actually IS. Defaults to the bounding-box edge midpoint. Callers inside a renderer must pass the SHAPE-AWARE resolver (`portWorldPosition`) — see the note on `findNearestPort`. |

### `SerializedDiagram`

Also has every member of `SerializedEntity`, listed on its own entry.

```ts
interface SerializedDiagram extends SerializedEntity
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `schemaVersion?` | `number` |  | Document schema version (shape of THIS payload), distinct from the per-entity mutation counter `version`. Absent on pre-versioning documents, which are treated as schemaVersion 1 and migrated on load. |
| `name` | `string` |  |  |
| `nodes` | `SerializedNode[]` |  |  |
| `links` | `SerializedLink[]` |  |  |
| `groups` | `SerializedGroup[]` |  |  |
| `strokes?` | `SerializedStroke[]` |  | Freehand ink. |
| `viewport` | `{ x: number; y: number; width: number; // Phase 0.5 - Viewport-aware layout height: number; // Phase 0.5 - Viewport-aware layout zoom: number; }` |  |  |
| `comments?` | `CommentRegisterTree` |  | Anchored comment threads. Document data, saved with the document — a comment that does not survive a save is a comment that does not exist. |

### `SerializedGroup`

Also has every member of `SerializedEntity`, listed on its own entry.

```ts
interface SerializedGroup extends SerializedEntity
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `name` | `string` |  |  |
| `members` | `string[]` |  |  |
| `isCollapsed` | `boolean` |  |  |
| `bounds?` | `{ x: number; y: number; width: number; height: number }` |  |  |
| `layoutType?` | `LayoutType` |  |  |
| `layoutConfig?` | `LayoutConfig` |  |  |
| `position?` | `{ x: number; y: number }` |  |  |
| `size?` | `{ width: number; height: number; depth: number }` |  |  |
| `parentGroupId?` | `string` |  |  |
| `padding?` | `GroupPadding` |  |  |
| `headerHeight?` | `number` |  |  |
| `zIndex?` | `number` |  |  |
| `fitMode?` | `GroupFitMode` |  |  |
| `constrainChildren?` | `boolean` |  |  |
| `collapsedState?` | `CollapsedState` |  |  |
| `subgraphLayout?` | `SubgraphGroupConfig` |  |  |
| `laneConfig?` | `LaneConfig` |  |  |
| `membershipRule?` | `MembershipRule` |  |  |
| `capacity?` | `number` |  |  |

### `SerializedLink`

Also has every member of `SerializedEntity`, listed on its own entry.

```ts
interface SerializedLink extends SerializedEntity
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `sourcePortId` | `string` |  |  |
| `targetPortId` | `string` |  |  |
| `sourceNodeId?` | `string` |  |  |
| `targetNodeId?` | `string` |  |  |
| `pathType` | `'direct' \| 'orthogonal' \| 'smooth' \| 'bezier'` |  |  |
| `router?` | `LinkRouterName` |  | Explicit routing geometry; absent = derived from pathType. |
| `connector?` | `LinkConnectorName` |  | Explicit polyline rendering; absent = derived from pathType. |
| `points` | `Point[]` |  |  |
| `segments` | `PathSegment[]` |  |  |
| `labels` | `LinkLabel[]` |  |  |
| `state` | `'default' \| 'selected' \| 'hovered' \| 'highlighted'` |  |  |
| `style` | `Partial<LinkStyle>` |  |  |
| `data` | `Record<string, any>` |  |  |

### `SerializedNode`

Also has every member of `SerializedEntity`, listed on its own entry.

```ts
interface SerializedNode extends SerializedEntity
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `position` | `Point` |  |  |
| `size` | `Size` |  |  |
| `rotation` | `number` |  |  |
| `scale` | `Point` |  |  |
| `type` | `string` |  |  |
| `systemType?` | `string` |  |  |
| `definitionId?` | `string` |  |  |
| `parentId?` | `string` |  |  |
| `children` | `string[]` |  |  |
| `ports` | `SerializedPort[]` |  |  |
| `state` | `NodeState` |  |  |
| `behavior` | `NodeBehavior` |  |  |
| `style` | `Partial<NodeStyle>` |  |  |
| `data` | `Record<string, any>` |  |  |
| `positionMode?` | `PositioningMode` |  |  |
| `transformOrigin?` | `Point` |  |  |
| `zIndex?` | `number` |  | Model-level stacking order. OMITTED when the node never set one, so every document written before this field existed round-trips byte-for-byte and no schema migration is needed — absence means "unset", not 0. |
| `flexConfig?` | `FlexItemConfig` |  |  |
| `gridConfig?` | `GridItemConfig` |  |  |
| `portRenderingConfig?` | `any` |  |  |
| `dragHandlerConfig?` | `any` |  |  |
| `connectionGroup?` | `string` |  |  |

### `SerializedStroke`

Also has every member of `SerializedEntity`, listed on its own entry.

```ts
interface SerializedStroke extends SerializedEntity
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `type` | `'stroke'` |  |  |
| `points` | `StrokePoint[]` |  |  |
| `style` | `StrokeStyle` |  |  |
| `label?` | `string` |  | An author-supplied name. THE ENTIRE ACCESSIBILITY STORY LIVES ON THIS FIELD — see the a11y note on the renderer's ink layer. Absent for anonymous ink, which is the normal case and is rendered `aria-hidden`. |

### `StrokePoint`

One sample from the pointer.

`pressure` is 0..1 and OPTIONAL — a mouse does not have any. It is stored only when
the device actually reported a varying one (see {@link hasPressure}), because a
field that is always 0.5 is noise on the wire and a lie in the model.

It is not decoration: the renderer builds a variable-width outline from it. A
pressure that does not change the picture would be exactly the "machinery wired to
nothing" this project has shipped in all nine previous waves.

```ts
interface StrokePoint
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `x` | `number` |  |  |
| `y` | `number` |  |  |
| `pressure?` | `number` |  | 0..1. Absent when the device did not report a meaningful one. |

### `StrokeStyle`

How the ink looks. Flat and JSON-safe — this crosses the wire as an op payload.

```ts
interface StrokeStyle
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `color` | `string` |  | Any CSS colour. |
| `width` | `number` |  | Nominal width in WORLD units (so ink zooms with the diagram, like everything else). |
| `opacity?` | `number` |  | 0..1. Highlighter ink is translucent; a pen is not. |

### `SubgraphGroupConfig`

A group's own compound-layout configuration — the subset of
the GroupInfo layout contract that is intrinsic to the group and round-trips.

```ts
interface SubgraphGroupConfig
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `algorithm?` | `'dagre' \| 'elk' \| 'grid' \| 'inherit' \| (string & {})` |  | Algorithm for THIS group's contents. 'inherit' uses the parent/default. |
| `fixed?` | `boolean` |  | Pinned: neither laid out internally nor moved by the parent layout. |
| `layoutOptions?` | `Record<string, unknown>` |  | Opaque options forwarded to the chosen layout adapter. |
