ooxml-core 1.22.0 → 1.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +7 -2
  2. package/dist/automation/index.cjs +559 -339
  3. package/dist/automation/index.d.ts +1 -0
  4. package/dist/automation/index.d.ts.map +1 -1
  5. package/dist/automation/index.mjs +558 -340
  6. package/dist/automation/live.d.ts +89 -0
  7. package/dist/automation/live.d.ts.map +1 -0
  8. package/dist/collab/embedding.d.ts +7 -0
  9. package/dist/collab/embedding.d.ts.map +1 -1
  10. package/dist/collab/index.cjs +189 -0
  11. package/dist/collab/index.d.ts +2 -0
  12. package/dist/collab/index.d.ts.map +1 -1
  13. package/dist/collab/index.mjs +186 -1
  14. package/dist/collab/write-back-lifecycle.d.ts +33 -0
  15. package/dist/collab/write-back-lifecycle.d.ts.map +1 -0
  16. package/dist/collab/write-back.d.ts +75 -0
  17. package/dist/collab/write-back.d.ts.map +1 -0
  18. package/dist/docx/ui/customization.d.ts +30 -0
  19. package/dist/docx/ui/customization.d.ts.map +1 -0
  20. package/dist/docx/ui/index.cjs +51 -0
  21. package/dist/docx/ui/index.d.ts +1 -0
  22. package/dist/docx/ui/index.d.ts.map +1 -1
  23. package/dist/docx/ui/index.mjs +46 -1
  24. package/dist/embedding/backstage.d.ts +48 -0
  25. package/dist/embedding/backstage.d.ts.map +1 -0
  26. package/dist/embedding/capabilities.d.ts +60 -0
  27. package/dist/embedding/capabilities.d.ts.map +1 -0
  28. package/dist/embedding/customization.d.ts +32 -0
  29. package/dist/embedding/customization.d.ts.map +1 -0
  30. package/dist/embedding/index.cjs +229 -0
  31. package/dist/embedding/index.d.ts +7 -0
  32. package/dist/embedding/index.d.ts.map +1 -0
  33. package/dist/embedding/index.mjs +204 -0
  34. package/dist/embedding/menu-commands.d.ts +66 -0
  35. package/dist/embedding/menu-commands.d.ts.map +1 -0
  36. package/dist/embedding/regions.d.ts +58 -0
  37. package/dist/embedding/regions.d.ts.map +1 -0
  38. package/dist/embedding/storage.d.ts +111 -0
  39. package/dist/embedding/storage.d.ts.map +1 -0
  40. package/dist/index.cjs +233 -0
  41. package/dist/index.d.ts +1 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.mjs +233 -1
  44. package/dist/visio/collab/baseline.d.ts +36 -0
  45. package/dist/visio/collab/baseline.d.ts.map +1 -0
  46. package/dist/visio/collab/bind.d.ts +20 -2
  47. package/dist/visio/collab/bind.d.ts.map +1 -1
  48. package/dist/visio/collab/compose-lists.d.ts +27 -0
  49. package/dist/visio/collab/compose-lists.d.ts.map +1 -0
  50. package/dist/visio/collab/compose.d.ts +6 -2
  51. package/dist/visio/collab/compose.d.ts.map +1 -1
  52. package/dist/visio/collab/fixups.d.ts +5 -0
  53. package/dist/visio/collab/fixups.d.ts.map +1 -0
  54. package/dist/visio/collab/index.cjs +1603 -361
  55. package/dist/visio/collab/index.d.ts +3 -2
  56. package/dist/visio/collab/index.d.ts.map +1 -1
  57. package/dist/visio/collab/index.mjs +1596 -362
  58. package/dist/visio/collab/keys.d.ts +32 -1
  59. package/dist/visio/collab/keys.d.ts.map +1 -1
  60. package/dist/visio/collab/package.d.ts +22 -1
  61. package/dist/visio/collab/package.d.ts.map +1 -1
  62. package/dist/visio/collab/pieces.d.ts +41 -0
  63. package/dist/visio/collab/pieces.d.ts.map +1 -0
  64. package/dist/visio/collab/read-ids.d.ts +35 -0
  65. package/dist/visio/collab/read-ids.d.ts.map +1 -0
  66. package/dist/visio/collab/read-parts.d.ts +34 -0
  67. package/dist/visio/collab/read-parts.d.ts.map +1 -0
  68. package/dist/visio/collab/read-shapes.d.ts +34 -0
  69. package/dist/visio/collab/read-shapes.d.ts.map +1 -0
  70. package/dist/visio/collab/read-util.d.ts +20 -0
  71. package/dist/visio/collab/read-util.d.ts.map +1 -0
  72. package/dist/visio/collab/read.d.ts +40 -19
  73. package/dist/visio/collab/read.d.ts.map +1 -1
  74. package/dist/visio/collab/schema.d.ts +55 -1
  75. package/dist/visio/collab/schema.d.ts.map +1 -1
  76. package/dist/visio/collab/snapshot-contents.d.ts +9 -0
  77. package/dist/visio/collab/snapshot-contents.d.ts.map +1 -0
  78. package/dist/visio/collab/snapshot-io.d.ts +26 -0
  79. package/dist/visio/collab/snapshot-io.d.ts.map +1 -0
  80. package/dist/visio/collab/snapshot-parts.d.ts +14 -0
  81. package/dist/visio/collab/snapshot-parts.d.ts.map +1 -0
  82. package/dist/visio/collab/snapshot.d.ts +31 -24
  83. package/dist/visio/collab/snapshot.d.ts.map +1 -1
  84. package/dist/visio/collab/write-parts.d.ts +8 -0
  85. package/dist/visio/collab/write-parts.d.ts.map +1 -0
  86. package/dist/visio/collab/write-shapes.d.ts +30 -0
  87. package/dist/visio/collab/write-shapes.d.ts.map +1 -0
  88. package/dist/visio/collab/write.d.ts +4 -16
  89. package/dist/visio/collab/write.d.ts.map +1 -1
  90. package/dist/visio/collab/zip-store.d.ts +4 -0
  91. package/dist/visio/collab/zip-store.d.ts.map +1 -0
  92. package/dist/visio/document-level.d.ts +57 -0
  93. package/dist/visio/document-level.d.ts.map +1 -0
  94. package/dist/visio/index.cjs +485 -333
  95. package/dist/visio/index.d.ts +2 -0
  96. package/dist/visio/index.d.ts.map +1 -1
  97. package/dist/visio/index.mjs +484 -334
  98. package/dist/visio/layers.d.ts +3 -0
  99. package/dist/visio/layers.d.ts.map +1 -1
  100. package/dist/visio/package.d.ts +9 -0
  101. package/dist/visio/package.d.ts.map +1 -1
  102. package/dist/visio/parse-incremental.d.ts +16 -0
  103. package/dist/visio/parse-incremental.d.ts.map +1 -0
  104. package/dist/visio/parser.d.ts +14 -0
  105. package/dist/visio/parser.d.ts.map +1 -1
  106. package/dist/visio/shape-metadata.d.ts +3 -0
  107. package/dist/visio/shape-metadata.d.ts.map +1 -1
  108. package/dist/visio/ui/collab-options.d.ts +10 -5
  109. package/dist/visio/ui/collab-options.d.ts.map +1 -1
  110. package/dist/visio/ui/contract.d.ts +27 -2
  111. package/dist/visio/ui/contract.d.ts.map +1 -1
  112. package/dist/visio/ui/customization.d.ts +46 -0
  113. package/dist/visio/ui/customization.d.ts.map +1 -0
  114. package/dist/visio/ui/index.cjs +460 -320
  115. package/dist/visio/ui/index.d.ts +1 -0
  116. package/dist/visio/ui/index.d.ts.map +1 -1
  117. package/dist/visio/ui/index.mjs +458 -321
  118. package/dist/xlsx/ui/commands.d.ts +2 -0
  119. package/dist/xlsx/ui/commands.d.ts.map +1 -1
  120. package/dist/xlsx/ui/customization.d.ts +49 -0
  121. package/dist/xlsx/ui/customization.d.ts.map +1 -0
  122. package/dist/xlsx/ui/index.cjs +39 -1
  123. package/dist/xlsx/ui/index.d.ts +1 -0
  124. package/dist/xlsx/ui/index.d.ts.map +1 -1
  125. package/dist/xlsx/ui/index.mjs +37 -2
  126. package/package.json +6 -1
@@ -0,0 +1,89 @@
1
+ import type { AutomationFormat, AutomationTool } from './tools/types.js';
2
+ /**
3
+ * Runs the headless document tools against editors that are open on screen. A host's own
4
+ * assistant (or the suite's) registers each mounted editor under an id it chooses, and every call
5
+ * names the document it acts on: there is no "current document", so a chat that spans several
6
+ * tabs can never edit the wrong one. The tools are the same definitions the MCP servers use;
7
+ * this only adds the snapshot and load-back around them.
8
+ */
9
+ /** What a mounted editor must offer. The editor elements fit it through `liveEditorFromElement`. */
10
+ export interface LiveEditor {
11
+ readonly format: AutomationFormat;
12
+ /** The open document as a file, including unsaved edits. */
13
+ save(): Promise<Uint8Array> | Uint8Array;
14
+ /** Replaces the open document with `bytes`. */
15
+ load(bytes: Uint8Array): Promise<void> | void;
16
+ /** True while the editor refuses edits (a read-only role, a locked document). */
17
+ readonly readOnly?: boolean;
18
+ }
19
+ /** A tool call: the target document, then the tool's own parameters. */
20
+ export interface LiveToolCall {
21
+ /** The id the editor was registered under. Required: there is no default document. */
22
+ target: string;
23
+ params?: unknown;
24
+ }
25
+ export interface LiveToolResult {
26
+ target: string;
27
+ tool: string;
28
+ /** What the tool returned: a read's view, an edit's report. */
29
+ result: unknown;
30
+ /** True when an edit changed the open document. */
31
+ changed: boolean;
32
+ }
33
+ /** What an edit is about to do, for a host that wants to confirm it first. */
34
+ export interface LiveEditProposal {
35
+ target: string;
36
+ tool: string;
37
+ params: unknown;
38
+ /** The tool's report for the edit (warnings, results). */
39
+ result: unknown;
40
+ /** The file before and after, for a diff. */
41
+ before: Uint8Array;
42
+ after: Uint8Array;
43
+ }
44
+ export interface LiveToolHostOptions {
45
+ /**
46
+ * Called with each edit before it reaches the editor. Return false to discard it. Leave it out
47
+ * to apply edits straight away.
48
+ */
49
+ review?(proposal: LiveEditProposal): boolean | Promise<boolean>;
50
+ }
51
+ export interface LiveToolDescriptor {
52
+ name: string;
53
+ description: string;
54
+ kind: 'read' | 'edit';
55
+ format: AutomationFormat;
56
+ /** JSON Schema of the parameters, with the required `target` added. */
57
+ inputSchema: Record<string, unknown>;
58
+ }
59
+ export interface LiveToolHost {
60
+ /** Registers an editor under `id`. Returns a function that removes it. */
61
+ register(id: string, editor: LiveEditor): () => void;
62
+ /** The registered documents, so an assistant can offer them to the model. */
63
+ targets(): {
64
+ id: string;
65
+ format: AutomationFormat;
66
+ readOnly: boolean;
67
+ }[];
68
+ /** The read and edit tools that apply to the registered documents, as function-calling specs. */
69
+ describe(): LiveToolDescriptor[];
70
+ call(name: string, call: LiveToolCall): Promise<LiveToolResult>;
71
+ }
72
+ /** `tools` is the catalogue to serve: `automationTools.docx`, `pptxTools` and so on, in any mix. */
73
+ export declare function createLiveToolHost(tools: readonly AutomationTool[], options?: LiveToolHostOptions): LiveToolHost;
74
+ /** The members of an editor element that `liveEditorFromElement` uses. */
75
+ export interface LiveEditorElement {
76
+ saveBytes?(): Promise<Uint8Array> | Uint8Array;
77
+ exportVsdx?(): Promise<{
78
+ bytes: Uint8Array;
79
+ }>;
80
+ load(bytes: Uint8Array, name?: string): Promise<unknown> | unknown;
81
+ commitEdit?(): boolean;
82
+ readOnly?: boolean;
83
+ }
84
+ /**
85
+ * Adapts a mounted editor element (`<docx-editor>`, `<xlsx-editor>`, `<pptx-editor>`,
86
+ * `<visio-editor>`) so it can be registered with a host. `name` is the file name the editor shows.
87
+ */
88
+ export declare function liveEditorFromElement(format: AutomationFormat, element: LiveEditorElement, name?: string): LiveEditor;
89
+ //# sourceMappingURL=live.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../../automation/live.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ import type { CollaborationRole } from './identity.js';
3
3
  import type { ConnectionStatus, ProviderFactory } from './provider.js';
4
4
  import { type CollabSession } from './session.js';
5
5
  import { type WebrtcOptions } from './webrtc-provider.js';
6
+ import type { CollaborationWriteBackState } from './write-back.js';
6
7
  /** Who this window is in the room. */
7
8
  export interface CollaborationUser {
8
9
  /** Display name; each editor falls back to its own author name. */
@@ -58,6 +59,12 @@ export interface CollaborationState {
58
59
  /** The first exchange with the room finished. */
59
60
  synced: boolean;
60
61
  people: Collaborator[];
62
+ /**
63
+ * The owner's write-back (`onWriteBack`), present only in the window that writes back. `saved`
64
+ * means the host's callback returned (or its promise resolved): the host's acknowledgement and
65
+ * nothing more.
66
+ */
67
+ writeBack?: CollaborationWriteBackState;
61
68
  }
62
69
  /** The event every editor element dispatches, with a {@link CollaborationState} detail. */
63
70
  export declare const COLLABORATION_CHANGE_EVENT = "collaboration-change";
@@ -1 +1 @@
1
- {"version":3,"file":"embedding.d.ts","sourceRoot":"","sources":["../../collab/embedding.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"embedding.d.ts","sourceRoot":"","sources":["../../collab/embedding.ts"],"names":[],"mappings":"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"}
@@ -1523,6 +1523,191 @@ function freezeDeep(value) {
1523
1523
  return value;
1524
1524
  }
1525
1525
 
1526
+ // collab/write-back.ts
1527
+ var DEFAULT_WRITE_BACK_DEBOUNCE_MS = 5e3;
1528
+ var DEFAULT_RETRY_BASE_MS = 1e3;
1529
+ var DEFAULT_RETRY_MAX_MS = 3e4;
1530
+ var globalTimers = {
1531
+ setTimeout: (callback, ms) => globalThis.setTimeout(callback, ms),
1532
+ clearTimeout: (handle) => globalThis.clearTimeout(handle)
1533
+ };
1534
+ var isThenable = (value) => typeof value === "object" && value !== null && typeof value.then === "function";
1535
+ function writeBackStateOf(state) {
1536
+ const out = { status: state.status };
1537
+ if (state.lastSavedAt !== void 0) out.lastSavedAt = state.lastSavedAt;
1538
+ if (state.status === "failed" && state.lastError !== void 0) {
1539
+ out.error = state.lastError instanceof Error ? state.lastError.message : String(state.lastError);
1540
+ }
1541
+ return out;
1542
+ }
1543
+ function createWriteBackScheduler(options) {
1544
+ const timers = options.timers ?? globalTimers;
1545
+ const now = options.now ?? Date.now;
1546
+ const configured = options.debounceMs;
1547
+ const debounceMs = configured !== void 0 && Number.isFinite(configured) && configured >= 0 ? configured : DEFAULT_WRITE_BACK_DEBOUNCE_MS;
1548
+ const attempts = Math.max(1, Math.floor(options.retry?.attempts ?? 1) || 1);
1549
+ const baseDelay = Math.max(0, options.retry?.baseDelayMs ?? DEFAULT_RETRY_BASE_MS);
1550
+ const maxDelay = Math.max(baseDelay, options.retry?.maxDelayMs ?? DEFAULT_RETRY_MAX_MS);
1551
+ let state = { status: "idle" };
1552
+ let generation = 0;
1553
+ let disposed = false;
1554
+ let dirty = false;
1555
+ let timer = null;
1556
+ let running = null;
1557
+ let wake = null;
1558
+ let ended = false;
1559
+ let rushing = 0;
1560
+ const patch = (status, extra = {}) => {
1561
+ const next = { status };
1562
+ const saved = extra.lastSavedAt ?? state.lastSavedAt;
1563
+ if (saved !== void 0) next.lastSavedAt = saved;
1564
+ if (extra.lastError !== void 0) next.lastError = extra.lastError;
1565
+ state = next;
1566
+ options.onStatus?.(state);
1567
+ };
1568
+ const clearTimer = () => {
1569
+ if (timer !== null) timers.clearTimeout(timer);
1570
+ timer = null;
1571
+ };
1572
+ const arm = () => {
1573
+ clearTimer();
1574
+ timer = timers.setTimeout(() => {
1575
+ timer = null;
1576
+ void start();
1577
+ }, debounceMs);
1578
+ if (state.status !== "pending") patch("pending");
1579
+ };
1580
+ const sleep = (ms) => new Promise((resolve) => {
1581
+ if (rushing > 0) return resolve();
1582
+ const handle = timers.setTimeout(done, ms);
1583
+ function done() {
1584
+ timers.clearTimeout(handle);
1585
+ wake = null;
1586
+ resolve();
1587
+ }
1588
+ wake = done;
1589
+ });
1590
+ const settledStatus = () => state.lastSavedAt === void 0 ? "idle" : "saved";
1591
+ async function run() {
1592
+ const gen = generation;
1593
+ const isCurrent = () => gen === generation;
1594
+ patch("saving");
1595
+ try {
1596
+ for (let attempt = 1; ; attempt++) {
1597
+ dirty = false;
1598
+ try {
1599
+ let bytes = options.serialize({ isCurrent });
1600
+ if (isThenable(bytes)) bytes = await bytes;
1601
+ if (!isCurrent()) return;
1602
+ if (bytes === null || bytes === void 0) {
1603
+ if (dirty) arm();
1604
+ else patch(settledStatus());
1605
+ return;
1606
+ }
1607
+ const acknowledged = options.write(bytes);
1608
+ if (isThenable(acknowledged)) await acknowledged;
1609
+ if (!isCurrent()) return;
1610
+ const lastSavedAt = now();
1611
+ if (dirty) {
1612
+ patch("pending", { lastSavedAt });
1613
+ arm();
1614
+ } else {
1615
+ patch("saved", { lastSavedAt });
1616
+ }
1617
+ return;
1618
+ } catch (error) {
1619
+ if (!isCurrent()) return;
1620
+ if (attempt >= attempts) {
1621
+ dirty = true;
1622
+ patch("failed", { lastError: error });
1623
+ return;
1624
+ }
1625
+ await sleep(Math.min(maxDelay, baseDelay * 2 ** (attempt - 1)));
1626
+ if (!isCurrent()) return;
1627
+ }
1628
+ }
1629
+ } finally {
1630
+ ended = true;
1631
+ running = null;
1632
+ if (dirty && timer === null && !disposed && state.status !== "failed") arm();
1633
+ }
1634
+ }
1635
+ function start() {
1636
+ if (running) return running;
1637
+ ended = false;
1638
+ const promise = run();
1639
+ if (!ended) running = promise;
1640
+ return promise;
1641
+ }
1642
+ function cancel() {
1643
+ generation++;
1644
+ clearTimer();
1645
+ dirty = false;
1646
+ const waiting = wake;
1647
+ wake = null;
1648
+ waiting?.();
1649
+ if (state.status === "pending" || state.status === "saving") patch(settledStatus());
1650
+ }
1651
+ return {
1652
+ schedule() {
1653
+ if (disposed) return;
1654
+ dirty = true;
1655
+ if (running) return;
1656
+ arm();
1657
+ },
1658
+ async flush() {
1659
+ if (disposed) return;
1660
+ clearTimer();
1661
+ rushing++;
1662
+ try {
1663
+ wake?.();
1664
+ for (; ; ) {
1665
+ if (running) await running;
1666
+ else if (dirty) await start();
1667
+ else return;
1668
+ if (disposed) return;
1669
+ if (state.status === "failed") throw state.lastError;
1670
+ clearTimer();
1671
+ }
1672
+ } finally {
1673
+ rushing--;
1674
+ }
1675
+ },
1676
+ cancel,
1677
+ dispose() {
1678
+ if (disposed) return;
1679
+ cancel();
1680
+ disposed = true;
1681
+ },
1682
+ get state() {
1683
+ return state;
1684
+ },
1685
+ get dirty() {
1686
+ return dirty;
1687
+ }
1688
+ };
1689
+ }
1690
+
1691
+ // collab/write-back-lifecycle.ts
1692
+ function flushWriteBackOnPageClose(scheduler, options = {}) {
1693
+ const globals = globalThis;
1694
+ const win = options.window === void 0 ? typeof globals.addEventListener === "function" ? globalThis : null : options.window;
1695
+ const doc = options.document === void 0 ? globals.document ?? null : options.document;
1696
+ const flush = () => {
1697
+ if (!scheduler.dirty) return;
1698
+ scheduler.flush().catch((error) => options.onError?.(error));
1699
+ };
1700
+ const hidden = () => {
1701
+ if (doc?.visibilityState === "hidden") flush();
1702
+ };
1703
+ win?.addEventListener("pagehide", flush);
1704
+ doc?.addEventListener("visibilitychange", hidden);
1705
+ return () => {
1706
+ win?.removeEventListener("pagehide", flush);
1707
+ doc?.removeEventListener("visibilitychange", hidden);
1708
+ };
1709
+ }
1710
+
1526
1711
  exports.BROADCAST_THROTTLE_MS = BROADCAST_THROTTLE_MS;
1527
1712
  exports.BoundedMap = BoundedMap;
1528
1713
  exports.COLLABORATION_CHANGE_EVENT = COLLABORATION_CHANGE_EVENT;
@@ -1533,6 +1718,7 @@ exports.CONNECTION_TIMEOUT_MS = CONNECTION_TIMEOUT_MS;
1533
1718
  exports.CURSOR_PALETTE = CURSOR_PALETTE;
1534
1719
  exports.DEFAULT_COLOR = DEFAULT_COLOR;
1535
1720
  exports.DEFAULT_MAX_PACKAGE_BYTES = DEFAULT_MAX_PACKAGE_BYTES;
1721
+ exports.DEFAULT_WRITE_BACK_DEBOUNCE_MS = DEFAULT_WRITE_BACK_DEBOUNCE_MS;
1536
1722
  exports.DEPARTURE_CHANNEL = DEPARTURE_CHANNEL;
1537
1723
  exports.Emitter = Emitter;
1538
1724
  exports.INITIAL_SYNC_GRACE_MS = INITIAL_SYNC_GRACE_MS;
@@ -1575,11 +1761,13 @@ exports.createPresencePublisher = createPresencePublisher;
1575
1761
  exports.createSyncGate = createSyncGate;
1576
1762
  exports.createTransportProvider = createTransportProvider;
1577
1763
  exports.createWebSocketTransport = createWebSocketTransport;
1764
+ exports.createWriteBackScheduler = createWriteBackScheduler;
1578
1765
  exports.deriveCanvasPresence = deriveCanvasPresence;
1579
1766
  exports.derivePresence = derivePresence;
1580
1767
  exports.encodeDiff = encodeDiff;
1581
1768
  exports.encodeSnapshot = encodeSnapshot;
1582
1769
  exports.encodeStateVector = encodeStateVector2;
1770
+ exports.flushWriteBackOnPageClose = flushWriteBackOnPageClose;
1583
1771
  exports.formatCursorLabel = formatCursorLabel;
1584
1772
  exports.freezeDeep = freezeDeep;
1585
1773
  exports.fromBase64 = fromBase64;
@@ -1617,3 +1805,4 @@ exports.validateDisplayName = validateDisplayName;
1617
1805
  exports.validateRoomId = validateRoomId;
1618
1806
  exports.validateUpdate = validateUpdate;
1619
1807
  exports.webrtcProvider = webrtcProvider;
1808
+ exports.writeBackStateOf = writeBackStateOf;
@@ -19,4 +19,6 @@ export * from './transport-provider.js';
19
19
  export * from './validation.js';
20
20
  export * from './webrtc-provider.js';
21
21
  export * from './websocket-transport.js';
22
+ export * from './write-back.js';
23
+ export * from './write-back-lifecycle.js';
22
24
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../collab/index.ts"],"names":[],"mappings":"AAIA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,uBAAuB,CAAC;AACtC,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,sBAAsB,CAAC;AACrC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../collab/index.ts"],"names":[],"mappings":"AAIA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,uBAAuB,CAAC;AACtC,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,sBAAsB,CAAC;AACrC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,wBAAwB,CAAC"}
@@ -1499,4 +1499,189 @@ function freezeDeep(value) {
1499
1499
  return value;
1500
1500
  }
1501
1501
 
1502
- export { BROADCAST_THROTTLE_MS, BoundedMap, COLLABORATION_CHANGE_EVENT, COLLABORATION_OFF_STATE, COLLABORATION_ROLES, COLLAB_LEAVE_MESSAGE, CONNECTION_TIMEOUT_MS, CURSOR_PALETTE, DEFAULT_COLOR, DEFAULT_MAX_PACKAGE_BYTES, DEPARTURE_CHANNEL, Emitter, INITIAL_SYNC_GRACE_MS, INVALID_ROOM_MESSAGE, IdempotencyCache, LEGACY_PPTX_DEPARTURE_CHANNEL, LEGACY_PPTX_LEAVE_MESSAGE, LOCAL_ORIGIN, MAX_LABEL_CHARS, MAX_UPDATE_BYTES, MESSAGE_AWARENESS, MESSAGE_QUERY_AWARENESS, MESSAGE_SYNC, NO_BROADCAST_MESSAGE, PRESENCE_FIELD, PRESENCE_HEARTBEAT_MS, STALE_PRESENCE_MS, SequenceTracker, adaptYjsProvider, applyUpdateSafe, asSelectionIds, assignUserColor, bindDocument, borrowAwareness, buildRoster, canBroadcast, canWrite, clampCoordinate, classifyVersion, clearLocalAwareness, collaborationStateOf, createAssetSync, createBroadcastTransport, createClientId, createCollabSession, createDepartureChannel, createIdGenerator, createMemoryHub, createPresencePublisher, createSyncGate, createTransportProvider, createWebSocketTransport, deriveCanvasPresence, derivePresence, encodeDiff, encodeSnapshot, encodeStateVector2 as encodeStateVector, formatCursorLabel, freezeDeep, fromBase64, getUserInitials, isMixedContentBlocked, isNonNegativeSafeInteger, isPresenceFresh, isValidId, isValidRoomId, mergeUpdates2 as mergeUpdates, observeExternalSession, onCollaborationStateChange, openCollaborationSession, packageAdapter, presenceToCursors, randomToken, registerTeardown, removeAwarenessStatesLocally, restoreSnapshot, roomUrl, sanitizeAvatarUrl, sanitizeCanvasPayload, sanitizeColor, sanitizeIdentity, sanitizeIndex, sanitizeRole, sanitizeUserName, shouldAutoFollowBroadcaster, shouldRoomReplaceLoad, stripHtmlTags, toBase64, toExternalSession, transportProvider, validateDisplayName, validateRoomId, validateUpdate, webrtcProvider };
1502
+ // collab/write-back.ts
1503
+ var DEFAULT_WRITE_BACK_DEBOUNCE_MS = 5e3;
1504
+ var DEFAULT_RETRY_BASE_MS = 1e3;
1505
+ var DEFAULT_RETRY_MAX_MS = 3e4;
1506
+ var globalTimers = {
1507
+ setTimeout: (callback, ms) => globalThis.setTimeout(callback, ms),
1508
+ clearTimeout: (handle) => globalThis.clearTimeout(handle)
1509
+ };
1510
+ var isThenable = (value) => typeof value === "object" && value !== null && typeof value.then === "function";
1511
+ function writeBackStateOf(state) {
1512
+ const out = { status: state.status };
1513
+ if (state.lastSavedAt !== void 0) out.lastSavedAt = state.lastSavedAt;
1514
+ if (state.status === "failed" && state.lastError !== void 0) {
1515
+ out.error = state.lastError instanceof Error ? state.lastError.message : String(state.lastError);
1516
+ }
1517
+ return out;
1518
+ }
1519
+ function createWriteBackScheduler(options) {
1520
+ const timers = options.timers ?? globalTimers;
1521
+ const now = options.now ?? Date.now;
1522
+ const configured = options.debounceMs;
1523
+ const debounceMs = configured !== void 0 && Number.isFinite(configured) && configured >= 0 ? configured : DEFAULT_WRITE_BACK_DEBOUNCE_MS;
1524
+ const attempts = Math.max(1, Math.floor(options.retry?.attempts ?? 1) || 1);
1525
+ const baseDelay = Math.max(0, options.retry?.baseDelayMs ?? DEFAULT_RETRY_BASE_MS);
1526
+ const maxDelay = Math.max(baseDelay, options.retry?.maxDelayMs ?? DEFAULT_RETRY_MAX_MS);
1527
+ let state = { status: "idle" };
1528
+ let generation = 0;
1529
+ let disposed = false;
1530
+ let dirty = false;
1531
+ let timer = null;
1532
+ let running = null;
1533
+ let wake = null;
1534
+ let ended = false;
1535
+ let rushing = 0;
1536
+ const patch = (status, extra = {}) => {
1537
+ const next = { status };
1538
+ const saved = extra.lastSavedAt ?? state.lastSavedAt;
1539
+ if (saved !== void 0) next.lastSavedAt = saved;
1540
+ if (extra.lastError !== void 0) next.lastError = extra.lastError;
1541
+ state = next;
1542
+ options.onStatus?.(state);
1543
+ };
1544
+ const clearTimer = () => {
1545
+ if (timer !== null) timers.clearTimeout(timer);
1546
+ timer = null;
1547
+ };
1548
+ const arm = () => {
1549
+ clearTimer();
1550
+ timer = timers.setTimeout(() => {
1551
+ timer = null;
1552
+ void start();
1553
+ }, debounceMs);
1554
+ if (state.status !== "pending") patch("pending");
1555
+ };
1556
+ const sleep = (ms) => new Promise((resolve) => {
1557
+ if (rushing > 0) return resolve();
1558
+ const handle = timers.setTimeout(done, ms);
1559
+ function done() {
1560
+ timers.clearTimeout(handle);
1561
+ wake = null;
1562
+ resolve();
1563
+ }
1564
+ wake = done;
1565
+ });
1566
+ const settledStatus = () => state.lastSavedAt === void 0 ? "idle" : "saved";
1567
+ async function run() {
1568
+ const gen = generation;
1569
+ const isCurrent = () => gen === generation;
1570
+ patch("saving");
1571
+ try {
1572
+ for (let attempt = 1; ; attempt++) {
1573
+ dirty = false;
1574
+ try {
1575
+ let bytes = options.serialize({ isCurrent });
1576
+ if (isThenable(bytes)) bytes = await bytes;
1577
+ if (!isCurrent()) return;
1578
+ if (bytes === null || bytes === void 0) {
1579
+ if (dirty) arm();
1580
+ else patch(settledStatus());
1581
+ return;
1582
+ }
1583
+ const acknowledged = options.write(bytes);
1584
+ if (isThenable(acknowledged)) await acknowledged;
1585
+ if (!isCurrent()) return;
1586
+ const lastSavedAt = now();
1587
+ if (dirty) {
1588
+ patch("pending", { lastSavedAt });
1589
+ arm();
1590
+ } else {
1591
+ patch("saved", { lastSavedAt });
1592
+ }
1593
+ return;
1594
+ } catch (error) {
1595
+ if (!isCurrent()) return;
1596
+ if (attempt >= attempts) {
1597
+ dirty = true;
1598
+ patch("failed", { lastError: error });
1599
+ return;
1600
+ }
1601
+ await sleep(Math.min(maxDelay, baseDelay * 2 ** (attempt - 1)));
1602
+ if (!isCurrent()) return;
1603
+ }
1604
+ }
1605
+ } finally {
1606
+ ended = true;
1607
+ running = null;
1608
+ if (dirty && timer === null && !disposed && state.status !== "failed") arm();
1609
+ }
1610
+ }
1611
+ function start() {
1612
+ if (running) return running;
1613
+ ended = false;
1614
+ const promise = run();
1615
+ if (!ended) running = promise;
1616
+ return promise;
1617
+ }
1618
+ function cancel() {
1619
+ generation++;
1620
+ clearTimer();
1621
+ dirty = false;
1622
+ const waiting = wake;
1623
+ wake = null;
1624
+ waiting?.();
1625
+ if (state.status === "pending" || state.status === "saving") patch(settledStatus());
1626
+ }
1627
+ return {
1628
+ schedule() {
1629
+ if (disposed) return;
1630
+ dirty = true;
1631
+ if (running) return;
1632
+ arm();
1633
+ },
1634
+ async flush() {
1635
+ if (disposed) return;
1636
+ clearTimer();
1637
+ rushing++;
1638
+ try {
1639
+ wake?.();
1640
+ for (; ; ) {
1641
+ if (running) await running;
1642
+ else if (dirty) await start();
1643
+ else return;
1644
+ if (disposed) return;
1645
+ if (state.status === "failed") throw state.lastError;
1646
+ clearTimer();
1647
+ }
1648
+ } finally {
1649
+ rushing--;
1650
+ }
1651
+ },
1652
+ cancel,
1653
+ dispose() {
1654
+ if (disposed) return;
1655
+ cancel();
1656
+ disposed = true;
1657
+ },
1658
+ get state() {
1659
+ return state;
1660
+ },
1661
+ get dirty() {
1662
+ return dirty;
1663
+ }
1664
+ };
1665
+ }
1666
+
1667
+ // collab/write-back-lifecycle.ts
1668
+ function flushWriteBackOnPageClose(scheduler, options = {}) {
1669
+ const globals = globalThis;
1670
+ const win = options.window === void 0 ? typeof globals.addEventListener === "function" ? globalThis : null : options.window;
1671
+ const doc = options.document === void 0 ? globals.document ?? null : options.document;
1672
+ const flush = () => {
1673
+ if (!scheduler.dirty) return;
1674
+ scheduler.flush().catch((error) => options.onError?.(error));
1675
+ };
1676
+ const hidden = () => {
1677
+ if (doc?.visibilityState === "hidden") flush();
1678
+ };
1679
+ win?.addEventListener("pagehide", flush);
1680
+ doc?.addEventListener("visibilitychange", hidden);
1681
+ return () => {
1682
+ win?.removeEventListener("pagehide", flush);
1683
+ doc?.removeEventListener("visibilitychange", hidden);
1684
+ };
1685
+ }
1686
+
1687
+ export { BROADCAST_THROTTLE_MS, BoundedMap, COLLABORATION_CHANGE_EVENT, COLLABORATION_OFF_STATE, COLLABORATION_ROLES, COLLAB_LEAVE_MESSAGE, CONNECTION_TIMEOUT_MS, CURSOR_PALETTE, DEFAULT_COLOR, DEFAULT_MAX_PACKAGE_BYTES, DEFAULT_WRITE_BACK_DEBOUNCE_MS, DEPARTURE_CHANNEL, Emitter, INITIAL_SYNC_GRACE_MS, INVALID_ROOM_MESSAGE, IdempotencyCache, LEGACY_PPTX_DEPARTURE_CHANNEL, LEGACY_PPTX_LEAVE_MESSAGE, LOCAL_ORIGIN, MAX_LABEL_CHARS, MAX_UPDATE_BYTES, MESSAGE_AWARENESS, MESSAGE_QUERY_AWARENESS, MESSAGE_SYNC, NO_BROADCAST_MESSAGE, PRESENCE_FIELD, PRESENCE_HEARTBEAT_MS, STALE_PRESENCE_MS, SequenceTracker, adaptYjsProvider, applyUpdateSafe, asSelectionIds, assignUserColor, bindDocument, borrowAwareness, buildRoster, canBroadcast, canWrite, clampCoordinate, classifyVersion, clearLocalAwareness, collaborationStateOf, createAssetSync, createBroadcastTransport, createClientId, createCollabSession, createDepartureChannel, createIdGenerator, createMemoryHub, createPresencePublisher, createSyncGate, createTransportProvider, createWebSocketTransport, createWriteBackScheduler, deriveCanvasPresence, derivePresence, encodeDiff, encodeSnapshot, encodeStateVector2 as encodeStateVector, flushWriteBackOnPageClose, formatCursorLabel, freezeDeep, fromBase64, getUserInitials, isMixedContentBlocked, isNonNegativeSafeInteger, isPresenceFresh, isValidId, isValidRoomId, mergeUpdates2 as mergeUpdates, observeExternalSession, onCollaborationStateChange, openCollaborationSession, packageAdapter, presenceToCursors, randomToken, registerTeardown, removeAwarenessStatesLocally, restoreSnapshot, roomUrl, sanitizeAvatarUrl, sanitizeCanvasPayload, sanitizeColor, sanitizeIdentity, sanitizeIndex, sanitizeRole, sanitizeUserName, shouldAutoFollowBroadcaster, shouldRoomReplaceLoad, stripHtmlTags, toBase64, toExternalSession, transportProvider, validateDisplayName, validateRoomId, validateUpdate, webrtcProvider, writeBackStateOf };
@@ -0,0 +1,33 @@
1
+ import type { WriteBackScheduler } from './write-back.js';
2
+ /** The part of `window` used: `pagehide` is listened on it. */
3
+ export interface PageHideTarget {
4
+ addEventListener(type: 'pagehide', listener: () => void): void;
5
+ removeEventListener(type: 'pagehide', listener: () => void): void;
6
+ }
7
+ /** The part of `document` used: `visibilitychange` is listened on it. */
8
+ export interface VisibilityTarget {
9
+ readonly visibilityState?: string;
10
+ addEventListener(type: 'visibilitychange', listener: () => void): void;
11
+ removeEventListener(type: 'visibilitychange', listener: () => void): void;
12
+ }
13
+ export interface FlushOnPageCloseOptions {
14
+ /** Default `globalThis` when it can listen (a browser window), otherwise no `pagehide` hook. */
15
+ window?: PageHideTarget | null;
16
+ /** Default `globalThis.document` when present. */
17
+ document?: VisibilityTarget | null;
18
+ /** Receives a flush that failed (it never throws). Default ignores it. */
19
+ onError?: (error: unknown) => void;
20
+ }
21
+ /**
22
+ * Flushes `scheduler` on `pagehide` and when the page turns hidden, and returns the function that
23
+ * removes the listeners. Only unsaved work is written.
24
+ *
25
+ * Browsers do not wait for asynchronous work when a page unloads: the flush starts the write, but
26
+ * a write that needs a network round trip can still be lost on close. A host that must survive a
27
+ * close should send the bytes with `navigator.sendBeacon(url, bytes)` or
28
+ * `fetch(url, { method: 'PUT', body: bytes, keepalive: true })` (the browser caps keepalive bodies
29
+ * at about 64 KiB, so a large document may still not make it), which the browser completes after
30
+ * the page is gone.
31
+ */
32
+ export declare function flushWriteBackOnPageClose(scheduler: Pick<WriteBackScheduler, 'flush' | 'dirty'>, options?: FlushOnPageCloseOptions): () => void;
33
+ //# sourceMappingURL=write-back-lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-back-lifecycle.d.ts","sourceRoot":"","sources":["../../collab/write-back-lifecycle.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEvD,+DAA+D;AAC/D,MAAM,WAAW,cAAc;IAC9B,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC/D,mBAAmB,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;CAClE;AAED,yEAAyE;AACzE,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,gBAAgB,CAAC,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IACvE,mBAAmB,CAAC,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;CAC1E;AAED,MAAM,WAAW,uBAAuB;IACvC,gGAAgG;IAChG,MAAM,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/B,kDAAkD;IAClD,QAAQ,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACnC,0EAA0E;IAC1E,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACnC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CACxC,SAAS,EAAE,IAAI,CAAC,kBAAkB,EAAE,OAAO,GAAG,OAAO,CAAC,EACtD,OAAO,GAAE,uBAA4B,GACnC,MAAM,IAAI,CAyBZ"}
@@ -0,0 +1,75 @@
1
+ /** Where a write-back stands: `idle` until the first change, then `pending`, `saving`, `saved` or `failed`. */
2
+ export type WriteBackStatus = 'idle' | 'pending' | 'saving' | 'saved' | 'failed';
3
+ /** What {@link WriteBackScheduler.state} and `onStatus` report. */
4
+ export interface WriteBackState {
5
+ status: WriteBackStatus;
6
+ /** `now()` when the host last acknowledged a write. */
7
+ lastSavedAt?: number;
8
+ /** The error of the last failed write, once its retries are spent. */
9
+ lastError?: unknown;
10
+ }
11
+ /** The write-back status as an editor reports it in its collaboration state (JSON friendly). */
12
+ export interface CollaborationWriteBackState {
13
+ status: WriteBackStatus;
14
+ lastSavedAt?: number;
15
+ /** The message of the last failure, while `status` is `failed`. */
16
+ error?: string;
17
+ }
18
+ export interface WriteBackRetry {
19
+ /** Total tries per write, the first included. 1 (the default) never retries. */
20
+ attempts: number;
21
+ /** Wait before the first retry; doubles on each further retry. Default 1000. */
22
+ baseDelayMs?: number;
23
+ /** Upper bound of the wait. Default 30000. */
24
+ maxDelayMs?: number;
25
+ }
26
+ export interface WriteBackTimers {
27
+ setTimeout(callback: () => void, ms: number): unknown;
28
+ clearTimeout(handle: unknown): void;
29
+ }
30
+ export interface WriteBackOptions {
31
+ /**
32
+ * The bytes to store now. Resolve `null` when there is nothing to save yet (the change is not
33
+ * lost: call `schedule()` again when it is). `isCurrent` turns false once the scheduler was
34
+ * cancelled or disposed, so a long serialisation can stop early.
35
+ */
36
+ serialize: (context: {
37
+ isCurrent: () => boolean;
38
+ }) => Uint8Array | null | Promise<Uint8Array | null>;
39
+ /**
40
+ * Stores the bytes. A returned promise is the acknowledgement: resolving means stored, rejecting
41
+ * counts as a failed try. A plain return (void) is treated as acknowledged at once.
42
+ */
43
+ write: (bytes: Uint8Array) => void | Promise<void>;
44
+ /** Quiet time after the last change. Default 5000; invalid values fall back to it. */
45
+ debounceMs?: number;
46
+ retry?: WriteBackRetry;
47
+ onStatus?: (state: WriteBackState) => void;
48
+ /** Clock for `lastSavedAt`. Default `Date.now`. */
49
+ now?: () => number;
50
+ /** Timers, injectable for tests. Default the global ones, looked up at call time. */
51
+ timers?: WriteBackTimers;
52
+ }
53
+ export interface WriteBackScheduler {
54
+ /** Notes a change: (re)starts the quiet time, or queues one follow-up write during a write. */
55
+ schedule(): void;
56
+ /**
57
+ * Writes now and resolves once the host acknowledged it (and anything changed meanwhile).
58
+ * Resolves at once when nothing is unsaved; rejects with the last error when the write failed
59
+ * after its retries. When `serialize` and `write` return synchronously, the write has been
60
+ * handed over before `flush` returns.
61
+ */
62
+ flush(): Promise<void>;
63
+ /** Drops pending work and ignores the result of a write in flight; the scheduler stays usable. */
64
+ cancel(): void;
65
+ /** Cancels and stops for good: later calls do nothing. */
66
+ dispose(): void;
67
+ readonly state: WriteBackState;
68
+ /** True while a change waits for its quiet time or a write (or its retry) is under way. */
69
+ readonly dirty: boolean;
70
+ }
71
+ export declare const DEFAULT_WRITE_BACK_DEBOUNCE_MS = 5000;
72
+ /** The status of `state` for a collaboration state; the error becomes its message. */
73
+ export declare function writeBackStateOf(state: WriteBackState): CollaborationWriteBackState;
74
+ export declare function createWriteBackScheduler(options: WriteBackOptions): WriteBackScheduler;
75
+ //# sourceMappingURL=write-back.d.ts.map