@miragon/modeler-api 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -18,7 +18,15 @@
18
18
  * release (release-please-config.json `extra-files`), and the kit's own
19
19
  * test pins it to package.json exactly. Modelers pin the npm package; the
20
20
  * constant is what travels in `meta`. */
21
- declare const MODELER_API_VERSION = "1.0.0";
21
+ declare const MODELER_API_VERSION = "1.2.0";
22
+ /**
23
+ * apiVersion compatibility: same major — and, while the contract is 0.x,
24
+ * the same minor too (pre-1.0 minors may break; bump-minor-pre-major).
25
+ * Hosts call it at bind time with `meta.apiVersion` and their own
26
+ * MODELER_API_VERSION; it lives in the package root so that check never
27
+ * pulls the conformance kit into a host bundle (`/conformance` re-exports it)
28
+ */
29
+ declare function apiVersionsCompatible(a: string, b: string): boolean;
22
30
  interface ModelerMeta {
23
31
  /** stable notation id, e.g. "wardley", "team-topology", "event-storming" */
24
32
  readonly notation: string;
@@ -47,11 +55,32 @@ interface ElementInfo {
47
55
  * `?element=` deep links to it, so an id that renumbers when a line is
48
56
  * inserted above (positional edge ids) breaks every anchor below it. An
49
57
  * element without an id in the text gets one the serializer WRITES BACK.
58
+ *
59
+ * The id a session reports IS the element's id in the document: after
60
+ * `exportText()` → `importText()` — in this instance or in any other one
61
+ * (a peer, the viewer, the next session) — the element carries the same
62
+ * id. An id that lives only in memory anchors nothing: the todo or deep
63
+ * link a host stored against it points nowhere once the text travels.
64
+ *
65
+ * RECOMMENDED: when two peers create different elements at the same time,
66
+ * their ids do not collide. An id allocated regardless of the content —
67
+ * a per-instance counter (`event_1` on both peers) — does: once both edits
68
+ * merge into one document, two elements share one id; random or
69
+ * peer-scoped ids do not. An id derived from the content (OWM's
70
+ * `component_<slug>`) collides only when both users create the same
71
+ * content, which the merge has to reconcile anyway.
50
72
  */
51
73
  id: string;
52
74
  /** human label, when the notation has one */
53
75
  name?: string;
54
76
  }
77
+ /** an element's box in diagram coordinates, as `ElementsSurface.bounds` reports it */
78
+ interface ElementBounds {
79
+ x: number;
80
+ y: number;
81
+ width: number;
82
+ height: number;
83
+ }
55
84
  /**
56
85
  * Optional element surface — what a host needs for anchored todos, `?element=`
57
86
  * deep links and the selection half of live presence. Absent = the notation
@@ -71,6 +100,22 @@ interface ElementsSurface {
71
100
  selection(): string[];
72
101
  /** selection changes as STABLE element ids; returns the unsubscribe */
73
102
  onSelection(cb: (ids: string[]) => void): () => void;
103
+ /**
104
+ * the element's box in DIAGRAM coordinates — the canvas's own coordinate
105
+ * space, which zoom and scroll leave alone (a host maps it to the screen
106
+ * with the current view, or draws in a layer that moves with the canvas) —
107
+ * or `undefined` for an id `list()` does not report. Optional (1.2): hosts
108
+ * feature-detect it for presence outlines and todo markers instead of
109
+ * reaching into the engine.
110
+ *
111
+ * It reads the LIVE canvas: an element created, moved, resized or renamed
112
+ * in this session has its current box at once, not the one of the last
113
+ * import — a host outlining a peer's selection would otherwise draw it
114
+ * where the element was, or not at all, until the next import. The box is
115
+ * the element's own shape (a connection: the box around its waypoints); an
116
+ * external label is not part of it.
117
+ */
118
+ bounds?(id: string): ElementBounds | undefined;
74
119
  }
75
120
  /**
76
121
  * The collaborative-modeler contract. The LAWS (verified by the conformance
@@ -80,6 +125,14 @@ interface ElementsSurface {
80
125
  * the undo history without emitting — also when history exists. Hosts
81
126
  * re-import remote states on every sync; an import echo would re-export
82
127
  * the canonical serialization over half-typed peer text.
128
+ * An interaction in progress when an import runs (an open label editor,
129
+ * a popup with typed input) never commits during or because of the
130
+ * import: no change event comes from it, its input lands neither in the
131
+ * imported document nor on its fresh undo history, and nothing is
132
+ * applied to an element the import removed. RECOMMENDED: keep the typed
133
+ * input and reopen the interaction on the element with the same id when
134
+ * that element is still there after the import — a remote re-import
135
+ * should not cost the user what they were typing.
83
136
  * L2 CANONICAL FIXPOINT — `exportText` is deterministic, and for any text t:
84
137
  * with c = exportText() after importText(t), importText(c) followed by
85
138
  * exportText() returns c byte-for-byte. Canonicalization is idempotent;
@@ -104,6 +157,15 @@ interface ElementsSurface {
104
157
  * readback may be a NORMALISED form of what was set (a diagram-js
105
158
  * viewbox comes back rounded, with scale/inner/outer) — what must hold
106
159
  * is that setting a readback yields that readback again.
160
+ * A view change the HOST makes — `setViewState`, or a fit its chrome
161
+ * applies to the canvas — never commits an interaction in progress (an
162
+ * open label editor, a popup with typed input): no change event, the
163
+ * export unchanged. Hosts restore the viewport after every remote
164
+ * re-import and refit when their chrome changes; a commit there writes
165
+ * the half-typed input into the shared document for every peer.
166
+ * RECOMMENDED: the interaction stays open with its typed input, so the
167
+ * user's own commit afterwards writes what it would have written without
168
+ * the view change.
107
169
  * L6 EXPORT IS TOTAL AFTER IMPORT — after a successful import (and any
108
170
  * sequence of user commands and undos), `exportText` succeeds. Foreign or
109
171
  * auxiliary content the modeler does not understand is PRESERVED through
@@ -111,9 +173,11 @@ interface ElementsSurface {
111
173
  * rest), never dropped and never a reason to throw.
112
174
  * L7 REJECTED IMPORTS LEAVE NO TRACE — `importText` on non-importable text
113
175
  * REJECTS (resolve-with-warnings means "imported, with notes"; rejection
114
- * means "nothing imported"): afterwards the previously imported document
115
- * is still rendered with its elements, `exportText` still returns it, no
116
- * change event has fired and the undo history is untouched.
176
+ * means "nothing imported"). This holds for EVERY rejection, whatever
177
+ * the input (a truncated or half-typed text included): afterwards the
178
+ * previously imported document is still rendered with its elements,
179
+ * `exportText` still returns it, no change event has fired and the undo
180
+ * history is untouched.
117
181
  * The modeler stays USABLE: the next valid import renders, the next user
118
182
  * command applies. Hosts re-import half-typed peer text on every sync —
119
183
  * "blank (or wedged) until healed" is not an acceptable failure mode.
@@ -125,10 +189,16 @@ interface CollaborativeModeler {
125
189
  readonly meta: ModelerMeta;
126
190
  /** mount the canvas into a host element (once, before the first import).
127
191
  * The host must be attached to the document with a non-zero size — a
128
- * detached or 0×0 element gives diagram-js engines NaN viewboxes */
192
+ * detached or 0×0 element gives diagram-js engines NaN viewboxes.
193
+ * Calls made between mounting and the first import (`exportText()`, a
194
+ * user command) return whatever the modeler defines, or throw (only
195
+ * `getViewState` never does, L5), but they never wedge the instance:
196
+ * the first `importText` still behaves exactly as specified */
129
197
  attachTo(host: Element): void;
130
198
  /** parse + render `text` — SILENT per L1, the view fitted to the content
131
- * per L5; resolves when rendered, REJECTS when nothing was imported (L7) */
199
+ * per L5; resolves when rendered, REJECTS when nothing was imported (L7).
200
+ * This holds for the first import too, whatever was called before it — a
201
+ * host may export or route a command before its first document arrives */
132
202
  importText(text: string): Promise<ImportResult>;
133
203
  /** the canonical serialization of the current document (L2, L6) */
134
204
  exportText(): string;
@@ -142,5 +212,80 @@ interface CollaborativeModeler {
142
212
  * behavior, but a second destroy() must not throw */
143
213
  destroy(): void;
144
214
  }
215
+ /** px the host's chrome covers along the edges of the modeler's container */
216
+ interface FreeAreaInsets {
217
+ top: number;
218
+ right: number;
219
+ bottom: number;
220
+ left: number;
221
+ }
222
+ /** a point in diagram coordinates */
223
+ interface DiagramPoint {
224
+ x: number;
225
+ y: number;
226
+ }
227
+ /**
228
+ * The FREE AREA: the part of the canvas no host chrome covers (Miragon
229
+ * guide §5.9). Keyboard creation places a new element in its centre (§5.5)
230
+ * and a renderer that constrains panning keeps the content reachable around
231
+ * it, so both agree with a host that fits into the same rectangle. A host
232
+ * passes ONE of two forms, each a function the renderer reads whenever it
233
+ * needs it (the chrome changes when an inspector or a legend opens):
234
+ *
235
+ * - `insets`: what the chrome covers, in px from the container's edges
236
+ * (the modeler shell's `shell.fitInsets()`); the renderer computes the
237
+ * centre itself, the way a fit does;
238
+ * - `center`: the centre itself, in diagram coordinates, `undefined` while
239
+ * there is none (a 0×0 container) — the shell's `viewport.freeRectCenter()`.
240
+ *
241
+ * A renderer accepts both. One that needs the rectangle itself (a pan
242
+ * constraint) and is given only `center` treats the whole container as
243
+ * free, as it does without the option.
244
+ */
245
+ type FreeArea = {
246
+ insets: () => FreeAreaInsets;
247
+ center?: never;
248
+ } | {
249
+ center: () => DiagramPoint | undefined;
250
+ insets?: never;
251
+ };
252
+ /**
253
+ * The options a renderer's contract factory takes under THESE names once it
254
+ * implements contract 1.2, so a host feeds every notation the same object
255
+ * instead of one spelling per renderer. A renderer extends the type with its
256
+ * own options (diagram-js `additionalModules`); the contract fixes names,
257
+ * meaning and defaults. A viewer factory takes the same type and ignores
258
+ * what has no meaning without editing (`undoRedoKeys`).
259
+ *
260
+ * Each renderer adopts them in its own release, as part of its move to 1.2:
261
+ * `meta.apiVersion` follows the pinned package and no kit case checks the
262
+ * options, so the version alone does not tell a host they are honoured.
263
+ * Until a renderer ships them, a host passes the renderer's own names, or
264
+ * both. Those names then stay accepted as DEPRECATED aliases for one minor
265
+ * release of that renderer, then go: `freeRectInsets` (Wardley, Event
266
+ * Storming, Context Maps) is `freeArea: { insets }`, `freeRectCenter` (Team
267
+ * Topologies, Value Chain) is `freeArea: { center }`, and Wardley's
268
+ * `keyboard: { undoRedo }` is `undoRedoKeys`. Given both, the aligned name
269
+ * wins.
270
+ */
271
+ interface CollaborativeModelerOptions {
272
+ /** where the host's chrome leaves the canvas free; default: the whole container */
273
+ freeArea?: FreeArea | undefined;
274
+ /**
275
+ * fit the content into the view after every import — default true, the
276
+ * fitted view L5 defines. A host whose chrome fits the content itself
277
+ * (the modeler shell's viewport fits into the free area) passes false:
278
+ * the post-import view is then the host's to set, and L5's fit is the
279
+ * host's fit. The conformance kit runs with the default
280
+ */
281
+ fitOnImport?: boolean | undefined;
282
+ /**
283
+ * bind Cmd/Ctrl+Z, Cmd/Ctrl+Shift+Z and Cmd/Ctrl+Y to the canvas history —
284
+ * default true. A host that owns the document's history (VS Code) passes
285
+ * false, and the keys reach it unprevented; text fields keep their own
286
+ * undo either way
287
+ */
288
+ undoRedoKeys?: boolean | undefined;
289
+ }
145
290
 
146
- export { type CollaborativeModeler, type ElementInfo, type ElementsSurface, type ImportResult, MODELER_API_VERSION, type ModelerMeta };
291
+ export { type CollaborativeModeler, type CollaborativeModelerOptions, type DiagramPoint, type ElementBounds, type ElementInfo, type ElementsSurface, type FreeArea, type FreeAreaInsets, type ImportResult, MODELER_API_VERSION, type ModelerMeta, apiVersionsCompatible };
package/dist/index.d.ts CHANGED
@@ -18,7 +18,15 @@
18
18
  * release (release-please-config.json `extra-files`), and the kit's own
19
19
  * test pins it to package.json exactly. Modelers pin the npm package; the
20
20
  * constant is what travels in `meta`. */
21
- declare const MODELER_API_VERSION = "1.0.0";
21
+ declare const MODELER_API_VERSION = "1.2.0";
22
+ /**
23
+ * apiVersion compatibility: same major — and, while the contract is 0.x,
24
+ * the same minor too (pre-1.0 minors may break; bump-minor-pre-major).
25
+ * Hosts call it at bind time with `meta.apiVersion` and their own
26
+ * MODELER_API_VERSION; it lives in the package root so that check never
27
+ * pulls the conformance kit into a host bundle (`/conformance` re-exports it)
28
+ */
29
+ declare function apiVersionsCompatible(a: string, b: string): boolean;
22
30
  interface ModelerMeta {
23
31
  /** stable notation id, e.g. "wardley", "team-topology", "event-storming" */
24
32
  readonly notation: string;
@@ -47,11 +55,32 @@ interface ElementInfo {
47
55
  * `?element=` deep links to it, so an id that renumbers when a line is
48
56
  * inserted above (positional edge ids) breaks every anchor below it. An
49
57
  * element without an id in the text gets one the serializer WRITES BACK.
58
+ *
59
+ * The id a session reports IS the element's id in the document: after
60
+ * `exportText()` → `importText()` — in this instance or in any other one
61
+ * (a peer, the viewer, the next session) — the element carries the same
62
+ * id. An id that lives only in memory anchors nothing: the todo or deep
63
+ * link a host stored against it points nowhere once the text travels.
64
+ *
65
+ * RECOMMENDED: when two peers create different elements at the same time,
66
+ * their ids do not collide. An id allocated regardless of the content —
67
+ * a per-instance counter (`event_1` on both peers) — does: once both edits
68
+ * merge into one document, two elements share one id; random or
69
+ * peer-scoped ids do not. An id derived from the content (OWM's
70
+ * `component_<slug>`) collides only when both users create the same
71
+ * content, which the merge has to reconcile anyway.
50
72
  */
51
73
  id: string;
52
74
  /** human label, when the notation has one */
53
75
  name?: string;
54
76
  }
77
+ /** an element's box in diagram coordinates, as `ElementsSurface.bounds` reports it */
78
+ interface ElementBounds {
79
+ x: number;
80
+ y: number;
81
+ width: number;
82
+ height: number;
83
+ }
55
84
  /**
56
85
  * Optional element surface — what a host needs for anchored todos, `?element=`
57
86
  * deep links and the selection half of live presence. Absent = the notation
@@ -71,6 +100,22 @@ interface ElementsSurface {
71
100
  selection(): string[];
72
101
  /** selection changes as STABLE element ids; returns the unsubscribe */
73
102
  onSelection(cb: (ids: string[]) => void): () => void;
103
+ /**
104
+ * the element's box in DIAGRAM coordinates — the canvas's own coordinate
105
+ * space, which zoom and scroll leave alone (a host maps it to the screen
106
+ * with the current view, or draws in a layer that moves with the canvas) —
107
+ * or `undefined` for an id `list()` does not report. Optional (1.2): hosts
108
+ * feature-detect it for presence outlines and todo markers instead of
109
+ * reaching into the engine.
110
+ *
111
+ * It reads the LIVE canvas: an element created, moved, resized or renamed
112
+ * in this session has its current box at once, not the one of the last
113
+ * import — a host outlining a peer's selection would otherwise draw it
114
+ * where the element was, or not at all, until the next import. The box is
115
+ * the element's own shape (a connection: the box around its waypoints); an
116
+ * external label is not part of it.
117
+ */
118
+ bounds?(id: string): ElementBounds | undefined;
74
119
  }
75
120
  /**
76
121
  * The collaborative-modeler contract. The LAWS (verified by the conformance
@@ -80,6 +125,14 @@ interface ElementsSurface {
80
125
  * the undo history without emitting — also when history exists. Hosts
81
126
  * re-import remote states on every sync; an import echo would re-export
82
127
  * the canonical serialization over half-typed peer text.
128
+ * An interaction in progress when an import runs (an open label editor,
129
+ * a popup with typed input) never commits during or because of the
130
+ * import: no change event comes from it, its input lands neither in the
131
+ * imported document nor on its fresh undo history, and nothing is
132
+ * applied to an element the import removed. RECOMMENDED: keep the typed
133
+ * input and reopen the interaction on the element with the same id when
134
+ * that element is still there after the import — a remote re-import
135
+ * should not cost the user what they were typing.
83
136
  * L2 CANONICAL FIXPOINT — `exportText` is deterministic, and for any text t:
84
137
  * with c = exportText() after importText(t), importText(c) followed by
85
138
  * exportText() returns c byte-for-byte. Canonicalization is idempotent;
@@ -104,6 +157,15 @@ interface ElementsSurface {
104
157
  * readback may be a NORMALISED form of what was set (a diagram-js
105
158
  * viewbox comes back rounded, with scale/inner/outer) — what must hold
106
159
  * is that setting a readback yields that readback again.
160
+ * A view change the HOST makes — `setViewState`, or a fit its chrome
161
+ * applies to the canvas — never commits an interaction in progress (an
162
+ * open label editor, a popup with typed input): no change event, the
163
+ * export unchanged. Hosts restore the viewport after every remote
164
+ * re-import and refit when their chrome changes; a commit there writes
165
+ * the half-typed input into the shared document for every peer.
166
+ * RECOMMENDED: the interaction stays open with its typed input, so the
167
+ * user's own commit afterwards writes what it would have written without
168
+ * the view change.
107
169
  * L6 EXPORT IS TOTAL AFTER IMPORT — after a successful import (and any
108
170
  * sequence of user commands and undos), `exportText` succeeds. Foreign or
109
171
  * auxiliary content the modeler does not understand is PRESERVED through
@@ -111,9 +173,11 @@ interface ElementsSurface {
111
173
  * rest), never dropped and never a reason to throw.
112
174
  * L7 REJECTED IMPORTS LEAVE NO TRACE — `importText` on non-importable text
113
175
  * REJECTS (resolve-with-warnings means "imported, with notes"; rejection
114
- * means "nothing imported"): afterwards the previously imported document
115
- * is still rendered with its elements, `exportText` still returns it, no
116
- * change event has fired and the undo history is untouched.
176
+ * means "nothing imported"). This holds for EVERY rejection, whatever
177
+ * the input (a truncated or half-typed text included): afterwards the
178
+ * previously imported document is still rendered with its elements,
179
+ * `exportText` still returns it, no change event has fired and the undo
180
+ * history is untouched.
117
181
  * The modeler stays USABLE: the next valid import renders, the next user
118
182
  * command applies. Hosts re-import half-typed peer text on every sync —
119
183
  * "blank (or wedged) until healed" is not an acceptable failure mode.
@@ -125,10 +189,16 @@ interface CollaborativeModeler {
125
189
  readonly meta: ModelerMeta;
126
190
  /** mount the canvas into a host element (once, before the first import).
127
191
  * The host must be attached to the document with a non-zero size — a
128
- * detached or 0×0 element gives diagram-js engines NaN viewboxes */
192
+ * detached or 0×0 element gives diagram-js engines NaN viewboxes.
193
+ * Calls made between mounting and the first import (`exportText()`, a
194
+ * user command) return whatever the modeler defines, or throw (only
195
+ * `getViewState` never does, L5), but they never wedge the instance:
196
+ * the first `importText` still behaves exactly as specified */
129
197
  attachTo(host: Element): void;
130
198
  /** parse + render `text` — SILENT per L1, the view fitted to the content
131
- * per L5; resolves when rendered, REJECTS when nothing was imported (L7) */
199
+ * per L5; resolves when rendered, REJECTS when nothing was imported (L7).
200
+ * This holds for the first import too, whatever was called before it — a
201
+ * host may export or route a command before its first document arrives */
132
202
  importText(text: string): Promise<ImportResult>;
133
203
  /** the canonical serialization of the current document (L2, L6) */
134
204
  exportText(): string;
@@ -142,5 +212,80 @@ interface CollaborativeModeler {
142
212
  * behavior, but a second destroy() must not throw */
143
213
  destroy(): void;
144
214
  }
215
+ /** px the host's chrome covers along the edges of the modeler's container */
216
+ interface FreeAreaInsets {
217
+ top: number;
218
+ right: number;
219
+ bottom: number;
220
+ left: number;
221
+ }
222
+ /** a point in diagram coordinates */
223
+ interface DiagramPoint {
224
+ x: number;
225
+ y: number;
226
+ }
227
+ /**
228
+ * The FREE AREA: the part of the canvas no host chrome covers (Miragon
229
+ * guide §5.9). Keyboard creation places a new element in its centre (§5.5)
230
+ * and a renderer that constrains panning keeps the content reachable around
231
+ * it, so both agree with a host that fits into the same rectangle. A host
232
+ * passes ONE of two forms, each a function the renderer reads whenever it
233
+ * needs it (the chrome changes when an inspector or a legend opens):
234
+ *
235
+ * - `insets`: what the chrome covers, in px from the container's edges
236
+ * (the modeler shell's `shell.fitInsets()`); the renderer computes the
237
+ * centre itself, the way a fit does;
238
+ * - `center`: the centre itself, in diagram coordinates, `undefined` while
239
+ * there is none (a 0×0 container) — the shell's `viewport.freeRectCenter()`.
240
+ *
241
+ * A renderer accepts both. One that needs the rectangle itself (a pan
242
+ * constraint) and is given only `center` treats the whole container as
243
+ * free, as it does without the option.
244
+ */
245
+ type FreeArea = {
246
+ insets: () => FreeAreaInsets;
247
+ center?: never;
248
+ } | {
249
+ center: () => DiagramPoint | undefined;
250
+ insets?: never;
251
+ };
252
+ /**
253
+ * The options a renderer's contract factory takes under THESE names once it
254
+ * implements contract 1.2, so a host feeds every notation the same object
255
+ * instead of one spelling per renderer. A renderer extends the type with its
256
+ * own options (diagram-js `additionalModules`); the contract fixes names,
257
+ * meaning and defaults. A viewer factory takes the same type and ignores
258
+ * what has no meaning without editing (`undoRedoKeys`).
259
+ *
260
+ * Each renderer adopts them in its own release, as part of its move to 1.2:
261
+ * `meta.apiVersion` follows the pinned package and no kit case checks the
262
+ * options, so the version alone does not tell a host they are honoured.
263
+ * Until a renderer ships them, a host passes the renderer's own names, or
264
+ * both. Those names then stay accepted as DEPRECATED aliases for one minor
265
+ * release of that renderer, then go: `freeRectInsets` (Wardley, Event
266
+ * Storming, Context Maps) is `freeArea: { insets }`, `freeRectCenter` (Team
267
+ * Topologies, Value Chain) is `freeArea: { center }`, and Wardley's
268
+ * `keyboard: { undoRedo }` is `undoRedoKeys`. Given both, the aligned name
269
+ * wins.
270
+ */
271
+ interface CollaborativeModelerOptions {
272
+ /** where the host's chrome leaves the canvas free; default: the whole container */
273
+ freeArea?: FreeArea | undefined;
274
+ /**
275
+ * fit the content into the view after every import — default true, the
276
+ * fitted view L5 defines. A host whose chrome fits the content itself
277
+ * (the modeler shell's viewport fits into the free area) passes false:
278
+ * the post-import view is then the host's to set, and L5's fit is the
279
+ * host's fit. The conformance kit runs with the default
280
+ */
281
+ fitOnImport?: boolean | undefined;
282
+ /**
283
+ * bind Cmd/Ctrl+Z, Cmd/Ctrl+Shift+Z and Cmd/Ctrl+Y to the canvas history —
284
+ * default true. A host that owns the document's history (VS Code) passes
285
+ * false, and the keys reach it unprevented; text fields keep their own
286
+ * undo either way
287
+ */
288
+ undoRedoKeys?: boolean | undefined;
289
+ }
145
290
 
146
- export { type CollaborativeModeler, type ElementInfo, type ElementsSurface, type ImportResult, MODELER_API_VERSION, type ModelerMeta };
291
+ export { type CollaborativeModeler, type CollaborativeModelerOptions, type DiagramPoint, type ElementBounds, type ElementInfo, type ElementsSurface, type FreeArea, type FreeAreaInsets, type ImportResult, MODELER_API_VERSION, type ModelerMeta, apiVersionsCompatible };
package/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import {
2
- MODELER_API_VERSION
3
- } from "./chunk-HWB2EYDZ.js";
2
+ MODELER_API_VERSION,
3
+ apiVersionsCompatible
4
+ } from "./chunk-E6KJB7QH.js";
4
5
  export {
5
- MODELER_API_VERSION
6
+ MODELER_API_VERSION,
7
+ apiVersionsCompatible
6
8
  };
7
9
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miragon/modeler-api",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "ONE interface every Miragon modeler implements — the collaborative-modeler contract and its conformance test kit.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1,7 +0,0 @@
1
- // src/index.ts
2
- var MODELER_API_VERSION = "1.0.0";
3
-
4
- export {
5
- MODELER_API_VERSION
6
- };
7
- //# sourceMappingURL=chunk-HWB2EYDZ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @miragon/modeler-api — ONE interface every Miragon modeler implements.\n *\n * The contract encodes, as REQUIREMENTS, the behavioral drift that had to be\n * discovered per modeler against engine internals before it existed:\n * an `importDSL` that emitted change events (rewriting hand-authored files on\n * open), an import that left the undo stack on stale removed shapes, a\n * serializer that was not a byte fixpoint. A host embedding a conforming\n * modeler needs no per-engine suppression tricks — the laws below hold.\n *\n * The conformance test kit (`@miragon/modeler-api/conformance`) turns each\n * law into an executable case the modeler repo runs in its own CI.\n */\n\n/** the semver of THIS contract — a modeler declares the version it implements\n * in `meta.apiVersion`; hosts check compatibility with `apiVersionsCompatible`\n * (same major; while 0.x, the same minor too). The constant IS the\n * package version: release-please rewrites the literal below on every\n * release (release-please-config.json `extra-files`), and the kit's own\n * test pins it to package.json exactly. Modelers pin the npm package; the\n * constant is what travels in `meta`. */\nexport const MODELER_API_VERSION = \"1.0.0\"; // x-release-please-version\n\nexport interface ModelerMeta {\n /** stable notation id, e.g. \"wardley\", \"team-topology\", \"event-storming\" */\n readonly notation: string;\n /** the MODELER_API_VERSION this modeler implements — compatible when the\n * major matches and, while the contract is 0.x, the minor too (pre-1.0\n * minors may break: bump-minor-pre-major) */\n readonly apiVersion: string;\n /**\n * true on an editing mount (the package's Modeler), false on a VIEWER\n * (its NavigatedViewer/Viewer): a viewer never fires `onContentChanged`,\n * accepts no user commands, and still imports, exports, reveals and\n * reports view state exactly like the editor — hosts mount it on\n * read-only surfaces (an MCP-App widget in read-only mode) without\n * per-package knowledge or a command-stack shim.\n */\n readonly editable: boolean;\n}\n\nexport interface ImportResult {\n /** non-fatal notes from the import (unknown lines kept, migrations run) */\n warnings: string[];\n}\n\nexport interface ElementInfo {\n /**\n * stable element id — identical across re-imports of the same text AND\n * untouched by edits to OTHER elements: hosts anchor todos, presence and\n * `?element=` deep links to it, so an id that renumbers when a line is\n * inserted above (positional edge ids) breaks every anchor below it. An\n * element without an id in the text gets one the serializer WRITES BACK.\n */\n id: string;\n /** human label, when the notation has one */\n name?: string;\n}\n\n/**\n * Optional element surface — what a host needs for anchored todos, `?element=`\n * deep links and the selection half of live presence. Absent = the notation\n * has no addressable element identity. Ids are ELEMENT ids throughout: a\n * shape that only labels another element (diagram-js external labels) is\n * reported and revealed as its target, never under its own label id.\n */\nexport interface ElementsSurface {\n /** every addressable element currently on the canvas */\n list(): ElementInfo[];\n /** select + scroll the element into view; false when the id is unknown.\n * Revealing is view behavior: it delivers a selection, never a change event */\n reveal(id: string): boolean;\n /** the current selection as stable element ids — synchronous, so a host\n * can read it at the moment of a click (a deep link carrying the\n * selection) without caching every delivery */\n selection(): string[];\n /** selection changes as STABLE element ids; returns the unsubscribe */\n onSelection(cb: (ids: string[]) => void): () => void;\n}\n\n/**\n * The collaborative-modeler contract. The LAWS (verified by the conformance\n * kit) are part of the interface:\n *\n * L1 SILENT IMPORT — `importText` never fires `onContentChanged` and erases\n * the undo history without emitting — also when history exists. Hosts\n * re-import remote states on every sync; an import echo would re-export\n * the canonical serialization over half-typed peer text.\n * L2 CANONICAL FIXPOINT — `exportText` is deterministic, and for any text t:\n * with c = exportText() after importText(t), importText(c) followed by\n * exportText() returns c byte-for-byte. Canonicalization is idempotent;\n * opening a file never rewrites it.\n * L3 ONE CHANGE EVENT — every user-visible atomic change (element commands\n * AND config/axis/title/style edits that live in the document, AND\n * undo/redo) fires `onContentChanged` at least once, and nothing else\n * does: not `importText`, not undo-history housekeeping, not view or\n * selection changes. When a listener runs, `exportText()` ALREADY\n * returns the post-change serialization — hosts export inside the\n * listener; an emit-before-apply would lose the last edit.\n * L4 DEFINED UNDO ACROSS IMPORTS — undo directly after an `importText` is a\n * no-op: it must never mutate or resurrect shapes from the pre-import\n * document (id coincidence included).\n * L5 VIEW-STATE ROUND-TRIP — `getViewState`/`setViewState` survive a\n * re-import: snapshot before, restore after, viewport unchanged. An\n * import leaves the view FITTED to the content (the defined post-import\n * view, the same for the same document and host — a host that wants to\n * keep the user's viewport across a remote re-import snapshots before\n * and restores after); before the first import `getViewState()` returns\n * `undefined` or a state `setViewState` accepts, and never throws. The\n * readback may be a NORMALISED form of what was set (a diagram-js\n * viewbox comes back rounded, with scale/inner/outer) — what must hold\n * is that setting a readback yields that readback again.\n * L6 EXPORT IS TOTAL AFTER IMPORT — after a successful import (and any\n * sequence of user commands and undos), `exportText` succeeds. Foreign or\n * auxiliary content the modeler does not understand is PRESERVED through\n * import → export (it comes back in the export, canonicalised like the\n * rest), never dropped and never a reason to throw.\n * L7 REJECTED IMPORTS LEAVE NO TRACE — `importText` on non-importable text\n * REJECTS (resolve-with-warnings means \"imported, with notes\"; rejection\n * means \"nothing imported\"): afterwards the previously imported document\n * is still rendered with its elements, `exportText` still returns it, no\n * change event has fired and the undo history is untouched.\n * The modeler stays USABLE: the next valid import renders, the next user\n * command applies. Hosts re-import half-typed peer text on every sync —\n * \"blank (or wedged) until healed\" is not an acceptable failure mode.\n *\n * View state is NEVER part of the document: `setViewState` fires no change\n * events and `exportText` is independent of it.\n */\nexport interface CollaborativeModeler {\n readonly meta: ModelerMeta;\n\n /** mount the canvas into a host element (once, before the first import).\n * The host must be attached to the document with a non-zero size — a\n * detached or 0×0 element gives diagram-js engines NaN viewboxes */\n attachTo(host: Element): void;\n\n /** parse + render `text` — SILENT per L1, the view fitted to the content\n * per L5; resolves when rendered, REJECTS when nothing was imported (L7) */\n importText(text: string): Promise<ImportResult>;\n\n /** the canonical serialization of the current document (L2, L6) */\n exportText(): string;\n\n /** subscribe to user-visible model changes (L3); returns the unsubscribe */\n onContentChanged(cb: () => void): () => void;\n\n /** opaque viewport snapshot (zoom/scroll) — JSON-serializable (L5) */\n getViewState(): unknown;\n setViewState(state: unknown): void;\n\n readonly elements?: ElementsSurface;\n\n /** tear down DOM + listeners; further calls on the instance are undefined\n * behavior, but a second destroy() must not throw */\n destroy(): void;\n}\n"],"mappings":";AAqBO,IAAM,sBAAsB;","names":[]}