@ai-matrx/office 0.8.13 → 0.8.14

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/CHANGELOG.md CHANGED
@@ -1,9 +1,11 @@
1
1
  # Changelog
2
2
 
3
- ## 0.8.13
3
+ ## 0.8.14
4
4
 
5
5
  - **`/collab/sheets-transform` covers formulas (C5b; still inert, no consumer).** A formula typed on one seat now has its references rewritten by a concurrent row/column insert, removal or move and by a concurrent sheet rename, in both commit orders, exactly as Univer's own `@univerjs/sheets-formula` interceptor rewrites them: A1 references, ranges, absolute and mixed markers, whole rows and columns, cross-sheet references, references into a removed range (`#REF!`), array formulas (`ref` range moves; dynamic arrays are plain formulas). Defined names (`formula.mutation.set-defined-name` / `remove-defined-name`) are covered: their ranges follow structural edits and renames, a renamed name is renamed inside concurrent formulas, a removed one becomes `#REF!`. A rewrite a structural op carries for formulas that already existed (`derived`) never outranks a person's concurrent write to the same cell or name. Shared formulas (`si`) stay barriers (the failing case is in `sheet-formula-hard-cases.test.ts`). Rewrites match real sheets-formula 1.0.4 on 476 oracle cases (`fixtures/sheets-formula-oracle.json`, made by `spikes/c5b-probe/oracle.mjs`). Pairwise TP1 fuzz: 20 families (210 pairs) at 4,000 seeds each, both orders, 0 divergences, 0 throws. New exports: `annotateFormulas`, `forApply`, `SIDE_CAR_PARAMS`, `rewriteFormula`, `formulaBarrier`, `isFormulaText`, `refSheetsFor`, `refSheetsAfter`, `REF_ERROR` and the `RefChange`/`RefSheets`/`FormulaCtx` types. `CONTENT_KEYS` gains `ref`, `xf`, `ft`, `fd`; `SHEET_TRANSFORMER_VERSION` is `c5b-1`. `@univerjs/engine-formula` moves from devDependencies to dependencies (the lexer runs in shipped code). Consumer action: none (nothing imports this section yet). For C6: capture must call `annotateFormulas` on each group (sheet id → name, defined-name id → name, read before the command) and apply through `forApply`; the canonical sheet hash must sort the defined-names resource by id.
6
6
 
7
+ - **Docs co-editing: other people's carets and selections (C8), and a History restore reaches an open room (C7a).** Each seat publishes `caret = { ranges, at }` (body offsets, header/footer selections excluded) on Yjs awareness beside `quiet_hash`, on every selection change and every 2 s. A receiver keeps the last published ranges in `RemoteCaretBook` and moves them through every body edit it applies afterwards, remote or its own (`moveRangesThroughBodyEdit`), so a caret survives edits between publications; a caret not refreshed for 12 s (judged by the receiver's clock) is not listed, and a seat that leaves drops with its awareness state. `DocumentAwareness` gains `carets?: RemoteCaret[]`; `DocsOtPort` gains an optional `selection()` (the model supplies it from the first view). `restoreDocumentSnapshot` (`@ai-matrx/office/univer/collab`) is the one History restore: open in this tab, the editor swaps it in (an ordered room sends `collab_replace`); not open but the document has a room, `collab_replace` (snapshot row, `replace` op, checkpoint and frame in one transaction) so every open seat reloads; no room, a snapshot row. `hasOpenEditorContent(kind, id)` joins `showSavedSnapshot`. Consumer action: pass `displayName` to `documentOtFactory`, draw `awareness.carets` over the canvas, and call `restoreDocumentSnapshot` from History instead of `saveDocumentSnapshot` + `showSavedSnapshot`.
8
+
7
9
  - Docs co-editing (C3): a collaborator's edit now moves this seat's caret with the characters (§6.8). The view port gains an optional `selection { get, set }`; `DocumentModel` moves body ranges through each applied remote edit (`moveRangesThroughBodyEdit`). Found in the live two-browser run: with the caret left at its old offset, the next keystrokes landed scattered. Consumer action: pass `selection` from Univer's `DocSelectionManagerService` in the view port.
8
10
 
9
11
  - **Docs co-editing: two people typing at one spot keep their words whole (C3b).** A collaborator's insert that lands exactly at a collapsed caret now stays AFTER the caret: this person's next keystroke commits later, so by the one conflict rule (§6.4, later-committed sits first) it goes before it, the same side the session gives unsent and in-flight local inserts. 0.8.11 pushed the caret past it, so two people typing at one caret alternated letters ("FElbobod"). A selection never takes in a collaborator's text at either edge. The transform's tie rule is unchanged (later-committed first; Docs TP1 fuzz 20,000 seeds per pair, 0 divergences). Forcing test: `two-people-typing-at-one-caret-keep-their-words-whole.test.ts`. Consumer action: none.
package/dist/docs.cjs CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2;
2
2
 
3
3
 
4
4
 
@@ -864,6 +864,95 @@ function documentBodyWriteHandler(deps) {
864
864
  };
865
865
  }
866
866
 
867
+ // src/docs/remote-carets.ts
868
+ var CARET_HEARTBEAT_MS = 2e3;
869
+ var CARET_STALE_MS = 12e3;
870
+ var CARET_MAX_RANGES = 4;
871
+ function publishedCaretFromSelection(sel, now) {
872
+ if (!sel || sel.length === 0) return null;
873
+ if (sel.some((r) => r.segmentId)) return null;
874
+ const ranges = sel.slice(0, CARET_MAX_RANGES).map((r) => ({ start: Math.min(r.startOffset, r.endOffset), end: Math.max(r.startOffset, r.endOffset) }));
875
+ return { ranges, at: now };
876
+ }
877
+ var sameRanges = (a, b) => a.length === b.length && a.every((r, i) => r.start === b[i].start && r.end === b[i].end);
878
+ function readCaret(raw) {
879
+ const c = _optionalChain([raw, 'optionalAccess', _72 => _72.caret]);
880
+ if (!c || !Array.isArray(c.ranges) || typeof c.at !== "number") return null;
881
+ const ranges = [];
882
+ for (const r of c.ranges.slice(0, CARET_MAX_RANGES)) {
883
+ const s2 = _optionalChain([r, 'optionalAccess', _73 => _73.start]);
884
+ const e2 = _optionalChain([r, 'optionalAccess', _74 => _74.end]);
885
+ if (typeof s2 !== "number" || typeof e2 !== "number" || !Number.isFinite(s2) || !Number.isFinite(e2) || s2 < 0 || e2 < 0) return null;
886
+ ranges.push({ start: s2, end: e2 });
887
+ }
888
+ return ranges.length ? { ranges, at: c.at } : null;
889
+ }
890
+ var RemoteCaretBook = (_class2 = class {
891
+ constructor(selfClientId, now = Date.now) {;_class2.prototype.__init25.call(this);
892
+ this.selfClientId = selfClientId;
893
+ this.now = now;
894
+ }
895
+
896
+
897
+ __init25() {this.carets = /* @__PURE__ */ new Map()}
898
+ /** Take the room's awareness states: new or republished carets replace ours, seats that left are dropped. Returns whether anything changed. */
899
+ ingest(states) {
900
+ let changed = false;
901
+ const seen = /* @__PURE__ */ new Set();
902
+ states.forEach((raw, id) => {
903
+ if (id === this.selfClientId) return;
904
+ const s2 = raw;
905
+ const caret = readCaret(raw);
906
+ if (!s2 || typeof s2.uid !== "string" || !caret) return;
907
+ const key = String(id);
908
+ seen.add(key);
909
+ const prev = this.carets.get(key);
910
+ const name = typeof s2.name === "string" && s2.name ? s2.name : "Someone";
911
+ const color = typeof s2.color === "string" && s2.color ? s2.color : "#3b82f6";
912
+ if (prev && prev.at === caret.at && prev.name === name && prev.color === color) return;
913
+ this.carets.set(key, { key, uid: s2.uid, name, color, ranges: caret.ranges, at: caret.at, seenAt: this.now() });
914
+ changed = true;
915
+ });
916
+ for (const key of [...this.carets.keys()]) {
917
+ if (!seen.has(key)) {
918
+ this.carets.delete(key);
919
+ changed = true;
920
+ }
921
+ }
922
+ return changed;
923
+ }
924
+ /** Move every caret through one body edit that was just applied (`actions` of a rich-text mutation). Returns whether any moved. */
925
+ shiftThrough(actions) {
926
+ let moved = false;
927
+ for (const c of this.carets.values()) {
928
+ const next = moveRangesThroughBodyEdit(c.ranges.map((r) => ({ startOffset: r.start, endOffset: r.end })), actions);
929
+ if (!next) return false;
930
+ const ranges = next.map((r) => ({ start: r.startOffset, end: r.endOffset }));
931
+ if (!sameRanges(ranges, c.ranges)) {
932
+ c.ranges = ranges;
933
+ moved = true;
934
+ }
935
+ }
936
+ return moved;
937
+ }
938
+ /** The carets to draw now (stale ones left out). */
939
+ list() {
940
+ const t = this.now();
941
+ const out = [];
942
+ for (const c of this.carets.values()) {
943
+ if (t - c.seenAt > CARET_STALE_MS) continue;
944
+ out.push({ key: c.key, uid: c.uid, name: c.name, color: c.color, ranges: c.ranges.map((r) => ({ ...r })) });
945
+ }
946
+ out.sort((a, b) => a.key.localeCompare(b.key));
947
+ return out;
948
+ }
949
+ }, _class2);
950
+
951
+
952
+
953
+
954
+
955
+
867
956
 
868
957
 
869
958
 
@@ -900,5 +989,5 @@ function documentBodyWriteHandler(deps) {
900
989
 
901
990
 
902
991
 
903
- exports.DOCUMENT_BODY_MAX_LENGTH = DOCUMENT_BODY_MAX_LENGTH; exports.DOCUMENT_DESCRIPTION_MAX_LENGTH = DOCUMENT_DESCRIPTION_MAX_LENGTH; exports.DOCUMENT_NAME_MAX_LENGTH = DOCUMENT_NAME_MAX_LENGTH; exports.DOCUMENT_SAVE_DELAY_MS = DOCUMENT_SAVE_DELAY_MS; exports.DocumentModel = DocumentModel; exports.EMOJI_GROUPS = EMOJI_GROUPS; exports.MIN_FIT_ZOOM = MIN_FIT_ZOOM; exports.SPECIAL_GROUPS = SPECIAL_GROUPS; exports.bodyTextOf = bodyTextOf; exports.configureDocsHost = _chunkHX5TXQIXcjs.configureDocsHost; exports.copyDocument = _chunkHX5TXQIXcjs.copyDocument; exports.createDocument = _chunkHX5TXQIXcjs.createDocument; exports.deleteDocument = _chunkHX5TXQIXcjs.deleteDocument; exports.discardFailedDocument = _chunkHX5TXQIXcjs.discardFailedDocument; exports.documentBodyWriteHandler = documentBodyWriteHandler; exports.documentSourceLabel = documentSourceLabel; exports.fitZoomRatio = fitZoomRatio; exports.getDocsHost = _chunkHX5TXQIXcjs.getDocsHost; exports.getDocument = _chunkHX5TXQIXcjs.getDocument; exports.getLatestDocumentSnapshot = _chunkHX5TXQIXcjs.getLatestDocumentSnapshot; exports.listAccessibleDocuments = _chunkHX5TXQIXcjs.listAccessibleDocuments; exports.listDocumentSnapshots = _chunkHX5TXQIXcjs.listDocumentSnapshots; exports.listTrashedDocuments = _chunkHX5TXQIXcjs.listTrashedDocuments; exports.moveDocument = _chunkHX5TXQIXcjs.moveDocument; exports.moveRangesThroughBodyEdit = moveRangesThroughBodyEdit; exports.planBodyEdit = planBodyEdit; exports.renameDocument = _chunkHX5TXQIXcjs.renameDocument; exports.restoreDocument = _chunkHX5TXQIXcjs.restoreDocument; exports.sanitizeUniverDocSnapshot = _chunkHX5TXQIXcjs.sanitizeUniverDocSnapshot; exports.saveDocumentSnapshot = _chunkHX5TXQIXcjs.saveDocumentSnapshot; exports.searchSymbols = searchSymbols; exports.updateDocumentDescription = _chunkHX5TXQIXcjs.updateDocumentDescription; exports.validateDocumentBody = validateDocumentBody; exports.validateDocumentDescription = validateDocumentDescription; exports.validateDocumentName = validateDocumentName; exports.writeBodyText = writeBodyText;
992
+ exports.CARET_HEARTBEAT_MS = CARET_HEARTBEAT_MS; exports.CARET_MAX_RANGES = CARET_MAX_RANGES; exports.CARET_STALE_MS = CARET_STALE_MS; exports.DOCUMENT_BODY_MAX_LENGTH = DOCUMENT_BODY_MAX_LENGTH; exports.DOCUMENT_DESCRIPTION_MAX_LENGTH = DOCUMENT_DESCRIPTION_MAX_LENGTH; exports.DOCUMENT_NAME_MAX_LENGTH = DOCUMENT_NAME_MAX_LENGTH; exports.DOCUMENT_SAVE_DELAY_MS = DOCUMENT_SAVE_DELAY_MS; exports.DocumentModel = DocumentModel; exports.EMOJI_GROUPS = EMOJI_GROUPS; exports.MIN_FIT_ZOOM = MIN_FIT_ZOOM; exports.RemoteCaretBook = RemoteCaretBook; exports.SPECIAL_GROUPS = SPECIAL_GROUPS; exports.bodyTextOf = bodyTextOf; exports.configureDocsHost = _chunkHX5TXQIXcjs.configureDocsHost; exports.copyDocument = _chunkHX5TXQIXcjs.copyDocument; exports.createDocument = _chunkHX5TXQIXcjs.createDocument; exports.deleteDocument = _chunkHX5TXQIXcjs.deleteDocument; exports.discardFailedDocument = _chunkHX5TXQIXcjs.discardFailedDocument; exports.documentBodyWriteHandler = documentBodyWriteHandler; exports.documentSourceLabel = documentSourceLabel; exports.fitZoomRatio = fitZoomRatio; exports.getDocsHost = _chunkHX5TXQIXcjs.getDocsHost; exports.getDocument = _chunkHX5TXQIXcjs.getDocument; exports.getLatestDocumentSnapshot = _chunkHX5TXQIXcjs.getLatestDocumentSnapshot; exports.listAccessibleDocuments = _chunkHX5TXQIXcjs.listAccessibleDocuments; exports.listDocumentSnapshots = _chunkHX5TXQIXcjs.listDocumentSnapshots; exports.listTrashedDocuments = _chunkHX5TXQIXcjs.listTrashedDocuments; exports.moveDocument = _chunkHX5TXQIXcjs.moveDocument; exports.moveRangesThroughBodyEdit = moveRangesThroughBodyEdit; exports.planBodyEdit = planBodyEdit; exports.publishedCaretFromSelection = publishedCaretFromSelection; exports.renameDocument = _chunkHX5TXQIXcjs.renameDocument; exports.restoreDocument = _chunkHX5TXQIXcjs.restoreDocument; exports.sanitizeUniverDocSnapshot = _chunkHX5TXQIXcjs.sanitizeUniverDocSnapshot; exports.saveDocumentSnapshot = _chunkHX5TXQIXcjs.saveDocumentSnapshot; exports.searchSymbols = searchSymbols; exports.updateDocumentDescription = _chunkHX5TXQIXcjs.updateDocumentDescription; exports.validateDocumentBody = validateDocumentBody; exports.validateDocumentDescription = validateDocumentDescription; exports.validateDocumentName = validateDocumentName; exports.writeBodyText = writeBodyText;
904
993
  //# sourceMappingURL=docs.cjs.map
package/dist/docs.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/aidream/aidream/apps/shared/office/dist/docs.cjs","../src/docs/document-model.ts","../src/univer/isSnapshotMutation.ts","../src/univer/collab/covered.ts","../src/docs/document-write-validation.ts","../src/docs/fit-zoom-ratio.ts","../src/docs/documents-hub-display.ts","../src/docs/doc-symbols.ts","../src/docs/document-body-text.ts"],"names":["e","view","s"],"mappings":"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AAA;AACoB,IAAA;AACG,IAAA;AACf,IAAA;AACM,IAAA;AAChB,EAAA;AAIyB,EAAA;AACH,IAAA;AACG,IAAA;AACX,IAAA;AACK,IAAA;AACZ,EAAA;AACQ,IAAA;AACf,EAAA;AACuB,EAAA;AACzB;AAe6B;AACT,EAAA;AACR,EAAA;AACU,EAAA;AACP,EAAA;AACU,EAAA;AACE,EAAA;AACZ,EAAA;AAEI,EAAA;AAGf,IAAA;AACiB,EAAA;AACZ,EAAA;AACkB,IAAA;AACF,IAAA;AACL,IAAA;AAClB,EAAA;AACF;AAM4C;AACjC,EAAA;AACa,IAAA;AACN,IAAA;AACO,IAAA;AACA,MAAA;AACJ,MAAA;AACjB,IAAA;AACY,IAAA;AACd,EAAA;AACuB,EAAA;AACzB;AAIE;AAGgB,EAAA;AACH,EAAA;AACO,EAAA;AACA,EAAA;AACR,IAAA;AACR,MAAA;AACF,IAAA;AACF,EAAA;AACyB,EAAA;AACb,IAAA;AACQ,MAAA;AAGlB,IAAA;AACF,EAAA;AACO,EAAA;AACI,IAAA;AACW,IAAA;AACE,IAAA;AACxB,EAAA;AACF;AAEuB;AACD,EAAA;AACM,EAAA;AACL,EAAA;AACG,EAAA;AAC1B;AAGgB;AACO,EAAA;AACT,IAAA;AACR,MAAA;AACE,QAAA;AACD,MAAA;AACH,IAAA;AACF,EAAA;AACmB,EAAA;AACP,IAAA;AACR,MAAA;AACF,IAAA;AACF,EAAA;AACqB,EAAA;AACvB;AAOgB;AAIP,EAAA;AACgB,IAAA;AACE,MAAA;AACvB,IAAA;AACkB,IAAA;AACH,MAAA;AACO,MAAA;AACF,MAAA;AACP,MAAA;AACC,QAAA;AACR,UAAA;AACF,QAAA;AACF,MAAA;AACe,MAAA;AACM,MAAA;AACD,QAAA;AACpB,MAAA;AACO,MAAA;AACI,QAAA;AACQ,QAAA;AACnB,MAAA;AACF,IAAA;AACF,EAAA;AACF;AR0nB2B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/aidream/aidream/apps/shared/office/dist/docs.cjs","sourcesContent":[null,"/**\n * THE DOCUMENT MODEL — the engine of one cloud document per tab.\n *\n * Before this, the document lived only inside each `DocumentEditor`'s Univer\n * instance. A remount (a board tile waking, a tile removed and undone, a route\n * change and back) rebuilt the editor from the SERVER copy, so whatever the\n * last save had not carried yet was gone; two mounts of one document were two\n * editors, each saving full snapshots of its own copy (last write wins), each\n * with its own realtime channel and its own collab room.\n *\n * The document is a record on THE one working-copy primitive\n * (`@ai-matrx/kit/working-copy`, kind `udt_document`,\n * `./documentModels.ts`): its save status, dirty and view count are Redux state\n * (`workingCopies[\"udt_document:<id>\"]`), its one coalesced save is the kind's.\n * What Redux cannot hold — Univer's body — is this engine, registered on the\n * record's session under the same key:\n *\n * - BODY. Every local mutation in one view is replayed into every other view\n * of the document (the same mutation stream collab sends between machines),\n * so two views show one document. A new view boots from the engine's latest\n * state — a live view's snapshot, or the snapshot the last view left behind\n * — never the stale server copy while the record's session is alive.\n * - SIDE EFFECTS, ONCE. The snapshot realtime channel, the collab room, and\n * the pagehide / visibility / beforeunload flush are opened once per\n * document and closed once.\n * - THE EDITOR ITSELF, KEPT. Univer keeps its undo / redo history inside the\n * editor instance, so rebuilding the editor on a remount threw the history\n * away. When the last view leaves, its editor (a Univer instance with its\n * own DOM host) is parked here — off the page, alive — and the next view of\n * the document RE-ATTACHES that same instance to its own container instead\n * of booting a new one (`parkEditor` / `takeParkedEditor`). Undo and redo\n * therefore work across hide / show, a remount and a removed tile undone,\n * for as long as the record's session is warm; `close()` disposes it.\n */\n\nimport type { ICommandInfo, IDocumentData } from \"@univerjs/core\";\nimport { TextX } from \"@univerjs/core\";\nimport type { CommitReason, WorkingCopyHandle } from \"@ai-matrx/kit/working-copy\";\nimport type { AwarenessState } from \"@ai-matrx/data/realtime/collab\";\nimport { isSnapshotMutation } from \"../univer\";\nimport { stampCovered, takeCovered } from \"../univer/collab/covered\";\nimport type {\n CollabMutationInfo,\n CommandServiceLike,\n} from \"../univer/collab\";\nimport type { DocsLocalMutation, DocsOtPort } from \"../univer/collab/docs-ot/room\";\nimport type { RemoteCaret } from \"./remote-carets\";\n\n/** Univer's command service as a view lends it: the collab pair plus the command hooks capture groups by. */\ntype ViewCommandService = CommandServiceLike & {\n beforeCommandExecuted?: (listener: (info: { id: string; type?: number; params?: unknown }) => void) => { dispose: () => void };\n onCommandExecuted?: (listener: (info: { id: string; type?: number; params?: unknown }) => void) => { dispose: () => void };\n executeCommand?: (id: string, params?: unknown, options?: unknown) => Promise<unknown>;\n};\n\nconst RICH_TEXT_EDITING_ID = \"doc.mutation.rich-text-editing\";\n/** Univer's CommandType.COMMAND. */\nconst COMMAND_TYPE = 0;\nconst DEPTH_GUARDED = Symbol.for(\"ai-matrx.office.docs.command-depth-guard\");\n\n/** Debounce from the last edit to the save. */\nexport const DOCUMENT_SAVE_DELAY_MS = 2500;\n\nexport type DocumentSnapshotData = Partial<IDocumentData>;\n\n/** What a view lends the model while it is mounted. */\nexport interface DocumentViewPort {\n /** Univer's command service for this view's instance. */\n commandService: CommandServiceLike;\n /** The live document of this view (`doc.save()`), or null if it has none. */\n snapshot: () => DocumentSnapshotData | null;\n /** Replace the whole document in this view (a collaborator's snapshot). */\n remount: (snapshot: DocumentSnapshotData) => void;\n /** Whether this view may change the document (read at edit time). */\n editable: () => boolean;\n /**\n * This view's text selection (body offsets), so a collaborator's edit moves the caret with the characters\n * (§6.8). Without it a remote apply leaves the caret at its old offset and the next keystrokes land elsewhere.\n */\n selection?: {\n get: () => Array<{ startOffset: number; endOffset: number; segmentId?: string }> | null;\n set: (ranges: Array<{ startOffset: number; endOffset: number }>) => void;\n };\n /** Univer's undo/redo service of this view's instance (the co-editing room rebases its items, §6.9). */\n undoRedo?: () => unknown;\n /**\n * The Univer unit id of this view's mounted document. Every seat mounts its own unit, so a\n * mutation carries the SENDER's id and must be re-addressed to this view's unit before it is\n * applied. Falls back to the id of `snapshot()` when a view does not state it.\n */\n unitId?: () => string | null;\n}\n\n/** Everything the engine reaches outside itself — injected so it is testable. */\nexport interface DocumentModelDeps {\n /** The newest stored snapshot (its row id + body), or null for a document never saved. */\n loadLatest: (documentId: string) => Promise<{ id: string; snapshot: DocumentSnapshotData } | null>;\n save: (input: {\n documentId: string;\n snapshot: DocumentSnapshotData;\n origin: \"autosave\" | \"manual\";\n }) => Promise<{ id: string; createdBy: string | null }>;\n onSaved?: (documentId: string, origin: \"autosave\" | \"manual\") => void;\n /** Window-level listeners (pagehide, visibilitychange, beforeunload). */\n listenToPage?: (handlers: { flush: () => void; hasUnsaved: () => boolean }) => () => void;\n /** A mutation could not be applied to a view: the app says so (a notice); the model re-syncs from the saved version. */\n onApplyFailed?: (documentId: string, mutationId: string, error: unknown) => void;\n}\n\ninterface AttachedView {\n id: number;\n port: DocumentViewPort;\n dispose: () => void;\n /** The outermost commands running in this view (closed in try/finally, C0 surprise 7). */\n commands: string[];\n /** The document before the rich-text mutation about to run (only while a co-editing room listens). */\n pre: unknown | null;\n}\n\n/** The document's room on the ordered log (COLLAB-DESIGN §6, C3), bound through `startOtRoom`. */\nexport interface DocumentOtHandle {\n stop: () => void;\n write: (reason: CommitReason) => Promise<boolean>;\n replace: (snapshot: DocumentSnapshotData) => Promise<void>;\n isSaver: () => boolean;\n}\n\nexport type DocumentOtFactory = (\n port: DocsOtPort,\n onAwareness: (awareness: DocumentAwareness) => void,\n) => Promise<DocumentOtHandle | null>;\n\n/** A collab room (WorkbookCollabSession) bound to the model's command stream. */\nexport interface DocumentCollabHandle {\n stop: () => void;\n isHost: () => boolean;\n /** This tab replaced the whole document and saved it as `snapshotId`: peers reload it. */\n announceReplaced: (snapshotId: string) => void;\n /** The room entries this tab's body holds right now (read with the body that is about to be saved). */\n coveredNow: () => string[];\n /** The saved snapshot `snapshotId` holds `covered`: they leave the room's log (the elected saver only). */\n checkpoint: (snapshotId: string, covered: readonly string[]) => void;\n}\n\n/** The saved snapshot this tab's body started from — what the room must never replay on top of it. */\nexport interface DocumentCollabBase {\n snapshotId: () => string | null;\n covered: () => ReadonlySet<string>;\n /** Show the newest saved snapshot (the room's newest checkpoint is newer than what this tab loaded). */\n reload: () => Promise<void>;\n}\n\n/** Who else is in the document's room (shared by every view of it). */\nexport interface DocumentAwareness {\n states: Map<number, AwarenessState>;\n selfUid: string;\n /** Other seats' carets and selections (ordered-log rooms only, C8), already moved through every edit applied since. */\n carets?: RemoteCaret[];\n}\n\n/**\n * An editor instance kept alive between views of the document: its DOM host\n * (re-parented into the next view's container) and the instance behind it,\n * whose undo history survives because the instance does. Opaque to the model\n * apart from what it calls.\n */\nexport interface ParkedDocumentEditor<T = unknown> {\n /** The element the editor renders into; the next view appends it to its container. */\n element: HTMLElement;\n instance: T;\n /** Replace the whole document (a collaborator's snapshot arrived while parked). */\n remount: (snapshot: DocumentSnapshotData) => void;\n /** Throw the instance away (the record's session closed). */\n dispose: () => void;\n}\n\nexport type DocumentCollabFactory = (\n commandService: CommandServiceLike,\n onAwareness: (awareness: DocumentAwareness) => void,\n /** A peer replaced the whole document (history restore, Google update). */\n onReplaced: () => void,\n /** What this tab's body was loaded from; pass it to the session (`base`). */\n base: DocumentCollabBase,\n) => Promise<DocumentCollabHandle | null>;\n\nlet viewIds = 0;\n\nexport class DocumentModel {\n readonly documentId: string;\n private readonly deps: DocumentModelDeps;\n private readonly handle: WorkingCopyHandle;\n private readonly views = new Map<number, AttachedView>();\n private lastEditedView: number | null = null;\n /** The document as the last view left it, or as last loaded / saved. */\n private stored: DocumentSnapshotData | null = null;\n private loading: Promise<DocumentSnapshotData | null> | null = null;\n private relaying = false;\n /** Snapshot rows this tab already holds (loaded or written) — never re-applied. */\n private readonly knownSnapshots = new Set<string>();\n private readonly collabListeners = new Set<(info: CollabMutationInfo, options?: { onlyLocal?: boolean; fromCollab?: boolean }) => void>();\n private collab: DocumentCollabHandle | null = null;\n /** The ordered-log room (C3); exclusive with `collab` (the 0.6 relay room). */\n private ot: DocumentOtHandle | null = null;\n private otStarting: Promise<void> | null = null;\n private readonly otListeners = new Set<(m: DocsLocalMutation) => void>();\n /** The saved snapshot the body started from, and the room entries it already holds. */\n private baseId: string | null = null;\n private baseCovered: ReadonlySet<string> = new Set();\n private collabStarting: Promise<void> | null = null;\n private awareness: DocumentAwareness | null = null;\n private readonly awarenessListeners = new Set<() => void>();\n private realtimeClose: (() => void) | null = null;\n private pageClose: (() => void) | null = null;\n /** The last view's editor, alive and off the page until a view takes it back. */\n private parked: ParkedDocumentEditor | null = null;\n\n constructor(handle: WorkingCopyHandle, deps: DocumentModelDeps) {\n this.documentId = handle.id;\n this.handle = handle;\n this.deps = deps;\n }\n\n // ── body ────────────────────────────────────────────────────────────────\n\n /** The newest state of the body this tab holds, without a network read. */\n latest(): DocumentSnapshotData | null {\n const preferred = this.lastEditedView !== null ? this.views.get(this.lastEditedView) : undefined;\n for (const view of preferred ? [preferred, ...this.views.values()] : this.views.values()) {\n try {\n const snapshot = view.port.snapshot();\n if (snapshot) return snapshot;\n } catch (error) {\n console.warn(`[document-model] a view of ${this.documentId} could not report its document`, error);\n }\n }\n return this.stored;\n }\n\n /**\n * What a NEW view should boot from: the model's latest state, or (only when\n * this tab holds none) the newest server snapshot. Null = an empty document.\n * Re-read `latest()` synchronously right before mounting — another view may\n * have typed while the server read was in flight.\n */\n async openingSnapshot(createEmpty: () => DocumentSnapshotData): Promise<DocumentSnapshotData> {\n const held = this.latest();\n if (held) return held;\n if (!this.loading) {\n this.loading = this.deps.loadLatest(this.documentId).then(\n (row) => {\n const loaded = row ? this.takeBase(row) : null;\n if (row && loaded) {\n this.knownSnapshots.add(row.id);\n this.savedFingerprint = contentFingerprint(loaded);\n }\n // A document never saved opens as ONE empty document for every view\n // (one unit id), so their edits replay into each other.\n if (!this.stored) this.stored = loaded ?? createEmpty();\n return this.latest() ?? this.stored;\n },\n (error: unknown) => {\n this.loading = null;\n throw error;\n },\n );\n }\n return (await this.loading) ?? createEmpty();\n }\n\n /** A view's Univer instance is ready: it shares the document from now on. */\n attachView(port: DocumentViewPort): () => void {\n const id = ++viewIds;\n const subscription = port.commandService.onMutationExecutedForCollab((info, options) =>\n this.onViewMutation(id, info, options),\n );\n const view: AttachedView = { id, port, dispose: () => {}, commands: [], pre: null };\n const hooks = this.trackCommands(view);\n view.dispose = () => {\n subscription.dispose();\n hooks();\n };\n this.views.set(id, view);\n // Nothing unsaved: what this view mounted IS the saved version (Univer and\n // the snapshot repair may restate it — page geometry, defaults — without\n // anyone changing a word). That is the baseline a save compares against.\n if (!this.handle.hasPending()) {\n try {\n const mounted = port.snapshot();\n if (mounted) this.savedFingerprint = contentFingerprint(mounted);\n } catch (error) {\n console.warn(`[document-model] could not read ${this.documentId}'s mounted document`, error);\n }\n }\n let detached = false;\n return () => {\n if (detached) return;\n detached = true;\n const view = this.views.get(id);\n if (!view) return;\n // Whatever this view shows is the newest body when it is the last one:\n // keep it, so a remount (or the flush on the way out) reads it.\n if (this.views.size === 1) {\n try {\n const snapshot = port.snapshot();\n if (snapshot) this.stored = snapshot;\n } catch (error) {\n console.warn(`[document-model] could not keep ${this.documentId}'s last view's document`, error);\n }\n }\n view.dispose();\n this.views.delete(id);\n if (this.lastEditedView === id) this.lastEditedView = null;\n };\n }\n\n /**\n * The last view of the document is leaving: keep its editor (and Univer's\n * undo history inside it) for the next view. Call AFTER the view's\n * `attachView` detach. Refused — the caller disposes its editor — while\n * another view is still attached (it carries the document) or one is\n * already kept.\n */\n parkEditor(editor: ParkedDocumentEditor): boolean {\n if (this.closed || this.views.size > 0 || this.parked) return false;\n this.parked = editor;\n return true;\n }\n\n /** The kept editor, handed to the view that mounts next (null when none is kept). */\n takeParkedEditor(): ParkedDocumentEditor | null {\n const editor = this.parked;\n this.parked = null;\n return editor;\n }\n\n private onViewMutation(\n viewId: number,\n info: Readonly<CollabMutationInfo>,\n options?: { fromCollab?: boolean; fromChangeset?: boolean; onlyLocal?: boolean },\n ): void {\n // Our own replay into this view, a collab peer's edit, or a load: not a\n // new local edit (each is accounted where it came from).\n if (this.relaying || options?.fromCollab || options?.fromChangeset) return;\n const view = this.views.get(viewId);\n if (!view || !view.port.editable()) return;\n this.lastEditedView = viewId;\n this.relay(info, viewId);\n for (const listener of this.collabListeners) listener(info as CollabMutationInfo, options);\n if (this.otListeners.size && !options?.onlyLocal) {\n const m: DocsLocalMutation = {\n id: info.id,\n params: info.params,\n pre: info.id === RICH_TEXT_EDITING_ID ? view.pre : null,\n cmd: view.commands[0] ?? null,\n content: isContentMutation(info),\n };\n view.pre = null;\n for (const listener of Array.from(this.otListeners)) listener(m);\n }\n if (isContentMutation(info)) this.markDirty();\n }\n\n /**\n * Per view: the outermost command running (a mutation's group label) and, while a room listens, the document\n * before each rich-text mutation (its inverse is computed from the APPLIED actions against this copy). Univer's\n * `executeCommand` has no `finally`: a command that mutates then throws never fires `onCommandExecuted`, so\n * the depth is restored in a try/finally around the instance's `executeCommand` (C0 surprise 7).\n */\n private trackCommands(view: AttachedView): () => void {\n const cs = view.port.commandService as ViewCommandService;\n if (typeof cs.beforeCommandExecuted !== \"function\" || typeof cs.onCommandExecuted !== \"function\") return () => {};\n const before = cs.beforeCommandExecuted((info) => {\n if (info.type === COMMAND_TYPE) view.commands.push(info.id);\n else if (info.id === RICH_TEXT_EDITING_ID && this.otListeners.size && !this.relaying) {\n try {\n const snap = view.port.snapshot();\n view.pre = snap ? structuredClone(snap) : null;\n } catch {\n view.pre = null;\n }\n }\n });\n const after = cs.onCommandExecuted((info) => {\n if (info.type !== COMMAND_TYPE) return;\n const at = view.commands.lastIndexOf(info.id);\n if (at >= 0) view.commands.splice(at, 1);\n });\n const guarded = cs as ViewCommandService & { [DEPTH_GUARDED]?: true };\n if (typeof cs.executeCommand === \"function\" && !guarded[DEPTH_GUARDED]) {\n const original = cs.executeCommand.bind(cs);\n guarded[DEPTH_GUARDED] = true;\n cs.executeCommand = async (id, params, options) => {\n const depth = view.commands.length;\n try {\n return await original(id, params, options);\n } finally {\n if (view.commands.length > depth) view.commands.length = depth;\n }\n };\n }\n return () => {\n before.dispose();\n after.dispose();\n };\n }\n\n /** The unit id a view's document has (what a replayed mutation must be addressed to). */\n private unitIdOf(view: AttachedView): string | null {\n try {\n return view.port.unitId?.() ?? view.port.snapshot()?.id ?? null;\n } catch {\n return null;\n }\n }\n\n /** Replay one mutation into every view except `exceptViewId`, addressed to each view's own unit. */\n private relay(info: Readonly<CollabMutationInfo>, exceptViewId: number | null): void {\n if (this.views.size === 0 || (this.views.size === 1 && exceptViewId !== null)) return;\n this.relaying = true;\n let failure: unknown = null;\n try {\n for (const view of this.views.values()) {\n if (view.id === exceptViewId) continue;\n try {\n const params = info.params as unknown;\n const unitId = this.unitIdOf(view);\n const addressed =\n unitId && params && typeof params === \"object\" && !Array.isArray(params) && typeof (params as { unitId?: unknown }).unitId === \"string\" && (params as { unitId: string }).unitId !== unitId\n ? { ...(params as Record<string, unknown>), unitId }\n : info.params;\n view.port.commandService.syncExecuteCommand(info.id, addressed as never, { onlyLocal: true, fromCollab: true });\n } catch (error) {\n failure ??= error;\n console.error(\n `[document-model] a second view of ${this.documentId} could not apply \"${info.id}\" — it may show an older document until it reopens`,\n error,\n );\n }\n }\n } finally {\n this.relaying = false;\n }\n if (failure !== null) this.applyFailed(info.id, failure);\n }\n\n /** A view could not follow an edit: say so, then show the saved version (unless this tab has unsaved edits of its own). */\n private applyFailed(mutationId: string, error: unknown): void {\n try {\n this.deps.onApplyFailed?.(this.documentId, mutationId, error);\n } catch (notifyError) {\n console.warn(`[document-model] the notice for ${this.documentId}'s failed apply also failed`, notifyError);\n }\n if (this.hasUnsaved()) return;\n void this.deps\n .loadLatest(this.documentId)\n .then((row) => {\n if (row && !this.closed) this.show(row);\n })\n .catch((e) => console.warn(`[document-model] could not re-sync ${this.documentId} after a failed apply`, e));\n }\n\n // ── save (run by the record's one coalesced save — documentModels.ts) ─\n\n private markDirty(): void {\n this.handle.touch();\n }\n\n private saving = false;\n /**\n * The content of the version the server holds (loaded or last written). A\n * save of the same content is no save: attaching, detaching, waking or a\n * flush of an unchanged document never writes a snapshot row.\n */\n private savedFingerprint: string | null = null;\n\n /**\n * Write the body as it is now. Returns false when this tab is a collab peer\n * that does not write (the elected host writes the canonical snapshot; a\n * peer's edits reach it through the room). An explicit Save always writes.\n */\n async write(reason: CommitReason): Promise<boolean> {\n if (this.ot) {\n const wrote = await this.ot.write(reason);\n if (wrote) this.deps.onSaved?.(this.documentId, reason === \"manual\" ? \"manual\" : \"autosave\");\n return wrote;\n }\n const snapshot = this.latest();\n if (!snapshot) throw new Error(\"There is no open document to save.\");\n if (this.collab && !this.collab.isHost() && reason !== \"manual\") return false;\n const fingerprint = contentFingerprint(snapshot);\n if (reason !== \"manual\" && fingerprint === this.savedFingerprint) return false;\n const origin = reason === \"manual\" ? \"manual\" : \"autosave\";\n // The room entries this body holds, read in the same step as the body: the saved row names them,\n // so a tab that reloads from it never replays them on top of it.\n const collab = this.collab;\n const covered = collab ? collab.coveredNow() : null;\n this.saving = true;\n try {\n const { id } = await this.deps.save({\n documentId: this.documentId,\n snapshot: covered ? stampCovered(snapshot, covered) : snapshot,\n origin,\n });\n this.knownSnapshots.add(id);\n this.savedFingerprint = fingerprint;\n if (collab && covered && collab.isHost()) collab.checkpoint(id, covered);\n } finally {\n this.saving = false;\n }\n if (this.views.size === 0) this.stored = snapshot;\n this.deps.onSaved?.(this.documentId, origin);\n return true;\n }\n\n private hasUnsaved(): boolean {\n return this.handle.hasPending();\n }\n\n hasViews(): boolean {\n return this.views.size > 0;\n }\n\n // ── realtime (snapshot inserts) ─────────────────────────────────────────\n\n /** Opened once per document by the first view that asks; idempotent. */\n connectRealtime(open: (onSnapshot: (snapshotId: string) => void) => () => void): void {\n if (this.realtimeClose) return;\n this.realtimeClose = open((snapshotId) => void this.onRemoteSnapshot(snapshotId));\n }\n\n /**\n * A snapshot was committed (here or elsewhere): show a foreign one in every\n * view. Over unsaved edits it is a CONFLICT — the working copy holds it and\n * no save runs (one would overwrite the collaborator's snapshot) until the\n * person chooses; `overUnsaved` is \"Take theirs\" (`./documentModels.ts`).\n */\n async onRemoteSnapshot(snapshotId: string, { overUnsaved = false }: { overUnsaved?: boolean } = {}): Promise<void> {\n if (this.collab || this.ot) return; // the room is the live channel; snapshots are checkpoints\n if (this.knownSnapshots.has(snapshotId)) return; // ours, or already shown\n if (this.saving) return; // our own save's echo, ahead of its response\n if (this.hasUnsaved() && !overUnsaved) {\n this.handle.conflict({ ref: snapshotId });\n return;\n }\n const row = await this.deps.loadLatest(this.documentId);\n if (!row || (this.hasUnsaved() && !overUnsaved) || this.knownSnapshots.has(row.id)) return;\n this.show(row);\n }\n\n /**\n * THE content swap (see @ai-matrx/office/univer openEditorContent): a SAVED snapshot\n * replaces the document in every view and the kept editor. It is the saved\n * version from now on, so the pending save compares equal and writes\n * nothing (it would put the old content back over the new). In a collab\n * room the peers reload it and the shared log is emptied.\n */\n replaceContent(row: { id: string; snapshot: DocumentSnapshotData }): void | Promise<void> {\n // A document with an ordered-log room is replaced through `collab_replace` (one atomic door, §20).\n if (this.ot) return this.ot.replace(row.snapshot);\n this.show(row);\n this.collab?.announceReplaced(row.id);\n }\n\n /** A peer replaced the document: show the newest save (once). */\n private async onPeerReplaced(): Promise<void> {\n const row = await this.deps.loadLatest(this.documentId);\n if (!row || this.knownSnapshots.has(row.id)) return;\n this.show(row);\n }\n\n /** A loaded row becomes the base: its content (what views mount) and the room entries it holds. */\n private takeBase(row: { id: string; snapshot: DocumentSnapshotData }): DocumentSnapshotData {\n const { snapshot, covered } = takeCovered(row.snapshot);\n this.baseId = row.id;\n this.baseCovered = covered;\n return snapshot;\n }\n\n private show(row: { id: string; snapshot: DocumentSnapshotData }): void {\n const snapshot = this.takeBase(row);\n this.knownSnapshots.add(row.id);\n this.savedFingerprint = contentFingerprint(snapshot);\n this.stored = snapshot;\n this.relaying = true;\n try {\n for (const view of this.views.values()) view.port.remount(snapshot);\n this.parked?.remount(snapshot);\n } finally {\n this.relaying = false;\n }\n }\n\n // ── collab (one room per document) ──────────────────────────────────────\n\n /**\n * The model's command stream as ONE command service — what the collab room\n * binds to. Local edits from any view go out once; a peer's edit is applied\n * to every view.\n */\n private readonly virtualCommandService: CommandServiceLike = {\n onMutationExecutedForCollab: (listener) => {\n this.collabListeners.add(listener);\n return { dispose: () => this.collabListeners.delete(listener) };\n },\n syncExecuteCommand: (id, params) => {\n const info = { id, type: 2, params } as CollabMutationInfo;\n this.relay(info, null);\n // The host writes what peers typed.\n if (isContentMutation(info)) this.markDirty();\n return true;\n },\n };\n\n /** Join the document's collab room once (the first view that asks). */\n startCollab(factory: DocumentCollabFactory): Promise<void> {\n if (this.collab) return Promise.resolve();\n if (!this.collabStarting) {\n this.collabStarting = factory(\n this.virtualCommandService,\n (awareness) => {\n this.awareness = awareness;\n for (const listener of Array.from(this.awarenessListeners)) listener();\n },\n () => {\n void this.onPeerReplaced().catch((error: unknown) =>\n console.warn(`[document-model] could not load ${this.documentId}'s replaced version`, error),\n );\n },\n {\n snapshotId: () => this.baseId,\n covered: () => this.baseCovered,\n reload: async () => {\n const row = await this.deps.loadLatest(this.documentId);\n if (row && !this.closed) this.show(row);\n },\n },\n )\n .then((handle) => {\n if (!handle) return;\n if (this.views.size === 0) {\n handle.stop();\n return;\n }\n this.collab = handle;\n })\n .finally(() => {\n this.collabStarting = null;\n });\n }\n return this.collabStarting;\n }\n\n /** The model as the ordered-log room sees it (COLLAB-DESIGN §6.7: the model is the client, not the view). */\n private readonly otPort: DocsOtPort = {\n onLocal: (listener) => {\n this.otListeners.add(listener);\n return () => void this.otListeners.delete(listener);\n },\n applyRemote: (id, params) => {\n if (this.views.size === 0) throw new Error(\"no view of the document is mounted\");\n this.relaying = true;\n try {\n for (const view of this.views.values()) {\n const unitId = this.unitIdOf(view);\n const input = Array.isArray(params.actions) ? params.actions.length : 0;\n let sel: Array<{ startOffset: number; endOffset: number; segmentId?: string }> | null = null;\n try {\n sel = view.port.selection?.get() ?? null;\n } catch {\n sel = null;\n }\n const p: Record<string, unknown> = { ...params, ...(unitId ? { unitId } : {}), textRanges: null, noNeedSetTextRange: true };\n const ok = view.port.commandService.syncExecuteCommand(id, p as never, { onlyLocal: true, fromCollab: true });\n if (ok === false) throw new Error(`\"${id}\" was refused by the editor`);\n // the content-control guard empties `actions` on the params object it was handed (§6.6)\n if (input > 0 && Array.isArray(p.actions) && p.actions.length === 0) throw new Error(`\"${id}\" was emptied by the editor`);\n const moved = sel && sel.length && sel.every((r) => !r.segmentId) ? moveRangesThroughBodyEdit(sel, params.actions) : null;\n if (moved) {\n try {\n view.port.selection?.set(moved);\n } catch (error) {\n console.warn(`[document-model] could not move this view's caret past a collaborator's edit`, error);\n }\n }\n }\n } finally {\n this.relaying = false;\n }\n if (isContentMutation({ id, type: 2, params } as unknown as CollabMutationInfo)) this.markDirty();\n },\n snapshot: () => this.latest(),\n load: (snapshot) => {\n const s = snapshot as DocumentSnapshotData;\n this.stored = s;\n this.savedFingerprint = contentFingerprint(s);\n this.relaying = true;\n try {\n for (const view of this.views.values()) view.port.remount(s);\n this.parked?.remount(s);\n } finally {\n this.relaying = false;\n }\n },\n undoTargets: () => {\n const out: Array<{ service: unknown; unitId: string }> = [];\n for (const view of this.views.values()) {\n const unitId = this.unitIdOf(view);\n const service = view.port.undoRedo?.();\n if (unitId && service) out.push({ service, unitId });\n }\n return out;\n },\n markDirty: () => this.markDirty(),\n selection: () => {\n for (const view of this.views.values()) {\n try {\n const sel = view.port.selection?.get();\n if (sel) return sel;\n } catch {\n /* a view mid-teardown has no selection */\n }\n }\n return null;\n },\n };\n\n /** Join the document's ordered-log room once (C3). Exclusive with `startCollab`. */\n startOtRoom(factory: DocumentOtFactory): Promise<void> {\n if (this.ot || this.collab) return Promise.resolve();\n if (!this.otStarting) {\n this.otStarting = factory(this.otPort, (awareness) => {\n this.awareness = awareness;\n for (const listener of Array.from(this.awarenessListeners)) listener();\n })\n .then((handle) => {\n if (!handle) return;\n if (this.views.size === 0) {\n handle.stop();\n return;\n }\n this.ot = handle;\n })\n .finally(() => {\n this.otStarting = null;\n });\n }\n return this.otStarting;\n }\n\n /** Which co-editing room this document is in right now. */\n collabMode(): \"ordered\" | \"relay\" | null {\n return this.ot ? \"ordered\" : this.collab ? \"relay\" : null;\n }\n\n isCollabHost(): boolean {\n if (this.ot) return this.ot.isSaver();\n return this.collab ? this.collab.isHost() : true;\n }\n\n getAwareness(): DocumentAwareness | null {\n return this.awareness;\n }\n\n subscribeAwareness(listener: () => void): () => void {\n this.awarenessListeners.add(listener);\n return () => this.awarenessListeners.delete(listener);\n }\n\n // ── lifecycle (driven by the record's session) ──────────────────────\n\n /** A view arrived on a document with none. */\n wake(): void {\n if (!this.pageClose && this.deps.listenToPage) {\n this.pageClose = this.deps.listenToPage({\n flush: () => void this.handle.flush(),\n hasUnsaved: () => this.hasUnsaved(),\n });\n }\n }\n\n /**\n * The last view left: leave the collab room (presence must not outlive the\n * person). The snapshot channel stays open while the session is kept alive,\n * so a collaborator's save still reaches the body a returning view boots from.\n */\n rest(): void {\n this.collab?.stop();\n this.collab = null;\n this.ot?.stop();\n this.ot = null;\n this.awareness = null;\n }\n\n private closed = false;\n\n close(): void {\n this.closed = true;\n const parked = this.parked;\n this.parked = null;\n if (parked) {\n try {\n parked.dispose();\n } catch (error) {\n console.warn(`[document-model] could not dispose ${this.documentId}'s kept editor`, error);\n }\n }\n this.realtimeClose?.();\n this.realtimeClose = null;\n this.pageClose?.();\n this.pageClose = null;\n }\n}\n\n/**\n * Body offsets moved through a collaborator's body edit (`[\"body\", {et:\"text-x\", e}]`), §6.4 and §6.8. Text inserted\n * before the caret pushes it right; text inserted after it does not.\n *\n * A tie (text inserted EXACTLY at a collapsed caret) follows the one conflict rule. The caret is where this person's\n * next keystroke goes, and that keystroke commits after the edit being applied, so it takes `'left'` and sits first:\n * the caret stays BEFORE the collaborator's text. That is the side the session already gives this seat's unsent and\n * in-flight inserts (`T(local, remote, 'left')`), so the caret stays at the end of this person's own run and two\n * people typing at one spot each keep their words whole (\"FloodEbb\", never \"FElbobod\"). A selection never grows to\n * take in a collaborator's text: an insert at its start lands before it, at its end after it.\n * Null when the edit is not a body edit.\n */\nexport function moveRangesThroughBodyEdit(\n ranges: Array<{ startOffset: number; endOffset: number }>,\n actions: unknown,\n): Array<{ startOffset: number; endOffset: number }> | null {\n const a = actions as unknown[];\n if (!Array.isArray(a) || a[0] !== \"body\") return null;\n const sub = a[1] as { et?: string; e?: unknown } | undefined;\n if (!sub || sub.et !== \"text-x\" || !Array.isArray(sub.e)) return null;\n const e = sub.e as Parameters<typeof TextX.transformPosition>[0];\n return ranges.map((r) => {\n const collapsed = r.startOffset === r.endOffset;\n // TextX.transformPosition's third argument: true = an insert exactly at this offset lands after it\n const startOffset = TextX.transformPosition(e, r.startOffset, collapsed);\n return { startOffset, endOffset: collapsed ? startOffset : TextX.transformPosition(e, r.endOffset, true) };\n });\n}\n\n/**\n * What a snapshot STORES, as a comparable string: everything but the unit id\n * and Univer's revision counter (both move without the content moving).\n */\nfunction contentFingerprint(snapshot: DocumentSnapshotData): string {\n const { id: _id, rev: _rev, ...content } = snapshot as DocumentSnapshotData & { rev?: unknown };\n return JSON.stringify(content);\n}\n\n/** Mutations that change what a snapshot stores (never scroll / selection) — the editors' one dirty filter. */\nfunction isContentMutation(info: Readonly<CollabMutationInfo>): boolean {\n return isSnapshotMutation({ id: info.id, type: info.type, params: info.params } as ICommandInfo);\n}\n","/**\n * isSnapshotMutation — the autosave dirty-filter for the Univer editors.\n *\n * D97: `onCommandExecuted` fires for EVERY command — including viewport\n * scrolls and selection moves — so an unfiltered listener marked the doc\n * dirty on mere scrolling and wrote a new snapshot row (version history +\n * collab broadcast) 2.5s later. Only CommandType.MUTATION changes the data\n * that a snapshot persists (Univer's own docs: OPERATION = \"not saved to\n * snapshot, such as modifying scroll position\"). We therefore accept ONLY\n * mutations, and additionally deny-list any mutation whose id marks it as\n * scroll / selection / viewport bookkeeping, belt-and-braces.\n */\nimport type { ICommandInfo } from \"@univerjs/core\";\n\n/**\n * Univer's `CommandType.MUTATION`. A literal, so this filter (and the document\n * model that uses it outside the editor chunk) never pulls Univer's runtime —\n * which touches `window` at import — into a server-rendered chunk.\n */\nconst MUTATION = 2;\n\n/** Non-content command ids that must never mark the document dirty. */\nconst NON_CONTENT_ID_PATTERN =\n /(scroll|selection|set-selections|viewport|zoom|hover|cursor|focus|activate)/i;\n\nexport function isSnapshotMutation(command: ICommandInfo): boolean {\n if (command.type !== MUTATION) return false;\n if (NON_CONTENT_ID_PATTERN.test(command.id)) return false;\n return true;\n}\n\n/**\n * Mutations a SPREADSHEET fires on its own while it opens and recalculates —\n * they change nothing the person typed, so they must never mark the workbook\n * dirty. Observed on a plain open of a workbook with formulas (2026-10-10):\n * `formula.mutation.set-trigger-formula-calculation-start`,\n * `...set-formula-calculation-start`, `...set-formula-calculation-notification`\n * and a `doc.mutation.rich-text-editing` from the internal cell-editor document.\n * Each open then wrote a new snapshot (history bloat, and a false \"both changed\"\n * against Google). A real edit always arrives as a `sheet.mutation.*`.\n */\nconst WORKBOOK_SELF_MUTATION_PATTERN =\n /^(formula\\.mutation\\.[a-z-]*(calculation|trigger)[a-z-]*|doc\\.mutation\\.)/;\n\nexport function isWorkbookSnapshotMutation(command: ICommandInfo): boolean {\n if (!isSnapshotMutation(command)) return false;\n return !WORKBOOK_SELF_MUTATION_PATTERN.test(command.id);\n}\n","/**\n * A saved snapshot names the collab-room entries it already holds, so a seat that boots from it never\n * replays them (2026-10-16: a reload showed the text twice). Pure — no Yjs — so the editors' model can\n * stamp and read it without loading the room.\n */\n\n/** The key a saved snapshot carries its covered room entries under (`stampCovered` / `takeCovered`). */\nexport const COLLAB_COVERED_KEY = \"__matrxCollabCovered\";\n\n/** The snapshot to SAVE: `snapshot` plus the room entries it holds (`WorkbookCollabSession.coveredNow`). */\nexport function stampCovered<T extends object>(snapshot: T, covered: readonly string[]): T {\n return { ...snapshot, [COLLAB_COVERED_KEY]: [...covered] };\n}\n\n/** A LOADED snapshot split into the content to mount and the room entries it already holds. */\nexport function takeCovered<T>(snapshot: T): { snapshot: T; covered: Set<string> } {\n if (!snapshot || typeof snapshot !== \"object\" || !(COLLAB_COVERED_KEY in (snapshot as object))) {\n return { snapshot, covered: new Set() };\n }\n const { [COLLAB_COVERED_KEY]: list, ...rest } = snapshot as Record<string, unknown>;\n return {\n snapshot: rest as T,\n covered: new Set(Array.isArray(list) ? list.filter((e): e is string => typeof e === \"string\") : []),\n };\n}\n","/**\n * Pure validation for the `matrx-user/documents` write targets.\n *\n * Deliberately OUTSIDE the React updater. `applySurfaceWrite`\n * (`features/surfaces/runtime/surface-writeback.ts`) turns a THROW from a\n * handler into the error envelope the agent reads back. Validating inside a\n * `setState` updater would instead throw during React's render/commit — after\n * the seam has already reported success — so the agent would be told its bad\n * value landed. Validate here, synchronously, before touching any state.\n *\n * `DOCUMENT_NAME_MAX_LENGTH` is the single source of truth for the limit: it is\n * enforced here, interpolated into the manifest target description, AND set as\n * the `maxLength` of the header rename field on `/documents/[id]` — so the\n * contract the agent reads, the rule the handler enforces, and the limit the\n * human's own control applies cannot drift apart. The last of those matters\n * for a non-obvious reason: the blur commit swallows service failures, so\n * before the field was bounded a pasted 300-character title came back as a\n * `varchar(255)` 400 and reverted with nothing on screen to explain it.\n */\n\n/**\n * `workbench.udt_documents.document_name` is `varchar(255) NOT NULL` — a\n * longer value is rejected by Postgres, not merely by taste. Verified against\n * `information_schema.columns` on 2026-08-11.\n */\nexport const DOCUMENT_NAME_MAX_LENGTH = 255;\n\n/**\n * `workbench.udt_documents.description` is unbounded `text`, so this is a\n * product bound rather than a database one: it matches the 2000 the sibling\n * `workbook_description` target enforces, keeping the two mirrored services\n * mirrored in behavior too. The library renders this as a two-line blurb —\n * anything near the cap is already past what a reader sees.\n */\nexport const DOCUMENT_DESCRIPTION_MAX_LENGTH = 2000;\n\n/** How a rejected value is described back to the agent, without dumping it. */\nfunction describeValue(value: unknown): string {\n if (value === null) return \"null\";\n if (Array.isArray(value)) return \"an array\";\n if (typeof value === \"object\") return \"an object\";\n return `a ${typeof value}`;\n}\n\n/**\n * Validate an agent-supplied document title and return the exact string to\n * persist. Throws (never coerces) so the agent hears about its own mistake.\n *\n * The `typeof` guard is load-bearing: the inline-tool layer PARSES a\n * JSON-looking argument before the handler ever sees it, so a caller that\n * sends `{\"document_name\":\"...\"}` or `\"\\\"Quoted\\\"\"` arrives here as an object,\n * not text. The message names the fix explicitly, because an agent that only\n * hears \"invalid\" tends to retry by double-encoding — which lands escaped\n * quotes and `\\n` in the user's title box.\n */\nexport function validateDocumentName(value: unknown): string {\n if (typeof value !== \"string\") {\n throw new Error(\n `document_name must be plain text, not JSON and not JSON-encoded — received ${describeValue(\n value,\n )}. Send only the title itself (for example: Q3 Revenue Review) with no surrounding braces, brackets, quotes or escape sequences.`,\n );\n }\n\n const trimmed = value.trim();\n\n if (trimmed.length === 0) {\n throw new Error(\n \"document_name cannot be empty or whitespace — a document must keep a title. Send the title text you want, or leave the current one alone.\",\n );\n }\n\n if (/[\\r\\n]/.test(trimmed)) {\n throw new Error(\n \"document_name must be a SINGLE line — it renders in the page header, and line breaks are not a title. Send one line of plain text (this is a title, not the document body).\",\n );\n }\n\n if (trimmed.length > DOCUMENT_NAME_MAX_LENGTH) {\n throw new Error(\n `document_name must be ${DOCUMENT_NAME_MAX_LENGTH} characters or fewer (received ${trimmed.length}). Shorten it to a title; the document body is not stored in this field.`,\n );\n }\n\n return trimmed;\n}\n\n/**\n * Validate an agent-supplied document description and return the value to\n * persist — `null` for a deliberate clear, so the caller never has to decide\n * whether \"\" means \"empty string\" or \"no description\".\n *\n * Unlike the title this MAY span lines (it is a blurb, not a header), but it\n * carries the same not-JSON guard for the same reason: the inline-tool layer\n * parses a JSON-looking argument before the handler sees it.\n */\nexport function validateDocumentDescription(value: unknown): string | null {\n if (typeof value !== \"string\") {\n throw new Error(\n `document_description must be plain text, not JSON and not JSON-encoded — received ${describeValue(\n value,\n )}. Send only the description prose itself, with no surrounding braces, brackets, quotes or escape sequences.`,\n );\n }\n\n const trimmed = value.trim();\n\n // An empty string is the documented way to CLEAR the description, so it is\n // valid input rather than a bad shape — normalize it to null for the column.\n if (trimmed.length === 0) return null;\n\n if (trimmed.length > DOCUMENT_DESCRIPTION_MAX_LENGTH) {\n throw new Error(\n `document_description must be ${DOCUMENT_DESCRIPTION_MAX_LENGTH} characters or fewer (received ${trimmed.length}). This is the short blurb shown in the documents library, not the document body.`,\n );\n }\n\n return trimmed;\n}\n","/**\n * The zoom that fits a document page inside a narrow editor (a phone), so the\n * page reflows into view instead of scrolling sideways. Never above 100%, and\n * never so small the text is unreadable. Pure — guarded by fit-zoom-ratio.test.ts.\n */\nexport const MIN_FIT_ZOOM = 0.45;\n\nexport function fitZoomRatio(containerWidth: number, pageWidth: number, gutter = 8): number {\n if (!(containerWidth > 0) || !(pageWidth > 0)) return 1;\n const ratio = (containerWidth - gutter * 2) / pageWidth;\n return Math.min(1, Math.max(MIN_FIT_ZOOM, Math.round(ratio * 100) / 100));\n}\n","import type { DocumentSource } from \"../core\";\n\nconst SOURCE_LABELS: Record<DocumentSource, string> = {\n created: \"Created\",\n imported_docx: \"Imported DOCX\",\n imported_md: \"Imported Markdown\",\n imported_txt: \"Imported Text\",\n linked_gdoc: \"Imported from Google Docs\",\n};\n\nexport function documentSourceLabel(source: DocumentSource): string {\n return SOURCE_LABELS[source] ?? source;\n}\n","/** Insert, Emoji and Special characters: searchable sets, a name per entry. */\n\nexport interface Glyph {\n char: string;\n name: string;\n}\n\nconst e = (rows: string): Glyph[] =>\n rows.split(\"|\").map((r) => r.trim()).filter(Boolean).map((r) => {\n const [char, ...name] = r.split(\" \");\n return { char: char!, name: name.join(\" \") };\n });\n\nexport const EMOJI_GROUPS: Array<{ id: string; label: string; items: Glyph[] }> = [\n { id: \"faces\", label: \"Faces\", items: e(\"😀 grinning|😃 smile|😄 happy|😁 beaming|😆 laughing|😅 sweat smile|😂 tears of joy|🤣 rolling|🙂 slight smile|🙃 upside down|😉 wink|😊 blush|😇 angel|🥰 love|😍 heart eyes|🤩 star struck|😘 kiss|😋 yum|😎 cool|🤓 nerd|🤔 thinking|🤨 skeptical|😐 neutral|🙄 eye roll|😬 grimace|😴 sleeping|😢 cry|😭 sobbing|😤 huff|😡 angry|🤯 mind blown|😱 scream|🥳 party|🤗 hug|🫡 salute|😮 surprised|😳 flushed|🥺 pleading|😷 mask|🤒 sick\") },\n { id: \"people\", label: \"Gestures\", items: e(\"👍 thumbs up|👎 thumbs down|👏 clap|🙌 raised hands|🙏 pray thanks|🤝 handshake|💪 strong flex|👌 ok|✌ victory peace|🤞 fingers crossed|👋 wave|✋ raised hand|👆 point up|👉 point right|👈 point left|👇 point down|✍ writing|🤷 shrug|🙋 raise hand|👀 eyes|🧠 brain|❤ heart|💔 broken heart|💯 hundred\") },\n { id: \"objects\", label: \"Objects\", items: e(\"💡 idea light bulb|📌 pin|📎 paperclip|📝 memo note|📅 calendar|📈 chart up|📉 chart down|📊 bar chart|📁 folder|📄 page|📧 email|📞 phone|💻 laptop|📱 mobile|🔒 lock|🔑 key|🔍 search|🔔 bell|⏰ alarm clock|⌛ hourglass|🎯 target|🏆 trophy|🎁 gift|📦 package|🛠 tools|⚙ gear|💰 money bag|💵 dollar|🧾 receipt|📚 books\") },\n { id: \"symbols\", label: \"Marks\", items: e(\"✅ check mark|❌ cross|⭐ star|🌟 glowing star|✨ sparkles|🔥 fire|⚡ lightning|🚀 rocket|🎉 party popper|🎊 confetti|⚠ warning|❓ question|❗ exclamation|➕ plus|➖ minus|🔴 red circle|🟠 orange circle|🟡 yellow circle|🟢 green circle|🔵 blue circle|🟣 purple circle|⬆ up|⬇ down|➡ right|⬅ left|🔁 repeat|✔ heavy check\") },\n { id: \"nature\", label: \"Nature and food\", items: e(\"🌞 sun|🌙 moon|☁ cloud|🌧 rain|❄ snowflake|🌈 rainbow|🌱 seedling|🌳 tree|🌸 blossom|🌍 earth|🐶 dog|🐱 cat|🦊 fox|🐝 bee|🦋 butterfly|🍎 apple|🍕 pizza|🍔 burger|☕ coffee|🍺 beer|🍷 wine|🎂 cake|🍪 cookie|🥑 avocado\") },\n];\n\nconst s = (chars: string, names: string[]): Glyph[] => Array.from(chars).map((char, i) => ({ char, name: names[i] ?? char }));\n\nexport const SPECIAL_GROUPS: Array<{ id: string; label: string; items: Glyph[] }> = [\n { id: \"punctuation\", label: \"Punctuation\", items: s(\"©®™°§¶†‡•…‰№‘’“”«»–—¡¿·\", [\"copyright\", \"registered\", \"trademark\", \"degree\", \"section\", \"pilcrow\", \"dagger\", \"double dagger\", \"bullet\", \"ellipsis\", \"per mille\", \"numero\", \"left single quote\", \"right single quote\", \"left double quote\", \"right double quote\", \"left guillemet\", \"right guillemet\", \"en dash\", \"em dash\", \"inverted exclamation\", \"inverted question\", \"middle dot\"]) },\n { id: \"arrows\", label: \"Arrows\", items: s(\"←↑→↓↔↕⇐⇑⇒⇓⇔↩↪➜➤↖↗↘↙↺↻\", [\"left arrow\", \"up arrow\", \"right arrow\", \"down arrow\", \"left right arrow\", \"up down arrow\", \"left double arrow\", \"up double arrow\", \"right double arrow\", \"down double arrow\", \"left right double arrow\", \"return arrow\", \"hook arrow\", \"heavy arrow\", \"arrowhead\", \"north west arrow\", \"north east arrow\", \"south east arrow\", \"south west arrow\", \"anticlockwise arrow\", \"clockwise arrow\"]) },\n { id: \"math\", label: \"Math\", items: s(\"±×÷≈≠≤≥∞√∑∏∫∂∆∇∈∉∪∩⊂⊃∧∨¬∀∃∅∝∠¼½¾⅓⅔²³\", [\"plus minus\", \"times\", \"divide\", \"approximately\", \"not equal\", \"less or equal\", \"greater or equal\", \"infinity\", \"square root\", \"sum\", \"product\", \"integral\", \"partial\", \"increment\", \"nabla\", \"element of\", \"not element\", \"union\", \"intersection\", \"subset\", \"superset\", \"and\", \"or\", \"not\", \"for all\", \"exists\", \"empty set\", \"proportional\", \"angle\", \"one quarter\", \"one half\", \"three quarters\", \"one third\", \"two thirds\", \"squared\", \"cubed\"]) },\n { id: \"currency\", label: \"Currency\", items: s(\"$€£¥¢₹₩₽₺₿฿₫₪₴₦₱\", [\"dollar\", \"euro\", \"pound\", \"yen\", \"cent\", \"rupee\", \"won\", \"ruble\", \"lira\", \"bitcoin\", \"baht\", \"dong\", \"shekel\", \"hryvnia\", \"naira\", \"peso\"]) },\n { id: \"greek\", label: \"Greek\", items: s(\"αβγδεζηθικλμνξοπρστυφχψωΩΣΔΠΦΨΛΘ\", [\"alpha\", \"beta\", \"gamma\", \"delta\", \"epsilon\", \"zeta\", \"eta\", \"theta\", \"iota\", \"kappa\", \"lambda\", \"mu\", \"nu\", \"xi\", \"omicron\", \"pi\", \"rho\", \"sigma\", \"tau\", \"upsilon\", \"phi\", \"chi\", \"psi\", \"omega\", \"capital omega\", \"capital sigma\", \"capital delta\", \"capital pi\", \"capital phi\", \"capital psi\", \"capital lambda\", \"capital theta\"]) },\n { id: \"latin\", label: \"Accented letters\", items: s(\"àáâãäåæçèéêëìíîïñòóôõöøœùúûüýÿßÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÑÒÓÔÕÖØŒÙÚÛÜÝŸ\", []) },\n { id: \"shapes\", label: \"Shapes\", items: s(\"■□▲△▼▽◆◇●○★☆♠♣♥♦♪♫☑☒\", [\"black square\", \"white square\", \"black up triangle\", \"white up triangle\", \"black down triangle\", \"white down triangle\", \"black diamond\", \"white diamond\", \"black circle\", \"white circle\", \"black star\", \"white star\", \"spade\", \"club\", \"heart suit\", \"diamond suit\", \"eighth note\", \"beamed notes\", \"checked box\", \"crossed box\"]) },\n];\n\nexport function searchSymbols(groups: typeof EMOJI_GROUPS, query: string): Glyph[] {\n const q = query.trim().toLowerCase();\n if (!q) return [];\n const seen = new Set<string>();\n const out: Glyph[] = [];\n for (const g of groups) for (const it of g.items) if ((it.char === q || it.name.toLowerCase().includes(q)) && !seen.has(it.char)) (seen.add(it.char), out.push(it));\n return out;\n}\n","/**\n * The BODY TEXT of a Univer document, as agents read and write it (PURE).\n *\n * `matrx-user/documents` declares the body as a value (`document_body_text`)\n * and a write target (`document_body`). Univer owns the document model, so\n * both go through a small port the editor hands up (`DocumentEditor`\n * `onBodyPort`): the read is the body's data stream as plain text, and a write\n * is ONE changed span, applied through Univer's own facade (`deleteRange` /\n * `insertText`, which run `InsertTextCommand` on the command service). That\n * keeps every agent edit on the one editing path a keystroke takes: undo,\n * autosave snapshots, History and collab all see it, and formatting outside\n * the changed span is left exactly as it was.\n *\n * Univer's data stream encodes a paragraph end as `\\r`, a section break as\n * `\\n`, and custom blocks / tables with control characters below U+0020. The\n * plain text maps a paragraph end to `\\n` and leaves the other control tokens\n * out; `offsets` maps each text position back to its data-stream index so a\n * change found in the text lands at the right place in the stream.\n */\n\nimport { looksLikeMarkdown } from \"./doc-tools-core\";\n\n/** The shape of a surface write handler (structurally the chat runtime's `SurfaceWriteHandlerEntry`; the package imports no chat). */\nexport interface DocumentBodyWriteHandler {\n validate: (value: unknown) => void;\n apply: (value: unknown) => { summary: string; data?: unknown };\n}\n\n/**\n * A product bound, not a database one (snapshots are jsonb): a body an agent\n * sends larger than this is almost certainly a mistake (a whole file pasted\n * twice), and past it the approval card stops being readable.\n */\nexport const DOCUMENT_BODY_MAX_LENGTH = 200_000;\n\n/** What the editor lends the surface. Each call resolves the live document. */\nexport interface DocumentBodyPort {\n /** The main body's Univer data stream (ends with `\\r\\n`). */\n getDataStream: () => string;\n /** The live document snapshot (body with its text runs), for reading the formatting back out. */\n getSnapshot?: () => unknown;\n /** Delete `[start, end)` of the data stream; false when Univer refused. */\n deleteRange: (start: number, end: number) => boolean;\n /** Insert plain text (a `\\n` starts a new paragraph) at a stream index. */\n insertText: (at: number, text: string) => boolean;\n /**\n * Insert MARKDOWN at a stream index as real structure (tables, headings, lists, bold, links).\n * Absent only where a port cannot (then the text goes in as typed).\n */\n insertMarkdown?: (at: number, markdown: string) => boolean;\n /** Run a Univer command in the open editor (File menu: find and replace, comments). */\n runCommand?: (commandId: string) => Promise<void>;\n /** File → Page setup: open the page setup dialog in the open editor. */\n openPageSetup?: () => void;\n /** File → Language (and the other Docs tool dialogs): open one in the open editor. */\n openTool?: (id: \"language\") => void;\n}\n\nexport interface BodyText {\n text: string;\n /** `offsets[i]` = the stream index of text position `i`; length is text.length + 1. */\n offsets: number[];\n}\n\nconst PARAGRAPH = \"\\r\";\nconst SECTION = \"\\n\";\n\n/** The body's plain text and where each character sits in the stream. */\nexport function bodyTextOf(dataStream: string): BodyText {\n let text = \"\";\n const offsets: number[] = [];\n for (let i = 0; i < dataStream.length; i++) {\n const ch = dataStream[i];\n if (ch === PARAGRAPH) {\n text += \"\\n\";\n offsets.push(i);\n continue;\n }\n if (ch === SECTION) continue;\n if (ch !== \"\\t\" && ch!.charCodeAt(0) < 0x20) continue;\n text += ch;\n offsets.push(i);\n }\n // Every body ends with its last paragraph mark: it is not text a person\n // typed, and it can never be deleted (Univer protects it). Text that ends\n // there inserts before it.\n if (text.endsWith(\"\\n\")) {\n const end = offsets[offsets.length - 1];\n text = text.slice(0, -1);\n offsets.pop();\n offsets.push(end!);\n } else {\n offsets.push(dataStream.length);\n }\n return { text, offsets };\n}\n\nexport interface BodyEdit {\n /** Stream range to remove (may be empty). */\n start: number;\n end: number;\n /** Plain text to insert at `start` (may be empty). */\n insert: string;\n}\n\n/**\n * The ONE span that turns the current body into `next`: the longest common\n * prefix and suffix stay untouched (with their formatting), only the middle\n * changes. Null when nothing differs.\n */\nexport function planBodyEdit(current: BodyText, next: string): BodyEdit | null {\n const a = current.text;\n const b = next;\n if (a === b) return null;\n let prefix = 0;\n const max = Math.min(a.length, b.length);\n while (prefix < max && a[prefix] === b[prefix]) prefix++;\n let suffix = 0;\n while (\n suffix < max - prefix &&\n a[a.length - 1 - suffix] === b[b.length - 1 - suffix]\n )\n suffix++;\n const removeTo = a.length - suffix;\n return {\n start: current.offsets[prefix]!,\n end: current.offsets[removeTo]!,\n insert: b.slice(prefix, b.length - suffix),\n };\n}\n\n/**\n * Put the new span in. Markdown structure in it (a table above all) becomes real document structure\n * through the one converter; the span starts on its own paragraph so a block never splits a line (a span that would start mid-line goes in at the next paragraph start).\n */\nfunction insertSpan(port: DocumentBodyPort, _current: BodyText, edit: BodyEdit): boolean {\n if (port.insertMarkdown && looksLikeMarkdown(edit.insert)) {\n const stream = port.getDataStream();\n let at = edit.start;\n if (at > 0 && stream[at - 1] !== PARAGRAPH) {\n const end = stream.indexOf(PARAGRAPH, at);\n at = end < 0 ? stream.length : end + 1;\n }\n return port.insertMarkdown(at, edit.insert.replace(/^\\n+/, \"\"));\n }\n return port.insertText(edit.start, edit.insert);\n}\n\n/** Apply `next` as the whole body text through the port. */\nexport function writeBodyText(\n port: DocumentBodyPort,\n next: string,\n): { changed: boolean; removed: number; inserted: number } {\n const current = bodyTextOf(port.getDataStream());\n const edit = planBodyEdit(current, next);\n if (!edit) return { changed: false, removed: 0, inserted: 0 };\n if (edit.end > edit.start && !port.deleteRange(edit.start, edit.end)) {\n throw new Error(\n \"The editor refused to remove the old text (the document may be read-only right now). Nothing was changed.\",\n );\n }\n if (edit.insert.length > 0 && !insertSpan(port, current, edit)) {\n throw new Error(\n edit.end > edit.start\n ? \"The editor removed the old text but refused the new text. Press Undo in the document to bring the old text back, then try again.\"\n : \"The editor refused the new text (the document may be read-only right now). Nothing was changed.\",\n );\n }\n return {\n changed: true,\n removed: edit.end - edit.start,\n inserted: edit.insert.length,\n };\n}\n\nfunction describeValue(value: unknown): string {\n if (value === null) return \"null\";\n if (Array.isArray(value)) return \"an array\";\n if (typeof value === \"object\") return \"an object\";\n return `a ${typeof value}`;\n}\n\n/** Shape check for an agent-sent body; throws a sentence the agent can act on. */\nexport function validateDocumentBody(value: unknown): string {\n if (typeof value !== \"string\") {\n throw new Error(\n `document_body must be the document's whole text as a plain string (or an anchored edit {command, old_str, new_str}) — received ${describeValue(\n value,\n )}. Read document_body_text, change it, and send the full new text.`,\n );\n }\n if (value.length > DOCUMENT_BODY_MAX_LENGTH) {\n throw new Error(\n `document_body must be ${DOCUMENT_BODY_MAX_LENGTH} characters or fewer (received ${value.length}). Nothing was changed.`,\n );\n }\n return value.replace(/\\r\\n?/g, \"\\n\");\n}\n\n/**\n * The `document_body` write handler. `getPort` answers the live editor's port\n * (null until Univer has mounted the document); `assertWritable` throws when\n * the record is not loaded or the person may only view it.\n */\nexport function documentBodyWriteHandler(deps: {\n getPort: () => DocumentBodyPort | null;\n assertWritable: (whatItBlocks: string) => void;\n}): DocumentBodyWriteHandler {\n return {\n validate: (value) => {\n validateDocumentBody(value);\n },\n apply: (value) => {\n const next = validateDocumentBody(value);\n deps.assertWritable(\"its text cannot be changed\");\n const port = deps.getPort();\n if (!port) {\n throw new Error(\n \"The document editor has not finished opening yet. Nothing was changed; try again in a moment.\",\n );\n }\n const result = writeBodyText(port, next);\n if (!result.changed) {\n return { summary: \"The document already has exactly this text; nothing changed.\" };\n }\n return {\n summary: `Changed the document's text in the editor (removed ${result.removed} characters, inserted ${result.inserted}); the editor saves it within a few seconds, and Undo in the document reverses it.`,\n data: { removed: result.removed, inserted: result.inserted },\n };\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/work/aidream/aidream/apps/shared/office/dist/docs.cjs","../src/docs/document-model.ts","../src/univer/isSnapshotMutation.ts","../src/univer/collab/covered.ts","../src/docs/document-write-validation.ts","../src/docs/fit-zoom-ratio.ts","../src/docs/documents-hub-display.ts","../src/docs/doc-symbols.ts","../src/docs/document-body-text.ts","../src/docs/remote-carets.ts"],"names":["e","view","s"],"mappings":"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EAAA;AACM,IAAA;AACA,IAAA;AACZ,IAAA;AACIE,IAAAA;AACvB,EAAA;AACyB,EAAA;AAC3B;AAEO;AAIc,EAAA;AAAA,IAAA;AACA,IAAA;AAChB,EAAA;AAFgB,EAAA;AACA,EAAA;AAJO,mBAAA;AAA8D;AAQ1C,EAAA;AAC9B,IAAA;AACD,IAAA;AACQ,IAAA;AACH,MAAA;AACN,MAAA;AACI,MAAA;AACK,MAAA;AACE,MAAA;AACT,MAAA;AACM,MAAA;AACEA,MAAAA;AACCA,MAAAA;AAEJ,MAAA;AACI,MAAA;AACX,MAAA;AACX,IAAA;AACqB,IAAA;AACA,MAAA;AACC,QAAA;AACT,QAAA;AACZ,MAAA;AACF,IAAA;AACO,IAAA;AACT,EAAA;AAAA;AAGwC,EAAA;AAC1B,IAAA;AACS,IAAA;AACN,MAAA;AACK,MAAA;AACE,MAAA;AACJ,MAAA;AACH,QAAA;AACH,QAAA;AACV,MAAA;AACF,IAAA;AACO,IAAA;AACT,EAAA;AAAA;AAGsB,EAAA;AACD,IAAA;AACS,IAAA;AACP,IAAA;AACA,MAAA;AACD,MAAA;AACpB,IAAA;AACqB,IAAA;AACd,IAAA;AACT,EAAA;AACF;ATuzB2B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/aidream/aidream/apps/shared/office/dist/docs.cjs","sourcesContent":[null,"/**\n * THE DOCUMENT MODEL — the engine of one cloud document per tab.\n *\n * Before this, the document lived only inside each `DocumentEditor`'s Univer\n * instance. A remount (a board tile waking, a tile removed and undone, a route\n * change and back) rebuilt the editor from the SERVER copy, so whatever the\n * last save had not carried yet was gone; two mounts of one document were two\n * editors, each saving full snapshots of its own copy (last write wins), each\n * with its own realtime channel and its own collab room.\n *\n * The document is a record on THE one working-copy primitive\n * (`@ai-matrx/kit/working-copy`, kind `udt_document`,\n * `./documentModels.ts`): its save status, dirty and view count are Redux state\n * (`workingCopies[\"udt_document:<id>\"]`), its one coalesced save is the kind's.\n * What Redux cannot hold — Univer's body — is this engine, registered on the\n * record's session under the same key:\n *\n * - BODY. Every local mutation in one view is replayed into every other view\n * of the document (the same mutation stream collab sends between machines),\n * so two views show one document. A new view boots from the engine's latest\n * state — a live view's snapshot, or the snapshot the last view left behind\n * — never the stale server copy while the record's session is alive.\n * - SIDE EFFECTS, ONCE. The snapshot realtime channel, the collab room, and\n * the pagehide / visibility / beforeunload flush are opened once per\n * document and closed once.\n * - THE EDITOR ITSELF, KEPT. Univer keeps its undo / redo history inside the\n * editor instance, so rebuilding the editor on a remount threw the history\n * away. When the last view leaves, its editor (a Univer instance with its\n * own DOM host) is parked here — off the page, alive — and the next view of\n * the document RE-ATTACHES that same instance to its own container instead\n * of booting a new one (`parkEditor` / `takeParkedEditor`). Undo and redo\n * therefore work across hide / show, a remount and a removed tile undone,\n * for as long as the record's session is warm; `close()` disposes it.\n */\n\nimport type { ICommandInfo, IDocumentData } from \"@univerjs/core\";\nimport { TextX } from \"@univerjs/core\";\nimport type { CommitReason, WorkingCopyHandle } from \"@ai-matrx/kit/working-copy\";\nimport type { AwarenessState } from \"@ai-matrx/data/realtime/collab\";\nimport { isSnapshotMutation } from \"../univer\";\nimport { stampCovered, takeCovered } from \"../univer/collab/covered\";\nimport type {\n CollabMutationInfo,\n CommandServiceLike,\n} from \"../univer/collab\";\nimport type { DocsLocalMutation, DocsOtPort } from \"../univer/collab/docs-ot/room\";\nimport type { RemoteCaret } from \"./remote-carets\";\n\n/** Univer's command service as a view lends it: the collab pair plus the command hooks capture groups by. */\ntype ViewCommandService = CommandServiceLike & {\n beforeCommandExecuted?: (listener: (info: { id: string; type?: number; params?: unknown }) => void) => { dispose: () => void };\n onCommandExecuted?: (listener: (info: { id: string; type?: number; params?: unknown }) => void) => { dispose: () => void };\n executeCommand?: (id: string, params?: unknown, options?: unknown) => Promise<unknown>;\n};\n\nconst RICH_TEXT_EDITING_ID = \"doc.mutation.rich-text-editing\";\n/** Univer's CommandType.COMMAND. */\nconst COMMAND_TYPE = 0;\nconst DEPTH_GUARDED = Symbol.for(\"ai-matrx.office.docs.command-depth-guard\");\n\n/** Debounce from the last edit to the save. */\nexport const DOCUMENT_SAVE_DELAY_MS = 2500;\n\nexport type DocumentSnapshotData = Partial<IDocumentData>;\n\n/** What a view lends the model while it is mounted. */\nexport interface DocumentViewPort {\n /** Univer's command service for this view's instance. */\n commandService: CommandServiceLike;\n /** The live document of this view (`doc.save()`), or null if it has none. */\n snapshot: () => DocumentSnapshotData | null;\n /** Replace the whole document in this view (a collaborator's snapshot). */\n remount: (snapshot: DocumentSnapshotData) => void;\n /** Whether this view may change the document (read at edit time). */\n editable: () => boolean;\n /**\n * This view's text selection (body offsets), so a collaborator's edit moves the caret with the characters\n * (§6.8). Without it a remote apply leaves the caret at its old offset and the next keystrokes land elsewhere.\n */\n selection?: {\n get: () => Array<{ startOffset: number; endOffset: number; segmentId?: string }> | null;\n set: (ranges: Array<{ startOffset: number; endOffset: number }>) => void;\n };\n /** Univer's undo/redo service of this view's instance (the co-editing room rebases its items, §6.9). */\n undoRedo?: () => unknown;\n /**\n * The Univer unit id of this view's mounted document. Every seat mounts its own unit, so a\n * mutation carries the SENDER's id and must be re-addressed to this view's unit before it is\n * applied. Falls back to the id of `snapshot()` when a view does not state it.\n */\n unitId?: () => string | null;\n}\n\n/** Everything the engine reaches outside itself — injected so it is testable. */\nexport interface DocumentModelDeps {\n /** The newest stored snapshot (its row id + body), or null for a document never saved. */\n loadLatest: (documentId: string) => Promise<{ id: string; snapshot: DocumentSnapshotData } | null>;\n save: (input: {\n documentId: string;\n snapshot: DocumentSnapshotData;\n origin: \"autosave\" | \"manual\";\n }) => Promise<{ id: string; createdBy: string | null }>;\n onSaved?: (documentId: string, origin: \"autosave\" | \"manual\") => void;\n /** Window-level listeners (pagehide, visibilitychange, beforeunload). */\n listenToPage?: (handlers: { flush: () => void; hasUnsaved: () => boolean }) => () => void;\n /** A mutation could not be applied to a view: the app says so (a notice); the model re-syncs from the saved version. */\n onApplyFailed?: (documentId: string, mutationId: string, error: unknown) => void;\n}\n\ninterface AttachedView {\n id: number;\n port: DocumentViewPort;\n dispose: () => void;\n /** The outermost commands running in this view (closed in try/finally, C0 surprise 7). */\n commands: string[];\n /** The document before the rich-text mutation about to run (only while a co-editing room listens). */\n pre: unknown | null;\n}\n\n/** The document's room on the ordered log (COLLAB-DESIGN §6, C3), bound through `startOtRoom`. */\nexport interface DocumentOtHandle {\n stop: () => void;\n write: (reason: CommitReason) => Promise<boolean>;\n replace: (snapshot: DocumentSnapshotData) => Promise<void>;\n isSaver: () => boolean;\n}\n\nexport type DocumentOtFactory = (\n port: DocsOtPort,\n onAwareness: (awareness: DocumentAwareness) => void,\n) => Promise<DocumentOtHandle | null>;\n\n/** A collab room (WorkbookCollabSession) bound to the model's command stream. */\nexport interface DocumentCollabHandle {\n stop: () => void;\n isHost: () => boolean;\n /** This tab replaced the whole document and saved it as `snapshotId`: peers reload it. */\n announceReplaced: (snapshotId: string) => void;\n /** The room entries this tab's body holds right now (read with the body that is about to be saved). */\n coveredNow: () => string[];\n /** The saved snapshot `snapshotId` holds `covered`: they leave the room's log (the elected saver only). */\n checkpoint: (snapshotId: string, covered: readonly string[]) => void;\n}\n\n/** The saved snapshot this tab's body started from — what the room must never replay on top of it. */\nexport interface DocumentCollabBase {\n snapshotId: () => string | null;\n covered: () => ReadonlySet<string>;\n /** Show the newest saved snapshot (the room's newest checkpoint is newer than what this tab loaded). */\n reload: () => Promise<void>;\n}\n\n/** Who else is in the document's room (shared by every view of it). */\nexport interface DocumentAwareness {\n states: Map<number, AwarenessState>;\n selfUid: string;\n /** Other seats' carets and selections (ordered-log rooms only, C8), already moved through every edit applied since. */\n carets?: RemoteCaret[];\n}\n\n/**\n * An editor instance kept alive between views of the document: its DOM host\n * (re-parented into the next view's container) and the instance behind it,\n * whose undo history survives because the instance does. Opaque to the model\n * apart from what it calls.\n */\nexport interface ParkedDocumentEditor<T = unknown> {\n /** The element the editor renders into; the next view appends it to its container. */\n element: HTMLElement;\n instance: T;\n /** Replace the whole document (a collaborator's snapshot arrived while parked). */\n remount: (snapshot: DocumentSnapshotData) => void;\n /** Throw the instance away (the record's session closed). */\n dispose: () => void;\n}\n\nexport type DocumentCollabFactory = (\n commandService: CommandServiceLike,\n onAwareness: (awareness: DocumentAwareness) => void,\n /** A peer replaced the whole document (history restore, Google update). */\n onReplaced: () => void,\n /** What this tab's body was loaded from; pass it to the session (`base`). */\n base: DocumentCollabBase,\n) => Promise<DocumentCollabHandle | null>;\n\nlet viewIds = 0;\n\nexport class DocumentModel {\n readonly documentId: string;\n private readonly deps: DocumentModelDeps;\n private readonly handle: WorkingCopyHandle;\n private readonly views = new Map<number, AttachedView>();\n private lastEditedView: number | null = null;\n /** The document as the last view left it, or as last loaded / saved. */\n private stored: DocumentSnapshotData | null = null;\n private loading: Promise<DocumentSnapshotData | null> | null = null;\n private relaying = false;\n /** Snapshot rows this tab already holds (loaded or written) — never re-applied. */\n private readonly knownSnapshots = new Set<string>();\n private readonly collabListeners = new Set<(info: CollabMutationInfo, options?: { onlyLocal?: boolean; fromCollab?: boolean }) => void>();\n private collab: DocumentCollabHandle | null = null;\n /** The ordered-log room (C3); exclusive with `collab` (the 0.6 relay room). */\n private ot: DocumentOtHandle | null = null;\n private otStarting: Promise<void> | null = null;\n private readonly otListeners = new Set<(m: DocsLocalMutation) => void>();\n /** The saved snapshot the body started from, and the room entries it already holds. */\n private baseId: string | null = null;\n private baseCovered: ReadonlySet<string> = new Set();\n private collabStarting: Promise<void> | null = null;\n private awareness: DocumentAwareness | null = null;\n private readonly awarenessListeners = new Set<() => void>();\n private realtimeClose: (() => void) | null = null;\n private pageClose: (() => void) | null = null;\n /** The last view's editor, alive and off the page until a view takes it back. */\n private parked: ParkedDocumentEditor | null = null;\n\n constructor(handle: WorkingCopyHandle, deps: DocumentModelDeps) {\n this.documentId = handle.id;\n this.handle = handle;\n this.deps = deps;\n }\n\n // ── body ────────────────────────────────────────────────────────────────\n\n /** The newest state of the body this tab holds, without a network read. */\n latest(): DocumentSnapshotData | null {\n const preferred = this.lastEditedView !== null ? this.views.get(this.lastEditedView) : undefined;\n for (const view of preferred ? [preferred, ...this.views.values()] : this.views.values()) {\n try {\n const snapshot = view.port.snapshot();\n if (snapshot) return snapshot;\n } catch (error) {\n console.warn(`[document-model] a view of ${this.documentId} could not report its document`, error);\n }\n }\n return this.stored;\n }\n\n /**\n * What a NEW view should boot from: the model's latest state, or (only when\n * this tab holds none) the newest server snapshot. Null = an empty document.\n * Re-read `latest()` synchronously right before mounting — another view may\n * have typed while the server read was in flight.\n */\n async openingSnapshot(createEmpty: () => DocumentSnapshotData): Promise<DocumentSnapshotData> {\n const held = this.latest();\n if (held) return held;\n if (!this.loading) {\n this.loading = this.deps.loadLatest(this.documentId).then(\n (row) => {\n const loaded = row ? this.takeBase(row) : null;\n if (row && loaded) {\n this.knownSnapshots.add(row.id);\n this.savedFingerprint = contentFingerprint(loaded);\n }\n // A document never saved opens as ONE empty document for every view\n // (one unit id), so their edits replay into each other.\n if (!this.stored) this.stored = loaded ?? createEmpty();\n return this.latest() ?? this.stored;\n },\n (error: unknown) => {\n this.loading = null;\n throw error;\n },\n );\n }\n return (await this.loading) ?? createEmpty();\n }\n\n /** A view's Univer instance is ready: it shares the document from now on. */\n attachView(port: DocumentViewPort): () => void {\n const id = ++viewIds;\n const subscription = port.commandService.onMutationExecutedForCollab((info, options) =>\n this.onViewMutation(id, info, options),\n );\n const view: AttachedView = { id, port, dispose: () => {}, commands: [], pre: null };\n const hooks = this.trackCommands(view);\n view.dispose = () => {\n subscription.dispose();\n hooks();\n };\n this.views.set(id, view);\n // Nothing unsaved: what this view mounted IS the saved version (Univer and\n // the snapshot repair may restate it — page geometry, defaults — without\n // anyone changing a word). That is the baseline a save compares against.\n if (!this.handle.hasPending()) {\n try {\n const mounted = port.snapshot();\n if (mounted) this.savedFingerprint = contentFingerprint(mounted);\n } catch (error) {\n console.warn(`[document-model] could not read ${this.documentId}'s mounted document`, error);\n }\n }\n let detached = false;\n return () => {\n if (detached) return;\n detached = true;\n const view = this.views.get(id);\n if (!view) return;\n // Whatever this view shows is the newest body when it is the last one:\n // keep it, so a remount (or the flush on the way out) reads it.\n if (this.views.size === 1) {\n try {\n const snapshot = port.snapshot();\n if (snapshot) this.stored = snapshot;\n } catch (error) {\n console.warn(`[document-model] could not keep ${this.documentId}'s last view's document`, error);\n }\n }\n view.dispose();\n this.views.delete(id);\n if (this.lastEditedView === id) this.lastEditedView = null;\n };\n }\n\n /**\n * The last view of the document is leaving: keep its editor (and Univer's\n * undo history inside it) for the next view. Call AFTER the view's\n * `attachView` detach. Refused — the caller disposes its editor — while\n * another view is still attached (it carries the document) or one is\n * already kept.\n */\n parkEditor(editor: ParkedDocumentEditor): boolean {\n if (this.closed || this.views.size > 0 || this.parked) return false;\n this.parked = editor;\n return true;\n }\n\n /** The kept editor, handed to the view that mounts next (null when none is kept). */\n takeParkedEditor(): ParkedDocumentEditor | null {\n const editor = this.parked;\n this.parked = null;\n return editor;\n }\n\n private onViewMutation(\n viewId: number,\n info: Readonly<CollabMutationInfo>,\n options?: { fromCollab?: boolean; fromChangeset?: boolean; onlyLocal?: boolean },\n ): void {\n // Our own replay into this view, a collab peer's edit, or a load: not a\n // new local edit (each is accounted where it came from).\n if (this.relaying || options?.fromCollab || options?.fromChangeset) return;\n const view = this.views.get(viewId);\n if (!view || !view.port.editable()) return;\n this.lastEditedView = viewId;\n this.relay(info, viewId);\n for (const listener of this.collabListeners) listener(info as CollabMutationInfo, options);\n if (this.otListeners.size && !options?.onlyLocal) {\n const m: DocsLocalMutation = {\n id: info.id,\n params: info.params,\n pre: info.id === RICH_TEXT_EDITING_ID ? view.pre : null,\n cmd: view.commands[0] ?? null,\n content: isContentMutation(info),\n };\n view.pre = null;\n for (const listener of Array.from(this.otListeners)) listener(m);\n }\n if (isContentMutation(info)) this.markDirty();\n }\n\n /**\n * Per view: the outermost command running (a mutation's group label) and, while a room listens, the document\n * before each rich-text mutation (its inverse is computed from the APPLIED actions against this copy). Univer's\n * `executeCommand` has no `finally`: a command that mutates then throws never fires `onCommandExecuted`, so\n * the depth is restored in a try/finally around the instance's `executeCommand` (C0 surprise 7).\n */\n private trackCommands(view: AttachedView): () => void {\n const cs = view.port.commandService as ViewCommandService;\n if (typeof cs.beforeCommandExecuted !== \"function\" || typeof cs.onCommandExecuted !== \"function\") return () => {};\n const before = cs.beforeCommandExecuted((info) => {\n if (info.type === COMMAND_TYPE) view.commands.push(info.id);\n else if (info.id === RICH_TEXT_EDITING_ID && this.otListeners.size && !this.relaying) {\n try {\n const snap = view.port.snapshot();\n view.pre = snap ? structuredClone(snap) : null;\n } catch {\n view.pre = null;\n }\n }\n });\n const after = cs.onCommandExecuted((info) => {\n if (info.type !== COMMAND_TYPE) return;\n const at = view.commands.lastIndexOf(info.id);\n if (at >= 0) view.commands.splice(at, 1);\n });\n const guarded = cs as ViewCommandService & { [DEPTH_GUARDED]?: true };\n if (typeof cs.executeCommand === \"function\" && !guarded[DEPTH_GUARDED]) {\n const original = cs.executeCommand.bind(cs);\n guarded[DEPTH_GUARDED] = true;\n cs.executeCommand = async (id, params, options) => {\n const depth = view.commands.length;\n try {\n return await original(id, params, options);\n } finally {\n if (view.commands.length > depth) view.commands.length = depth;\n }\n };\n }\n return () => {\n before.dispose();\n after.dispose();\n };\n }\n\n /** The unit id a view's document has (what a replayed mutation must be addressed to). */\n private unitIdOf(view: AttachedView): string | null {\n try {\n return view.port.unitId?.() ?? view.port.snapshot()?.id ?? null;\n } catch {\n return null;\n }\n }\n\n /** Replay one mutation into every view except `exceptViewId`, addressed to each view's own unit. */\n private relay(info: Readonly<CollabMutationInfo>, exceptViewId: number | null): void {\n if (this.views.size === 0 || (this.views.size === 1 && exceptViewId !== null)) return;\n this.relaying = true;\n let failure: unknown = null;\n try {\n for (const view of this.views.values()) {\n if (view.id === exceptViewId) continue;\n try {\n const params = info.params as unknown;\n const unitId = this.unitIdOf(view);\n const addressed =\n unitId && params && typeof params === \"object\" && !Array.isArray(params) && typeof (params as { unitId?: unknown }).unitId === \"string\" && (params as { unitId: string }).unitId !== unitId\n ? { ...(params as Record<string, unknown>), unitId }\n : info.params;\n view.port.commandService.syncExecuteCommand(info.id, addressed as never, { onlyLocal: true, fromCollab: true });\n } catch (error) {\n failure ??= error;\n console.error(\n `[document-model] a second view of ${this.documentId} could not apply \"${info.id}\" — it may show an older document until it reopens`,\n error,\n );\n }\n }\n } finally {\n this.relaying = false;\n }\n if (failure !== null) this.applyFailed(info.id, failure);\n }\n\n /** A view could not follow an edit: say so, then show the saved version (unless this tab has unsaved edits of its own). */\n private applyFailed(mutationId: string, error: unknown): void {\n try {\n this.deps.onApplyFailed?.(this.documentId, mutationId, error);\n } catch (notifyError) {\n console.warn(`[document-model] the notice for ${this.documentId}'s failed apply also failed`, notifyError);\n }\n if (this.hasUnsaved()) return;\n void this.deps\n .loadLatest(this.documentId)\n .then((row) => {\n if (row && !this.closed) this.show(row);\n })\n .catch((e) => console.warn(`[document-model] could not re-sync ${this.documentId} after a failed apply`, e));\n }\n\n // ── save (run by the record's one coalesced save — documentModels.ts) ─\n\n private markDirty(): void {\n this.handle.touch();\n }\n\n private saving = false;\n /**\n * The content of the version the server holds (loaded or last written). A\n * save of the same content is no save: attaching, detaching, waking or a\n * flush of an unchanged document never writes a snapshot row.\n */\n private savedFingerprint: string | null = null;\n\n /**\n * Write the body as it is now. Returns false when this tab is a collab peer\n * that does not write (the elected host writes the canonical snapshot; a\n * peer's edits reach it through the room). An explicit Save always writes.\n */\n async write(reason: CommitReason): Promise<boolean> {\n if (this.ot) {\n const wrote = await this.ot.write(reason);\n if (wrote) this.deps.onSaved?.(this.documentId, reason === \"manual\" ? \"manual\" : \"autosave\");\n return wrote;\n }\n const snapshot = this.latest();\n if (!snapshot) throw new Error(\"There is no open document to save.\");\n if (this.collab && !this.collab.isHost() && reason !== \"manual\") return false;\n const fingerprint = contentFingerprint(snapshot);\n if (reason !== \"manual\" && fingerprint === this.savedFingerprint) return false;\n const origin = reason === \"manual\" ? \"manual\" : \"autosave\";\n // The room entries this body holds, read in the same step as the body: the saved row names them,\n // so a tab that reloads from it never replays them on top of it.\n const collab = this.collab;\n const covered = collab ? collab.coveredNow() : null;\n this.saving = true;\n try {\n const { id } = await this.deps.save({\n documentId: this.documentId,\n snapshot: covered ? stampCovered(snapshot, covered) : snapshot,\n origin,\n });\n this.knownSnapshots.add(id);\n this.savedFingerprint = fingerprint;\n if (collab && covered && collab.isHost()) collab.checkpoint(id, covered);\n } finally {\n this.saving = false;\n }\n if (this.views.size === 0) this.stored = snapshot;\n this.deps.onSaved?.(this.documentId, origin);\n return true;\n }\n\n private hasUnsaved(): boolean {\n return this.handle.hasPending();\n }\n\n hasViews(): boolean {\n return this.views.size > 0;\n }\n\n // ── realtime (snapshot inserts) ─────────────────────────────────────────\n\n /** Opened once per document by the first view that asks; idempotent. */\n connectRealtime(open: (onSnapshot: (snapshotId: string) => void) => () => void): void {\n if (this.realtimeClose) return;\n this.realtimeClose = open((snapshotId) => void this.onRemoteSnapshot(snapshotId));\n }\n\n /**\n * A snapshot was committed (here or elsewhere): show a foreign one in every\n * view. Over unsaved edits it is a CONFLICT — the working copy holds it and\n * no save runs (one would overwrite the collaborator's snapshot) until the\n * person chooses; `overUnsaved` is \"Take theirs\" (`./documentModels.ts`).\n */\n async onRemoteSnapshot(snapshotId: string, { overUnsaved = false }: { overUnsaved?: boolean } = {}): Promise<void> {\n if (this.collab || this.ot) return; // the room is the live channel; snapshots are checkpoints\n if (this.knownSnapshots.has(snapshotId)) return; // ours, or already shown\n if (this.saving) return; // our own save's echo, ahead of its response\n if (this.hasUnsaved() && !overUnsaved) {\n this.handle.conflict({ ref: snapshotId });\n return;\n }\n const row = await this.deps.loadLatest(this.documentId);\n if (!row || (this.hasUnsaved() && !overUnsaved) || this.knownSnapshots.has(row.id)) return;\n this.show(row);\n }\n\n /**\n * THE content swap (see @ai-matrx/office/univer openEditorContent): a SAVED snapshot\n * replaces the document in every view and the kept editor. It is the saved\n * version from now on, so the pending save compares equal and writes\n * nothing (it would put the old content back over the new). In a collab\n * room the peers reload it and the shared log is emptied.\n */\n replaceContent(row: { id: string; snapshot: DocumentSnapshotData }): void | Promise<void> {\n // A document with an ordered-log room is replaced through `collab_replace` (one atomic door, §20).\n if (this.ot) return this.ot.replace(row.snapshot);\n this.show(row);\n this.collab?.announceReplaced(row.id);\n }\n\n /** A peer replaced the document: show the newest save (once). */\n private async onPeerReplaced(): Promise<void> {\n const row = await this.deps.loadLatest(this.documentId);\n if (!row || this.knownSnapshots.has(row.id)) return;\n this.show(row);\n }\n\n /** A loaded row becomes the base: its content (what views mount) and the room entries it holds. */\n private takeBase(row: { id: string; snapshot: DocumentSnapshotData }): DocumentSnapshotData {\n const { snapshot, covered } = takeCovered(row.snapshot);\n this.baseId = row.id;\n this.baseCovered = covered;\n return snapshot;\n }\n\n private show(row: { id: string; snapshot: DocumentSnapshotData }): void {\n const snapshot = this.takeBase(row);\n this.knownSnapshots.add(row.id);\n this.savedFingerprint = contentFingerprint(snapshot);\n this.stored = snapshot;\n this.relaying = true;\n try {\n for (const view of this.views.values()) view.port.remount(snapshot);\n this.parked?.remount(snapshot);\n } finally {\n this.relaying = false;\n }\n }\n\n // ── collab (one room per document) ──────────────────────────────────────\n\n /**\n * The model's command stream as ONE command service — what the collab room\n * binds to. Local edits from any view go out once; a peer's edit is applied\n * to every view.\n */\n private readonly virtualCommandService: CommandServiceLike = {\n onMutationExecutedForCollab: (listener) => {\n this.collabListeners.add(listener);\n return { dispose: () => this.collabListeners.delete(listener) };\n },\n syncExecuteCommand: (id, params) => {\n const info = { id, type: 2, params } as CollabMutationInfo;\n this.relay(info, null);\n // The host writes what peers typed.\n if (isContentMutation(info)) this.markDirty();\n return true;\n },\n };\n\n /** Join the document's collab room once (the first view that asks). */\n startCollab(factory: DocumentCollabFactory): Promise<void> {\n if (this.collab) return Promise.resolve();\n if (!this.collabStarting) {\n this.collabStarting = factory(\n this.virtualCommandService,\n (awareness) => {\n this.awareness = awareness;\n for (const listener of Array.from(this.awarenessListeners)) listener();\n },\n () => {\n void this.onPeerReplaced().catch((error: unknown) =>\n console.warn(`[document-model] could not load ${this.documentId}'s replaced version`, error),\n );\n },\n {\n snapshotId: () => this.baseId,\n covered: () => this.baseCovered,\n reload: async () => {\n const row = await this.deps.loadLatest(this.documentId);\n if (row && !this.closed) this.show(row);\n },\n },\n )\n .then((handle) => {\n if (!handle) return;\n if (this.views.size === 0) {\n handle.stop();\n return;\n }\n this.collab = handle;\n })\n .finally(() => {\n this.collabStarting = null;\n });\n }\n return this.collabStarting;\n }\n\n /** The model as the ordered-log room sees it (COLLAB-DESIGN §6.7: the model is the client, not the view). */\n private readonly otPort: DocsOtPort = {\n onLocal: (listener) => {\n this.otListeners.add(listener);\n return () => void this.otListeners.delete(listener);\n },\n applyRemote: (id, params) => {\n if (this.views.size === 0) throw new Error(\"no view of the document is mounted\");\n this.relaying = true;\n try {\n for (const view of this.views.values()) {\n const unitId = this.unitIdOf(view);\n const input = Array.isArray(params.actions) ? params.actions.length : 0;\n let sel: Array<{ startOffset: number; endOffset: number; segmentId?: string }> | null = null;\n try {\n sel = view.port.selection?.get() ?? null;\n } catch {\n sel = null;\n }\n const p: Record<string, unknown> = { ...params, ...(unitId ? { unitId } : {}), textRanges: null, noNeedSetTextRange: true };\n const ok = view.port.commandService.syncExecuteCommand(id, p as never, { onlyLocal: true, fromCollab: true });\n if (ok === false) throw new Error(`\"${id}\" was refused by the editor`);\n // the content-control guard empties `actions` on the params object it was handed (§6.6)\n if (input > 0 && Array.isArray(p.actions) && p.actions.length === 0) throw new Error(`\"${id}\" was emptied by the editor`);\n const moved = sel && sel.length && sel.every((r) => !r.segmentId) ? moveRangesThroughBodyEdit(sel, params.actions) : null;\n if (moved) {\n try {\n view.port.selection?.set(moved);\n } catch (error) {\n console.warn(`[document-model] could not move this view's caret past a collaborator's edit`, error);\n }\n }\n }\n } finally {\n this.relaying = false;\n }\n if (isContentMutation({ id, type: 2, params } as unknown as CollabMutationInfo)) this.markDirty();\n },\n snapshot: () => this.latest(),\n load: (snapshot) => {\n const s = snapshot as DocumentSnapshotData;\n this.stored = s;\n this.savedFingerprint = contentFingerprint(s);\n this.relaying = true;\n try {\n for (const view of this.views.values()) view.port.remount(s);\n this.parked?.remount(s);\n } finally {\n this.relaying = false;\n }\n },\n undoTargets: () => {\n const out: Array<{ service: unknown; unitId: string }> = [];\n for (const view of this.views.values()) {\n const unitId = this.unitIdOf(view);\n const service = view.port.undoRedo?.();\n if (unitId && service) out.push({ service, unitId });\n }\n return out;\n },\n markDirty: () => this.markDirty(),\n selection: () => {\n for (const view of this.views.values()) {\n try {\n const sel = view.port.selection?.get();\n if (sel) return sel;\n } catch {\n /* a view mid-teardown has no selection */\n }\n }\n return null;\n },\n };\n\n /** Join the document's ordered-log room once (C3). Exclusive with `startCollab`. */\n startOtRoom(factory: DocumentOtFactory): Promise<void> {\n if (this.ot || this.collab) return Promise.resolve();\n if (!this.otStarting) {\n this.otStarting = factory(this.otPort, (awareness) => {\n this.awareness = awareness;\n for (const listener of Array.from(this.awarenessListeners)) listener();\n })\n .then((handle) => {\n if (!handle) return;\n if (this.views.size === 0) {\n handle.stop();\n return;\n }\n this.ot = handle;\n })\n .finally(() => {\n this.otStarting = null;\n });\n }\n return this.otStarting;\n }\n\n /** Which co-editing room this document is in right now. */\n collabMode(): \"ordered\" | \"relay\" | null {\n return this.ot ? \"ordered\" : this.collab ? \"relay\" : null;\n }\n\n isCollabHost(): boolean {\n if (this.ot) return this.ot.isSaver();\n return this.collab ? this.collab.isHost() : true;\n }\n\n getAwareness(): DocumentAwareness | null {\n return this.awareness;\n }\n\n subscribeAwareness(listener: () => void): () => void {\n this.awarenessListeners.add(listener);\n return () => this.awarenessListeners.delete(listener);\n }\n\n // ── lifecycle (driven by the record's session) ──────────────────────\n\n /** A view arrived on a document with none. */\n wake(): void {\n if (!this.pageClose && this.deps.listenToPage) {\n this.pageClose = this.deps.listenToPage({\n flush: () => void this.handle.flush(),\n hasUnsaved: () => this.hasUnsaved(),\n });\n }\n }\n\n /**\n * The last view left: leave the collab room (presence must not outlive the\n * person). The snapshot channel stays open while the session is kept alive,\n * so a collaborator's save still reaches the body a returning view boots from.\n */\n rest(): void {\n this.collab?.stop();\n this.collab = null;\n this.ot?.stop();\n this.ot = null;\n this.awareness = null;\n }\n\n private closed = false;\n\n close(): void {\n this.closed = true;\n const parked = this.parked;\n this.parked = null;\n if (parked) {\n try {\n parked.dispose();\n } catch (error) {\n console.warn(`[document-model] could not dispose ${this.documentId}'s kept editor`, error);\n }\n }\n this.realtimeClose?.();\n this.realtimeClose = null;\n this.pageClose?.();\n this.pageClose = null;\n }\n}\n\n/**\n * Body offsets moved through a collaborator's body edit (`[\"body\", {et:\"text-x\", e}]`), §6.4 and §6.8. Text inserted\n * before the caret pushes it right; text inserted after it does not.\n *\n * A tie (text inserted EXACTLY at a collapsed caret) follows the one conflict rule. The caret is where this person's\n * next keystroke goes, and that keystroke commits after the edit being applied, so it takes `'left'` and sits first:\n * the caret stays BEFORE the collaborator's text. That is the side the session already gives this seat's unsent and\n * in-flight inserts (`T(local, remote, 'left')`), so the caret stays at the end of this person's own run and two\n * people typing at one spot each keep their words whole (\"FloodEbb\", never \"FElbobod\"). A selection never grows to\n * take in a collaborator's text: an insert at its start lands before it, at its end after it.\n * Null when the edit is not a body edit.\n */\nexport function moveRangesThroughBodyEdit(\n ranges: Array<{ startOffset: number; endOffset: number }>,\n actions: unknown,\n): Array<{ startOffset: number; endOffset: number }> | null {\n const a = actions as unknown[];\n if (!Array.isArray(a) || a[0] !== \"body\") return null;\n const sub = a[1] as { et?: string; e?: unknown } | undefined;\n if (!sub || sub.et !== \"text-x\" || !Array.isArray(sub.e)) return null;\n const e = sub.e as Parameters<typeof TextX.transformPosition>[0];\n return ranges.map((r) => {\n const collapsed = r.startOffset === r.endOffset;\n // TextX.transformPosition's third argument: true = an insert exactly at this offset lands after it\n const startOffset = TextX.transformPosition(e, r.startOffset, collapsed);\n return { startOffset, endOffset: collapsed ? startOffset : TextX.transformPosition(e, r.endOffset, true) };\n });\n}\n\n/**\n * What a snapshot STORES, as a comparable string: everything but the unit id\n * and Univer's revision counter (both move without the content moving).\n */\nfunction contentFingerprint(snapshot: DocumentSnapshotData): string {\n const { id: _id, rev: _rev, ...content } = snapshot as DocumentSnapshotData & { rev?: unknown };\n return JSON.stringify(content);\n}\n\n/** Mutations that change what a snapshot stores (never scroll / selection) — the editors' one dirty filter. */\nfunction isContentMutation(info: Readonly<CollabMutationInfo>): boolean {\n return isSnapshotMutation({ id: info.id, type: info.type, params: info.params } as ICommandInfo);\n}\n","/**\n * isSnapshotMutation — the autosave dirty-filter for the Univer editors.\n *\n * D97: `onCommandExecuted` fires for EVERY command — including viewport\n * scrolls and selection moves — so an unfiltered listener marked the doc\n * dirty on mere scrolling and wrote a new snapshot row (version history +\n * collab broadcast) 2.5s later. Only CommandType.MUTATION changes the data\n * that a snapshot persists (Univer's own docs: OPERATION = \"not saved to\n * snapshot, such as modifying scroll position\"). We therefore accept ONLY\n * mutations, and additionally deny-list any mutation whose id marks it as\n * scroll / selection / viewport bookkeeping, belt-and-braces.\n */\nimport type { ICommandInfo } from \"@univerjs/core\";\n\n/**\n * Univer's `CommandType.MUTATION`. A literal, so this filter (and the document\n * model that uses it outside the editor chunk) never pulls Univer's runtime —\n * which touches `window` at import — into a server-rendered chunk.\n */\nconst MUTATION = 2;\n\n/** Non-content command ids that must never mark the document dirty. */\nconst NON_CONTENT_ID_PATTERN =\n /(scroll|selection|set-selections|viewport|zoom|hover|cursor|focus|activate)/i;\n\nexport function isSnapshotMutation(command: ICommandInfo): boolean {\n if (command.type !== MUTATION) return false;\n if (NON_CONTENT_ID_PATTERN.test(command.id)) return false;\n return true;\n}\n\n/**\n * Mutations a SPREADSHEET fires on its own while it opens and recalculates —\n * they change nothing the person typed, so they must never mark the workbook\n * dirty. Observed on a plain open of a workbook with formulas (2026-10-10):\n * `formula.mutation.set-trigger-formula-calculation-start`,\n * `...set-formula-calculation-start`, `...set-formula-calculation-notification`\n * and a `doc.mutation.rich-text-editing` from the internal cell-editor document.\n * Each open then wrote a new snapshot (history bloat, and a false \"both changed\"\n * against Google). A real edit always arrives as a `sheet.mutation.*`.\n */\nconst WORKBOOK_SELF_MUTATION_PATTERN =\n /^(formula\\.mutation\\.[a-z-]*(calculation|trigger)[a-z-]*|doc\\.mutation\\.)/;\n\nexport function isWorkbookSnapshotMutation(command: ICommandInfo): boolean {\n if (!isSnapshotMutation(command)) return false;\n return !WORKBOOK_SELF_MUTATION_PATTERN.test(command.id);\n}\n","/**\n * A saved snapshot names the collab-room entries it already holds, so a seat that boots from it never\n * replays them (2026-10-16: a reload showed the text twice). Pure — no Yjs — so the editors' model can\n * stamp and read it without loading the room.\n */\n\n/** The key a saved snapshot carries its covered room entries under (`stampCovered` / `takeCovered`). */\nexport const COLLAB_COVERED_KEY = \"__matrxCollabCovered\";\n\n/** The snapshot to SAVE: `snapshot` plus the room entries it holds (`WorkbookCollabSession.coveredNow`). */\nexport function stampCovered<T extends object>(snapshot: T, covered: readonly string[]): T {\n return { ...snapshot, [COLLAB_COVERED_KEY]: [...covered] };\n}\n\n/** A LOADED snapshot split into the content to mount and the room entries it already holds. */\nexport function takeCovered<T>(snapshot: T): { snapshot: T; covered: Set<string> } {\n if (!snapshot || typeof snapshot !== \"object\" || !(COLLAB_COVERED_KEY in (snapshot as object))) {\n return { snapshot, covered: new Set() };\n }\n const { [COLLAB_COVERED_KEY]: list, ...rest } = snapshot as Record<string, unknown>;\n return {\n snapshot: rest as T,\n covered: new Set(Array.isArray(list) ? list.filter((e): e is string => typeof e === \"string\") : []),\n };\n}\n","/**\n * Pure validation for the `matrx-user/documents` write targets.\n *\n * Deliberately OUTSIDE the React updater. `applySurfaceWrite`\n * (`features/surfaces/runtime/surface-writeback.ts`) turns a THROW from a\n * handler into the error envelope the agent reads back. Validating inside a\n * `setState` updater would instead throw during React's render/commit — after\n * the seam has already reported success — so the agent would be told its bad\n * value landed. Validate here, synchronously, before touching any state.\n *\n * `DOCUMENT_NAME_MAX_LENGTH` is the single source of truth for the limit: it is\n * enforced here, interpolated into the manifest target description, AND set as\n * the `maxLength` of the header rename field on `/documents/[id]` — so the\n * contract the agent reads, the rule the handler enforces, and the limit the\n * human's own control applies cannot drift apart. The last of those matters\n * for a non-obvious reason: the blur commit swallows service failures, so\n * before the field was bounded a pasted 300-character title came back as a\n * `varchar(255)` 400 and reverted with nothing on screen to explain it.\n */\n\n/**\n * `workbench.udt_documents.document_name` is `varchar(255) NOT NULL` — a\n * longer value is rejected by Postgres, not merely by taste. Verified against\n * `information_schema.columns` on 2026-08-11.\n */\nexport const DOCUMENT_NAME_MAX_LENGTH = 255;\n\n/**\n * `workbench.udt_documents.description` is unbounded `text`, so this is a\n * product bound rather than a database one: it matches the 2000 the sibling\n * `workbook_description` target enforces, keeping the two mirrored services\n * mirrored in behavior too. The library renders this as a two-line blurb —\n * anything near the cap is already past what a reader sees.\n */\nexport const DOCUMENT_DESCRIPTION_MAX_LENGTH = 2000;\n\n/** How a rejected value is described back to the agent, without dumping it. */\nfunction describeValue(value: unknown): string {\n if (value === null) return \"null\";\n if (Array.isArray(value)) return \"an array\";\n if (typeof value === \"object\") return \"an object\";\n return `a ${typeof value}`;\n}\n\n/**\n * Validate an agent-supplied document title and return the exact string to\n * persist. Throws (never coerces) so the agent hears about its own mistake.\n *\n * The `typeof` guard is load-bearing: the inline-tool layer PARSES a\n * JSON-looking argument before the handler ever sees it, so a caller that\n * sends `{\"document_name\":\"...\"}` or `\"\\\"Quoted\\\"\"` arrives here as an object,\n * not text. The message names the fix explicitly, because an agent that only\n * hears \"invalid\" tends to retry by double-encoding — which lands escaped\n * quotes and `\\n` in the user's title box.\n */\nexport function validateDocumentName(value: unknown): string {\n if (typeof value !== \"string\") {\n throw new Error(\n `document_name must be plain text, not JSON and not JSON-encoded — received ${describeValue(\n value,\n )}. Send only the title itself (for example: Q3 Revenue Review) with no surrounding braces, brackets, quotes or escape sequences.`,\n );\n }\n\n const trimmed = value.trim();\n\n if (trimmed.length === 0) {\n throw new Error(\n \"document_name cannot be empty or whitespace — a document must keep a title. Send the title text you want, or leave the current one alone.\",\n );\n }\n\n if (/[\\r\\n]/.test(trimmed)) {\n throw new Error(\n \"document_name must be a SINGLE line — it renders in the page header, and line breaks are not a title. Send one line of plain text (this is a title, not the document body).\",\n );\n }\n\n if (trimmed.length > DOCUMENT_NAME_MAX_LENGTH) {\n throw new Error(\n `document_name must be ${DOCUMENT_NAME_MAX_LENGTH} characters or fewer (received ${trimmed.length}). Shorten it to a title; the document body is not stored in this field.`,\n );\n }\n\n return trimmed;\n}\n\n/**\n * Validate an agent-supplied document description and return the value to\n * persist — `null` for a deliberate clear, so the caller never has to decide\n * whether \"\" means \"empty string\" or \"no description\".\n *\n * Unlike the title this MAY span lines (it is a blurb, not a header), but it\n * carries the same not-JSON guard for the same reason: the inline-tool layer\n * parses a JSON-looking argument before the handler sees it.\n */\nexport function validateDocumentDescription(value: unknown): string | null {\n if (typeof value !== \"string\") {\n throw new Error(\n `document_description must be plain text, not JSON and not JSON-encoded — received ${describeValue(\n value,\n )}. Send only the description prose itself, with no surrounding braces, brackets, quotes or escape sequences.`,\n );\n }\n\n const trimmed = value.trim();\n\n // An empty string is the documented way to CLEAR the description, so it is\n // valid input rather than a bad shape — normalize it to null for the column.\n if (trimmed.length === 0) return null;\n\n if (trimmed.length > DOCUMENT_DESCRIPTION_MAX_LENGTH) {\n throw new Error(\n `document_description must be ${DOCUMENT_DESCRIPTION_MAX_LENGTH} characters or fewer (received ${trimmed.length}). This is the short blurb shown in the documents library, not the document body.`,\n );\n }\n\n return trimmed;\n}\n","/**\n * The zoom that fits a document page inside a narrow editor (a phone), so the\n * page reflows into view instead of scrolling sideways. Never above 100%, and\n * never so small the text is unreadable. Pure — guarded by fit-zoom-ratio.test.ts.\n */\nexport const MIN_FIT_ZOOM = 0.45;\n\nexport function fitZoomRatio(containerWidth: number, pageWidth: number, gutter = 8): number {\n if (!(containerWidth > 0) || !(pageWidth > 0)) return 1;\n const ratio = (containerWidth - gutter * 2) / pageWidth;\n return Math.min(1, Math.max(MIN_FIT_ZOOM, Math.round(ratio * 100) / 100));\n}\n","import type { DocumentSource } from \"../core\";\n\nconst SOURCE_LABELS: Record<DocumentSource, string> = {\n created: \"Created\",\n imported_docx: \"Imported DOCX\",\n imported_md: \"Imported Markdown\",\n imported_txt: \"Imported Text\",\n linked_gdoc: \"Imported from Google Docs\",\n};\n\nexport function documentSourceLabel(source: DocumentSource): string {\n return SOURCE_LABELS[source] ?? source;\n}\n","/** Insert, Emoji and Special characters: searchable sets, a name per entry. */\n\nexport interface Glyph {\n char: string;\n name: string;\n}\n\nconst e = (rows: string): Glyph[] =>\n rows.split(\"|\").map((r) => r.trim()).filter(Boolean).map((r) => {\n const [char, ...name] = r.split(\" \");\n return { char: char!, name: name.join(\" \") };\n });\n\nexport const EMOJI_GROUPS: Array<{ id: string; label: string; items: Glyph[] }> = [\n { id: \"faces\", label: \"Faces\", items: e(\"😀 grinning|😃 smile|😄 happy|😁 beaming|😆 laughing|😅 sweat smile|😂 tears of joy|🤣 rolling|🙂 slight smile|🙃 upside down|😉 wink|😊 blush|😇 angel|🥰 love|😍 heart eyes|🤩 star struck|😘 kiss|😋 yum|😎 cool|🤓 nerd|🤔 thinking|🤨 skeptical|😐 neutral|🙄 eye roll|😬 grimace|😴 sleeping|😢 cry|😭 sobbing|😤 huff|😡 angry|🤯 mind blown|😱 scream|🥳 party|🤗 hug|🫡 salute|😮 surprised|😳 flushed|🥺 pleading|😷 mask|🤒 sick\") },\n { id: \"people\", label: \"Gestures\", items: e(\"👍 thumbs up|👎 thumbs down|👏 clap|🙌 raised hands|🙏 pray thanks|🤝 handshake|💪 strong flex|👌 ok|✌ victory peace|🤞 fingers crossed|👋 wave|✋ raised hand|👆 point up|👉 point right|👈 point left|👇 point down|✍ writing|🤷 shrug|🙋 raise hand|👀 eyes|🧠 brain|❤ heart|💔 broken heart|💯 hundred\") },\n { id: \"objects\", label: \"Objects\", items: e(\"💡 idea light bulb|📌 pin|📎 paperclip|📝 memo note|📅 calendar|📈 chart up|📉 chart down|📊 bar chart|📁 folder|📄 page|📧 email|📞 phone|💻 laptop|📱 mobile|🔒 lock|🔑 key|🔍 search|🔔 bell|⏰ alarm clock|⌛ hourglass|🎯 target|🏆 trophy|🎁 gift|📦 package|🛠 tools|⚙ gear|💰 money bag|💵 dollar|🧾 receipt|📚 books\") },\n { id: \"symbols\", label: \"Marks\", items: e(\"✅ check mark|❌ cross|⭐ star|🌟 glowing star|✨ sparkles|🔥 fire|⚡ lightning|🚀 rocket|🎉 party popper|🎊 confetti|⚠ warning|❓ question|❗ exclamation|➕ plus|➖ minus|🔴 red circle|🟠 orange circle|🟡 yellow circle|🟢 green circle|🔵 blue circle|🟣 purple circle|⬆ up|⬇ down|➡ right|⬅ left|🔁 repeat|✔ heavy check\") },\n { id: \"nature\", label: \"Nature and food\", items: e(\"🌞 sun|🌙 moon|☁ cloud|🌧 rain|❄ snowflake|🌈 rainbow|🌱 seedling|🌳 tree|🌸 blossom|🌍 earth|🐶 dog|🐱 cat|🦊 fox|🐝 bee|🦋 butterfly|🍎 apple|🍕 pizza|🍔 burger|☕ coffee|🍺 beer|🍷 wine|🎂 cake|🍪 cookie|🥑 avocado\") },\n];\n\nconst s = (chars: string, names: string[]): Glyph[] => Array.from(chars).map((char, i) => ({ char, name: names[i] ?? char }));\n\nexport const SPECIAL_GROUPS: Array<{ id: string; label: string; items: Glyph[] }> = [\n { id: \"punctuation\", label: \"Punctuation\", items: s(\"©®™°§¶†‡•…‰№‘’“”«»–—¡¿·\", [\"copyright\", \"registered\", \"trademark\", \"degree\", \"section\", \"pilcrow\", \"dagger\", \"double dagger\", \"bullet\", \"ellipsis\", \"per mille\", \"numero\", \"left single quote\", \"right single quote\", \"left double quote\", \"right double quote\", \"left guillemet\", \"right guillemet\", \"en dash\", \"em dash\", \"inverted exclamation\", \"inverted question\", \"middle dot\"]) },\n { id: \"arrows\", label: \"Arrows\", items: s(\"←↑→↓↔↕⇐⇑⇒⇓⇔↩↪➜➤↖↗↘↙↺↻\", [\"left arrow\", \"up arrow\", \"right arrow\", \"down arrow\", \"left right arrow\", \"up down arrow\", \"left double arrow\", \"up double arrow\", \"right double arrow\", \"down double arrow\", \"left right double arrow\", \"return arrow\", \"hook arrow\", \"heavy arrow\", \"arrowhead\", \"north west arrow\", \"north east arrow\", \"south east arrow\", \"south west arrow\", \"anticlockwise arrow\", \"clockwise arrow\"]) },\n { id: \"math\", label: \"Math\", items: s(\"±×÷≈≠≤≥∞√∑∏∫∂∆∇∈∉∪∩⊂⊃∧∨¬∀∃∅∝∠¼½¾⅓⅔²³\", [\"plus minus\", \"times\", \"divide\", \"approximately\", \"not equal\", \"less or equal\", \"greater or equal\", \"infinity\", \"square root\", \"sum\", \"product\", \"integral\", \"partial\", \"increment\", \"nabla\", \"element of\", \"not element\", \"union\", \"intersection\", \"subset\", \"superset\", \"and\", \"or\", \"not\", \"for all\", \"exists\", \"empty set\", \"proportional\", \"angle\", \"one quarter\", \"one half\", \"three quarters\", \"one third\", \"two thirds\", \"squared\", \"cubed\"]) },\n { id: \"currency\", label: \"Currency\", items: s(\"$€£¥¢₹₩₽₺₿฿₫₪₴₦₱\", [\"dollar\", \"euro\", \"pound\", \"yen\", \"cent\", \"rupee\", \"won\", \"ruble\", \"lira\", \"bitcoin\", \"baht\", \"dong\", \"shekel\", \"hryvnia\", \"naira\", \"peso\"]) },\n { id: \"greek\", label: \"Greek\", items: s(\"αβγδεζηθικλμνξοπρστυφχψωΩΣΔΠΦΨΛΘ\", [\"alpha\", \"beta\", \"gamma\", \"delta\", \"epsilon\", \"zeta\", \"eta\", \"theta\", \"iota\", \"kappa\", \"lambda\", \"mu\", \"nu\", \"xi\", \"omicron\", \"pi\", \"rho\", \"sigma\", \"tau\", \"upsilon\", \"phi\", \"chi\", \"psi\", \"omega\", \"capital omega\", \"capital sigma\", \"capital delta\", \"capital pi\", \"capital phi\", \"capital psi\", \"capital lambda\", \"capital theta\"]) },\n { id: \"latin\", label: \"Accented letters\", items: s(\"àáâãäåæçèéêëìíîïñòóôõöøœùúûüýÿßÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÑÒÓÔÕÖØŒÙÚÛÜÝŸ\", []) },\n { id: \"shapes\", label: \"Shapes\", items: s(\"■□▲△▼▽◆◇●○★☆♠♣♥♦♪♫☑☒\", [\"black square\", \"white square\", \"black up triangle\", \"white up triangle\", \"black down triangle\", \"white down triangle\", \"black diamond\", \"white diamond\", \"black circle\", \"white circle\", \"black star\", \"white star\", \"spade\", \"club\", \"heart suit\", \"diamond suit\", \"eighth note\", \"beamed notes\", \"checked box\", \"crossed box\"]) },\n];\n\nexport function searchSymbols(groups: typeof EMOJI_GROUPS, query: string): Glyph[] {\n const q = query.trim().toLowerCase();\n if (!q) return [];\n const seen = new Set<string>();\n const out: Glyph[] = [];\n for (const g of groups) for (const it of g.items) if ((it.char === q || it.name.toLowerCase().includes(q)) && !seen.has(it.char)) (seen.add(it.char), out.push(it));\n return out;\n}\n","/**\n * The BODY TEXT of a Univer document, as agents read and write it (PURE).\n *\n * `matrx-user/documents` declares the body as a value (`document_body_text`)\n * and a write target (`document_body`). Univer owns the document model, so\n * both go through a small port the editor hands up (`DocumentEditor`\n * `onBodyPort`): the read is the body's data stream as plain text, and a write\n * is ONE changed span, applied through Univer's own facade (`deleteRange` /\n * `insertText`, which run `InsertTextCommand` on the command service). That\n * keeps every agent edit on the one editing path a keystroke takes: undo,\n * autosave snapshots, History and collab all see it, and formatting outside\n * the changed span is left exactly as it was.\n *\n * Univer's data stream encodes a paragraph end as `\\r`, a section break as\n * `\\n`, and custom blocks / tables with control characters below U+0020. The\n * plain text maps a paragraph end to `\\n` and leaves the other control tokens\n * out; `offsets` maps each text position back to its data-stream index so a\n * change found in the text lands at the right place in the stream.\n */\n\nimport { looksLikeMarkdown } from \"./doc-tools-core\";\n\n/** The shape of a surface write handler (structurally the chat runtime's `SurfaceWriteHandlerEntry`; the package imports no chat). */\nexport interface DocumentBodyWriteHandler {\n validate: (value: unknown) => void;\n apply: (value: unknown) => { summary: string; data?: unknown };\n}\n\n/**\n * A product bound, not a database one (snapshots are jsonb): a body an agent\n * sends larger than this is almost certainly a mistake (a whole file pasted\n * twice), and past it the approval card stops being readable.\n */\nexport const DOCUMENT_BODY_MAX_LENGTH = 200_000;\n\n/** What the editor lends the surface. Each call resolves the live document. */\nexport interface DocumentBodyPort {\n /** The main body's Univer data stream (ends with `\\r\\n`). */\n getDataStream: () => string;\n /** The live document snapshot (body with its text runs), for reading the formatting back out. */\n getSnapshot?: () => unknown;\n /** Delete `[start, end)` of the data stream; false when Univer refused. */\n deleteRange: (start: number, end: number) => boolean;\n /** Insert plain text (a `\\n` starts a new paragraph) at a stream index. */\n insertText: (at: number, text: string) => boolean;\n /**\n * Insert MARKDOWN at a stream index as real structure (tables, headings, lists, bold, links).\n * Absent only where a port cannot (then the text goes in as typed).\n */\n insertMarkdown?: (at: number, markdown: string) => boolean;\n /** Run a Univer command in the open editor (File menu: find and replace, comments). */\n runCommand?: (commandId: string) => Promise<void>;\n /** File → Page setup: open the page setup dialog in the open editor. */\n openPageSetup?: () => void;\n /** File → Language (and the other Docs tool dialogs): open one in the open editor. */\n openTool?: (id: \"language\") => void;\n}\n\nexport interface BodyText {\n text: string;\n /** `offsets[i]` = the stream index of text position `i`; length is text.length + 1. */\n offsets: number[];\n}\n\nconst PARAGRAPH = \"\\r\";\nconst SECTION = \"\\n\";\n\n/** The body's plain text and where each character sits in the stream. */\nexport function bodyTextOf(dataStream: string): BodyText {\n let text = \"\";\n const offsets: number[] = [];\n for (let i = 0; i < dataStream.length; i++) {\n const ch = dataStream[i];\n if (ch === PARAGRAPH) {\n text += \"\\n\";\n offsets.push(i);\n continue;\n }\n if (ch === SECTION) continue;\n if (ch !== \"\\t\" && ch!.charCodeAt(0) < 0x20) continue;\n text += ch;\n offsets.push(i);\n }\n // Every body ends with its last paragraph mark: it is not text a person\n // typed, and it can never be deleted (Univer protects it). Text that ends\n // there inserts before it.\n if (text.endsWith(\"\\n\")) {\n const end = offsets[offsets.length - 1];\n text = text.slice(0, -1);\n offsets.pop();\n offsets.push(end!);\n } else {\n offsets.push(dataStream.length);\n }\n return { text, offsets };\n}\n\nexport interface BodyEdit {\n /** Stream range to remove (may be empty). */\n start: number;\n end: number;\n /** Plain text to insert at `start` (may be empty). */\n insert: string;\n}\n\n/**\n * The ONE span that turns the current body into `next`: the longest common\n * prefix and suffix stay untouched (with their formatting), only the middle\n * changes. Null when nothing differs.\n */\nexport function planBodyEdit(current: BodyText, next: string): BodyEdit | null {\n const a = current.text;\n const b = next;\n if (a === b) return null;\n let prefix = 0;\n const max = Math.min(a.length, b.length);\n while (prefix < max && a[prefix] === b[prefix]) prefix++;\n let suffix = 0;\n while (\n suffix < max - prefix &&\n a[a.length - 1 - suffix] === b[b.length - 1 - suffix]\n )\n suffix++;\n const removeTo = a.length - suffix;\n return {\n start: current.offsets[prefix]!,\n end: current.offsets[removeTo]!,\n insert: b.slice(prefix, b.length - suffix),\n };\n}\n\n/**\n * Put the new span in. Markdown structure in it (a table above all) becomes real document structure\n * through the one converter; the span starts on its own paragraph so a block never splits a line (a span that would start mid-line goes in at the next paragraph start).\n */\nfunction insertSpan(port: DocumentBodyPort, _current: BodyText, edit: BodyEdit): boolean {\n if (port.insertMarkdown && looksLikeMarkdown(edit.insert)) {\n const stream = port.getDataStream();\n let at = edit.start;\n if (at > 0 && stream[at - 1] !== PARAGRAPH) {\n const end = stream.indexOf(PARAGRAPH, at);\n at = end < 0 ? stream.length : end + 1;\n }\n return port.insertMarkdown(at, edit.insert.replace(/^\\n+/, \"\"));\n }\n return port.insertText(edit.start, edit.insert);\n}\n\n/** Apply `next` as the whole body text through the port. */\nexport function writeBodyText(\n port: DocumentBodyPort,\n next: string,\n): { changed: boolean; removed: number; inserted: number } {\n const current = bodyTextOf(port.getDataStream());\n const edit = planBodyEdit(current, next);\n if (!edit) return { changed: false, removed: 0, inserted: 0 };\n if (edit.end > edit.start && !port.deleteRange(edit.start, edit.end)) {\n throw new Error(\n \"The editor refused to remove the old text (the document may be read-only right now). Nothing was changed.\",\n );\n }\n if (edit.insert.length > 0 && !insertSpan(port, current, edit)) {\n throw new Error(\n edit.end > edit.start\n ? \"The editor removed the old text but refused the new text. Press Undo in the document to bring the old text back, then try again.\"\n : \"The editor refused the new text (the document may be read-only right now). Nothing was changed.\",\n );\n }\n return {\n changed: true,\n removed: edit.end - edit.start,\n inserted: edit.insert.length,\n };\n}\n\nfunction describeValue(value: unknown): string {\n if (value === null) return \"null\";\n if (Array.isArray(value)) return \"an array\";\n if (typeof value === \"object\") return \"an object\";\n return `a ${typeof value}`;\n}\n\n/** Shape check for an agent-sent body; throws a sentence the agent can act on. */\nexport function validateDocumentBody(value: unknown): string {\n if (typeof value !== \"string\") {\n throw new Error(\n `document_body must be the document's whole text as a plain string (or an anchored edit {command, old_str, new_str}) — received ${describeValue(\n value,\n )}. Read document_body_text, change it, and send the full new text.`,\n );\n }\n if (value.length > DOCUMENT_BODY_MAX_LENGTH) {\n throw new Error(\n `document_body must be ${DOCUMENT_BODY_MAX_LENGTH} characters or fewer (received ${value.length}). Nothing was changed.`,\n );\n }\n return value.replace(/\\r\\n?/g, \"\\n\");\n}\n\n/**\n * The `document_body` write handler. `getPort` answers the live editor's port\n * (null until Univer has mounted the document); `assertWritable` throws when\n * the record is not loaded or the person may only view it.\n */\nexport function documentBodyWriteHandler(deps: {\n getPort: () => DocumentBodyPort | null;\n assertWritable: (whatItBlocks: string) => void;\n}): DocumentBodyWriteHandler {\n return {\n validate: (value) => {\n validateDocumentBody(value);\n },\n apply: (value) => {\n const next = validateDocumentBody(value);\n deps.assertWritable(\"its text cannot be changed\");\n const port = deps.getPort();\n if (!port) {\n throw new Error(\n \"The document editor has not finished opening yet. Nothing was changed; try again in a moment.\",\n );\n }\n const result = writeBodyText(port, next);\n if (!result.changed) {\n return { summary: \"The document already has exactly this text; nothing changed.\" };\n }\n return {\n summary: `Changed the document's text in the editor (removed ${result.removed} characters, inserted ${result.inserted}); the editor saves it within a few seconds, and Undo in the document reverses it.`,\n data: { removed: result.removed, inserted: result.inserted },\n };\n },\n };\n}\n","/**\n * Other people's carets and selections in a Docs co-editing room (COLLAB-DESIGN §6.8, unit C8).\n *\n * Presence travels on Yjs awareness beside `quiet_hash`: each seat publishes `caret = { ranges, at }`, body\n * offsets in ITS OWN editor (header and footer selections are not published). Offsets do not survive edits, so a\n * receiver keeps a book of the last published ranges and moves them through every body edit it applies afterwards,\n * remote or its own, with the same function that moves its own caret (`moveRangesThroughBodyEdit`). A peer\n * republishes on each selection change and every `CARET_HEARTBEAT_MS`, so a race between its awareness and an op\n * frame (a keystroke counted twice) corrects itself within a heartbeat. A caret older than `CARET_STALE_MS` is\n * not shown (judged by when THIS seat received it, never the sender's clock); one whose seat left is dropped with its awareness state.\n */\nimport { moveRangesThroughBodyEdit } from \"./document-model\";\n\nexport const CARET_HEARTBEAT_MS = 2000;\nexport const CARET_STALE_MS = 12000;\n/** Most ranges one seat publishes (a multi-range selection is rare; the rest is dropped, never the first). */\nexport const CARET_MAX_RANGES = 4;\n\nexport interface CaretRange {\n start: number;\n end: number;\n}\n\n/** The `caret` field of a seat's awareness state. */\nexport interface PublishedCaret {\n ranges: CaretRange[];\n at: number;\n}\n\n/** One other seat's caret, ready to draw. */\nexport interface RemoteCaret {\n /** The seat (Yjs client id as a string): two tabs of one person are two carets. */\n key: string;\n uid: string;\n name: string;\n color: string;\n ranges: CaretRange[];\n}\n\ntype SelectionRange = { startOffset: number; endOffset: number; segmentId?: string };\n\n/** What a seat publishes for its selection, or null when there is nothing to show (header/footer, no selection). */\nexport function publishedCaretFromSelection(sel: SelectionRange[] | null | undefined, now: number): PublishedCaret | null {\n if (!sel || sel.length === 0) return null;\n if (sel.some((r) => r.segmentId)) return null;\n const ranges = sel.slice(0, CARET_MAX_RANGES).map((r) => ({ start: Math.min(r.startOffset, r.endOffset), end: Math.max(r.startOffset, r.endOffset) }));\n return { ranges, at: now };\n}\n\nconst sameRanges = (a: CaretRange[], b: CaretRange[]) => a.length === b.length && a.every((r, i) => r.start === b[i]!.start && r.end === b[i]!.end);\n\nfunction readCaret(raw: unknown): PublishedCaret | null {\n const c = (raw as { caret?: { ranges?: unknown; at?: unknown } } | null)?.caret;\n if (!c || !Array.isArray(c.ranges) || typeof c.at !== \"number\") return null;\n const ranges: CaretRange[] = [];\n for (const r of c.ranges.slice(0, CARET_MAX_RANGES)) {\n const s = (r as CaretRange)?.start;\n const e = (r as CaretRange)?.end;\n if (typeof s !== \"number\" || typeof e !== \"number\" || !Number.isFinite(s) || !Number.isFinite(e) || s < 0 || e < 0) return null;\n ranges.push({ start: s, end: e });\n }\n return ranges.length ? { ranges, at: c.at } : null;\n}\n\nexport class RemoteCaretBook {\n private readonly carets = new Map<string, RemoteCaret & { at: number; seenAt: number }>();\n\n constructor(\n private readonly selfClientId: number,\n private readonly now: () => number = Date.now,\n ) {}\n\n /** Take the room's awareness states: new or republished carets replace ours, seats that left are dropped. Returns whether anything changed. */\n ingest(states: Map<number, unknown>): boolean {\n let changed = false;\n const seen = new Set<string>();\n states.forEach((raw, id) => {\n if (id === this.selfClientId) return;\n const s = raw as { uid?: unknown; name?: unknown; color?: unknown } | null;\n const caret = readCaret(raw);\n if (!s || typeof s.uid !== \"string\" || !caret) return;\n const key = String(id);\n seen.add(key);\n const prev = this.carets.get(key);\n const name = typeof s.name === \"string\" && s.name ? s.name : \"Someone\";\n const color = typeof s.color === \"string\" && s.color ? s.color : \"#3b82f6\";\n // The same publication again (awareness re-delivers state): keep the ranges we have already moved.\n if (prev && prev.at === caret.at && prev.name === name && prev.color === color) return;\n this.carets.set(key, { key, uid: s.uid, name, color, ranges: caret.ranges, at: caret.at, seenAt: this.now() });\n changed = true;\n });\n for (const key of [...this.carets.keys()]) {\n if (!seen.has(key)) {\n this.carets.delete(key);\n changed = true;\n }\n }\n return changed;\n }\n\n /** Move every caret through one body edit that was just applied (`actions` of a rich-text mutation). Returns whether any moved. */\n shiftThrough(actions: unknown): boolean {\n let moved = false;\n for (const c of this.carets.values()) {\n const next = moveRangesThroughBodyEdit(c.ranges.map((r) => ({ startOffset: r.start, endOffset: r.end })), actions);\n if (!next) return false; // not a body edit: nothing moves\n const ranges = next.map((r) => ({ start: r.startOffset, end: r.endOffset }));\n if (!sameRanges(ranges, c.ranges)) {\n c.ranges = ranges;\n moved = true;\n }\n }\n return moved;\n }\n\n /** The carets to draw now (stale ones left out). */\n list(): RemoteCaret[] {\n const t = this.now();\n const out: RemoteCaret[] = [];\n for (const c of this.carets.values()) {\n if (t - c.seenAt > CARET_STALE_MS) continue;\n out.push({ key: c.key, uid: c.uid, name: c.name, color: c.color, ranges: c.ranges.map((r) => ({ ...r })) });\n }\n out.sort((a, b) => a.key.localeCompare(b.key));\n return out;\n }\n}\n"]}