@ai-matrx/office 0.8.37 → 0.8.39

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.
@@ -290,9 +290,12 @@ declare function stampDeterministicIds<T>(snapshot: T): T;
290
290
  * never skips. While an IME composition is open, remote applies QUEUE (acks continue); a local op captured
291
291
  * meanwhile is rebased over the queue (`L' = T(L, Q, 'left')`, `Q' = T(Q, L, 'right')`), and the queue drains
292
292
  * at `compositionend`.
293
- * - UNDO (§6.9). Each applied remote op rebases every stored undo and redo item of this seat
294
- * (`T(item, R1, 'left')`); `textRanges` and `layoutState` are stripped from rebased items; an item whose rebase
295
- * is a barrier, throws or comes back empty is dropped. Undo therefore only ever reverts this person's changes.
293
+ * - UNDO (§6.9). Each applied remote op rebases every stored undo and redo item of this seat. The side of an item
294
+ * that applies now (an undo item's undo list, a redo item's redo list) meets R as it is, each mutation in turn
295
+ * with R carried past it; the other side meets R carried past the first (`rebaseUndoStack`). The typing burst
296
+ * Univer still holds outside the stack is pushed onto it first. `textRanges` and `layoutState` are stripped
297
+ * from rebased items; an item whose rebase is a barrier, throws or comes back empty is dropped. Undo therefore
298
+ * only ever reverts this person's changes.
296
299
  * - SAVES (§7.3). Only a quiet seat whose hash matches every peer at its rev saves, and only the chosen saver
297
300
  * (the lowest client id among seats publishing a quiet hash) saves on its own; a manual save always tries.
298
301
  * - RESTORE (§20). A whole-document replace goes through `collab_replace`: the snapshot is loaded into this seat's
@@ -325,10 +328,14 @@ interface DocsOtPort {
325
328
  snapshot(): unknown | null;
326
329
  /** Replace the document in every view (and the kept editor). */
327
330
  load(snapshot: unknown): void;
328
- /** Univer's undo/redo service of each mounted view and the unit it holds. */
331
+ /**
332
+ * Univer's undo/redo service of each mounted view and the unit it holds. `flushHistory` pushes the typing burst
333
+ * Univer still holds outside the stack (its 300 ms history debounce) onto the stack, so a rebase reaches it.
334
+ */
329
335
  undoTargets(): Array<{
330
336
  service: unknown;
331
337
  unitId: string;
338
+ flushHistory?: () => void;
332
339
  }>;
333
340
  /** Ask for a save (the record's one coalesced save). */
334
341
  markDirty(): void;
@@ -401,8 +408,17 @@ declare function undoStacksOf(service: unknown): {
401
408
  undo: Map<string, UndoItem$1[]>;
402
409
  redo: Map<string, UndoItem$1[]>;
403
410
  } | null;
404
- /** §6.9: rebase one stack over a remote op; items that cannot follow are dropped. Returns how many were dropped. */
405
- declare function rebaseUndoStack(items: UndoItem$1[], remote: DocsOp): number;
411
+ /**
412
+ * §6.9: rebase one stack over a remote op; items that cannot follow are dropped. Returns how many were dropped.
413
+ *
414
+ * `stack` says which side of each item applies to the document as it is NOW: an undo-stack item's
415
+ * `undoMutations` (its `redoMutations` apply after them), a redo-stack item's `redoMutations` (its
416
+ * `undoMutations` apply after them). The side that applies now meets the remote op as it is; the other side meets
417
+ * the remote op carried past the first. Rebasing both sides against the same op (as before) left the inactive
418
+ * side in coordinates of a document it never applies to: after undo → peer types → redo → undo, the second undo
419
+ * deleted the peer's letters instead of the redone ones (F1).
420
+ */
421
+ declare function rebaseUndoStack(items: UndoItem$1[], remote: DocsOp, stack: "undo" | "redo"): number;
406
422
  declare function openDocsOtRoom(o: OpenDocsOtRoomOptions): DocsOtRoom;
407
423
 
408
424
  interface CaretRange {
@@ -290,9 +290,12 @@ declare function stampDeterministicIds<T>(snapshot: T): T;
290
290
  * never skips. While an IME composition is open, remote applies QUEUE (acks continue); a local op captured
291
291
  * meanwhile is rebased over the queue (`L' = T(L, Q, 'left')`, `Q' = T(Q, L, 'right')`), and the queue drains
292
292
  * at `compositionend`.
293
- * - UNDO (§6.9). Each applied remote op rebases every stored undo and redo item of this seat
294
- * (`T(item, R1, 'left')`); `textRanges` and `layoutState` are stripped from rebased items; an item whose rebase
295
- * is a barrier, throws or comes back empty is dropped. Undo therefore only ever reverts this person's changes.
293
+ * - UNDO (§6.9). Each applied remote op rebases every stored undo and redo item of this seat. The side of an item
294
+ * that applies now (an undo item's undo list, a redo item's redo list) meets R as it is, each mutation in turn
295
+ * with R carried past it; the other side meets R carried past the first (`rebaseUndoStack`). The typing burst
296
+ * Univer still holds outside the stack is pushed onto it first. `textRanges` and `layoutState` are stripped
297
+ * from rebased items; an item whose rebase is a barrier, throws or comes back empty is dropped. Undo therefore
298
+ * only ever reverts this person's changes.
296
299
  * - SAVES (§7.3). Only a quiet seat whose hash matches every peer at its rev saves, and only the chosen saver
297
300
  * (the lowest client id among seats publishing a quiet hash) saves on its own; a manual save always tries.
298
301
  * - RESTORE (§20). A whole-document replace goes through `collab_replace`: the snapshot is loaded into this seat's
@@ -325,10 +328,14 @@ interface DocsOtPort {
325
328
  snapshot(): unknown | null;
326
329
  /** Replace the document in every view (and the kept editor). */
327
330
  load(snapshot: unknown): void;
328
- /** Univer's undo/redo service of each mounted view and the unit it holds. */
331
+ /**
332
+ * Univer's undo/redo service of each mounted view and the unit it holds. `flushHistory` pushes the typing burst
333
+ * Univer still holds outside the stack (its 300 ms history debounce) onto the stack, so a rebase reaches it.
334
+ */
329
335
  undoTargets(): Array<{
330
336
  service: unknown;
331
337
  unitId: string;
338
+ flushHistory?: () => void;
332
339
  }>;
333
340
  /** Ask for a save (the record's one coalesced save). */
334
341
  markDirty(): void;
@@ -401,8 +408,17 @@ declare function undoStacksOf(service: unknown): {
401
408
  undo: Map<string, UndoItem$1[]>;
402
409
  redo: Map<string, UndoItem$1[]>;
403
410
  } | null;
404
- /** §6.9: rebase one stack over a remote op; items that cannot follow are dropped. Returns how many were dropped. */
405
- declare function rebaseUndoStack(items: UndoItem$1[], remote: DocsOp): number;
411
+ /**
412
+ * §6.9: rebase one stack over a remote op; items that cannot follow are dropped. Returns how many were dropped.
413
+ *
414
+ * `stack` says which side of each item applies to the document as it is NOW: an undo-stack item's
415
+ * `undoMutations` (its `redoMutations` apply after them), a redo-stack item's `redoMutations` (its
416
+ * `undoMutations` apply after them). The side that applies now meets the remote op as it is; the other side meets
417
+ * the remote op carried past the first. Rebasing both sides against the same op (as before) left the inactive
418
+ * side in coordinates of a document it never applies to: after undo → peer types → redo → undo, the second undo
419
+ * deleted the peer's letters instead of the redone ones (F1).
420
+ */
421
+ declare function rebaseUndoStack(items: UndoItem$1[], remote: DocsOp, stack: "undo" | "redo"): number;
406
422
  declare function openDocsOtRoom(o: OpenDocsOtRoomOptions): DocsOtRoom;
407
423
 
408
424
  interface CaretRange {
@@ -1089,7 +1089,7 @@ import { isOpBarrier, openOpSession } from "@ai-matrx/data/realtime/collab";
1089
1089
  // src/docs/comment-anchors.ts
1090
1090
  import { BuildTextUtils, CustomRangeType, JSONX as JSONX2 } from "@univerjs/core";
1091
1091
  var COMMENT_ANCHOR_RANGE_TYPE = CustomRangeType.COMMENT;
1092
- var RETAIN_KEYS = /* @__PURE__ */ new Set(["t", "len", "body", "coverType"]);
1092
+ var RETAIN_KEYS = /* @__PURE__ */ new Set(["t", "len", "body", "coverType", "oldBody"]);
1093
1093
  var RANGE_KEYS = /* @__PURE__ */ new Set(["rangeId", "rangeType", "startIndex", "endIndex", "properties"]);
1094
1094
  var isObj = (v) => !!v && typeof v === "object" && !Array.isArray(v);
1095
1095
  var keysOf = (o) => Object.keys(o).filter((k) => o[k] !== void 0);
@@ -1141,29 +1141,38 @@ function undoStacksOf(service) {
1141
1141
  if (!s || !(s._undoStacks instanceof Map) || !(s._redoStacks instanceof Map)) return null;
1142
1142
  return { undo: s._undoStacks, redo: s._redoStacks };
1143
1143
  }
1144
- function rebaseUndoStack(items, remote) {
1144
+ function threadThrough(list, remote) {
1145
+ if (!list?.length || isNoopDocsOp(remote)) return { next: null, after: remote };
1146
+ let R = remote;
1147
+ let changed = false;
1148
+ const next = list.map((m) => {
1149
+ if (m.id !== RICH_TEXT_EDITING || isNoopDocsOp(R)) return m;
1150
+ const own = m.params.actions;
1151
+ if (touchesPageSetup(own) && touchesPageSetup(R)) throw new Error("page setup");
1152
+ const x = transformDocsOp(own, R, "left");
1153
+ if (isNoopDocsOp(x.op)) throw new Error("emptied");
1154
+ R = transformDocsOp(R, own, "right").op;
1155
+ changed = true;
1156
+ const params = { ...m.params, actions: x.op };
1157
+ delete params.textRanges;
1158
+ delete params.layoutState;
1159
+ return { ...m, params };
1160
+ });
1161
+ return { next: changed ? next : null, after: R };
1162
+ }
1163
+ function rebaseUndoStack(items, remote, stack) {
1164
+ if (isNoopDocsOp(remote)) return 0;
1165
+ const first = stack === "undo" ? "undoMutations" : "redoMutations";
1166
+ const second = stack === "undo" ? "redoMutations" : "undoMutations";
1145
1167
  let dropped = 0;
1146
1168
  for (let i = items.length - 1; i >= 0; i--) {
1147
1169
  const item = items[i];
1148
- let ok3 = true;
1149
- for (const list of [item.undoMutations, item.redoMutations]) {
1150
- for (const m of list ?? []) {
1151
- if (m.id !== RICH_TEXT_EDITING) continue;
1152
- try {
1153
- if (touchesPageSetup(m.params.actions) && touchesPageSetup(remote)) throw new Error("page setup");
1154
- const r = transformDocsOp(m.params.actions, remote, "left");
1155
- if (isNoopDocsOp(r.op)) ok3 = false;
1156
- else {
1157
- m.params = { ...m.params, actions: r.op };
1158
- delete m.params.textRanges;
1159
- delete m.params.layoutState;
1160
- }
1161
- } catch {
1162
- ok3 = false;
1163
- }
1164
- }
1165
- }
1166
- if (!ok3) {
1170
+ try {
1171
+ const a = threadThrough(item[first], remote);
1172
+ const b = threadThrough(item[second], a.after);
1173
+ if (a.next) item[first] = a.next;
1174
+ if (b.next) item[second] = b.next;
1175
+ } catch {
1167
1176
  items.splice(i, 1);
1168
1177
  dropped++;
1169
1178
  }
@@ -1184,6 +1193,7 @@ function openDocsOtRoom(o) {
1184
1193
  }
1185
1194
  };
1186
1195
  const applyNow = (op) => {
1196
+ for (const t of port.undoTargets()) t.flushHistory?.();
1187
1197
  for (const b of branches(op)) {
1188
1198
  const params = { segmentId: segmentOf(b), actions: b };
1189
1199
  port.applyRemote(RICH_TEXT_EDITING, params);
@@ -1191,10 +1201,10 @@ function openDocsOtRoom(o) {
1191
1201
  for (const t of port.undoTargets()) {
1192
1202
  const stacks = undoStacksOf(t.service);
1193
1203
  if (!stacks) continue;
1194
- for (const m of [stacks.undo, stacks.redo]) {
1195
- const items = m.get(t.unitId);
1196
- if (items?.length) rebaseUndoStack(items, op);
1197
- }
1204
+ const undo = stacks.undo.get(t.unitId);
1205
+ if (undo?.length) rebaseUndoStack(undo, op, "undo");
1206
+ const redo = stacks.redo.get(t.unitId);
1207
+ if (redo?.length) rebaseUndoStack(redo, op, "redo");
1198
1208
  }
1199
1209
  port.markDirty();
1200
1210
  };
@@ -1824,13 +1834,10 @@ var SHEET_MUTATIONS = {
1824
1834
  "data-validation.mutation.updateRule": covered("dv", "ruleId", "payload", "source", "derived"),
1825
1835
  "data-validation.mutation.removeRule": covered("dv", "ruleId", "source", "derived"),
1826
1836
  "sheet.mutation.set-filter-range": covered("filter", "range", "derived"),
1827
- // C5f: Univer's cell notes. Their transform is built (comment-anchor-transform.ts `transformCellNote`, pairwise and
1828
- // chained fuzz green) but the session fuzz still diverges on note cells (seed 1015, 6 seats: a note at column 5 on
1829
- // one seat, 8 on another), so they stay barriers until that seed is green. Covered form, for the next lane:
1830
- // covered("note", "sheetId", "row", "col", "note" | "noteId", "newPosition", "silent", "derived")
1831
- "sheet.mutation.update-note": barrier("C5c", "cell note: the session fuzz diverges on note cells (seed 1015)"),
1832
- "sheet.mutation.remove-note": barrier("C5c", "cell note: the session fuzz diverges on note cells (seed 1015)"),
1833
- "sheet.mutation.update-note-position": barrier("C5c", "cell note: the session fuzz diverges on note cells (seed 1015)"),
1837
+ // C5f/C5g: Univer's cell notes, keyed by note id, anchored to one cell (their transform: comment-anchor-transform.ts)
1838
+ "sheet.mutation.update-note": covered("note", "sheetId", "row", "col", "note", "silent", "derived"),
1839
+ "sheet.mutation.remove-note": covered("note", "sheetId", "noteId", "row", "col", "silent", "derived"),
1840
+ "sheet.mutation.update-note-position": covered("note", "sheetId", "noteId", "row", "col", "newPosition", "silent", "derived"),
1834
1841
  "sheet.mutation.set-filter-criteria": covered("filter", "col", "criteria", "reCalc", "derived"),
1835
1842
  "sheet.mutation.remove-filter": covered("filter", "derived"),
1836
1843
  "sheet.mutation.add-table": barrier("C5c", RESOURCE),