superdoc 2.18.0-next.8 → 2.18.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 (29) hide show
  1. package/dist/chunks/{create-super-doc-ui-D9JWPXRh.cjs → create-super-doc-ui-wDvhW9Tz.cjs} +996 -912
  2. package/dist/chunks/{create-super-doc-ui-qTSa0PbD.es.js → create-super-doc-ui-wKzxrztu.es.js} +982 -910
  3. package/dist/collaboration-upgrade-engine.cjs +1 -1
  4. package/dist/collaboration-upgrade-engine.es.js +1 -1
  5. package/dist/document-api/src/diff/diff.types.d.ts +1 -1
  6. package/dist/document-api/src/images/images.types.d.ts +2 -0
  7. package/dist/document-api/src/types/blocks.types.d.ts +2 -0
  8. package/dist/document-api/src/types/clipboard.d.ts +24 -1
  9. package/dist/layout-engine/contracts/src/index.d.ts +4 -0
  10. package/dist/public/ui-react.cjs +1 -1
  11. package/dist/public/ui-react.es.js +1 -1
  12. package/dist/public/ui-vue.cjs +1 -1
  13. package/dist/public/ui-vue.es.js +1 -1
  14. package/dist/public/ui.cjs +1 -1
  15. package/dist/public/ui.es.js +1 -1
  16. package/dist/style.css +22 -22
  17. package/dist/style.layered.css +22 -22
  18. package/dist/superdoc/src/core/SuperDoc.d.ts +10 -3
  19. package/dist/superdoc/src/core/types/index.d.ts +37 -0
  20. package/dist/superdoc/src/internal/toolbar/built-in/LinkInput.vue.d.ts +4 -4
  21. package/dist/superdoc/src/public/index.d.cts +10 -0
  22. package/dist/superdoc/src/public/index.d.ts +5 -0
  23. package/dist/superdoc/src/public/ui/create-super-doc-ui.d.ts +9 -1
  24. package/dist/superdoc.cjs +232 -104
  25. package/dist/superdoc.es.js +232 -104
  26. package/dist-cdn/style.layered.css +1 -1
  27. package/dist-cdn/superdoc.min.css +1 -1
  28. package/dist-cdn/superdoc.min.js +37 -37
  29. package/package.json +2 -2
@@ -1,4 +1,11 @@
1
- import { SuperDocUI, SuperDocUIOptions } from './types.js';
1
+ import { CommandExecutionResult, SuperDocUI, SuperDocUIOptions } from './types.js';
2
+ type FirstPartyCommandMutation = {
3
+ supports: (memberPath: string) => boolean;
4
+ run: (memberPath: string, args: readonly unknown[]) => unknown;
5
+ runListApply: (input: unknown) => Promise<boolean>;
6
+ };
7
+ export declare function registerFirstPartyCommandMutation(superdoc: object, host: object, mutation: FirstPartyCommandMutation): void;
8
+ export declare function executeFirstPartyCommandAsync(ui: Pick<SuperDocUI, 'commands'>, id: string, payload?: unknown): Promise<CommandExecutionResult>;
2
9
  /**
3
10
  * Heavy-read policy for the async read coordinator (source-loading deferral).
4
11
  * One shared table: the coordinator's gate and the table-driven policy tests
@@ -16,3 +23,4 @@ export declare const HEAVY_DOC_READ_POLICY: readonly HeavyDocReadPolicyEntry[];
16
23
  /** Whether a coordinator cache key falls under the heavy-read policy. */
17
24
  export declare function isHeavyDocReadKey(key: string): boolean;
18
25
  export declare function createSuperDocUI(options: SuperDocUIOptions): SuperDocUI;
26
+ export {};
package/dist/superdoc.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_rolldown_runtime = require("./chunks/rolldown-runtime-74VwNCz7.cjs");
3
3
  const require_blank_docx = require("./chunks/blank-docx-BuFAbRjs.cjs");
4
- const require_create_super_doc_ui = require("./chunks/create-super-doc-ui-D9JWPXRh.cjs");
4
+ const require_create_super_doc_ui = require("./chunks/create-super-doc-ui-wDvhW9Tz.cjs");
5
5
  const require_eventemitter3 = require("./chunks/eventemitter3-C_TAnXOl.cjs");
6
6
  const require_uuid = require("./chunks/uuid-BhG0ngwk.cjs");
7
7
  const require_jszip = require("./chunks/jszip-D8mAFF-r.cjs");
@@ -316,7 +316,7 @@ var shuffleArray = (array) => {
316
316
  var DEFAULT_ENDPOINT = "https://ingest.superdoc.dev/v1/collect";
317
317
  function getSuperdocVersion() {
318
318
  try {
319
- return "2.18.0-next.8";
319
+ return "2.18.0";
320
320
  } catch {
321
321
  return "unknown";
322
322
  }
@@ -14979,6 +14979,79 @@ function useViewportFit({ getSuperdoc, superdocContainerWidth, isReady, activeZo
14979
14979
  return { evaluateViewport };
14980
14980
  }
14981
14981
  //#endregion
14982
+ //#region ../layout-engine/contracts/src/author-colors.ts
14983
+ /**
14984
+ * Curated, high-contrast fallback palette. Used when neither `overrides` nor
14985
+ * `resolve` produces a color so imported/discovered authors the host did not
14986
+ * configure ahead of time still get a stable, distinct color.
14987
+ */
14988
+ var FALLBACK_PALETTE = [
14989
+ "#1f6feb",
14990
+ "#d1242f",
14991
+ "#8250df",
14992
+ "#bf3989",
14993
+ "#1a7f37",
14994
+ "#9a6700",
14995
+ "#bc4c00",
14996
+ "#0969da",
14997
+ "#cf222e",
14998
+ "#6639ba",
14999
+ "#116329",
15000
+ "#7d4e00"
15001
+ ];
15002
+ /** Stable identity string for an author (used for hashing + dedupe). */
15003
+ var authorIdentityKey = (author) => {
15004
+ if (!author) return "";
15005
+ return `${typeof author.name === "string" ? author.name : ""} ${typeof author.email === "string" ? author.email : ""}`;
15006
+ };
15007
+ /** Deterministic 32-bit FNV-1a hash of a string. */
15008
+ var hashString = (value) => {
15009
+ let hash = 2166136261;
15010
+ for (let i = 0; i < value.length; i += 1) {
15011
+ hash ^= value.charCodeAt(i);
15012
+ hash = Math.imul(hash, 16777619);
15013
+ }
15014
+ return hash >>> 0;
15015
+ };
15016
+ /**
15017
+ * Deterministic fallback color derived from the author identity. The same
15018
+ * identity always maps to the same palette entry, so colors stay stable across
15019
+ * reloads and across the paint / snapshot surfaces.
15020
+ */
15021
+ var fallbackAuthorColor = (author) => {
15022
+ return FALLBACK_PALETTE[hashString(authorIdentityKey(author)) % FALLBACK_PALETTE.length];
15023
+ };
15024
+ var isNonEmptyString = (value) => typeof value === "string" && value.length > 0;
15025
+ /**
15026
+ * Composes the host `authorColors` config into a single resolver.
15027
+ *
15028
+ * Resolution order per author:
15029
+ * 1. `overrides` by identity — `email` first, then `name` (exact match).
15030
+ * 2. `resolve(author)`.
15031
+ * 3. A deterministic fallback color from the author identity.
15032
+ *
15033
+ * Returns `undefined` when colors are disabled (`enabled === false`) or no
15034
+ * config was provided, so callers can leave the existing default palette in
15035
+ * place by simply not threading a resolver.
15036
+ */
15037
+ var composeAuthorColorResolver = (config) => {
15038
+ if (!config || config.enabled === false) return void 0;
15039
+ const overrides = config.overrides && typeof config.overrides === "object" ? config.overrides : void 0;
15040
+ const resolve = typeof config.resolve === "function" ? config.resolve : void 0;
15041
+ return (author) => {
15042
+ const safeAuthor = author ?? {};
15043
+ if (overrides) {
15044
+ if (isNonEmptyString(safeAuthor.email) && isNonEmptyString(overrides[safeAuthor.email])) return overrides[safeAuthor.email];
15045
+ if (isNonEmptyString(safeAuthor.name) && isNonEmptyString(overrides[safeAuthor.name])) return overrides[safeAuthor.name];
15046
+ }
15047
+ if (resolve) try {
15048
+ const resolved = resolve(safeAuthor);
15049
+ if (isNonEmptyString(resolved)) return resolved;
15050
+ } catch {}
15051
+ return fallbackAuthorColor(safeAuthor);
15052
+ };
15053
+ };
15054
+ //#endregion
14982
15055
  //#region src/components/CommentsLayer/floating-comment-positioning.js
14983
15056
  var isPersistentReviewSidebarItem = (comment) => {
14984
15057
  return Boolean(comment?.trackedChange);
@@ -16392,79 +16465,6 @@ var _sfc_main$27 = {
16392
16465
  };
16393
16466
  var WhiteboardLayer_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_vue_export_helper_default(_sfc_main$27, [["__scopeId", "data-v-54546c3d"]]);
16394
16467
  //#endregion
16395
- //#region ../layout-engine/contracts/src/author-colors.ts
16396
- /**
16397
- * Curated, high-contrast fallback palette. Used when neither `overrides` nor
16398
- * `resolve` produces a color so imported/discovered authors the host did not
16399
- * configure ahead of time still get a stable, distinct color.
16400
- */
16401
- var FALLBACK_PALETTE = [
16402
- "#1f6feb",
16403
- "#d1242f",
16404
- "#8250df",
16405
- "#bf3989",
16406
- "#1a7f37",
16407
- "#9a6700",
16408
- "#bc4c00",
16409
- "#0969da",
16410
- "#cf222e",
16411
- "#6639ba",
16412
- "#116329",
16413
- "#7d4e00"
16414
- ];
16415
- /** Stable identity string for an author (used for hashing + dedupe). */
16416
- var authorIdentityKey = (author) => {
16417
- if (!author) return "";
16418
- return `${typeof author.name === "string" ? author.name : ""} ${typeof author.email === "string" ? author.email : ""}`;
16419
- };
16420
- /** Deterministic 32-bit FNV-1a hash of a string. */
16421
- var hashString = (value) => {
16422
- let hash = 2166136261;
16423
- for (let i = 0; i < value.length; i += 1) {
16424
- hash ^= value.charCodeAt(i);
16425
- hash = Math.imul(hash, 16777619);
16426
- }
16427
- return hash >>> 0;
16428
- };
16429
- /**
16430
- * Deterministic fallback color derived from the author identity. The same
16431
- * identity always maps to the same palette entry, so colors stay stable across
16432
- * reloads and across the paint / snapshot surfaces.
16433
- */
16434
- var fallbackAuthorColor = (author) => {
16435
- return FALLBACK_PALETTE[hashString(authorIdentityKey(author)) % FALLBACK_PALETTE.length];
16436
- };
16437
- var isNonEmptyString = (value) => typeof value === "string" && value.length > 0;
16438
- /**
16439
- * Composes the host `authorColors` config into a single resolver.
16440
- *
16441
- * Resolution order per author:
16442
- * 1. `overrides` by identity — `email` first, then `name` (exact match).
16443
- * 2. `resolve(author)`.
16444
- * 3. A deterministic fallback color from the author identity.
16445
- *
16446
- * Returns `undefined` when colors are disabled (`enabled === false`) or no
16447
- * config was provided, so callers can leave the existing default palette in
16448
- * place by simply not threading a resolver.
16449
- */
16450
- var composeAuthorColorResolver = (config) => {
16451
- if (!config || config.enabled === false) return void 0;
16452
- const overrides = config.overrides && typeof config.overrides === "object" ? config.overrides : void 0;
16453
- const resolve = typeof config.resolve === "function" ? config.resolve : void 0;
16454
- return (author) => {
16455
- const safeAuthor = author ?? {};
16456
- if (overrides) {
16457
- if (isNonEmptyString(safeAuthor.email) && isNonEmptyString(overrides[safeAuthor.email])) return overrides[safeAuthor.email];
16458
- if (isNonEmptyString(safeAuthor.name) && isNonEmptyString(overrides[safeAuthor.name])) return overrides[safeAuthor.name];
16459
- }
16460
- if (resolve) try {
16461
- const resolved = resolve(safeAuthor);
16462
- if (isNonEmptyString(resolved)) return resolved;
16463
- } catch {}
16464
- return fallbackAuthorColor(safeAuthor);
16465
- };
16466
- };
16467
- //#endregion
16468
16468
  //#region src/components/HtmlViewer/HtmlViewer.vue
16469
16469
  var _hoisted_1$20 = { class: "superdoc-html-viewer" };
16470
16470
  var _hoisted_2$16 = { class: "superdoc-html-viewer__document" };
@@ -22171,7 +22171,7 @@ var SuperDoc_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_v
22171
22171
  executeAsync: (commandId, payload) => {
22172
22172
  const ui = getSuperDocUI();
22173
22173
  if (!ui) return Promise.resolve(UNAVAILABLE_COMMAND_RESULT);
22174
- return ui.commands.executeAsync(commandId, payload);
22174
+ return require_create_super_doc_ui.executeFirstPartyCommandAsync(ui, commandId, payload);
22175
22175
  },
22176
22176
  getState: (commandId) => getSuperDocUI()?.commands.get(commandId).getState() ?? UNAVAILABLE_COMMAND_STATE
22177
22177
  },
@@ -22372,7 +22372,7 @@ var SuperDoc_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_v
22372
22372
  if (!payload) return;
22373
22373
  clearV2EditorFailure(payload.documentId ?? null);
22374
22374
  clearV2MutationRejectionNotifications(payload.documentId ?? null);
22375
- const { host, mount, documentId, capabilities, editCommands, bindEditShortcuts, bindSessionShortcuts, commentsAdapter, trackedChangesAdapter, contextMenu, documentApi, documentMutationReadiness, documentApiUnavailableReason, pageMetrics, pageLayout, pageFurniture, presence, lock, collaborationProvider, fonts, replaceFile, upgradeToCollaboration, documentOpenToken } = payload;
22375
+ const { host, firstPartyCommandMutation, mount, documentId, capabilities, editCommands, bindEditShortcuts, bindSessionShortcuts, commentsAdapter, trackedChangesAdapter, contextMenu, documentApi, documentMutationReadiness, documentApiUnavailableReason, pageMetrics, pageLayout, pageFurniture, presence, lock, connection, collaborationProvider, fonts, replaceFile, upgradeToCollaboration, documentOpenToken } = payload;
22376
22376
  documentOpenTelemetry?.trackDocumentOpen(documentOpenToken ?? null, documentId ?? null);
22377
22377
  const saveV2Bytes = createV2SaveQueue(async (saveOptions = {}) => {
22378
22378
  if (!host || typeof host.save !== "function") throw new Error("v2-editor: save unavailable");
@@ -22649,6 +22649,7 @@ var SuperDoc_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_v
22649
22649
  pageFurniture: pageFurniture ?? null,
22650
22650
  presence: presence ?? null,
22651
22651
  lock: lock ?? null,
22652
+ connection: connection ?? null,
22652
22653
  provider: collaborationProvider ?? null,
22653
22654
  reviewWindow: {
22654
22655
  getDiagnostics: () => v2ReviewWindowController.getDiagnostics(),
@@ -22687,6 +22688,7 @@ var SuperDoc_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_v
22687
22688
  if (doc) doc.provider = provider;
22688
22689
  }
22689
22690
  proxy.$superdoc.broadcastEditorCreate(facade);
22691
+ if (host && firstPartyCommandMutation) require_create_super_doc_ui.registerFirstPartyCommandMutation(proxy.$superdoc, host, firstPartyCommandMutation);
22690
22692
  installV2CommandShortcutBinding({
22691
22693
  documentId,
22692
22694
  bindEditShortcuts
@@ -23247,7 +23249,8 @@ var SuperDoc_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_v
23247
23249
  case "collaboration-room-corrupt": return "SuperDoc v2 found a structurally invalid collaboration room. No changes were made.";
23248
23250
  case "collaboration-v2-room-missing": return "SuperDoc v2 could not find a committed v2 collaboration room. No changes were made. Use roomMode: \"create\" only when creating a new room.";
23249
23251
  case "collaboration-v2-room-already-exists": return "SuperDoc v2 was asked to create a collaboration room that already exists. Use roomMode: \"join\" to open it.";
23250
- case "collaboration-v2-room-initializing": return "The SuperDoc v2 collaboration room is still initializing. Join mode did not modify it.";
23252
+ case "collaboration-v2-room-initializing": return "The SuperDoc v2 collaboration room has not completed initialization. This open attempt did not modify it.";
23253
+ case "collaboration-v2-room-bootstrap-stalled": return "The SuperDoc v2 collaboration room bootstrap appears stalled. This open attempt did not modify it. Preserve the room data if a create retry cannot recover it.";
23251
23254
  case "collaboration-open-intent-invalid": return "SuperDoc v2 received an invalid collaboration room mode. No provider was connected.";
23252
23255
  case "collaboration-config-invalid": return "SuperDoc v2 received an invalid collaboration configuration. No provider was connected.";
23253
23256
  default: return "SuperDoc could not load the document editor.";
@@ -23274,7 +23277,7 @@ var SuperDoc_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_v
23274
23277
  ...workerFailure ? { workerFailure } : {},
23275
23278
  reason
23276
23279
  };
23277
- if (reason === "collaboration-v1-config-unsupported" || reason === "collaboration-room-format-unsupported" || reason === "collaboration-room-format-conflict" || reason === "collaboration-room-corrupt" || reason === "collaboration-v2-room-missing" || reason === "collaboration-v2-room-already-exists" || reason === "collaboration-v2-room-initializing" || reason === "collaboration-open-intent-invalid" || reason === "collaboration-config-invalid") console.warn(`[SuperDoc] ${message}`, logContext);
23280
+ if (reason === "collaboration-v1-config-unsupported" || reason === "collaboration-room-format-unsupported" || reason === "collaboration-room-format-conflict" || reason === "collaboration-room-corrupt" || reason === "collaboration-v2-room-missing" || reason === "collaboration-v2-room-already-exists" || reason === "collaboration-v2-room-initializing" || reason === "collaboration-v2-room-bootstrap-stalled" || reason === "collaboration-open-intent-invalid" || reason === "collaboration-config-invalid") console.warn(`[SuperDoc] ${message}`, logContext);
23278
23281
  else console.error(`[SuperDoc] ${message}`, logContext);
23279
23282
  proxy.$superdoc.emit("exception", collaborationException ?? {
23280
23283
  error: new Error(message),
@@ -24494,7 +24497,7 @@ var SuperDoc_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_v
24494
24497
  ], 38);
24495
24498
  };
24496
24499
  }
24497
- }, [["__scopeId", "data-v-4efb0cab"]]);
24500
+ }, [["__scopeId", "data-v-77e0209a"]]);
24498
24501
  //#endregion
24499
24502
  //#region src/core/create-app.js
24500
24503
  var PINIA_DEVTOOLS_SETUP_EVENT = "devtools-plugin:setup";
@@ -44367,7 +44370,7 @@ function executeCommand(ui, commandId, argument, options = {}) {
44367
44370
  if (typeof ui.commands.has === "function" && !ui.commands.has(commandId)) return false;
44368
44371
  const execute = typeof ui.commands.executeAsync === "function" ? ui.commands.executeAsync : ui.commands.execute;
44369
44372
  if (typeof execute !== "function") return false;
44370
- const result = argument === void 0 ? execute.call(ui.commands, commandId) : execute.call(ui.commands, commandId, argument);
44373
+ const result = options.firstParty ? require_create_super_doc_ui.executeFirstPartyCommandAsync(ui, commandId, argument) : argument === void 0 ? execute.call(ui.commands, commandId) : execute.call(ui.commands, commandId, argument);
44371
44374
  const reportFailure = (settled) => {
44372
44375
  if (!options.reportUnhandled || settled !== false) return;
44373
44376
  options.onError?.(/* @__PURE__ */ new Error(`[superdoc toolbar] Command "${commandId}" did not run. Check that it is enabled and has the required input.`));
@@ -45015,6 +45018,7 @@ var BuiltInToolbar = class extends require_eventemitter3.import_eventemitter3.de
45015
45018
  const name = item?.name?.value;
45016
45019
  if (!name) return false;
45017
45020
  const callbacks = {
45021
+ firstParty: true,
45018
45022
  onSettled: () => this.updateToolbarState(),
45019
45023
  onError: (error) => this.#emitCommandException(error, name)
45020
45024
  };
@@ -45043,6 +45047,7 @@ var BuiltInToolbar = class extends require_eventemitter3.import_eventemitter3.de
45043
45047
  onPick: async (file) => {
45044
45048
  const src = await resolveImageSrc(file, this.superdoc?.config?.handleImageUpload);
45045
45049
  executeCommand(this.ui, "image", { src }, {
45050
+ firstParty: true,
45046
45051
  onSettled: () => this.updateToolbarState(),
45047
45052
  onError: (error) => this.#emitCommandException(error, "image")
45048
45053
  });
@@ -45370,6 +45375,14 @@ function contentControlSelectionKey(selection) {
45370
45375
  return null;
45371
45376
  }
45372
45377
  }
45378
+ function deriveCollaborationConnectionKind(snapshot, hasSyncedBefore) {
45379
+ switch (snapshot.state) {
45380
+ case "failed": return "failed";
45381
+ case "degraded": return snapshot.detail === "reconnecting" ? "reconnecting" : "lost";
45382
+ case "synced": return hasSyncedBefore ? "recovered" : "initial";
45383
+ default: return hasSyncedBefore ? "reconnecting" : "initial";
45384
+ }
45385
+ }
45373
45386
  function isV2ActiveEditorFacade(editor) {
45374
45387
  return Boolean(editor && typeof editor === "object" && editor.editorVersion === 2);
45375
45388
  }
@@ -45426,6 +45439,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
45426
45439
  #destroyed;
45427
45440
  #diagnostics;
45428
45441
  #isUpgrading;
45442
+ #pendingUpgrade;
45429
45443
  /** Aborts an in-flight upgrade (sync wait or ready wait). */
45430
45444
  #abortUpgrade;
45431
45445
  /**
@@ -45437,6 +45451,12 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
45437
45451
  #v2AwarenessUnsub;
45438
45452
  /** Unsubscribe handle for the v2 root-doc lock observer. */
45439
45453
  #v2LockUnsub;
45454
+ /** Unsubscribe handle for the v2 collaboration connection observer. */
45455
+ #v2ConnectionUnsub;
45456
+ /** Latest `collaboration-connection-change` payload, for late readers. */
45457
+ #v2ConnectionState;
45458
+ /** Whether the current collaboration room has completed a sync at least once. */
45459
+ #v2ConnectionHasSynced;
45440
45460
  /** Lock state captured before a local → v2 collaboration promotion remount. */
45441
45461
  #pendingV2LockSeed;
45442
45462
  #mountWrapper;
@@ -45525,9 +45545,13 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
45525
45545
  super();
45526
45546
  this.#destroyed = false;
45527
45547
  this.#isUpgrading = false;
45548
+ this.#pendingUpgrade = null;
45528
45549
  this.#abortUpgrade = null;
45529
45550
  this.#v2AwarenessUnsub = null;
45530
45551
  this.#v2LockUnsub = null;
45552
+ this.#v2ConnectionUnsub = null;
45553
+ this.#v2ConnectionState = null;
45554
+ this.#v2ConnectionHasSynced = false;
45531
45555
  this.#pendingV2LockSeed = null;
45532
45556
  this.#mountWrapper = null;
45533
45557
  this.#contentControlClickRoot = null;
@@ -45726,7 +45750,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
45726
45750
  this.config.colors = shuffleArray(this.config.colors);
45727
45751
  this.userColorMap = /* @__PURE__ */ new Map();
45728
45752
  this.colorIndex = 0;
45729
- this.version = "2.18.0-next.8";
45753
+ this.version = "2.18.0";
45730
45754
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
45731
45755
  this.superdocId = config.superdocId || require_uuid.v4();
45732
45756
  this.colors = this.config.colors ?? [];
@@ -45828,7 +45852,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
45828
45852
  return this.#diagnostics;
45829
45853
  }
45830
45854
  emit(event, ...args) {
45831
- if (event === "exception" || event === "document-replaced" || event === "ready" || event === "active-editor-change" || event === "collaboration-ready" || event === "locked") require_create_super_doc_ui.recordInteraction(this, event, () => args[0]);
45855
+ if (event === "exception" || event === "document-replaced" || event === "ready" || event === "active-editor-change" || event === "collaboration-ready" || event === "collaboration-connection-change" || event === "locked") require_create_super_doc_ui.recordInteraction(this, event, () => args[0]);
45832
45856
  return super.emit(event, ...args);
45833
45857
  }
45834
45858
  on(event, fn, context) {
@@ -46070,6 +46094,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
46070
46094
  this.#onConfig("pdf:document-ready", this.config.onPdfDocumentReady);
46071
46095
  this.#onConfig("sidebar-toggle", this.config.onSidebarToggle);
46072
46096
  this.#onConfig("collaboration-ready", this.config.onCollaborationReady);
46097
+ this.#onConfig("collaboration-connection-change", this.config.onCollaborationConnectionChange);
46073
46098
  this.on("collaboration-ready", (payload) => this.#startV2CollaborationEventBridge(payload?.editor ?? null));
46074
46099
  this.#onConfig("editor-update", this.config.onEditorUpdate);
46075
46100
  this.#onConfig("tracked-changes:bulk-decision", this.config.onTrackedChangesBulkDecision);
@@ -46160,12 +46185,59 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
46160
46185
  } catch {}
46161
46186
  this.#v2LockUnsub = null;
46162
46187
  }
46188
+ if (this.#v2ConnectionUnsub) {
46189
+ try {
46190
+ this.#v2ConnectionUnsub();
46191
+ } catch {}
46192
+ this.#v2ConnectionUnsub = null;
46193
+ }
46163
46194
  }
46164
46195
  #startV2CollaborationEventBridge(editor) {
46165
46196
  this.#stopV2CollaborationEventBridge();
46166
46197
  if (!isV2ActiveEditorFacade(editor)) return;
46167
46198
  this.#startV2AwarenessBridge(editor);
46168
46199
  this.#startV2LockBridge(editor);
46200
+ this.#startV2ConnectionBridge(editor);
46201
+ }
46202
+ #startV2ConnectionBridge(editor) {
46203
+ const connection = editor.connection;
46204
+ if (!connection || typeof connection.subscribe !== "function") return;
46205
+ const { documentId } = connection;
46206
+ if (this.#v2ConnectionState?.documentId !== documentId) {
46207
+ this.#v2ConnectionState = null;
46208
+ this.#v2ConnectionHasSynced = false;
46209
+ }
46210
+ const publish = (snapshot) => {
46211
+ if (this.#destroyed) return;
46212
+ const previous = this.#v2ConnectionState;
46213
+ if (previous && previous.state === snapshot.state && previous.detail === (snapshot.detail ?? null)) return;
46214
+ const payload = {
46215
+ documentId,
46216
+ state: snapshot.state,
46217
+ previousState: previous?.state ?? null,
46218
+ kind: deriveCollaborationConnectionKind(snapshot, this.#v2ConnectionHasSynced),
46219
+ detail: snapshot.detail ?? null,
46220
+ superdoc: this
46221
+ };
46222
+ this.#v2ConnectionState = payload;
46223
+ if (snapshot.state === "synced") this.#v2ConnectionHasSynced = true;
46224
+ this.emit("collaboration-connection-change", payload);
46225
+ };
46226
+ try {
46227
+ const initialSnapshot = connection.getSnapshot?.();
46228
+ if (initialSnapshot) publish(initialSnapshot);
46229
+ this.#v2ConnectionUnsub = connection.subscribe(publish);
46230
+ } catch (err) {
46231
+ console.warn("[SuperDoc] v2 connection bridge failed to subscribe", err);
46232
+ }
46233
+ }
46234
+ /**
46235
+ * Latest v2 collaboration connection change, or `null` when no v2
46236
+ * collaboration session has reported one. Same payload as the
46237
+ * `collaboration-connection-change` event.
46238
+ */
46239
+ getCollaborationConnectionState() {
46240
+ return this.#v2ConnectionState;
46169
46241
  }
46170
46242
  #startV2AwarenessBridge(editor) {
46171
46243
  const presence = editor.presence;
@@ -46253,29 +46325,78 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
46253
46325
  * - A supported v2 single-doc `v2Collaboration` target
46254
46326
  * - Create-and-upgrade only (no merge semantics)
46255
46327
  *
46256
- * @returns Resolves once the collaborative runtime is ready
46328
+ * @returns The attached room and document once the collaborative runtime is ready
46257
46329
  */
46258
46330
  async upgradeToCollaboration(options) {
46331
+ if (this.#pendingUpgrade) {
46332
+ const { target } = this.#resolveCollaborationUpgradeTarget(options);
46333
+ if (this.#sameUpgradeTarget(target, this.#pendingUpgrade.target)) return this.#pendingUpgrade.promise;
46334
+ throw Object.assign(/* @__PURE__ */ new Error("SuperDoc: a different collaboration target is already upgrading"), { code: "collaboration-upgrade-target-conflict" });
46335
+ }
46259
46336
  const { target } = this.#validateUpgradePrerequisites(options);
46260
46337
  this.#isUpgrading = true;
46261
- try {
46262
- const localSource = await this.#captureCurrentDocxSourceForUpgrade();
46263
- const rollback = this.#snapshotV2UpgradeState();
46264
- const lockSeed = this.#snapshotV2LockSeed();
46265
- this.#assertNotDestroyed();
46338
+ const operation = (async () => {
46266
46339
  try {
46267
- this.#pendingV2LockSeed = lockSeed;
46268
- const promotion = await this.#promoteSingleDocumentToV2Collaboration(target, localSource);
46269
- this.#finalizeSingleDocumentV2Collaboration(promotion, target);
46270
- this.#pendingV2LockSeed = null;
46271
- } catch (err) {
46272
- this.#rollbackV2UpgradeState(rollback);
46273
- throw err;
46274
- }
46275
- } finally {
46276
- this.#abortUpgrade = null;
46277
- this.#isUpgrading = false;
46278
- }
46340
+ const localSource = await this.#captureCurrentDocxSourceForUpgrade();
46341
+ const rollback = this.#snapshotV2UpgradeState();
46342
+ const lockSeed = this.#snapshotV2LockSeed();
46343
+ this.#assertNotDestroyed();
46344
+ try {
46345
+ this.#pendingV2LockSeed = lockSeed;
46346
+ const promotion = await this.#promoteSingleDocumentToV2Collaboration(target, localSource);
46347
+ this.#finalizeSingleDocumentV2Collaboration(promotion, target);
46348
+ this.#pendingV2LockSeed = null;
46349
+ const attachedDocumentId = this.activeEditor?.options?.documentId;
46350
+ const attachedRoomId = promotion.configDoc.v2Collaboration?.documentId;
46351
+ if (typeof attachedDocumentId !== "string" || attachedDocumentId !== promotion.configDoc.id || typeof attachedRoomId !== "string" || attachedRoomId !== target.documentId) throw new Error("SuperDoc: collaboration upgrade did not attach the expected room and document");
46352
+ return {
46353
+ roomId: attachedRoomId,
46354
+ documentId: attachedDocumentId
46355
+ };
46356
+ } catch (err) {
46357
+ this.#rollbackV2UpgradeState(rollback);
46358
+ throw err;
46359
+ }
46360
+ } finally {
46361
+ this.#abortUpgrade = null;
46362
+ this.#isUpgrading = false;
46363
+ this.#pendingUpgrade = null;
46364
+ }
46365
+ })();
46366
+ this.#pendingUpgrade = {
46367
+ target,
46368
+ promise: operation
46369
+ };
46370
+ return operation;
46371
+ }
46372
+ #sameUpgradeTarget(left, right) {
46373
+ if (left.token !== right.token) return false;
46374
+ const seen = /* @__PURE__ */ new WeakMap();
46375
+ const sameValue = (first, second) => {
46376
+ if (Object.is(first, second)) return true;
46377
+ if (!first || !second || typeof first !== "object" || typeof second !== "object") return false;
46378
+ if (Object.getPrototypeOf(first) !== Object.getPrototypeOf(second)) return false;
46379
+ if (seen.has(first)) return seen.get(first) === second;
46380
+ seen.set(first, second);
46381
+ if (first instanceof Date && second instanceof Date) return first.getTime() === second.getTime();
46382
+ if (first instanceof RegExp && second instanceof RegExp) return first.source === second.source && first.flags === second.flags;
46383
+ if (first instanceof ArrayBuffer && second instanceof ArrayBuffer) return sameValue(Array.from(new Uint8Array(first)), Array.from(new Uint8Array(second)));
46384
+ if (ArrayBuffer.isView(first) && ArrayBuffer.isView(second)) return first.constructor === second.constructor && sameValue(Array.from(new Uint8Array(first.buffer, first.byteOffset, first.byteLength)), Array.from(new Uint8Array(second.buffer, second.byteOffset, second.byteLength)));
46385
+ if (first instanceof Map && second instanceof Map) return first.size === second.size && sameValue(Array.from(first.entries()), Array.from(second.entries()));
46386
+ if (first instanceof Set && second instanceof Set) return first.size === second.size && sameValue(Array.from(first.values()), Array.from(second.values()));
46387
+ if (Array.isArray(first) && Array.isArray(second)) return first.length === second.length && first.every((value, index) => sameValue(value, second[index]));
46388
+ if (Object.getPrototypeOf(first) !== Object.prototype && Object.getPrototypeOf(first) !== null) return false;
46389
+ const keys = Object.keys(first).sort();
46390
+ const otherKeys = Object.keys(second).sort();
46391
+ return keys.length === otherKeys.length && keys.every((key, index) => key === otherKeys[index] && sameValue(first[key], second[key]));
46392
+ };
46393
+ return sameValue({
46394
+ ...left,
46395
+ token: void 0
46396
+ }, {
46397
+ ...right,
46398
+ token: void 0
46399
+ });
46279
46400
  }
46280
46401
  #snapshotV2LockSeed() {
46281
46402
  return {
@@ -46602,9 +46723,13 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
46602
46723
  if (docxDocs.length > 1) throw new Error("SuperDoc: upgradeToCollaboration() only supports a single DOCX document");
46603
46724
  if (cfg.documents.length !== docxDocs.length) throw new Error("SuperDoc: upgradeToCollaboration() only supports single-DOCX instances");
46604
46725
  if (!isV2ActiveEditorFacade(this.#resolveSourceEditor())) throw new Error("SuperDoc: upgradeToCollaboration() requires a ready v2 DOCX editor");
46605
- const configDoc = docxDocs[0];
46606
- const mountedDocumentId = configDoc.id;
46726
+ const mountedDocumentId = docxDocs[0].id;
46607
46727
  if (typeof mountedDocumentId !== "string" || mountedDocumentId.length === 0) throw new Error("SuperDoc: source document is missing its mounted document identity");
46728
+ return this.#resolveCollaborationUpgradeTarget(options);
46729
+ }
46730
+ #resolveCollaborationUpgradeTarget(options) {
46731
+ const cfg = this.config;
46732
+ const configDoc = cfg.documents.find((doc) => doc.type === DOCX);
46608
46733
  const collaborationModule = cfg.modules?.collaboration;
46609
46734
  const legacyCollaboration = options.ydoc || options.provider ? {
46610
46735
  ydoc: options.ydoc,
@@ -46620,7 +46745,10 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
46620
46745
  ...typeof window !== "undefined" ? { authEndpointBaseUrl: window.location.href } : {}
46621
46746
  });
46622
46747
  if (!resolution.ok) throw new Error(`SuperDoc: upgradeToCollaboration() ${resolution.reason}: ${resolution.message}`);
46623
- return { target: resolution.target };
46748
+ return { target: {
46749
+ ...resolution.target,
46750
+ roomMode: "create"
46751
+ } };
46624
46752
  }
46625
46753
  #unwrapMaybeRef(value) {
46626
46754
  if (value && typeof value === "object" && "value" in value) return value.value;