ooxml-core 1.21.0 → 1.23.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 (147) hide show
  1. package/README.md +7 -2
  2. package/dist/automation/index.cjs +33925 -12663
  3. package/dist/automation/index.d.ts +4 -0
  4. package/dist/automation/index.d.ts.map +1 -1
  5. package/dist/automation/index.mjs +33913 -12664
  6. package/dist/automation/node.cjs +37 -0
  7. package/dist/automation/node.d.ts +32 -1
  8. package/dist/automation/node.d.ts.map +1 -1
  9. package/dist/automation/node.mjs +36 -1
  10. package/dist/automation/proposal.d.ts +25 -0
  11. package/dist/automation/proposal.d.ts.map +1 -0
  12. package/dist/automation/tools/define.d.ts +27 -0
  13. package/dist/automation/tools/define.d.ts.map +1 -0
  14. package/dist/automation/tools/docx-tools.d.ts +4 -0
  15. package/dist/automation/tools/docx-tools.d.ts.map +1 -0
  16. package/dist/automation/tools/index.d.ts +16 -0
  17. package/dist/automation/tools/index.d.ts.map +1 -0
  18. package/dist/automation/tools/types.d.ts +52 -0
  19. package/dist/automation/tools/types.d.ts.map +1 -0
  20. package/dist/automation/tools/visio-tools.d.ts +4 -0
  21. package/dist/automation/tools/visio-tools.d.ts.map +1 -0
  22. package/dist/automation/tools/xlsx-tools.d.ts +8 -0
  23. package/dist/automation/tools/xlsx-tools.d.ts.map +1 -0
  24. package/dist/automation/xlsx-edits.d.ts +88 -0
  25. package/dist/automation/xlsx-edits.d.ts.map +1 -0
  26. package/dist/automation/xlsx-proposal.d.ts +34 -0
  27. package/dist/automation/xlsx-proposal.d.ts.map +1 -0
  28. package/dist/automation/xlsx.d.ts +10 -5
  29. package/dist/automation/xlsx.d.ts.map +1 -1
  30. package/dist/chunk-MHNETXQB.mjs +1 -0
  31. package/dist/collab/embedding.d.ts +15 -3
  32. package/dist/collab/embedding.d.ts.map +1 -1
  33. package/dist/collab/index.cjs +313 -102
  34. package/dist/collab/index.d.ts +3 -0
  35. package/dist/collab/index.d.ts.map +1 -1
  36. package/dist/collab/index.mjs +309 -103
  37. package/dist/collab/webrtc-provider.d.ts +21 -0
  38. package/dist/collab/webrtc-provider.d.ts.map +1 -0
  39. package/dist/collab/write-back-lifecycle.d.ts +33 -0
  40. package/dist/collab/write-back-lifecycle.d.ts.map +1 -0
  41. package/dist/collab/write-back.d.ts +75 -0
  42. package/dist/collab/write-back.d.ts.map +1 -0
  43. package/dist/pptx/automation/index.cjs +28707 -7376
  44. package/dist/pptx/automation/index.d.ts +91 -1
  45. package/dist/pptx/automation/index.d.ts.map +1 -1
  46. package/dist/pptx/automation/index.mjs +734 -57
  47. package/dist/pptx/automation/schemas/chart-formatting-schemas.d.ts +1 -1
  48. package/dist/pptx/automation/schemas/chart-schemas.d.ts +1 -1
  49. package/dist/pptx/automation/schemas/chart-user-shape-schemas.d.ts +1 -1
  50. package/dist/pptx/automation/schemas/element-schemas.d.ts +1 -1
  51. package/dist/pptx/automation/schemas/export-schemas.d.ts +1 -1
  52. package/dist/pptx/automation/schemas/geometry-schemas.d.ts +1 -1
  53. package/dist/pptx/automation/schemas/hyperlink-schemas.d.ts +1 -1
  54. package/dist/pptx/automation/schemas/index.mjs +1 -0
  55. package/dist/pptx/automation/schemas/json-schemas.d.ts +1 -1
  56. package/dist/pptx/automation/schemas/layout-schemas.d.ts +1 -1
  57. package/dist/pptx/automation/schemas/lock-schemas.d.ts +1 -1
  58. package/dist/pptx/automation/schemas/metadata-schemas.d.ts +1 -1
  59. package/dist/pptx/automation/schemas/ole-schemas.d.ts +1 -1
  60. package/dist/pptx/automation/schemas/presentation-schemas.d.ts +1 -1
  61. package/dist/pptx/automation/schemas/section-schemas.d.ts +1 -1
  62. package/dist/pptx/automation/schemas/slide-schemas.d.ts +1 -1
  63. package/dist/pptx/automation/schemas/smartart-schemas.d.ts +1 -1
  64. package/dist/pptx/automation/schemas/table-style-schemas.d.ts +1 -1
  65. package/dist/pptx/automation/schemas/template-schemas.d.ts +1 -1
  66. package/dist/pptx/automation/schemas/theme-schemas.d.ts +1 -1
  67. package/dist/pptx/automation/schemas/validation-schemas.d.ts +1 -1
  68. package/dist/pptx/chunks/{schemas-CWr181Wx.d.ts → schemas-fuDGetRe.d.ts} +2 -2
  69. package/dist/pptx/chunks/{schemas-CWr181Wx.d.ts.map → schemas-fuDGetRe.d.ts.map} +1 -1
  70. package/dist/visio/collab/baseline.d.ts +36 -0
  71. package/dist/visio/collab/baseline.d.ts.map +1 -0
  72. package/dist/visio/collab/bind.d.ts +62 -0
  73. package/dist/visio/collab/bind.d.ts.map +1 -0
  74. package/dist/visio/collab/compose-lists.d.ts +27 -0
  75. package/dist/visio/collab/compose-lists.d.ts.map +1 -0
  76. package/dist/visio/collab/compose.d.ts +19 -0
  77. package/dist/visio/collab/compose.d.ts.map +1 -0
  78. package/dist/visio/collab/fixups.d.ts +5 -0
  79. package/dist/visio/collab/fixups.d.ts.map +1 -0
  80. package/dist/visio/collab/index.cjs +2331 -0
  81. package/dist/visio/collab/index.d.ts +9 -0
  82. package/dist/visio/collab/index.d.ts.map +1 -0
  83. package/dist/visio/collab/index.mjs +2281 -0
  84. package/dist/visio/collab/keys.d.ts +51 -0
  85. package/dist/visio/collab/keys.d.ts.map +1 -0
  86. package/dist/visio/collab/order.d.ts +11 -0
  87. package/dist/visio/collab/order.d.ts.map +1 -0
  88. package/dist/visio/collab/package.d.ts +58 -0
  89. package/dist/visio/collab/package.d.ts.map +1 -0
  90. package/dist/visio/collab/pieces.d.ts +34 -0
  91. package/dist/visio/collab/pieces.d.ts.map +1 -0
  92. package/dist/visio/collab/read-ids.d.ts +29 -0
  93. package/dist/visio/collab/read-ids.d.ts.map +1 -0
  94. package/dist/visio/collab/read-parts.d.ts +34 -0
  95. package/dist/visio/collab/read-parts.d.ts.map +1 -0
  96. package/dist/visio/collab/read-shapes.d.ts +35 -0
  97. package/dist/visio/collab/read-shapes.d.ts.map +1 -0
  98. package/dist/visio/collab/read-util.d.ts +20 -0
  99. package/dist/visio/collab/read-util.d.ts.map +1 -0
  100. package/dist/visio/collab/read.d.ts +62 -0
  101. package/dist/visio/collab/read.d.ts.map +1 -0
  102. package/dist/visio/collab/scan.d.ts +28 -0
  103. package/dist/visio/collab/scan.d.ts.map +1 -0
  104. package/dist/visio/collab/schema.d.ts +124 -0
  105. package/dist/visio/collab/schema.d.ts.map +1 -0
  106. package/dist/visio/collab/snapshot-contents.d.ts +9 -0
  107. package/dist/visio/collab/snapshot-contents.d.ts.map +1 -0
  108. package/dist/visio/collab/snapshot-io.d.ts +26 -0
  109. package/dist/visio/collab/snapshot-io.d.ts.map +1 -0
  110. package/dist/visio/collab/snapshot-parts.d.ts +14 -0
  111. package/dist/visio/collab/snapshot-parts.d.ts.map +1 -0
  112. package/dist/visio/collab/snapshot.d.ts +68 -0
  113. package/dist/visio/collab/snapshot.d.ts.map +1 -0
  114. package/dist/visio/collab/write-parts.d.ts +8 -0
  115. package/dist/visio/collab/write-parts.d.ts.map +1 -0
  116. package/dist/visio/collab/write-shapes.d.ts +30 -0
  117. package/dist/visio/collab/write-shapes.d.ts.map +1 -0
  118. package/dist/visio/collab/write.d.ts +8 -0
  119. package/dist/visio/collab/write.d.ts.map +1 -0
  120. package/dist/visio/index.cjs +57 -4
  121. package/dist/visio/index.d.ts +1 -0
  122. package/dist/visio/index.d.ts.map +1 -1
  123. package/dist/visio/index.mjs +56 -5
  124. package/dist/visio/parse-incremental.d.ts +16 -0
  125. package/dist/visio/parse-incremental.d.ts.map +1 -0
  126. package/dist/visio/parser.d.ts +7 -0
  127. package/dist/visio/parser.d.ts.map +1 -1
  128. package/dist/visio/ui/collab-options.d.ts +29 -0
  129. package/dist/visio/ui/collab-options.d.ts.map +1 -0
  130. package/dist/visio/ui/collab-presence.d.ts +31 -0
  131. package/dist/visio/ui/collab-presence.d.ts.map +1 -0
  132. package/dist/visio/ui/contract.d.ts +4 -3
  133. package/dist/visio/ui/contract.d.ts.map +1 -1
  134. package/dist/visio/ui/document-history.d.ts +3 -1
  135. package/dist/visio/ui/document-history.d.ts.map +1 -1
  136. package/dist/visio/ui/index.cjs +125 -56
  137. package/dist/visio/ui/index.d.ts +2 -0
  138. package/dist/visio/ui/index.d.ts.map +1 -1
  139. package/dist/visio/ui/index.mjs +120 -57
  140. package/dist/xlsx/ui/index.cjs +5 -0
  141. package/dist/xlsx/ui/index.mjs +5 -0
  142. package/dist/xlsx/ui/locales/de/shell.d.ts.map +1 -1
  143. package/dist/xlsx/ui/locales/en/shell.d.ts.map +1 -1
  144. package/dist/xlsx/ui/locales/es/shell.d.ts.map +1 -1
  145. package/dist/xlsx/ui/locales/fr/shell.d.ts.map +1 -1
  146. package/dist/xlsx/ui/locales/zh-CN/shell.d.ts.map +1 -1
  147. package/package.json +6 -1
@@ -1024,6 +1024,118 @@ function createTransportProvider({ doc, awareness }, { transport, maxMessageByte
1024
1024
  };
1025
1025
  }
1026
1026
 
1027
+ // collab/external-provider.ts
1028
+ function adaptYjsProvider(provider) {
1029
+ const events = new Emitter();
1030
+ let destroyed = false;
1031
+ let status = provider.wsconnected || provider.connected ? "connected" : provider.wsconnecting ? "connecting" : "disconnected";
1032
+ let synced = Boolean(provider.synced);
1033
+ const subscriptions = [];
1034
+ const listen = (name, handler) => {
1035
+ const wrapped = handler;
1036
+ provider.on(name, wrapped);
1037
+ subscriptions.push([name, wrapped]);
1038
+ };
1039
+ const setStatus = (next) => {
1040
+ if (destroyed || next === status) return;
1041
+ status = next;
1042
+ events.emit("status", next);
1043
+ };
1044
+ const setSynced = (next) => {
1045
+ if (destroyed || next === synced) return;
1046
+ synced = next;
1047
+ events.emit("synced", next);
1048
+ };
1049
+ listen("status", (payload) => {
1050
+ if (typeof payload.connected === "boolean") {
1051
+ if (!payload.connected) setSynced(false);
1052
+ return setStatus(payload.connected ? "connected" : "disconnected");
1053
+ }
1054
+ if (payload.status === "connected" || payload.status === "connecting")
1055
+ setStatus(payload.status);
1056
+ else if (payload.status === "disconnected") {
1057
+ setSynced(false);
1058
+ setStatus("disconnected");
1059
+ }
1060
+ });
1061
+ const onSync = (value) => setSynced(typeof value === "boolean" ? value : value.synced === true);
1062
+ listen("sync", onSync);
1063
+ listen("synced", onSync);
1064
+ listen("connection-error", (cause) => {
1065
+ if (destroyed) return;
1066
+ setStatus("error");
1067
+ events.emit("error", cause instanceof Error ? cause : new Error("Provider connection error"));
1068
+ });
1069
+ return {
1070
+ get status() {
1071
+ return status;
1072
+ },
1073
+ get synced() {
1074
+ return synced;
1075
+ },
1076
+ connect: () => {
1077
+ if (destroyed || status === "connected" || status === "connecting") return;
1078
+ setStatus("connecting");
1079
+ provider.connect?.();
1080
+ },
1081
+ disconnect: () => {
1082
+ if (destroyed) return;
1083
+ provider.disconnect?.();
1084
+ setSynced(false);
1085
+ setStatus("disconnected");
1086
+ },
1087
+ destroy: () => {
1088
+ if (destroyed) return;
1089
+ setSynced(false);
1090
+ setStatus("disconnected");
1091
+ destroyed = true;
1092
+ for (const [name, handler] of subscriptions) provider.off?.(name, handler);
1093
+ subscriptions.length = 0;
1094
+ events.clear();
1095
+ provider.destroy?.();
1096
+ },
1097
+ on: (event, listener) => events.on(event, listener)
1098
+ };
1099
+ }
1100
+ function observeExternalSession(session, onSnapshot) {
1101
+ let active = true;
1102
+ let subscribing = true;
1103
+ let previous;
1104
+ let unsubscribe;
1105
+ const notify = () => {
1106
+ if (!active || subscribing) return;
1107
+ const snapshot = session.getSnapshot();
1108
+ if (previous?.status === snapshot.status && previous.synced === snapshot.synced) return;
1109
+ previous = { status: snapshot.status, synced: snapshot.synced };
1110
+ onSnapshot(previous);
1111
+ };
1112
+ const dispose = () => {
1113
+ if (!active) return;
1114
+ active = false;
1115
+ unsubscribe?.();
1116
+ };
1117
+ try {
1118
+ unsubscribe = session.subscribe(notify);
1119
+ subscribing = false;
1120
+ notify();
1121
+ } catch (error) {
1122
+ dispose();
1123
+ throw error;
1124
+ }
1125
+ return dispose;
1126
+ }
1127
+
1128
+ // collab/webrtc-provider.ts
1129
+ function webrtcProvider(options) {
1130
+ return ({ doc, awareness, roomId }) => adaptYjsProvider(
1131
+ new options.WebrtcProvider(roomId, doc, {
1132
+ awareness,
1133
+ ...options.signaling ? { signaling: options.signaling } : {},
1134
+ ...options.password ? { password: options.password } : {}
1135
+ })
1136
+ );
1137
+ }
1138
+
1027
1139
  // collab/websocket-transport.ts
1028
1140
  var OPEN = 1;
1029
1141
  function roomUrl(server, roomId) {
@@ -1120,9 +1232,15 @@ function openCollaborationSession(options, defaults) {
1120
1232
  const roomId = options.roomId ?? "";
1121
1233
  if (!isValidRoomId(roomId)) throw new Error(INVALID_ROOM_MESSAGE);
1122
1234
  let provider = options.provider;
1235
+ if (!provider && options.webrtc) {
1236
+ const password = options.webrtc.password ?? options.authToken;
1237
+ provider = webrtcProvider({ ...options.webrtc, ...password ? { password } : {} });
1238
+ }
1123
1239
  if (!provider && options.serverUrl)
1124
1240
  provider = transportProvider({
1125
- transport: createWebSocketTransport({ url: roomUrl(options.serverUrl, roomId) })
1241
+ transport: createWebSocketTransport({
1242
+ url: withToken(roomUrl(options.serverUrl, roomId), options.authToken)
1243
+ })
1126
1244
  });
1127
1245
  if (!provider) {
1128
1246
  if (!canBroadcast()) throw new Error(NO_BROADCAST_MESSAGE);
@@ -1146,6 +1264,10 @@ function openCollaborationSession(options, defaults) {
1146
1264
  });
1147
1265
  return { session, owned: true };
1148
1266
  }
1267
+ function withToken(url, token) {
1268
+ if (!token) return url;
1269
+ return `${url}${url.includes("?") ? "&" : "?"}token=${encodeURIComponent(token)}`;
1270
+ }
1149
1271
  function collaborationStateOf(session) {
1150
1272
  return {
1151
1273
  active: true,
@@ -1202,107 +1324,6 @@ function toExternalSession(session) {
1202
1324
  };
1203
1325
  }
1204
1326
 
1205
- // collab/external-provider.ts
1206
- function adaptYjsProvider(provider) {
1207
- const events = new Emitter();
1208
- let destroyed = false;
1209
- let status = provider.wsconnected || provider.connected ? "connected" : provider.wsconnecting ? "connecting" : "disconnected";
1210
- let synced = Boolean(provider.synced);
1211
- const subscriptions = [];
1212
- const listen = (name, handler) => {
1213
- const wrapped = handler;
1214
- provider.on(name, wrapped);
1215
- subscriptions.push([name, wrapped]);
1216
- };
1217
- const setStatus = (next) => {
1218
- if (destroyed || next === status) return;
1219
- status = next;
1220
- events.emit("status", next);
1221
- };
1222
- const setSynced = (next) => {
1223
- if (destroyed || next === synced) return;
1224
- synced = next;
1225
- events.emit("synced", next);
1226
- };
1227
- listen("status", (payload) => {
1228
- if (typeof payload.connected === "boolean") {
1229
- if (!payload.connected) setSynced(false);
1230
- return setStatus(payload.connected ? "connected" : "disconnected");
1231
- }
1232
- if (payload.status === "connected" || payload.status === "connecting")
1233
- setStatus(payload.status);
1234
- else if (payload.status === "disconnected") {
1235
- setSynced(false);
1236
- setStatus("disconnected");
1237
- }
1238
- });
1239
- const onSync = (value) => setSynced(typeof value === "boolean" ? value : value.synced === true);
1240
- listen("sync", onSync);
1241
- listen("synced", onSync);
1242
- listen("connection-error", (cause) => {
1243
- if (destroyed) return;
1244
- setStatus("error");
1245
- events.emit("error", cause instanceof Error ? cause : new Error("Provider connection error"));
1246
- });
1247
- return {
1248
- get status() {
1249
- return status;
1250
- },
1251
- get synced() {
1252
- return synced;
1253
- },
1254
- connect: () => {
1255
- if (destroyed || status === "connected" || status === "connecting") return;
1256
- setStatus("connecting");
1257
- provider.connect?.();
1258
- },
1259
- disconnect: () => {
1260
- if (destroyed) return;
1261
- provider.disconnect?.();
1262
- setSynced(false);
1263
- setStatus("disconnected");
1264
- },
1265
- destroy: () => {
1266
- if (destroyed) return;
1267
- setSynced(false);
1268
- setStatus("disconnected");
1269
- destroyed = true;
1270
- for (const [name, handler] of subscriptions) provider.off?.(name, handler);
1271
- subscriptions.length = 0;
1272
- events.clear();
1273
- provider.destroy?.();
1274
- },
1275
- on: (event, listener) => events.on(event, listener)
1276
- };
1277
- }
1278
- function observeExternalSession(session, onSnapshot) {
1279
- let active = true;
1280
- let subscribing = true;
1281
- let previous;
1282
- let unsubscribe;
1283
- const notify = () => {
1284
- if (!active || subscribing) return;
1285
- const snapshot = session.getSnapshot();
1286
- if (previous?.status === snapshot.status && previous.synced === snapshot.synced) return;
1287
- previous = { status: snapshot.status, synced: snapshot.synced };
1288
- onSnapshot(previous);
1289
- };
1290
- const dispose = () => {
1291
- if (!active) return;
1292
- active = false;
1293
- unsubscribe?.();
1294
- };
1295
- try {
1296
- unsubscribe = session.subscribe(notify);
1297
- subscribing = false;
1298
- notify();
1299
- } catch (error) {
1300
- dispose();
1301
- throw error;
1302
- }
1303
- return dispose;
1304
- }
1305
-
1306
1327
  // collab/memory-transport.ts
1307
1328
  function createMemoryHub(options = {}) {
1308
1329
  const rooms = /* @__PURE__ */ new Map();
@@ -1478,4 +1499,189 @@ function freezeDeep(value) {
1478
1499
  return value;
1479
1500
  }
1480
1501
 
1481
- 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 };
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,21 @@
1
+ import type { Awareness } from 'y-protocols/awareness';
2
+ import type * as Y from 'yjs';
3
+ import { type YjsProviderLike } from './external-provider.js';
4
+ import type { ProviderFactory } from './provider.js';
5
+ /** The y-webrtc `WebrtcProvider` constructor, structurally. */
6
+ export type WebrtcProviderConstructor = new (roomId: string, doc: Y.Doc, options: {
7
+ signaling?: string[];
8
+ password?: string;
9
+ awareness?: Awareness;
10
+ }) => YjsProviderLike;
11
+ export interface WebrtcOptions {
12
+ /** `WebrtcProvider` from the host's own `y-webrtc` install. */
13
+ WebrtcProvider: WebrtcProviderConstructor;
14
+ /** Signaling server URLs; y-webrtc's defaults when omitted. */
15
+ signaling?: string[];
16
+ /** Room password: peers without it cannot read the room. */
17
+ password?: string;
18
+ }
19
+ /** A provider factory that joins the session's room over y-webrtc, sharing its awareness. */
20
+ export declare function webrtcProvider(options: WebrtcOptions): ProviderFactory;
21
+ //# sourceMappingURL=webrtc-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webrtc-provider.d.ts","sourceRoot":"","sources":["../../collab/webrtc-provider.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,KAAK,CAAC,MAAM,KAAK,CAAC;AAC9B,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,+DAA+D;AAC/D,MAAM,MAAM,yBAAyB,GAAG,KACvC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,CAAC,CAAC,GAAG,EACV,OAAO,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,CAAA;CAAE,KACvE,eAAe,CAAC;AAErB,MAAM,WAAW,aAAa;IAC7B,+DAA+D;IAC/D,cAAc,EAAE,yBAAyB,CAAC;IAC1C,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,6FAA6F;AAC7F,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,GAAG,eAAe,CAStE"}
@@ -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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-back.d.ts","sourceRoot":"","sources":["../../collab/write-back.ts"],"names":[],"mappings":"AAKA,+GAA+G;AAC/G,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEjF,mEAAmE;AACnE,MAAM,WAAW,cAAc;IAC9B,MAAM,EAAE,eAAe,CAAC;IACxB,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sEAAsE;IACtE,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,gGAAgG;AAChG,MAAM,WAAW,2BAA2B;IAC3C,MAAM,EAAE,eAAe,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC9B,gFAAgF;IAChF,QAAQ,EAAE,MAAM,CAAC;IACjB,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IACtD,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,gBAAgB;IAChC;;;;OAIG;IACH,SAAS,EAAE,CAAC,OAAO,EAAE;QACpB,SAAS,EAAE,MAAM,OAAO,CAAC;KACzB,KAAK,UAAU,GAAG,IAAI,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACrD;;;OAGG;IACH,KAAK,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,sFAAsF;IACtF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC3C,mDAAmD;IACnD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,qFAAqF;IACrF,MAAM,CAAC,EAAE,eAAe,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IAClC,+FAA+F;IAC/F,QAAQ,IAAI,IAAI,CAAC;IACjB;;;;;OAKG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,kGAAkG;IAClG,MAAM,IAAI,IAAI,CAAC;IACf,0DAA0D;IAC1D,OAAO,IAAI,IAAI,CAAC;IAChB,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,2FAA2F;IAC3F,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACxB;AAED,eAAO,MAAM,8BAA8B,OAAQ,CAAC;AAcpD,sFAAsF;AACtF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,GAAG,2BAA2B,CAQnF;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,gBAAgB,GAAG,kBAAkB,CAkKtF"}