@hydranium/glsp-server 1.0.0-next.117 → 1.0.0-next.123

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.
Files changed (39) hide show
  1. package/lib/command/hydranium-glsp-recording-command.d.ts +1 -1
  2. package/lib/command/hydranium-glsp-recording-command.js +1 -1
  3. package/lib/messages/index.d.ts +1 -1
  4. package/lib/messages/index.d.ts.map +1 -1
  5. package/lib/messages/index.js +1 -1
  6. package/lib/messages/index.js.map +1 -1
  7. package/lib/state/abstract-hydranium-glsp-state.d.ts +52 -8
  8. package/lib/state/abstract-hydranium-glsp-state.d.ts.map +1 -1
  9. package/lib/state/abstract-hydranium-glsp-state.js +77 -5
  10. package/lib/state/abstract-hydranium-glsp-state.js.map +1 -1
  11. package/lib/state/full-text-hydranium-glsp-state.d.ts +4 -4
  12. package/lib/state/full-text-hydranium-glsp-state.d.ts.map +1 -1
  13. package/lib/state/full-text-hydranium-glsp-state.js +5 -10
  14. package/lib/state/full-text-hydranium-glsp-state.js.map +1 -1
  15. package/lib/state/reconcile-source-model-write.d.ts +2 -2
  16. package/lib/state/reconcile-source-model-write.d.ts.map +1 -1
  17. package/lib/state/reconcile-source-model-write.js +1 -1
  18. package/lib/state/reconcile-source-model-write.js.map +1 -1
  19. package/lib/state/reconciling-multi-document-glsp-state.d.ts +54 -74
  20. package/lib/state/reconciling-multi-document-glsp-state.d.ts.map +1 -1
  21. package/lib/state/reconciling-multi-document-glsp-state.js +77 -102
  22. package/lib/state/reconciling-multi-document-glsp-state.js.map +1 -1
  23. package/lib/state/reconciling-transfer-hydranium-glsp-state.d.ts +16 -15
  24. package/lib/state/reconciling-transfer-hydranium-glsp-state.d.ts.map +1 -1
  25. package/lib/state/reconciling-transfer-hydranium-glsp-state.js +21 -25
  26. package/lib/state/reconciling-transfer-hydranium-glsp-state.js.map +1 -1
  27. package/lib/storage/hydranium-glsp-storage.d.ts +103 -26
  28. package/lib/storage/hydranium-glsp-storage.d.ts.map +1 -1
  29. package/lib/storage/hydranium-glsp-storage.js +199 -32
  30. package/lib/storage/hydranium-glsp-storage.js.map +1 -1
  31. package/package.json +7 -7
  32. package/src/command/hydranium-glsp-recording-command.ts +1 -1
  33. package/src/messages/index.ts +6 -1
  34. package/src/state/abstract-hydranium-glsp-state.ts +85 -8
  35. package/src/state/full-text-hydranium-glsp-state.ts +5 -10
  36. package/src/state/reconcile-source-model-write.ts +3 -3
  37. package/src/state/reconciling-multi-document-glsp-state.ts +78 -103
  38. package/src/state/reconciling-transfer-hydranium-glsp-state.ts +21 -25
  39. package/src/storage/hydranium-glsp-storage.ts +236 -33
@@ -8,6 +8,7 @@
8
8
  ********************************************************************************/
9
9
  import { type JsonModelState } from '@eclipse-glsp/server';
10
10
  import { type AstNode } from '@hydranium/langium';
11
+ import { type ClientSession } from '@hydranium/core';
11
12
  import { type BasedOn, type TransferElement } from '@hydranium/protocol';
12
13
  import { AbstractHydraniumGlspState } from './abstract-hydranium-glsp-state.js';
13
14
  /**
@@ -39,44 +40,30 @@ export interface MultiDocumentSourceModel<TPrimary extends TransferElement = Tra
39
40
  * defines them over the primary plus the secondary write set registered through
40
41
  * {@link AbstractHydraniumGlspState.trackSecondaryDocument}.
41
42
  *
42
- * **Writes are NOT atomic, deliberately, and the window is real.** Each document
43
- * goes through its own `ModelService.update`, so a failure after the first write
44
- * has landed leaves the set inconsistent on disk. There is no multi-document
45
- * transaction to lean on: `WorkspaceLock` serialises builds but does not roll
46
- * back, and the document store commits per URI. An adopter that cannot accept the
47
- * window should not span documents in one operation.
43
+ * **The write set is written all or none.** {@link persist} hands every
44
+ * changed document to one `ClientSession.updateAll` on the diagram's session,
45
+ * so a conflict on any document leaves every document of the set as it was,
46
+ * and write order carries no meaning.
48
47
  *
49
- * **What makes the window tolerable is write ORDER, and the rule is
50
- * referenced-before-referencing** — not "secondaries first" as such. Write the
51
- * document whose content the others point AT before the documents that point at
52
- * it, so a partial write leaves an unreferenced element (inert, and the direction
53
- * an integrity rule can repair) rather than a reference to something that does
54
- * not exist (a linking error). {@link persist} implements that as
55
- * secondaries-then-primary, which is correct for the common shape where the
56
- * primary is the DIAGRAM and the semantics it references are secondaries: the
57
- * user opened the diagram, so it is also the document the conflict gate should
58
- * guard. **An adopter whose primary is the referenced document — a semantic file
59
- * as the diagram source, with layout in a secondary — has the ordering backwards
60
- * and must override {@link persist} to write the primary first.** Overriding it
61
- * is the supported route; the base order is a default for the common case, not an
62
- * invariant of the class.
48
+ * **Every document of the set is gated.** The primary on the caller's
49
+ * `basedOn`, each secondary on {@link secondaryBasedOn}, by default the version
50
+ * it had when the source root was last read. A conflict on any of them is
51
+ * reconciled against the whole write set. A write based on `'anything'` — a
52
+ * merged retry, an undo or redo replaying a patch — forces every document of
53
+ * the set.
63
54
  *
64
- * **The conflict gate covers the primary only.** Secondaries are written without
65
- * a based-on version, so a concurrent foreign edit to one is overwritten rather
66
- * than reconciled. Gating them too would need a per-document reconcile whose
67
- * outcomes can disagree (merge one, conflict another) with no way to un-write the
68
- * merged one — the atomicity problem again, one layer up. An adopter that wants
69
- * a coarser check overrides {@link secondaryBasedOn} to return the version
70
- * {@link AbstractHydraniumGlspState.snapshotVersionOf} already holds, and takes
71
- * on the partial-write window named there.
55
+ * A secondary is written only while the diagram's session has it open. The
56
+ * storage opens it as it joins the write set, and {@link openForWrite} opens it
57
+ * again before each write; an adopter whose write set can name a document that
58
+ * does not exist yet overrides {@link openForWrite} to create it.
72
59
  */
73
60
  export declare class ReconcilingMultiDocumentGlspState<TRoot extends AstNode, TPrimary extends TransferElement = TransferElement> extends AbstractHydraniumGlspState<TRoot, MultiDocumentSourceModel<TPrimary>> implements JsonModelState<MultiDocumentSourceModel<TPrimary>> {
74
61
  /**
75
62
  * Last in-sync projection across the whole write set, captured on every
76
- * {@link setSourceRoot}. Same role as the single-document baseline: the state a
63
+ * {@link setSourceRoot}. Same role as the single-document base: the state a
77
64
  * forward-write conflict reconciles the user's intent against.
78
65
  */
79
- protected baseline?: MultiDocumentSourceModel<TPrimary>;
66
+ protected base?: MultiDocumentSourceModel<TPrimary>;
80
67
  /**
81
68
  * Projection of the primary plus every registered secondary, in the framework
82
69
  * encoder's `'grammar'` mode (authored state only — cross-references as
@@ -94,14 +81,14 @@ export declare class ReconcilingMultiDocumentGlspState<TRoot extends AstNode, TP
94
81
  * Register the secondary documents that belong to the primary at `uri`, via
95
82
  * {@link AbstractHydraniumGlspState.trackSecondaryDocument}. Called on every
96
83
  * {@link setSourceRoot}, after the primary is captured (so `sourceUri` is
97
- * current) and BEFORE the baseline is taken (so the baseline includes them).
84
+ * current) and BEFORE the base is taken (so the base includes them).
98
85
  * Default: no secondaries.
99
86
  *
100
87
  * This hook exists because that ordering is a trap an adopter would otherwise
101
88
  * hit silently. Registering from an overridden `setSourceRoot` *after*
102
- * `super.setSourceRoot(...)` runs too late — the baseline has already been
89
+ * `super.setSourceRoot(...)` runs too late — the base has already been
103
90
  * captured without the secondaries, so the first conflict reconcile measures
104
- * the user's intent against a baseline missing half the write set and the
91
+ * the user's intent against a base missing half the write set and the
105
92
  * secondary edits look like foreign changes. Registering *before* the super
106
93
  * call is too early for a URI derived from the new primary. Overriding this
107
94
  * instead removes the choice.
@@ -109,68 +96,61 @@ export declare class ReconcilingMultiDocumentGlspState<TRoot extends AstNode, TP
109
96
  protected trackWriteSet(_uri: string): void;
110
97
  /**
111
98
  * Persist the whole write set, then capture the resulting primary root. On a
112
- * `ConflictError` from the primary, reconcile via the injected policy exactly
113
- * as the single-document state does — the orchestration is shared.
99
+ * `ConflictError` from any document of the set, reconcile via the injected
100
+ * policy exactly as the single-document state does — the orchestration is
101
+ * shared.
114
102
  */
115
103
  updateSourceModel(model: MultiDocumentSourceModel<TPrimary>, basedOn?: BasedOn): Promise<void>;
116
104
  /**
117
- * Write hook — secondaries first (ungated), primary last (gated on
118
- * `basedOn`). The order is the failure-mode choice documented on the
119
- * class, not incidental: override this when the primary is the document the
120
- * others REFERENCE, since then this order writes the references first.
105
+ * Write hook — every document of `model` that changed, opened first through
106
+ * {@link openForWrite}, in one `updateAll` on the diagram's session: the
107
+ * primary gated on `basedOn`, each secondary on {@link secondaryBasedOn}, or
108
+ * every document on `'anything'` when `basedOn` is `'anything'`. Resolves to
109
+ * the primary's root, the one already captured when the primary did not
110
+ * change. A write that bypasses `updateAll` gives up the all-or-none
111
+ * guarantee the class describes. Throws without a session
112
+ * ({@link requireModelSession}).
121
113
  */
122
114
  protected persist(model: MultiDocumentSourceModel<TPrimary>, basedOn: BasedOn): Promise<{
123
115
  root: TRoot;
124
116
  }>;
125
117
  /**
126
- * Whether `candidate` differs from the baseline projection of the same
118
+ * Whether `candidate` differs from the base projection of the same
127
119
  * document, and therefore needs writing.
128
120
  *
129
121
  * **Skipping unchanged documents is correctness, not an optimisation.** A
130
- * write goes through `ModelService.update`, which re-serializes from the AST —
131
- * so writing a document that did not change still rewrites its text in the
132
- * serializer's own layout. Persisting the whole write set unconditionally
133
- * therefore means a pure layout drag reflows the semantic file, a change the
134
- * user never asked for and would struggle to attribute. Comments survive that
135
- * rewrite, but the hand-formatting around them does not.
122
+ * write re-serializes from the AST, so writing a document that did not
123
+ * change still rewrites its text in the serializer's own layout. Persisting
124
+ * the whole write set unconditionally therefore means a pure layout drag
125
+ * reflows the semantic file, a change the user never asked for and would
126
+ * struggle to attribute. Comments survive that rewrite, but the
127
+ * hand-formatting around them does not.
136
128
  *
137
129
  * Compared by serialised form. Both sides come from the same encoder walking
138
130
  * the same shape, so key order is stable and a string compare is sound here;
139
131
  * it is also cheap enough to run per document per write.
140
132
  */
141
- protected hasChanged(baseline: object | undefined, candidate: object): boolean;
142
- /** Write the primary document, opting into the conflict gate unless `basedOn` is `'anything'`. */
143
- protected persistPrimary(model: TPrimary, basedOn: BasedOn): Promise<{
144
- root: TRoot;
145
- }>;
133
+ protected hasChanged(base: object | undefined, candidate: object): boolean;
146
134
  /**
147
- * Write one secondary document, gated on whatever {@link secondaryBasedOn}
148
- * returns. Override alongside {@link persistPrimary} when the round-trip
149
- * differs per document role — a layout file and a semantic file need not
150
- * share a serializer.
135
+ * Make sure the diagram's session has `uri` open before the write set is
136
+ * written. Default: open it, a no-op for a document the session already
137
+ * has open. Override to create a document the write set names before it
138
+ * exists, through `session.create`: `updateAll` opens nothing.
151
139
  */
152
- protected persistSecondary(uri: string, model: TransferElement): Promise<void>;
140
+ protected openForWrite(session: ClientSession<AstNode>, uri: string): Promise<void>;
153
141
  /**
154
- * What a secondary write declares it was based on. Default `'anything'` —
155
- * ungated, because gating the whole set needs a per-document reconcile whose
156
- * outcomes can disagree, with no way to un-write an already-merged sibling.
157
- *
158
- * **The hook exists so that opting in is an override rather than a
159
- * reimplementation.** The state already holds what such a check needs
160
- * ({@link AbstractHydraniumGlspState.snapshotVersionOf}), and returning that
161
- * value here is the whole opt-in; without it the only place to put the
162
- * comparison is a copy of {@link persistSecondary}, which then has to be kept
163
- * in step with the framework's write call.
164
- *
165
- * **Opting in buys a conflict report and costs atomicity.** A gated secondary
166
- * throws mid-set, after earlier secondaries have already been written, and if
167
- * the reconcile then drops the edit those writes stay. Weigh that against the
168
- * default, which lets a foreign edit to a secondary be overwritten silently.
142
+ * What a secondary write declares it was based on. Default: the version the
143
+ * secondary had when the source root was last read
144
+ * ({@link AbstractHydraniumGlspState.snapshotVersionOf}), so a foreign edit
145
+ * to it since is reported as a conflict and reconciled rather than
146
+ * overwritten; `'anything'` for a secondary with no recorded version.
147
+ * Return `'anything'` to force secondary writes.
169
148
  */
170
- protected secondaryBasedOn(_uri: string): BasedOn;
149
+ protected secondaryBasedOn(uri: string): BasedOn;
171
150
  /**
172
- * Refetch hook — the current settled projection across the write set, used by
173
- * the conflict resolver to replay the user's intent against fresh state.
151
+ * Refetch hook — the current projection across the write set, each document
152
+ * read through {@link AbstractHydraniumGlspState.readCurrentRoot}: theirs,
153
+ * which the conflict resolver replays the user's intent onto.
174
154
  * Returns `undefined` when the PRIMARY cannot be read, since a reconcile
175
155
  * without it has nothing to merge into; an unreadable secondary is omitted the
176
156
  * same way {@link sourceModel} omits one.
@@ -1 +1 @@
1
- {"version":3,"file":"reconciling-multi-document-glsp-state.d.ts","sourceRoot":"","sources":["../../src/state/reconciling-multi-document-glsp-state.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAGhF;;;;;;;;;GASG;AACH,MAAM,WAAW,wBAAwB,CAAC,QAAQ,SAAS,eAAe,GAAG,eAAe;IACzF,gFAAgF;IAChF,OAAO,EAAE,QAAQ,CAAC;IAClB,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CAC/C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,qBACa,iCAAiC,CAAC,KAAK,SAAS,OAAO,EAAE,QAAQ,SAAS,eAAe,GAAG,eAAe,CACrH,SAAQ,0BAA0B,CAAC,KAAK,EAAE,wBAAwB,CAAC,QAAQ,CAAC,CAC5E,YAAW,cAAc,CAAC,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IAE7D;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,EAAE,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IAExD;;;;;;;;;;OAUG;IACH,IAAI,WAAW,IAAI,wBAAwB,CAAC,QAAQ,CAAC,CASpD;IAEQ,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG,IAAI;IAMtD;;;;;;;;;;;;;;;OAeG;IACH,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI3C;;;;OAIG;IACG,iBAAiB,CAAC,KAAK,EAAE,wBAAwB,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAE,OAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAclH;;;;;OAKG;cACa,OAAO,CAAC,KAAK,EAAE,wBAAwB,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE,CAAC;IAc9G;;;;;;;;;;;;;;;OAeG;IACH,SAAS,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAI9E,kGAAkG;cAClF,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE,CAAC;IAU3F;;;;;OAKG;cACa,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IASpF;;;;;;;;;;;;;;;;OAgBG;IACH,SAAS,CAAC,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIjD;;;;;;OAMG;cACa,OAAO,IAAI,OAAO,CAAC,wBAAwB,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC;IAelF,wFAAwF;IACxF,SAAS,CAAC,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAKnE,oFAAoF;IACpF,SAAS,CAAC,WAAW,CAAC,CAAC,SAAS,eAAe,GAAG,eAAe,EAAE,IAAI,EAAE,OAAO,GAAG,CAAC;CAGtF"}
1
+ {"version":3,"file":"reconciling-multi-document-glsp-state.d.ts","sourceRoot":"","sources":["../../src/state/reconciling-multi-document-glsp-state.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,KAAK,aAAa,EAA+B,MAAM,iBAAiB,CAAC;AAClF,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAGhF;;;;;;;;;GASG;AACH,MAAM,WAAW,wBAAwB,CAAC,QAAQ,SAAS,eAAe,GAAG,eAAe;IACzF,gFAAgF;IAChF,OAAO,EAAE,QAAQ,CAAC;IAClB,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CAC/C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,qBACa,iCAAiC,CAAC,KAAK,SAAS,OAAO,EAAE,QAAQ,SAAS,eAAe,GAAG,eAAe,CACrH,SAAQ,0BAA0B,CAAC,KAAK,EAAE,wBAAwB,CAAC,QAAQ,CAAC,CAC5E,YAAW,cAAc,CAAC,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IAE7D;;;;OAIG;IACH,SAAS,CAAC,IAAI,CAAC,EAAE,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IAEpD;;;;;;;;;;OAUG;IACH,IAAI,WAAW,IAAI,wBAAwB,CAAC,QAAQ,CAAC,CASpD;IAEQ,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG,IAAI;IAMtD;;;;;;;;;;;;;;;OAeG;IACH,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI3C;;;;;OAKG;IACG,iBAAiB,CAAC,KAAK,EAAE,wBAAwB,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAE,OAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAclH;;;;;;;;;OASG;cACa,OAAO,CAAC,KAAK,EAAE,wBAAwB,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE,CAAC;IAqB9G;;;;;;;;;;;;;;;OAeG;IACH,SAAS,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAI1E;;;;;OAKG;IACH,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAInF;;;;;;;OAOG;IACH,SAAS,CAAC,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIhD;;;;;;;OAOG;cACa,OAAO,IAAI,OAAO,CAAC,wBAAwB,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC;IAelF,wFAAwF;IACxF,SAAS,CAAC,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAKnE,oFAAoF;IACpF,SAAS,CAAC,WAAW,CAAC,CAAC,SAAS,eAAe,GAAG,eAAe,EAAE,IAAI,EAAE,OAAO,GAAG,CAAC;CAGtF"}
@@ -28,44 +28,30 @@ import { reconcileSourceModelWrite } from './reconcile-source-model-write.js';
28
28
  * defines them over the primary plus the secondary write set registered through
29
29
  * {@link AbstractHydraniumGlspState.trackSecondaryDocument}.
30
30
  *
31
- * **Writes are NOT atomic, deliberately, and the window is real.** Each document
32
- * goes through its own `ModelService.update`, so a failure after the first write
33
- * has landed leaves the set inconsistent on disk. There is no multi-document
34
- * transaction to lean on: `WorkspaceLock` serialises builds but does not roll
35
- * back, and the document store commits per URI. An adopter that cannot accept the
36
- * window should not span documents in one operation.
31
+ * **The write set is written all or none.** {@link persist} hands every
32
+ * changed document to one `ClientSession.updateAll` on the diagram's session,
33
+ * so a conflict on any document leaves every document of the set as it was,
34
+ * and write order carries no meaning.
37
35
  *
38
- * **What makes the window tolerable is write ORDER, and the rule is
39
- * referenced-before-referencing** — not "secondaries first" as such. Write the
40
- * document whose content the others point AT before the documents that point at
41
- * it, so a partial write leaves an unreferenced element (inert, and the direction
42
- * an integrity rule can repair) rather than a reference to something that does
43
- * not exist (a linking error). {@link persist} implements that as
44
- * secondaries-then-primary, which is correct for the common shape where the
45
- * primary is the DIAGRAM and the semantics it references are secondaries: the
46
- * user opened the diagram, so it is also the document the conflict gate should
47
- * guard. **An adopter whose primary is the referenced document — a semantic file
48
- * as the diagram source, with layout in a secondary — has the ordering backwards
49
- * and must override {@link persist} to write the primary first.** Overriding it
50
- * is the supported route; the base order is a default for the common case, not an
51
- * invariant of the class.
36
+ * **Every document of the set is gated.** The primary on the caller's
37
+ * `basedOn`, each secondary on {@link secondaryBasedOn}, by default the version
38
+ * it had when the source root was last read. A conflict on any of them is
39
+ * reconciled against the whole write set. A write based on `'anything'` — a
40
+ * merged retry, an undo or redo replaying a patch — forces every document of
41
+ * the set.
52
42
  *
53
- * **The conflict gate covers the primary only.** Secondaries are written without
54
- * a based-on version, so a concurrent foreign edit to one is overwritten rather
55
- * than reconciled. Gating them too would need a per-document reconcile whose
56
- * outcomes can disagree (merge one, conflict another) with no way to un-write the
57
- * merged one — the atomicity problem again, one layer up. An adopter that wants
58
- * a coarser check overrides {@link secondaryBasedOn} to return the version
59
- * {@link AbstractHydraniumGlspState.snapshotVersionOf} already holds, and takes
60
- * on the partial-write window named there.
43
+ * A secondary is written only while the diagram's session has it open. The
44
+ * storage opens it as it joins the write set, and {@link openForWrite} opens it
45
+ * again before each write; an adopter whose write set can name a document that
46
+ * does not exist yet overrides {@link openForWrite} to create it.
61
47
  */
62
48
  let ReconcilingMultiDocumentGlspState = class ReconcilingMultiDocumentGlspState extends AbstractHydraniumGlspState {
63
49
  /**
64
50
  * Last in-sync projection across the whole write set, captured on every
65
- * {@link setSourceRoot}. Same role as the single-document baseline: the state a
51
+ * {@link setSourceRoot}. Same role as the single-document base: the state a
66
52
  * forward-write conflict reconciles the user's intent against.
67
53
  */
68
- baseline;
54
+ base;
69
55
  /**
70
56
  * Projection of the primary plus every registered secondary, in the framework
71
57
  * encoder's `'grammar'` mode (authored state only — cross-references as
@@ -90,20 +76,20 @@ let ReconcilingMultiDocumentGlspState = class ReconcilingMultiDocumentGlspState
90
76
  setSourceRoot(uri, root) {
91
77
  super.setSourceRoot(uri, root);
92
78
  this.trackWriteSet(uri);
93
- this.baseline = this.sourceModel;
79
+ this.base = this.sourceModel;
94
80
  }
95
81
  /**
96
82
  * Register the secondary documents that belong to the primary at `uri`, via
97
83
  * {@link AbstractHydraniumGlspState.trackSecondaryDocument}. Called on every
98
84
  * {@link setSourceRoot}, after the primary is captured (so `sourceUri` is
99
- * current) and BEFORE the baseline is taken (so the baseline includes them).
85
+ * current) and BEFORE the base is taken (so the base includes them).
100
86
  * Default: no secondaries.
101
87
  *
102
88
  * This hook exists because that ordering is a trap an adopter would otherwise
103
89
  * hit silently. Registering from an overridden `setSourceRoot` *after*
104
- * `super.setSourceRoot(...)` runs too late — the baseline has already been
90
+ * `super.setSourceRoot(...)` runs too late — the base has already been
105
91
  * captured without the secondaries, so the first conflict reconcile measures
106
- * the user's intent against a baseline missing half the write set and the
92
+ * the user's intent against a base missing half the write set and the
107
93
  * secondary edits look like foreign changes. Registering *before* the super
108
94
  * call is too early for a URI derived from the new primary. Overriding this
109
95
  * instead removes the choice.
@@ -113,8 +99,9 @@ let ReconcilingMultiDocumentGlspState = class ReconcilingMultiDocumentGlspState
113
99
  }
114
100
  /**
115
101
  * Persist the whole write set, then capture the resulting primary root. On a
116
- * `ConflictError` from the primary, reconcile via the injected policy exactly
117
- * as the single-document state does — the orchestration is shared.
102
+ * `ConflictError` from any document of the set, reconcile via the injected
103
+ * policy exactly as the single-document state does — the orchestration is
104
+ * shared.
118
105
  */
119
106
  async updateSourceModel(model, basedOn = this.basedOn) {
120
107
  return reconcileSourceModelWrite(model, basedOn, {
@@ -123,114 +110,102 @@ let ReconcilingMultiDocumentGlspState = class ReconcilingMultiDocumentGlspState
123
110
  this.setSourceRoot(this._sourceUri, root);
124
111
  },
125
112
  refetch: () => this.refetch(),
126
- baseline: this.baseline,
113
+ base: this.base,
127
114
  conflictResolver: this.conflictResolver,
128
115
  logger: this.logger,
129
116
  onConflictDropped: () => this.refreshSourceRoot()
130
117
  });
131
118
  }
132
119
  /**
133
- * Write hook — secondaries first (ungated), primary last (gated on
134
- * `basedOn`). The order is the failure-mode choice documented on the
135
- * class, not incidental: override this when the primary is the document the
136
- * others REFERENCE, since then this order writes the references first.
120
+ * Write hook — every document of `model` that changed, opened first through
121
+ * {@link openForWrite}, in one `updateAll` on the diagram's session: the
122
+ * primary gated on `basedOn`, each secondary on {@link secondaryBasedOn}, or
123
+ * every document on `'anything'` when `basedOn` is `'anything'`. Resolves to
124
+ * the primary's root, the one already captured when the primary did not
125
+ * change. A write that bypasses `updateAll` gives up the all-or-none
126
+ * guarantee the class describes. Throws without a session
127
+ * ({@link requireModelSession}).
137
128
  */
138
129
  async persist(model, basedOn) {
130
+ const primaryChanged = this.hasChanged(this.base?.primary, model.primary);
131
+ const updates = primaryChanged
132
+ ? [{ uri: this._sourceUri, model: model.primary, basedOn }]
133
+ : [];
139
134
  for (const [uri, secondary] of Object.entries(model.secondaries)) {
140
- if (this.hasChanged(this.baseline?.secondaries[uri], secondary)) {
141
- await this.persistSecondary(uri, secondary);
135
+ if (this.hasChanged(this.base?.secondaries[uri], secondary)) {
136
+ updates.push({ uri, model: secondary, basedOn: basedOn === 'anything' ? 'anything' : this.secondaryBasedOn(uri) });
142
137
  }
143
138
  }
144
- if (!this.hasChanged(this.baseline?.primary, model.primary)) {
145
- // Nothing to write, so nothing to gate either — return the root already
146
- // captured rather than round-tripping the document for no reason.
139
+ if (updates.length === 0) {
147
140
  return { root: this._sourceRoot };
148
141
  }
149
- return this.persistPrimary(model.primary, basedOn);
142
+ const session = this.requireModelSession();
143
+ for (const update of updates) {
144
+ await this.openForWrite(session, update.uri);
145
+ }
146
+ const documents = await session.updateAll({ updates });
147
+ return { root: primaryChanged ? documents[0].root : this._sourceRoot };
150
148
  }
151
149
  /**
152
- * Whether `candidate` differs from the baseline projection of the same
150
+ * Whether `candidate` differs from the base projection of the same
153
151
  * document, and therefore needs writing.
154
152
  *
155
153
  * **Skipping unchanged documents is correctness, not an optimisation.** A
156
- * write goes through `ModelService.update`, which re-serializes from the AST —
157
- * so writing a document that did not change still rewrites its text in the
158
- * serializer's own layout. Persisting the whole write set unconditionally
159
- * therefore means a pure layout drag reflows the semantic file, a change the
160
- * user never asked for and would struggle to attribute. Comments survive that
161
- * rewrite, but the hand-formatting around them does not.
154
+ * write re-serializes from the AST, so writing a document that did not
155
+ * change still rewrites its text in the serializer's own layout. Persisting
156
+ * the whole write set unconditionally therefore means a pure layout drag
157
+ * reflows the semantic file, a change the user never asked for and would
158
+ * struggle to attribute. Comments survive that rewrite, but the
159
+ * hand-formatting around them does not.
162
160
  *
163
161
  * Compared by serialised form. Both sides come from the same encoder walking
164
162
  * the same shape, so key order is stable and a string compare is sound here;
165
163
  * it is also cheap enough to run per document per write.
166
164
  */
167
- hasChanged(baseline, candidate) {
168
- return baseline === undefined || JSON.stringify(baseline) !== JSON.stringify(candidate);
169
- }
170
- /** Write the primary document, opting into the conflict gate unless `basedOn` is `'anything'`. */
171
- async persistPrimary(model, basedOn) {
172
- const document = await this.sharedServices.model.ModelService.update({
173
- uri: this._sourceUri,
174
- model,
175
- clientId: this.clientId,
176
- basedOn
177
- });
178
- return document;
165
+ hasChanged(base, candidate) {
166
+ return base === undefined || JSON.stringify(base) !== JSON.stringify(candidate);
179
167
  }
180
168
  /**
181
- * Write one secondary document, gated on whatever {@link secondaryBasedOn}
182
- * returns. Override alongside {@link persistPrimary} when the round-trip
183
- * differs per document role — a layout file and a semantic file need not
184
- * share a serializer.
169
+ * Make sure the diagram's session has `uri` open before the write set is
170
+ * written. Default: open it, a no-op for a document the session already
171
+ * has open. Override to create a document the write set names before it
172
+ * exists, through `session.create`: `updateAll` opens nothing.
185
173
  */
186
- async persistSecondary(uri, model) {
187
- await this.sharedServices.model.ModelService.update({
188
- uri,
189
- model,
190
- clientId: this.clientId,
191
- basedOn: this.secondaryBasedOn(uri)
192
- });
174
+ openForWrite(session, uri) {
175
+ return session.open(uri);
193
176
  }
194
177
  /**
195
- * What a secondary write declares it was based on. Default `'anything'` —
196
- * ungated, because gating the whole set needs a per-document reconcile whose
197
- * outcomes can disagree, with no way to un-write an already-merged sibling.
198
- *
199
- * **The hook exists so that opting in is an override rather than a
200
- * reimplementation.** The state already holds what such a check needs
201
- * ({@link AbstractHydraniumGlspState.snapshotVersionOf}), and returning that
202
- * value here is the whole opt-in; without it the only place to put the
203
- * comparison is a copy of {@link persistSecondary}, which then has to be kept
204
- * in step with the framework's write call.
205
- *
206
- * **Opting in buys a conflict report and costs atomicity.** A gated secondary
207
- * throws mid-set, after earlier secondaries have already been written, and if
208
- * the reconcile then drops the edit those writes stay. Weigh that against the
209
- * default, which lets a foreign edit to a secondary be overwritten silently.
178
+ * What a secondary write declares it was based on. Default: the version the
179
+ * secondary had when the source root was last read
180
+ * ({@link AbstractHydraniumGlspState.snapshotVersionOf}), so a foreign edit
181
+ * to it since is reported as a conflict and reconciled rather than
182
+ * overwritten; `'anything'` for a secondary with no recorded version.
183
+ * Return `'anything'` to force secondary writes.
210
184
  */
211
- secondaryBasedOn(_uri) {
212
- return 'anything';
185
+ secondaryBasedOn(uri) {
186
+ return this.snapshotVersionOf(uri) ?? 'anything';
213
187
  }
214
188
  /**
215
- * Refetch hook — the current settled projection across the write set, used by
216
- * the conflict resolver to replay the user's intent against fresh state.
189
+ * Refetch hook — the current projection across the write set, each document
190
+ * read through {@link AbstractHydraniumGlspState.readCurrentRoot}: theirs,
191
+ * which the conflict resolver replays the user's intent onto.
217
192
  * Returns `undefined` when the PRIMARY cannot be read, since a reconcile
218
193
  * without it has nothing to merge into; an unreadable secondary is omitted the
219
194
  * same way {@link sourceModel} omits one.
220
195
  */
221
196
  async refetch() {
222
- const fresh = await this.sharedServices.model.ModelService.validated(this._sourceUri).catch(() => undefined);
223
- if (!fresh) {
197
+ const theirs = await this.readCurrentRoot(this._sourceUri);
198
+ if (!theirs) {
224
199
  return undefined;
225
200
  }
226
201
  const secondaries = {};
227
202
  for (const uri of this.secondaryUris) {
228
- const settled = await this.sharedServices.model.ModelService.validated(uri).catch(() => undefined);
229
- if (settled) {
230
- secondaries[uri] = this.projectRoot(settled.root);
203
+ const root = await this.readCurrentRoot(uri);
204
+ if (root) {
205
+ secondaries[uri] = this.projectRoot(root);
231
206
  }
232
207
  }
233
- return { primary: this.projectRoot(fresh.root), secondaries };
208
+ return { primary: this.projectRoot(theirs), secondaries };
234
209
  }
235
210
  /** Project a currently-loaded document's root, or `undefined` when it is not loaded. */
236
211
  projectDocument(uri) {
@@ -1 +1 @@
1
- {"version":3,"file":"reconciling-multi-document-glsp-state.js","sourceRoot":"","sources":["../../src/state/reconciling-multi-document-glsp-state.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;;;;;;;AAGlF,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvC,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAChF,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAmB9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEI,IAAM,iCAAiC,GAAvC,MAAM,iCACV,SAAQ,0BAAqE;IAG7E;;;;OAIG;IACO,QAAQ,CAAsC;IAExD;;;;;;;;;;OAUG;IACH,IAAI,WAAW;QACZ,MAAM,WAAW,GAAoC,EAAE,CAAC;QACxD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACpC,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;YAC7C,IAAI,UAAU,EAAE,CAAC;gBACd,WAAW,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC;YACjC,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC;IACvE,CAAC;IAEQ,aAAa,CAAC,GAAW,EAAE,IAAW;QAC5C,KAAK,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC;IACpC,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACO,aAAa,CAAC,IAAY;QACjC,wDAAwD;IAC3D,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,iBAAiB,CAAC,KAAyC,EAAE,UAAmB,IAAI,CAAC,OAAO;QAC/F,OAAO,yBAAyB,CAAqC,KAAK,EAAE,OAAO,EAAE;YAClF,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,EAAE;gBAC5C,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;gBACjE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;YAC7C,CAAC;YACD,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE;YAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,iBAAiB,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,iBAAiB,EAAE;SACnD,CAAC,CAAC;IACN,CAAC;IAED;;;;;OAKG;IACO,KAAK,CAAC,OAAO,CAAC,KAAyC,EAAE,OAAgB;QAChF,KAAK,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;YAChE,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC;gBAC/D,MAAM,IAAI,CAAC,gBAAgB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YAC/C,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3D,wEAAwE;YACxE,kEAAkE;YAClE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC;QACrC,CAAC;QACD,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACtD,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACO,UAAU,CAAC,QAA4B,EAAE,SAAiB;QACjE,OAAO,QAAQ,KAAK,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IAC3F,CAAC;IAED,kGAAkG;IACxF,KAAK,CAAC,cAAc,CAAC,KAAe,EAAE,OAAgB;QAC7D,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC;YAClE,GAAG,EAAE,IAAI,CAAC,UAAU;YACpB,KAAK;YACL,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,OAAO;SACT,CAAC,CAAC;QACH,OAAO,QAAsC,CAAC;IACjD,CAAC;IAED;;;;;OAKG;IACO,KAAK,CAAC,gBAAgB,CAAC,GAAW,EAAE,KAAsB;QACjE,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC;YACjD,GAAG;YACH,KAAK;YACL,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,OAAO,EAAE,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC;SACrC,CAAC,CAAC;IACN,CAAC;IAED;;;;;;;;;;;;;;;;OAgBG;IACO,gBAAgB,CAAC,IAAY;QACpC,OAAO,UAAU,CAAC;IACrB,CAAC;IAED;;;;;;OAMG;IACO,KAAK,CAAC,OAAO;QACpB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC7G,IAAI,CAAC,KAAK,EAAE,CAAC;YACV,OAAO,SAAS,CAAC;QACpB,CAAC;QACD,MAAM,WAAW,GAAoC,EAAE,CAAC;QACxD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACpC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YACnG,IAAI,OAAO,EAAE,CAAC;gBACX,WAAW,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,IAA0B,CAAC,CAAC;YAC3E,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAA0B,CAAa,EAAE,WAAW,EAAE,CAAC;IACnG,CAAC;IAED,wFAAwF;IAC9E,eAAe,CAAC,GAAW;QAClC,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC;QACzF,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACpD,CAAC;IAED,oFAAoF;IAC1E,WAAW,CAA8C,IAAa;QAC7E,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,eAAe,CAAC,UAAU,CAAC,IAAI,EAAE,SAAS,CAAiB,CAAC;IAChG,CAAC;CACH,CAAA;AArMY,iCAAiC;IAD7C,UAAU,EAAE;GACA,iCAAiC,CAqM7C"}
1
+ {"version":3,"file":"reconciling-multi-document-glsp-state.js","sourceRoot":"","sources":["../../src/state/reconciling-multi-document-glsp-state.ts"],"names":[],"mappings":"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"}
@@ -23,16 +23,16 @@ import { AbstractHydraniumGlspState } from './abstract-hydranium-glsp-state.js';
23
23
  * field-level shape is what lets `fast-json-patch` diff per field, so undo /
24
24
  * redo and forward-write reconcile act per field instead of clobbering the
25
25
  * whole document.
26
- * - {@link baseline} — the last in-sync projection, captured on every
26
+ * - {@link base} — the last in-sync projection, captured on every
27
27
  * {@link setSourceRoot}. A forward-write conflict reconciles the user's
28
- * intent (baseline → attempted) against the fresh server root.
28
+ * intent (base → ours) against the server's current root (theirs).
29
29
  * - {@link updateSourceModel} — the concrete reconcile template: persist,
30
30
  * and on a `ConflictError` consult the injected `conflictResolver` and act
31
31
  * on the merged / no-op / conflict / unavailable outcome.
32
32
  * - {@link persist} / {@link refetch} — the only I/O seams. Defaults route
33
- * through `ModelService.update` / `.validated` (reachable from the base via
34
- * `sharedServices.model`); adopters whose document round-trip differs
35
- * override these without touching the orchestration.
33
+ * through the diagram session's `update` and `ModelService.validated`;
34
+ * adopters whose document round-trip differs override these without
35
+ * touching the orchestration.
36
36
  *
37
37
  * Adopters whose source model is whole-document text (a bare `{ text }`
38
38
  * source model) or that are read-only do NOT extend this class — they extend
@@ -44,12 +44,12 @@ import { AbstractHydraniumGlspState } from './abstract-hydranium-glsp-state.js';
44
44
  export declare class ReconcilingTransferHydraniumGlspState<TRoot extends AstNode, TSourceModel extends TransferElement> extends AbstractHydraniumGlspState<TRoot, TSourceModel> implements JsonModelState<TSourceModel> {
45
45
  /**
46
46
  * Last in-sync source-model projection, captured on every
47
- * {@link setSourceRoot} (initial load + post-update). The baseline a
47
+ * {@link setSourceRoot} (initial load + post-update). The base a
48
48
  * forward-write conflict reconciles against: it stays the pre-command
49
49
  * state because operation handlers mutate `_sourceRoot` in place during
50
50
  * `execute` while `setSourceRoot` only re-runs once the write commits.
51
51
  */
52
- protected baseline?: TSourceModel;
52
+ protected base?: TSourceModel;
53
53
  /**
54
54
  * Persisted-shape projection of the current source root, consumed by GLSP's
55
55
  * {@link JsonModelState} read side and recorded for field-level undo / redo.
@@ -63,7 +63,7 @@ export declare class ReconcilingTransferHydraniumGlspState<TRoot extends AstNode
63
63
  /**
64
64
  * Persist `model` back to the document store, then capture the resulting
65
65
  * AST root. On a `ConflictError` (the based-on version was superseded),
66
- * reconcile the user's intent against the fresh server root via the bound
66
+ * reconcile the user's intent against the server's current root via the bound
67
67
  * `conflictResolver` and act on the outcome — one declarative policy
68
68
  * (force = last-writer-wins, reconciling = field-level merge) shared with
69
69
  * undo / redo.
@@ -71,8 +71,9 @@ export declare class ReconcilingTransferHydraniumGlspState<TRoot extends AstNode
71
71
  updateSourceModel(model: TSourceModel, basedOn?: BasedOn): Promise<void>;
72
72
  /**
73
73
  * Persist hook — the only write-side I/O. Default routes the structured
74
- * model through `ModelService.update` (serialize → reparse), opting into
75
- * the `ConflictError` gate when `version` is given. Adopters whose document
74
+ * model through the diagram session's `update` (serialize → reparse),
75
+ * opting into the `ConflictError` gate unless `basedOn` is `'anything'`,
76
+ * and throws without a session. Adopters whose document
76
77
  * round-trip differs override this; the orchestration in
77
78
  * {@link updateSourceModel} is unchanged.
78
79
  */
@@ -80,11 +81,11 @@ export declare class ReconcilingTransferHydraniumGlspState<TRoot extends AstNode
80
81
  root: TRoot;
81
82
  }>;
82
83
  /**
83
- * Refetch hook — reads the current settled server root as a persisted-shape
84
- * projection (or `undefined` when unavailable). The `conflictResolver`
85
- * replays the user's intent against this fresh state. Default uses
86
- * `ModelService.validated` + the framework encoder's `'grammar'` mode;
87
- * adopters override alongside {@link persist}.
84
+ * Refetch hook — the stored text parsed afresh, as a persisted-shape
85
+ * projection (or `undefined` when unavailable): theirs, which the
86
+ * `conflictResolver` replays the user's intent onto. Default uses
87
+ * {@link AbstractHydraniumGlspState.readCurrentRoot} + the framework
88
+ * encoder's `'grammar'` mode; adopters override alongside {@link persist}.
88
89
  */
89
90
  protected refetch(): Promise<TSourceModel | undefined>;
90
91
  }
@@ -1 +1 @@
1
- {"version":3,"file":"reconciling-transfer-hydranium-glsp-state.d.ts","sourceRoot":"","sources":["../../src/state/reconciling-transfer-hydranium-glsp-state.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAGhF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBACa,qCAAqC,CAAC,KAAK,SAAS,OAAO,EAAE,YAAY,SAAS,eAAe,CAC3G,SAAQ,0BAA0B,CAAC,KAAK,EAAE,YAAY,CACtD,YAAW,cAAc,CAAC,YAAY,CAAC;IAEvC;;;;;;OAMG;IACH,SAAS,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC;IAElC;;;;;;;OAOG;IACH,IAAI,WAAW,IAAI,YAAY,CAE9B;IAEQ,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG,IAAI;IAKtD;;;;;;;OAOG;IACG,iBAAiB,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,GAAE,OAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB5F;;;;;;OAMG;cACa,OAAO,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE,CAAC;IAUxF;;;;;;OAMG;cACa,OAAO,IAAI,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC;CAI9D"}
1
+ {"version":3,"file":"reconciling-transfer-hydranium-glsp-state.d.ts","sourceRoot":"","sources":["../../src/state/reconciling-transfer-hydranium-glsp-state.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAGhF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBACa,qCAAqC,CAAC,KAAK,SAAS,OAAO,EAAE,YAAY,SAAS,eAAe,CAC3G,SAAQ,0BAA0B,CAAC,KAAK,EAAE,YAAY,CACtD,YAAW,cAAc,CAAC,YAAY,CAAC;IAEvC;;;;;;OAMG;IACH,SAAS,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC;IAE9B;;;;;;;OAOG;IACH,IAAI,WAAW,IAAI,YAAY,CAE9B;IAEQ,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG,IAAI;IAKtD;;;;;;;OAOG;IACG,iBAAiB,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,GAAE,OAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB5F;;;;;;;OAOG;cACa,OAAO,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE,CAAC;IAKxF;;;;;;OAMG;cACa,OAAO,IAAI,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC;CAI9D"}