@ai-matrx/office 0.8.44 → 0.8.45

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.
@@ -411,14 +411,18 @@ declare function undoStacksOf(service: unknown): {
411
411
  /**
412
412
  * §6.9: rebase one stack over a remote op; items that cannot follow are dropped. Returns how many were dropped.
413
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).
414
+ * `stack` says which side of each item applies next: an undo-stack item's `undoMutations`, a redo-stack item's
415
+ * `redoMutations`. A stack applies top first, so each item's active side applies to the document as the items
416
+ * above it leave it: the top item meets the remote op as it is, and every item below meets it carried past the
417
+ * active sides of the items above (rebasing each item against the same op put a deeper item at offsets the items
418
+ * above had moved). The inactive side meets the op carried past its own active side; it is a fallback only: the
419
+ * room rewrites it from the real document whenever the item runs (`openDocsOtRoom`, walk 2 F1), because a tie at
420
+ * the edge of what the active side removes cannot say on which side of a collaborator's letters it belongs.
420
421
  */
421
422
  declare function rebaseUndoStack(items: UndoItem$1[], remote: DocsOp, stack: "undo" | "redo"): number;
423
+ /** Univer 1.0.4's undo and redo command ids (the outermost command of every mutation a history step runs). */
424
+ declare const UNDO_COMMAND = "univer.command.undo";
425
+ declare const REDO_COMMAND = "univer.command.redo";
422
426
  declare function openDocsOtRoom(o: OpenDocsOtRoomOptions): DocsOtRoom;
423
427
 
424
428
  interface CaretRange {
@@ -617,6 +621,11 @@ interface SheetsOtPort {
617
621
  busy(): boolean;
618
622
  /** Run `fn` once no local command is running (immediately when none is). */
619
623
  whenIdle(fn: () => void): void;
624
+ /**
625
+ * True when this remote op must wait (and so must every op after it) until `whenIdle`: the port's cell editor is
626
+ * open on a cell the op touches. The held ops apply when it closes, and the person's commit is rebased over them.
627
+ */
628
+ defers?(op: SheetMutation[]): boolean;
620
629
  /** Apply one committed mutation to this seat's workbook; throws when the editor refused it. */
621
630
  applyRemote(m: SheetMutation): void;
622
631
  /** The workbook as the editor holds it now (with resources), or null when none is mounted. */
@@ -637,11 +646,18 @@ interface SheetsOtPort {
637
646
  /** Ask for a save (the record's one coalesced save). */
638
647
  markDirty(): void;
639
648
  }
649
+ /**
650
+ * `resynced`: this seat's workbook disagreed with the room's (a peer's quiet hash, a save's hash or an ack) and the
651
+ * reload that healed it changed what the person sees. One notice per heal; a heal that changed nothing says nothing.
652
+ */
640
653
  type SheetsOtNotice = OpSessionNotice<SheetOp> | {
641
654
  kind: "not_shared";
642
655
  mutationId: string;
643
656
  } | {
644
657
  kind: "not_live";
658
+ } | {
659
+ kind: "resynced";
660
+ reason: string;
645
661
  };
646
662
  /**
647
663
  * The adapter's transform: the C5a/C5b group transform, with `lost` widened by what y can no longer apply
@@ -782,6 +798,10 @@ interface SheetsWorksheetLike {
782
798
  getMaxColumns?(): number;
783
799
  getCellRaw(row: number, col: number): Obj | null | undefined;
784
800
  getMergeData(): SheetRange[];
801
+ /** Univer's `Worksheet.getCellMatrix()` (every stored cell). */
802
+ getCellMatrix?(): {
803
+ forValue(fn: (row: number, col: number, cell: Obj | null | undefined) => unknown): void;
804
+ };
785
805
  }
786
806
  interface SheetsWorkbookLike {
787
807
  getUnitId(): string;
@@ -821,10 +841,51 @@ interface UniverSheetsOtPortOptions {
821
841
  * time on this seat. Without it a seat with a filter diverges from its peers on that write.
822
842
  */
823
843
  filterRange?(unitId: string, subUnitId: string): SheetRange | null | undefined;
844
+ /**
845
+ * The cell this seat's cell editor is open on, or null when it is closed (`IEditorBridgeService`:
846
+ * `isVisible().visible` and `getEditLocation()`). Univer rewrites an open editor's text whenever any write lands on
847
+ * its cell (`EditorDataSyncController` → `refreshEditCellState` → the editor's `ReplaceSnapshotCommand`, caret back
848
+ * to 0), so a peer's value landing mid-typing spliced into the draft and Enter committed the mix (the attack's
849
+ * "$1,234.50" vs "$7" → 507). While the editor is open, a remote op that touches its cell or its sheet is held,
850
+ * and so is everything after it: the person's draft and the cell it is committed against stay as they saw them,
851
+ * and their commit is rebased over the held ops when the editor closes (the later commit wins whole).
852
+ */
853
+ cellEditor?(): EditedCell | null;
824
854
  /** Replace the workbook's whole content, keeping its unit id. */
825
855
  load(snapshot: unknown): void;
826
856
  markDirty(): void;
827
857
  }
858
+ /** The cell an open cell editor is on. */
859
+ interface EditedCell {
860
+ sheetId: string;
861
+ row: number;
862
+ col: number;
863
+ }
864
+ /** What the port reads of Univer's `SheetsFilterService` (sheets-filter). */
865
+ interface FilterServiceLike {
866
+ getFilterModel(unitId: string, subUnitId: string): {
867
+ getRange(): SheetRange | null | undefined;
868
+ } | null | undefined;
869
+ }
870
+ /**
871
+ * The port's `filterRange` over Univer's filter service: the range as the filter stores it, `rangeType` included.
872
+ * Every host lends this one (the editor, the fold, the fuzz seats): a host that dropped `rangeType` restored a peer's
873
+ * growth without it, and that seat's filter saved differently from the others (hash_mismatch, live attack rev 90).
874
+ */
875
+ declare function filterServiceRange(service: () => FilterServiceLike | null | undefined): (unitId: string, subUnitId: string) => SheetRange | null;
876
+ /** What the port reads of Univer's `IEditorBridgeService` (sheets-ui). */
877
+ interface EditorBridgeLike {
878
+ isVisible(): {
879
+ visible: boolean;
880
+ };
881
+ getEditLocation(): {
882
+ sheetId: string;
883
+ row: number;
884
+ column: number;
885
+ } | null | undefined;
886
+ }
887
+ /** The port's `cellEditor` over Univer's editor bridge: the cell the cell editor is open on, or null. */
888
+ declare function editorBridgeCell(bridge: EditorBridgeLike): () => EditedCell | null;
828
889
  /** One selection as `SheetsSelectionsService` holds it (range, primary cell, style). */
829
890
  interface SheetSelection {
830
891
  range: SheetRange & {
@@ -933,4 +994,4 @@ declare function startWorkbookOtRoom(port: SheetsOtPort & {
933
994
  dispose?: () => void;
934
995
  }, o: WorkbookOtRoomOptions): Promise<WorkbookOtRoomHandle>;
935
996
 
936
- export { COLLAB_COVERED_KEY, type CollabBase, type CollabMutationInfo, type CollabProviderLike, type CommandServiceLike, DOCS_COLLAB_PROTO, DOCS_TRANSFORM_VERSION, DOC_LOCAL_KEYS, type DocsLocalMutation, type DocsLost, type DocsOp, type DocsOtNotice, type DocsOtPort, type DocsOtRoom, type DocsTransformResult, type DocumentOtFactoryOptions, type DocumentRestoreDeps, type DocumentRestoreResult, type OpenDocsOtRoomOptions, type OpenSheetsOtRoomOptions, type OtRoomsKnob, RICH_TEXT_EDITING, SENDER_VIEW_PARAMS, SHEETS_COLLAB_PROTO, SHEETS_EDIT_GROUP, SHEETS_READABLE_PROTOS, SHEET_ROOM_EDITOR_PRESETS, SHEET_ROOM_PLUGIN_PACKAGES, type SheetOp, type SheetSelection, type SheetsCommandService, type SheetsLocalEvent, type SheetsLocalGroup, type SheetsNotShared, type SheetsOtAdapter, type SheetsOtAdapterHooks, type SheetsOtNotice, type SheetsOtPort, type SheetsOtRoom, type SheetsWorkbookLike, type SheetsWorksheetLike, type UniverSheetsOtPortOptions, WorkbookCollabSession, type WorkbookCollabSessionOptions, type WorkbookOtRoomHandle, type WorkbookOtRoomOptions, type WorkbookOtRoomsKnob, applyDocsOp, asLoadedDocsSnapshot, canonicalDocsSnapshot, canonicalDocsString, canonicalKeys, canonicalSheet, canonicalSheetString, composeDocsOps, createSheetsOtAdapter, decodeSheetOp, docsStateHash, documentOtFactory, documentUsesOrderedRoom, dropEmptyStyleRetains, encodeSheetOp, invertDocsOp, isCellEditorScratch, isNoopDocsOp, moveSelectionsThrough, normalizeDocsOp, offlineTextOfGroups, openDocsOtRoom, openSheetsOtRoom, rebaseSheetUndoStack, rebaseUndoStack, restoreDocumentSnapshot, sheetsStateHash, stampCovered, stampDeterministicIds, startWorkbookOtRoom, stripSenderView, takeCovered, transformDocsOp, transformSheetOp, transformTextX, undoStacksOf, univerSheetsOtPort, workbookUsesOrderedRoom };
997
+ export { COLLAB_COVERED_KEY, type CollabBase, type CollabMutationInfo, type CollabProviderLike, type CommandServiceLike, DOCS_COLLAB_PROTO, DOCS_TRANSFORM_VERSION, DOC_LOCAL_KEYS, type DocsLocalMutation, type DocsLost, type DocsOp, type DocsOtNotice, type DocsOtPort, type DocsOtRoom, type DocsTransformResult, type DocumentOtFactoryOptions, type DocumentRestoreDeps, type DocumentRestoreResult, type EditedCell, type EditorBridgeLike, type FilterServiceLike, type OpenDocsOtRoomOptions, type OpenSheetsOtRoomOptions, type OtRoomsKnob, REDO_COMMAND, RICH_TEXT_EDITING, SENDER_VIEW_PARAMS, SHEETS_COLLAB_PROTO, SHEETS_EDIT_GROUP, SHEETS_READABLE_PROTOS, SHEET_ROOM_EDITOR_PRESETS, SHEET_ROOM_PLUGIN_PACKAGES, type SheetOp, type SheetSelection, type SheetsCommandService, type SheetsLocalEvent, type SheetsLocalGroup, type SheetsNotShared, type SheetsOtAdapter, type SheetsOtAdapterHooks, type SheetsOtNotice, type SheetsOtPort, type SheetsOtRoom, type SheetsWorkbookLike, type SheetsWorksheetLike, UNDO_COMMAND, type UniverSheetsOtPortOptions, WorkbookCollabSession, type WorkbookCollabSessionOptions, type WorkbookOtRoomHandle, type WorkbookOtRoomOptions, type WorkbookOtRoomsKnob, applyDocsOp, asLoadedDocsSnapshot, canonicalDocsSnapshot, canonicalDocsString, canonicalKeys, canonicalSheet, canonicalSheetString, composeDocsOps, createSheetsOtAdapter, decodeSheetOp, docsStateHash, documentOtFactory, documentUsesOrderedRoom, dropEmptyStyleRetains, editorBridgeCell, encodeSheetOp, filterServiceRange, invertDocsOp, isCellEditorScratch, isNoopDocsOp, moveSelectionsThrough, normalizeDocsOp, offlineTextOfGroups, openDocsOtRoom, openSheetsOtRoom, rebaseSheetUndoStack, rebaseUndoStack, restoreDocumentSnapshot, sheetsStateHash, stampCovered, stampDeterministicIds, startWorkbookOtRoom, stripSenderView, takeCovered, transformDocsOp, transformSheetOp, transformTextX, undoStacksOf, univerSheetsOtPort, workbookUsesOrderedRoom };
@@ -411,14 +411,18 @@ declare function undoStacksOf(service: unknown): {
411
411
  /**
412
412
  * §6.9: rebase one stack over a remote op; items that cannot follow are dropped. Returns how many were dropped.
413
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).
414
+ * `stack` says which side of each item applies next: an undo-stack item's `undoMutations`, a redo-stack item's
415
+ * `redoMutations`. A stack applies top first, so each item's active side applies to the document as the items
416
+ * above it leave it: the top item meets the remote op as it is, and every item below meets it carried past the
417
+ * active sides of the items above (rebasing each item against the same op put a deeper item at offsets the items
418
+ * above had moved). The inactive side meets the op carried past its own active side; it is a fallback only: the
419
+ * room rewrites it from the real document whenever the item runs (`openDocsOtRoom`, walk 2 F1), because a tie at
420
+ * the edge of what the active side removes cannot say on which side of a collaborator's letters it belongs.
420
421
  */
421
422
  declare function rebaseUndoStack(items: UndoItem$1[], remote: DocsOp, stack: "undo" | "redo"): number;
423
+ /** Univer 1.0.4's undo and redo command ids (the outermost command of every mutation a history step runs). */
424
+ declare const UNDO_COMMAND = "univer.command.undo";
425
+ declare const REDO_COMMAND = "univer.command.redo";
422
426
  declare function openDocsOtRoom(o: OpenDocsOtRoomOptions): DocsOtRoom;
423
427
 
424
428
  interface CaretRange {
@@ -617,6 +621,11 @@ interface SheetsOtPort {
617
621
  busy(): boolean;
618
622
  /** Run `fn` once no local command is running (immediately when none is). */
619
623
  whenIdle(fn: () => void): void;
624
+ /**
625
+ * True when this remote op must wait (and so must every op after it) until `whenIdle`: the port's cell editor is
626
+ * open on a cell the op touches. The held ops apply when it closes, and the person's commit is rebased over them.
627
+ */
628
+ defers?(op: SheetMutation[]): boolean;
620
629
  /** Apply one committed mutation to this seat's workbook; throws when the editor refused it. */
621
630
  applyRemote(m: SheetMutation): void;
622
631
  /** The workbook as the editor holds it now (with resources), or null when none is mounted. */
@@ -637,11 +646,18 @@ interface SheetsOtPort {
637
646
  /** Ask for a save (the record's one coalesced save). */
638
647
  markDirty(): void;
639
648
  }
649
+ /**
650
+ * `resynced`: this seat's workbook disagreed with the room's (a peer's quiet hash, a save's hash or an ack) and the
651
+ * reload that healed it changed what the person sees. One notice per heal; a heal that changed nothing says nothing.
652
+ */
640
653
  type SheetsOtNotice = OpSessionNotice<SheetOp> | {
641
654
  kind: "not_shared";
642
655
  mutationId: string;
643
656
  } | {
644
657
  kind: "not_live";
658
+ } | {
659
+ kind: "resynced";
660
+ reason: string;
645
661
  };
646
662
  /**
647
663
  * The adapter's transform: the C5a/C5b group transform, with `lost` widened by what y can no longer apply
@@ -782,6 +798,10 @@ interface SheetsWorksheetLike {
782
798
  getMaxColumns?(): number;
783
799
  getCellRaw(row: number, col: number): Obj | null | undefined;
784
800
  getMergeData(): SheetRange[];
801
+ /** Univer's `Worksheet.getCellMatrix()` (every stored cell). */
802
+ getCellMatrix?(): {
803
+ forValue(fn: (row: number, col: number, cell: Obj | null | undefined) => unknown): void;
804
+ };
785
805
  }
786
806
  interface SheetsWorkbookLike {
787
807
  getUnitId(): string;
@@ -821,10 +841,51 @@ interface UniverSheetsOtPortOptions {
821
841
  * time on this seat. Without it a seat with a filter diverges from its peers on that write.
822
842
  */
823
843
  filterRange?(unitId: string, subUnitId: string): SheetRange | null | undefined;
844
+ /**
845
+ * The cell this seat's cell editor is open on, or null when it is closed (`IEditorBridgeService`:
846
+ * `isVisible().visible` and `getEditLocation()`). Univer rewrites an open editor's text whenever any write lands on
847
+ * its cell (`EditorDataSyncController` → `refreshEditCellState` → the editor's `ReplaceSnapshotCommand`, caret back
848
+ * to 0), so a peer's value landing mid-typing spliced into the draft and Enter committed the mix (the attack's
849
+ * "$1,234.50" vs "$7" → 507). While the editor is open, a remote op that touches its cell or its sheet is held,
850
+ * and so is everything after it: the person's draft and the cell it is committed against stay as they saw them,
851
+ * and their commit is rebased over the held ops when the editor closes (the later commit wins whole).
852
+ */
853
+ cellEditor?(): EditedCell | null;
824
854
  /** Replace the workbook's whole content, keeping its unit id. */
825
855
  load(snapshot: unknown): void;
826
856
  markDirty(): void;
827
857
  }
858
+ /** The cell an open cell editor is on. */
859
+ interface EditedCell {
860
+ sheetId: string;
861
+ row: number;
862
+ col: number;
863
+ }
864
+ /** What the port reads of Univer's `SheetsFilterService` (sheets-filter). */
865
+ interface FilterServiceLike {
866
+ getFilterModel(unitId: string, subUnitId: string): {
867
+ getRange(): SheetRange | null | undefined;
868
+ } | null | undefined;
869
+ }
870
+ /**
871
+ * The port's `filterRange` over Univer's filter service: the range as the filter stores it, `rangeType` included.
872
+ * Every host lends this one (the editor, the fold, the fuzz seats): a host that dropped `rangeType` restored a peer's
873
+ * growth without it, and that seat's filter saved differently from the others (hash_mismatch, live attack rev 90).
874
+ */
875
+ declare function filterServiceRange(service: () => FilterServiceLike | null | undefined): (unitId: string, subUnitId: string) => SheetRange | null;
876
+ /** What the port reads of Univer's `IEditorBridgeService` (sheets-ui). */
877
+ interface EditorBridgeLike {
878
+ isVisible(): {
879
+ visible: boolean;
880
+ };
881
+ getEditLocation(): {
882
+ sheetId: string;
883
+ row: number;
884
+ column: number;
885
+ } | null | undefined;
886
+ }
887
+ /** The port's `cellEditor` over Univer's editor bridge: the cell the cell editor is open on, or null. */
888
+ declare function editorBridgeCell(bridge: EditorBridgeLike): () => EditedCell | null;
828
889
  /** One selection as `SheetsSelectionsService` holds it (range, primary cell, style). */
829
890
  interface SheetSelection {
830
891
  range: SheetRange & {
@@ -933,4 +994,4 @@ declare function startWorkbookOtRoom(port: SheetsOtPort & {
933
994
  dispose?: () => void;
934
995
  }, o: WorkbookOtRoomOptions): Promise<WorkbookOtRoomHandle>;
935
996
 
936
- export { COLLAB_COVERED_KEY, type CollabBase, type CollabMutationInfo, type CollabProviderLike, type CommandServiceLike, DOCS_COLLAB_PROTO, DOCS_TRANSFORM_VERSION, DOC_LOCAL_KEYS, type DocsLocalMutation, type DocsLost, type DocsOp, type DocsOtNotice, type DocsOtPort, type DocsOtRoom, type DocsTransformResult, type DocumentOtFactoryOptions, type DocumentRestoreDeps, type DocumentRestoreResult, type OpenDocsOtRoomOptions, type OpenSheetsOtRoomOptions, type OtRoomsKnob, RICH_TEXT_EDITING, SENDER_VIEW_PARAMS, SHEETS_COLLAB_PROTO, SHEETS_EDIT_GROUP, SHEETS_READABLE_PROTOS, SHEET_ROOM_EDITOR_PRESETS, SHEET_ROOM_PLUGIN_PACKAGES, type SheetOp, type SheetSelection, type SheetsCommandService, type SheetsLocalEvent, type SheetsLocalGroup, type SheetsNotShared, type SheetsOtAdapter, type SheetsOtAdapterHooks, type SheetsOtNotice, type SheetsOtPort, type SheetsOtRoom, type SheetsWorkbookLike, type SheetsWorksheetLike, type UniverSheetsOtPortOptions, WorkbookCollabSession, type WorkbookCollabSessionOptions, type WorkbookOtRoomHandle, type WorkbookOtRoomOptions, type WorkbookOtRoomsKnob, applyDocsOp, asLoadedDocsSnapshot, canonicalDocsSnapshot, canonicalDocsString, canonicalKeys, canonicalSheet, canonicalSheetString, composeDocsOps, createSheetsOtAdapter, decodeSheetOp, docsStateHash, documentOtFactory, documentUsesOrderedRoom, dropEmptyStyleRetains, encodeSheetOp, invertDocsOp, isCellEditorScratch, isNoopDocsOp, moveSelectionsThrough, normalizeDocsOp, offlineTextOfGroups, openDocsOtRoom, openSheetsOtRoom, rebaseSheetUndoStack, rebaseUndoStack, restoreDocumentSnapshot, sheetsStateHash, stampCovered, stampDeterministicIds, startWorkbookOtRoom, stripSenderView, takeCovered, transformDocsOp, transformSheetOp, transformTextX, undoStacksOf, univerSheetsOtPort, workbookUsesOrderedRoom };
997
+ export { COLLAB_COVERED_KEY, type CollabBase, type CollabMutationInfo, type CollabProviderLike, type CommandServiceLike, DOCS_COLLAB_PROTO, DOCS_TRANSFORM_VERSION, DOC_LOCAL_KEYS, type DocsLocalMutation, type DocsLost, type DocsOp, type DocsOtNotice, type DocsOtPort, type DocsOtRoom, type DocsTransformResult, type DocumentOtFactoryOptions, type DocumentRestoreDeps, type DocumentRestoreResult, type EditedCell, type EditorBridgeLike, type FilterServiceLike, type OpenDocsOtRoomOptions, type OpenSheetsOtRoomOptions, type OtRoomsKnob, REDO_COMMAND, RICH_TEXT_EDITING, SENDER_VIEW_PARAMS, SHEETS_COLLAB_PROTO, SHEETS_EDIT_GROUP, SHEETS_READABLE_PROTOS, SHEET_ROOM_EDITOR_PRESETS, SHEET_ROOM_PLUGIN_PACKAGES, type SheetOp, type SheetSelection, type SheetsCommandService, type SheetsLocalEvent, type SheetsLocalGroup, type SheetsNotShared, type SheetsOtAdapter, type SheetsOtAdapterHooks, type SheetsOtNotice, type SheetsOtPort, type SheetsOtRoom, type SheetsWorkbookLike, type SheetsWorksheetLike, UNDO_COMMAND, type UniverSheetsOtPortOptions, WorkbookCollabSession, type WorkbookCollabSessionOptions, type WorkbookOtRoomHandle, type WorkbookOtRoomOptions, type WorkbookOtRoomsKnob, applyDocsOp, asLoadedDocsSnapshot, canonicalDocsSnapshot, canonicalDocsString, canonicalKeys, canonicalSheet, canonicalSheetString, composeDocsOps, createSheetsOtAdapter, decodeSheetOp, docsStateHash, documentOtFactory, documentUsesOrderedRoom, dropEmptyStyleRetains, editorBridgeCell, encodeSheetOp, filterServiceRange, invertDocsOp, isCellEditorScratch, isNoopDocsOp, moveSelectionsThrough, normalizeDocsOp, offlineTextOfGroups, openDocsOtRoom, openSheetsOtRoom, rebaseSheetUndoStack, rebaseUndoStack, restoreDocumentSnapshot, sheetsStateHash, stampCovered, stampDeterministicIds, startWorkbookOtRoom, stripSenderView, takeCovered, transformDocsOp, transformSheetOp, transformTextX, undoStacksOf, univerSheetsOtPort, workbookUsesOrderedRoom };
@@ -1165,26 +1165,77 @@ function rebaseUndoStack(items, remote, stack) {
1165
1165
  const first = stack === "undo" ? "undoMutations" : "redoMutations";
1166
1166
  const second = stack === "undo" ? "redoMutations" : "undoMutations";
1167
1167
  let dropped = 0;
1168
- for (let i = items.length - 1; i >= 0; i--) {
1168
+ let R = remote;
1169
+ for (let i = items.length - 1; i >= 0 && !isNoopDocsOp(R); i--) {
1169
1170
  const item = items[i];
1170
1171
  try {
1171
- const a = threadThrough(item[first], remote);
1172
+ const a = threadThrough(item[first], R);
1172
1173
  const b = threadThrough(item[second], a.after);
1173
1174
  if (a.next) item[first] = a.next;
1174
1175
  if (b.next) item[second] = b.next;
1176
+ R = a.after;
1175
1177
  } catch {
1176
1178
  items.splice(i, 1);
1177
1179
  dropped++;
1180
+ R = carryPast(item[first], R);
1178
1181
  }
1179
1182
  }
1180
1183
  return dropped;
1181
1184
  }
1185
+ function carryPast(list, remote) {
1186
+ let R = remote;
1187
+ for (const m of list ?? []) {
1188
+ if (m.id !== RICH_TEXT_EDITING || isNoopDocsOp(R)) continue;
1189
+ const own = m.params.actions;
1190
+ if (touchesPageSetup(own) && touchesPageSetup(R)) continue;
1191
+ R = transformDocsOp(R, own, "right").op;
1192
+ }
1193
+ return R;
1194
+ }
1195
+ var UNDO_COMMAND = "univer.command.undo";
1196
+ var REDO_COMMAND = "univer.command.redo";
1182
1197
  function openDocsOtRoom(o) {
1183
1198
  const { port } = o;
1184
1199
  let session = null;
1185
1200
  let composing = false;
1186
1201
  let queue = [];
1187
1202
  const drainWaiters = [];
1203
+ let replay = null;
1204
+ const noteHistoryStep = (m, inverse) => {
1205
+ const side = m.cmd === UNDO_COMMAND ? "undo" : m.cmd === REDO_COMMAND ? "redo" : null;
1206
+ if (!side) {
1207
+ replay = null;
1208
+ return;
1209
+ }
1210
+ for (const t of port.undoTargets()) {
1211
+ const stacks = undoStacksOf(t.service);
1212
+ const stack = stacks ? (side === "undo" ? stacks.undo : stacks.redo).get(t.unitId) : void 0;
1213
+ const item = stack?.[stack.length - 1];
1214
+ const list = item ? side === "undo" ? item.undoMutations : item.redoMutations : void 0;
1215
+ const k = list ? list.findIndex((x) => x.params === m.params) : -1;
1216
+ if (!item || !list || k < 0) continue;
1217
+ if (k === 0 || !replay || replay.item !== item || replay.side !== side) {
1218
+ const other = (side === "undo" ? item.redoMutations : item.undoMutations)?.[0]?.params ?? {};
1219
+ const { textRanges: _t, layoutState: _l, actions: _a, ...template } = other;
1220
+ replay = { item, side, inverses: [], template };
1221
+ }
1222
+ if (inverse === void 0 || list.some((x) => x.id !== RICH_TEXT_EDITING)) {
1223
+ replay = null;
1224
+ return;
1225
+ }
1226
+ replay.inverses.unshift(inverse);
1227
+ if (k === list.length - 1) {
1228
+ const rewritten = replay.inverses.filter((op) => !isNoopDocsOp(op)).map((op) => ({ id: RICH_TEXT_EDITING, params: { ...replay.template, segmentId: m.params?.segmentId ?? "", actions: op } }));
1229
+ if (rewritten.length) {
1230
+ if (side === "undo") item.redoMutations = rewritten;
1231
+ else item.undoMutations = rewritten;
1232
+ }
1233
+ replay = null;
1234
+ }
1235
+ return;
1236
+ }
1237
+ replay = null;
1238
+ };
1188
1239
  const notice = (n) => {
1189
1240
  try {
1190
1241
  o.onNotice?.(n);
@@ -1282,7 +1333,10 @@ function openDocsOtRoom(o) {
1282
1333
  }
1283
1334
  const p = m.params ?? {};
1284
1335
  const applied = p.actions ?? null;
1285
- if (isNoopDocsOp(applied)) return;
1336
+ if (isNoopDocsOp(applied)) {
1337
+ noteHistoryStep(m, null);
1338
+ return;
1339
+ }
1286
1340
  let op = normalizeDocsOp(structuredClone(applied));
1287
1341
  let inverse;
1288
1342
  try {
@@ -1290,6 +1344,7 @@ function openDocsOtRoom(o) {
1290
1344
  } catch {
1291
1345
  inverse = void 0;
1292
1346
  }
1347
+ noteHistoryStep(m, inverse === void 0 ? void 0 : normalizeDocsOp(inverse));
1293
1348
  if (queue.length) {
1294
1349
  inverse = void 0;
1295
1350
  const next = [];
@@ -2781,6 +2836,18 @@ function transformCell(X, Y4, side) {
2781
2836
  if (styleKeys(xs).length !== styleKeys(kept ?? {}).length) xLost = true;
2782
2837
  }
2783
2838
  }
2839
+ if (hasContent(X) && hasContent(Y4)) {
2840
+ const has = (s) => !!s && typeof s === "object" && "n" in s;
2841
+ const outS = out.s;
2842
+ if (side === "left" && !has(X.s) && has(Y4.s) && X.s !== null) {
2843
+ out.s = { ...outS && typeof outS === "object" ? outS : {}, n: null };
2844
+ } else if (side === "right" && outS && typeof outS === "object" && "n" in outS) {
2845
+ const rest = withoutStyleKeys(outS, /* @__PURE__ */ new Set(["n"]));
2846
+ if (rest) out.s = rest;
2847
+ else delete out.s;
2848
+ xLost = true;
2849
+ }
2850
+ }
2784
2851
  return { entries: Object.keys(out).length ? [out, ...tail] : tail, xLost, yLost };
2785
2852
  }
2786
2853
  function transformCellsOverCells(x, y, side) {
@@ -3941,7 +4008,7 @@ function createSheetsOtAdapter(port, hooks = {}) {
3941
4008
  decode: decodeSheetOp,
3942
4009
  apply(op) {
3943
4010
  if (isNoopSheetOp(op)) return true;
3944
- if (port.busy() || queue.length) {
4011
+ if (port.busy() || queue.length || port.defers?.(op)) {
3945
4012
  queue.push(op);
3946
4013
  if (!draining) {
3947
4014
  draining = true;
@@ -3974,9 +4041,9 @@ function createSheetsOtAdapter(port, hooks = {}) {
3974
4041
  async hash() {
3975
4042
  if (port.busy() || queue.length) {
3976
4043
  await new Promise((resolve) => {
3977
- const done = setTimeout(resolve, 5e3);
4044
+ const done = queue.length ? null : setTimeout(resolve, 5e3);
3978
4045
  port.whenIdle(() => {
3979
- clearTimeout(done);
4046
+ if (done) clearTimeout(done);
3980
4047
  setTimeout(resolve, 0);
3981
4048
  });
3982
4049
  });
@@ -4006,7 +4073,6 @@ function createSheetsOtAdapter(port, hooks = {}) {
4006
4073
  function openSheetsOtRoom(o) {
4007
4074
  const { port } = o;
4008
4075
  let session = null;
4009
- const adapter = createSheetsOtAdapter(port);
4010
4076
  const notice = (n) => {
4011
4077
  try {
4012
4078
  o.onNotice?.(n);
@@ -4014,6 +4080,29 @@ function openSheetsOtRoom(o) {
4014
4080
  console.warn("[sheets-ot] notice handler failed", err);
4015
4081
  }
4016
4082
  };
4083
+ const adapter = createSheetsOtAdapter(port);
4084
+ let healing = null;
4085
+ const HEALS = /* @__PURE__ */ new Set(["hash_mismatch", "save_hash_mismatch", "ack_mismatch"]);
4086
+ const screen = () => {
4087
+ try {
4088
+ const s = port.snapshot();
4089
+ return s ? canonicalSheetString(s) : null;
4090
+ } catch {
4091
+ return null;
4092
+ }
4093
+ };
4094
+ const onIncident = (i) => {
4095
+ if (HEALS.has(i.kind) && !healing) healing = { reason: i.kind, before: screen() };
4096
+ o.onIncident?.(i);
4097
+ };
4098
+ const onStatus = (st) => {
4099
+ if (st === "live" && healing) {
4100
+ const h = healing;
4101
+ healing = null;
4102
+ if (h.before !== null && screen() !== h.before) notice({ kind: "resynced", reason: h.reason });
4103
+ } else if (st === "read_only" || st === "closed") healing = null;
4104
+ o.onStatus?.(st);
4105
+ };
4017
4106
  const onLocal = (e) => {
4018
4107
  if (!session) return;
4019
4108
  if (e.kind === "not_shared") {
@@ -4054,8 +4143,8 @@ function openSheetsOtRoom(o) {
4054
4143
  clientId: o.clientId,
4055
4144
  ...o.presence ? { presence: o.presence } : {},
4056
4145
  onNotice: (n) => notice(n),
4057
- ...o.onIncident ? { onIncident: o.onIncident } : {},
4058
- ...o.onStatus ? { onStatus: o.onStatus } : {},
4146
+ onIncident,
4147
+ onStatus,
4059
4148
  ...o.offline ? { offline: o.offline } : {},
4060
4149
  ...o.onOffline ? { onOffline: o.onOffline } : {}
4061
4150
  });
@@ -4148,6 +4237,23 @@ function releaseUnitPluginState(cs, unitId, saved) {
4148
4237
  }
4149
4238
 
4150
4239
  // src/univer/collab/sheets-ot/univer-port.ts
4240
+ function filterServiceRange(service) {
4241
+ return (unitId, subUnitId) => {
4242
+ try {
4243
+ const r = service()?.getFilterModel(unitId, subUnitId)?.getRange();
4244
+ return r ? { startRow: r.startRow, endRow: r.endRow, startColumn: r.startColumn, endColumn: r.endColumn, ...r.rangeType !== void 0 ? { rangeType: r.rangeType } : {} } : null;
4245
+ } catch {
4246
+ return null;
4247
+ }
4248
+ };
4249
+ }
4250
+ function editorBridgeCell(bridge) {
4251
+ return () => {
4252
+ if (!bridge.isVisible()?.visible) return null;
4253
+ const at = bridge.getEditLocation();
4254
+ return at ? { sheetId: at.sheetId, row: at.row, col: at.column } : null;
4255
+ };
4256
+ }
4151
4257
  var COMMAND = 0;
4152
4258
  var MUTATION = 2;
4153
4259
  var VALUES = "sheet.mutation.set-range-values";
@@ -4155,6 +4261,7 @@ var ADD_MERGE = "sheet.mutation.add-worksheet-merge";
4155
4261
  var REMOVE_MERGE = "sheet.mutation.remove-worksheet-merge";
4156
4262
  var SHEET_NAME = "sheet.mutation.set-worksheet-name";
4157
4263
  var INSERT_SHEET = "sheet.mutation.insert-sheet";
4264
+ var REMOVE_SHEET2 = "sheet.mutation.remove-sheet";
4158
4265
  var FILTER_RANGE = "sheet.mutation.set-filter-range";
4159
4266
  var RESHAPE = /* @__PURE__ */ new Set(["sheet.mutation.set-worksheet-row-count", "sheet.mutation.set-worksheet-column-count", "sheet.mutation.remove-sheet", INSERT_SHEET]);
4160
4267
  var UNDO = "univer.command.undo";
@@ -4174,6 +4281,18 @@ function univerSheetsOtPort(o) {
4174
4281
  const tracker = { stack: [], settle: () => settle() };
4175
4282
  let group = null;
4176
4283
  let applying = false;
4284
+ let editorHold = false;
4285
+ const edited = () => {
4286
+ try {
4287
+ return o.cellEditor?.() ?? null;
4288
+ } catch {
4289
+ return null;
4290
+ }
4291
+ };
4292
+ const holding = () => {
4293
+ if (editorHold && !edited()) editorHold = false;
4294
+ return editorHold;
4295
+ };
4177
4296
  const unitId = () => o.workbook()?.getUnitId() ?? null;
4178
4297
  const mine = (params) => {
4179
4298
  const u = unitId();
@@ -4202,7 +4321,7 @@ function univerSheetsOtPort(o) {
4202
4321
  if (!u || !o.filterRange) return null;
4203
4322
  try {
4204
4323
  const r = o.filterRange(u, sheet);
4205
- return r ? { startRow: r.startRow, endRow: r.endRow, startColumn: r.startColumn, endColumn: r.endColumn } : null;
4324
+ return r ? { startRow: r.startRow, endRow: r.endRow, startColumn: r.startColumn, endColumn: r.endColumn, ...r.rangeType !== void 0 ? { rangeType: r.rangeType } : {} } : null;
4206
4325
  } catch {
4207
4326
  return null;
4208
4327
  }
@@ -4218,10 +4337,45 @@ function univerSheetsOtPort(o) {
4218
4337
  }
4219
4338
  }
4220
4339
  };
4340
+ const sweepRemovedSheetRefs = (g) => {
4341
+ const removed = g.mutations.filter((m) => m.id === REMOVE_SHEET2).map((m) => String(m.params.subUnitId ?? ""));
4342
+ const wb = o.workbook();
4343
+ const u = unitId();
4344
+ if (!removed.length || !wb || !u) return;
4345
+ const refSheets = {};
4346
+ for (const [id, name] of Object.entries(g.sheets)) refSheets[name] = id;
4347
+ for (const gone of removed) {
4348
+ const name = g.sheets[gone];
4349
+ if (!name) continue;
4350
+ for (const ws of wb.getSheets()) {
4351
+ const sheet = ws.getSheetId();
4352
+ const cells = {};
4353
+ ws.getCellMatrix?.().forValue((r, c, cell) => {
4354
+ const f = cell?.f;
4355
+ if (typeof f !== "string" || !f.includes(name)) return;
4356
+ const out = rewriteFormula(f, { ownSheet: sheet, refSheets }, { kind: "remove-sheet", sheet: gone });
4357
+ if (typeof out !== "string" && out.changed) (cells[r] ??= {})[c] = { f: out.text, si: null };
4358
+ });
4359
+ if (!Object.keys(cells).length) continue;
4360
+ applying = true;
4361
+ try {
4362
+ cs.syncExecuteCommand(VALUES, { unitId: u, subUnitId: sheet, cellValue: json(cells) });
4363
+ } finally {
4364
+ applying = false;
4365
+ }
4366
+ const done = {};
4367
+ for (const r of Object.keys(cells))
4368
+ for (const c of Object.keys(cells[r])) (done[r] ??= {})[c] = completeCellContent(cells[r][c], json(ws.getCellRaw(Number(r), Number(c)) ?? null));
4369
+ g.mutations.push({ id: VALUES, params: { subUnitId: sheet, cellValue: done } });
4370
+ g.inverses.push(void 0);
4371
+ }
4372
+ }
4373
+ };
4221
4374
  const flush = () => {
4222
4375
  const g = group;
4223
4376
  group = null;
4224
4377
  if (!g) return;
4378
+ if (!g.notShared) sweepRemovedSheetRefs(g);
4225
4379
  if (g.notShared) emit({ kind: "not_shared", mutationId: g.notShared, label: g.label });
4226
4380
  else if (g.mutations.length) {
4227
4381
  const mutations = annotateSheetOps(annotateFormulas(g.mutations, g.sheets, g.names), g.order);
@@ -4233,7 +4387,7 @@ function univerSheetsOtPort(o) {
4233
4387
  };
4234
4388
  function settle() {
4235
4389
  if (tracker.stack.length === 0) flush();
4236
- if (tracker.stack.length === 0 && !group) for (const fn of idle.splice(0)) fn();
4390
+ if (tracker.stack.length === 0 && !group && !holding()) for (const fn of idle.splice(0)) fn();
4237
4391
  }
4238
4392
  const before = cs.beforeCommandExecuted((info, options) => {
4239
4393
  if (info.id === UNDO || info.id === REDO) for (const fn of [...undoWatchers]) fn();
@@ -4247,6 +4401,7 @@ function univerSheetsOtPort(o) {
4247
4401
  const ws = o.workbook()?.getSheetBySheetId(String(p.subUnitId ?? ""));
4248
4402
  if (!ws) return;
4249
4403
  const record = { merges: json(ws.getMergeData() ?? []) };
4404
+ if (!group) record.lone = openGroup(null);
4250
4405
  if (info.id === VALUES) {
4251
4406
  record.cells = /* @__PURE__ */ new Map();
4252
4407
  const cells = p.cellValue ?? {};
@@ -4283,6 +4438,7 @@ function univerSheetsOtPort(o) {
4283
4438
  }
4284
4439
  };
4285
4440
  const after = cs.onCommandExecuted((info) => {
4441
+ if (editorHold && tracker.stack.length === 0 && !group && !edited()) settle();
4286
4442
  if (info.type !== COMMAND) return;
4287
4443
  const at = tracker.stack.lastIndexOf(info.id);
4288
4444
  if (at >= 0) tracker.stack.splice(at, 1);
@@ -4364,7 +4520,7 @@ function univerSheetsOtPort(o) {
4364
4520
  else {
4365
4521
  inv = {};
4366
4522
  if (CONTENT_KEYS.some((k) => k !== "t" && k in done)) Object.assign(inv, fullContent(p));
4367
- if ("s" in done) inv.s = p?.s ?? null;
4523
+ if ("s" in done) inv.s = inverseStyle(p?.s, done.s);
4368
4524
  }
4369
4525
  (invCells[r] ??= {})[c] = inv;
4370
4526
  }
@@ -4402,7 +4558,7 @@ function univerSheetsOtPort(o) {
4402
4558
  };
4403
4559
  const collab = cs.onMutationExecutedForCollab((info, options) => {
4404
4560
  if (applying || flagged(options) || !mine(info.params)) return;
4405
- if (!group) group = openGroup(null);
4561
+ if (!group) group = pre.get(info.params)?.lone ?? openGroup(null);
4406
4562
  const g = group;
4407
4563
  if (!g.notShared) {
4408
4564
  const r = capture(info);
@@ -4483,11 +4639,18 @@ function univerSheetsOtPort(o) {
4483
4639
  listeners.add(listener);
4484
4640
  return () => void listeners.delete(listener);
4485
4641
  },
4486
- busy: () => tracker.stack.length > 0 || group !== null,
4642
+ busy: () => tracker.stack.length > 0 || group !== null || holding(),
4643
+ defers(op) {
4644
+ if (holding()) return true;
4645
+ const at = edited();
4646
+ if (!at || !op.some((m) => touchesEditedCell(m, at))) return false;
4647
+ editorHold = true;
4648
+ return true;
4649
+ },
4487
4650
  /** The outermost commands still running here (why the port is busy), for logs. */
4488
4651
  running: () => [...tracker.stack, ...group && tracker.stack.length === 0 ? ["(group)"] : []],
4489
4652
  whenIdle(fn) {
4490
- if (tracker.stack.length === 0 && !group) fn();
4653
+ if (tracker.stack.length === 0 && !group && !holding()) fn();
4491
4654
  else idle.push(fn);
4492
4655
  },
4493
4656
  applyRemote(m) {
@@ -4547,6 +4710,20 @@ function univerSheetsOtPort(o) {
4547
4710
  }
4548
4711
  };
4549
4712
  }
4713
+ function inverseStyle(prev, wrote) {
4714
+ if (!prev || typeof prev !== "object") return null;
4715
+ if (!wrote || typeof wrote !== "object") return prev;
4716
+ const out = { ...prev };
4717
+ for (const k of Object.keys(wrote)) if (!(k in out)) out[k] = null;
4718
+ return out;
4719
+ }
4720
+ function touchesEditedCell(m, at) {
4721
+ const sheet = String(m.params.subUnitId ?? "");
4722
+ if (sheet !== at.sheetId) return false;
4723
+ if (m.id !== VALUES) return true;
4724
+ const row = m.params.cellValue?.[at.row];
4725
+ return !!row && Object.prototype.hasOwnProperty.call(row, at.col);
4726
+ }
4550
4727
  function fullContent(cell) {
4551
4728
  const out = {};
4552
4729
  for (const k of CONTENT_KEYS) out[k] = cell && cell[k] !== void 0 ? cell[k] : null;
@@ -4857,6 +5034,7 @@ export {
4857
5034
  DOCS_COLLAB_PROTO,
4858
5035
  DOCS_TRANSFORM_VERSION,
4859
5036
  DOC_LOCAL_KEYS,
5037
+ REDO_COMMAND,
4860
5038
  RICH_TEXT_EDITING,
4861
5039
  SENDER_VIEW_PARAMS,
4862
5040
  SHEETS_COLLAB_PROTO,
@@ -4864,6 +5042,7 @@ export {
4864
5042
  SHEETS_READABLE_PROTOS,
4865
5043
  SHEET_ROOM_EDITOR_PRESETS,
4866
5044
  SHEET_ROOM_PLUGIN_PACKAGES,
5045
+ UNDO_COMMAND,
4867
5046
  WorkbookCollabSession,
4868
5047
  applyDocsOp,
4869
5048
  asLoadedDocsSnapshot,
@@ -4879,7 +5058,9 @@ export {
4879
5058
  documentOtFactory,
4880
5059
  documentUsesOrderedRoom,
4881
5060
  dropEmptyStyleRetains,
5061
+ editorBridgeCell,
4882
5062
  encodeSheetOp,
5063
+ filterServiceRange,
4883
5064
  invertDocsOp,
4884
5065
  isCellEditorScratch,
4885
5066
  isNoopDocsOp,