superdoc 2.13.0-next.1 → 2.13.0-next.10

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 (41) hide show
  1. package/dist/chunks/{create-super-doc-ui-BWWWNPP8.cjs → create-super-doc-ui-mHK2pqj3.cjs} +3 -1
  2. package/dist/chunks/{create-super-doc-ui-FnwgTkUv.es.js → create-super-doc-ui-u1giSvlm.es.js} +3 -1
  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/blocks/blocks.d.ts +3 -1
  6. package/dist/document-api/src/blocks/find-text.d.ts +3 -0
  7. package/dist/document-api/src/content-controls/content-controls.types.d.ts +1 -1
  8. package/dist/document-api/src/contract/command-catalog.d.ts +1 -1
  9. package/dist/document-api/src/contract/operation-definitions.d.ts +11 -1
  10. package/dist/document-api/src/contract/operation-registry.d.ts +7 -2
  11. package/dist/document-api/src/index.d.ts +7 -6
  12. package/dist/document-api/src/invoke/invoke.d.ts +2 -1
  13. package/dist/document-api/src/types/blocks.types.d.ts +38 -0
  14. package/dist/document-api/src/types/mutation-plan.types.d.ts +28 -4
  15. package/dist/document-api/src/types/table-operations.types.d.ts +2 -0
  16. package/dist/layout-engine/dom-contract/src/data-attrs.d.ts +3 -0
  17. package/dist/layout-engine/painters/dom/src/page-content.d.ts +3 -2
  18. package/dist/layout-engine/painters/dom/src/renderer.d.ts +1 -0
  19. package/dist/public/collaboration-worker.cjs +9 -0
  20. package/dist/public/collaboration-worker.es.js +8 -0
  21. package/dist/public/ui-react.cjs +1 -1
  22. package/dist/public/ui-react.es.js +1 -1
  23. package/dist/public/ui-vue.cjs +1 -1
  24. package/dist/public/ui-vue.es.js +1 -1
  25. package/dist/public/ui.cjs +1 -1
  26. package/dist/public/ui.es.js +1 -1
  27. package/dist/style.css +26 -26
  28. package/dist/style.layered.css +26 -26
  29. package/dist/superdoc/src/core/collaboration/collaboration-exception.d.ts +2 -0
  30. package/dist/superdoc/src/core/collaboration/resolve-v2-collaboration-target.d.ts +16 -5
  31. package/dist/superdoc/src/core/types/index.d.ts +58 -41
  32. package/dist/superdoc/src/public/collaboration-worker.d.cts +18 -0
  33. package/dist/superdoc/src/public/collaboration-worker.d.ts +48 -0
  34. package/dist/superdoc/src/public/index.d.cts +4 -0
  35. package/dist/superdoc/src/public/index.d.ts +2 -0
  36. package/dist/superdoc.cjs +334 -238
  37. package/dist/superdoc.es.js +334 -238
  38. package/dist-cdn/style.layered.css +1 -1
  39. package/dist-cdn/superdoc.min.css +1 -1
  40. package/dist-cdn/superdoc.min.js +35 -35
  41. package/package.json +13 -2
@@ -3,7 +3,7 @@ import { t as blank_default } from "./chunks/blank-docx-DzQccOlW.es.js";
3
3
  import { t as import_eventemitter3 } from "./chunks/eventemitter3-DEIiXiH2.es.js";
4
4
  import { t as v4 } from "./chunks/uuid-H0Xcmmhy.es.js";
5
5
  import { a as init_dist$1, i as global, n as init_dist$2, o as Buffer, r as process$1, s as init_dist, t as require_jszip_min } from "./chunks/jszip-BzJ3CyxR.es.js";
6
- import { a as DOM_CLASS_NAMES, i as getV2TrackedChangeMutationImpact, t as createSuperDocUI } from "./chunks/create-super-doc-ui-FnwgTkUv.es.js";
6
+ import { a as DOM_CLASS_NAMES, i as getV2TrackedChangeMutationImpact, t as createSuperDocUI } from "./chunks/create-super-doc-ui-u1giSvlm.es.js";
7
7
  import { t as _plugin_vue_export_helper_default } from "./chunks/_plugin-vue_export-helper-BOaGB7Aw.es.js";
8
8
  import { t as PDF_TO_CSS_UNITS } from "./chunks/constants-B6VBlmKp.es.js";
9
9
  import * as Vue from "vue";
@@ -315,7 +315,7 @@ var shuffleArray = (array) => {
315
315
  var DEFAULT_ENDPOINT = "https://ingest.superdoc.dev/v1/collect";
316
316
  function getSuperdocVersion() {
317
317
  try {
318
- return "2.13.0-next.1";
318
+ return "2.13.0-next.10";
319
319
  } catch {
320
320
  return "unknown";
321
321
  }
@@ -5310,6 +5310,274 @@ function storeToRefs(store) {
5310
5310
  return refs;
5311
5311
  }
5312
5312
  //#endregion
5313
+ //#region src/core/collaboration/resolve-v2-collaboration-target.ts
5314
+ /** Select the public spelling before validation; do not merge settings from different rooms. */
5315
+ function readCollaborationConfig(input) {
5316
+ return input.collaboration !== void 0 ? input.collaboration : input.v2Collaboration;
5317
+ }
5318
+ /**
5319
+ * Redact a connection URL for safe inclusion in diagnostics and artifacts.
5320
+ *
5321
+ * Strips the query string, fragment, and any embedded credentials (userinfo)
5322
+ * because those commonly carry auth tokens. Falls back to a coarse string scrub
5323
+ * when the value is not a parseable absolute URL so a malformed value with an
5324
+ * inline `?token=...` still cannot leak.
5325
+ */
5326
+ function redactCollaborationUrl(url) {
5327
+ if (typeof url !== "string" || url.length === 0) return "<none>";
5328
+ try {
5329
+ const parsed = new URL(url);
5330
+ parsed.search = "";
5331
+ parsed.hash = "";
5332
+ parsed.username = "";
5333
+ parsed.password = "";
5334
+ const redactedQuery = url.includes("?") ? "?<redacted>" : "";
5335
+ return `${parsed.toString().replace(/\?$/, "")}${redactedQuery}`;
5336
+ } catch {
5337
+ const withoutCredentials = url.replace(/\/\/[^/@]+@/, "//");
5338
+ const cut = withoutCredentials.search(/[?#]/);
5339
+ if (cut === -1) return withoutCredentials;
5340
+ return `${withoutCredentials.slice(0, cut)}?<redacted>`;
5341
+ }
5342
+ }
5343
+ function normalizeNonEmptyString(value) {
5344
+ return typeof value === "string" && value.length > 0 ? value : null;
5345
+ }
5346
+ function normalizeWebsocketUrl(value) {
5347
+ if (typeof value !== "string" || value.length === 0) return null;
5348
+ try {
5349
+ const parsed = new URL(value);
5350
+ return parsed.protocol === "ws:" || parsed.protocol === "wss:" ? value : null;
5351
+ } catch {
5352
+ return null;
5353
+ }
5354
+ }
5355
+ function normalizeHttpUrl(value, baseUrl) {
5356
+ if (typeof value !== "string") return null;
5357
+ const normalized = value.trim();
5358
+ if (normalized.length === 0) return null;
5359
+ try {
5360
+ const parsed = new URL(normalized);
5361
+ return parsed.protocol === "http:" || parsed.protocol === "https:" ? normalized : null;
5362
+ } catch {
5363
+ if (typeof baseUrl !== "string" || baseUrl.trim().length === 0) return null;
5364
+ try {
5365
+ const parsed = new URL(normalized, baseUrl);
5366
+ return parsed.protocol === "http:" || parsed.protocol === "https:" ? parsed.href : null;
5367
+ } catch {
5368
+ return null;
5369
+ }
5370
+ }
5371
+ }
5372
+ function normalizeParams(value) {
5373
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
5374
+ const params = {};
5375
+ for (const [key, raw] of Object.entries(value)) if (typeof raw === "string") params[key] = raw;
5376
+ return Object.keys(params).length > 0 ? params : void 0;
5377
+ }
5378
+ function normalizeRoomMode(value) {
5379
+ if (value === void 0) return "join";
5380
+ return value === "join" || value === "create" ? value : null;
5381
+ }
5382
+ function invalidRoomMode() {
5383
+ return {
5384
+ ok: false,
5385
+ reason: "invalid-room-mode",
5386
+ message: "SuperDoc v2 collaboration roomMode must be either \"join\" or \"create\"."
5387
+ };
5388
+ }
5389
+ /** Provider-family token recognized on a v2Collaboration config object. */
5390
+ function readProviderType(candidate) {
5391
+ const raw = candidate.providerType;
5392
+ return typeof raw === "string" && raw.length > 0 ? raw.toLowerCase() : null;
5393
+ }
5394
+ /**
5395
+ * Detect whether a legacy collaboration block names a provider family that the
5396
+ * shipped single-doc v2 runtime cannot drive. Returns the offending family name
5397
+ * (for diagnostics) or `null` when the block carries no recognizable family.
5398
+ */
5399
+ function detectUnsupportedLegacyFamily(legacy) {
5400
+ if (!legacy || typeof legacy !== "object") return null;
5401
+ const providerType = typeof legacy.providerType === "string" ? legacy.providerType.toLowerCase() : "";
5402
+ if (providerType === "hocuspocus") return "hocuspocus";
5403
+ if (providerType === "liveblocks") return "liveblocks";
5404
+ if (providerType === "superdoc") return "superdoc";
5405
+ if (legacy.ydoc != null || legacy.provider != null) return "external-ydoc-provider";
5406
+ return null;
5407
+ }
5408
+ /** Resolve a websocket-backed family (y-websocket / Hocuspocus). */
5409
+ function resolveWebsocketFamily(family, candidate) {
5410
+ const documentId = normalizeNonEmptyString(candidate.documentId);
5411
+ if (!documentId) return {
5412
+ ok: false,
5413
+ reason: "invalid-document-id",
5414
+ message: `SuperDoc v2 collaboration requires a non-empty collaboration.documentId for the "${family}" provider.`
5415
+ };
5416
+ const rawUrl = candidate.url ?? candidate.serverUrl;
5417
+ const serverUrl = normalizeWebsocketUrl(rawUrl);
5418
+ if (!serverUrl) return {
5419
+ ok: false,
5420
+ reason: "invalid-server-url",
5421
+ message: `SuperDoc v2 collaboration requires a valid ws:// or wss:// URL for the "${family}" provider (received: ${redactCollaborationUrl(rawUrl)}).`
5422
+ };
5423
+ const params = normalizeParams(candidate.params);
5424
+ const token = family === "hocuspocus" && typeof candidate.token === "function" ? candidate.token : family === "hocuspocus" ? normalizeNonEmptyString(candidate.token) : null;
5425
+ const roomMode = normalizeRoomMode(candidate.roomMode);
5426
+ if (!roomMode) return invalidRoomMode();
5427
+ return {
5428
+ ok: true,
5429
+ target: {
5430
+ providerFamily: family,
5431
+ documentId,
5432
+ roomMode,
5433
+ serverUrl,
5434
+ ...params ? { params } : {},
5435
+ ...token ? { token } : {}
5436
+ }
5437
+ };
5438
+ }
5439
+ function resolveProviderExtension(candidate) {
5440
+ const adapterId = normalizeNonEmptyString(candidate.adapterId);
5441
+ if (!adapterId) return {
5442
+ ok: false,
5443
+ reason: "invalid-adapter-id",
5444
+ message: "SuperDoc v2 provider extensions require a non-empty v2Collaboration.adapterId."
5445
+ };
5446
+ const documentId = normalizeNonEmptyString(candidate.documentId);
5447
+ if (!documentId) return {
5448
+ ok: false,
5449
+ reason: "invalid-document-id",
5450
+ message: "SuperDoc v2 provider extensions require a non-empty v2Collaboration.documentId."
5451
+ };
5452
+ const roomMode = normalizeRoomMode(candidate.roomMode);
5453
+ if (!roomMode) return invalidRoomMode();
5454
+ if (Object.prototype.hasOwnProperty.call(candidate, "providerOptions")) try {
5455
+ structuredClone(candidate.providerOptions);
5456
+ } catch {
5457
+ return {
5458
+ ok: false,
5459
+ reason: "invalid-provider-options",
5460
+ message: "SuperDoc v2 provider extension options must be structured-clone-safe."
5461
+ };
5462
+ }
5463
+ const token = typeof candidate.token === "function" ? candidate.token : normalizeNonEmptyString(candidate.token);
5464
+ return {
5465
+ ok: true,
5466
+ target: {
5467
+ providerFamily: "extension",
5468
+ adapterId,
5469
+ documentId,
5470
+ roomMode,
5471
+ ...Object.prototype.hasOwnProperty.call(candidate, "providerOptions") ? { providerOptions: candidate.providerOptions } : {},
5472
+ ...token ? { token } : {}
5473
+ }
5474
+ };
5475
+ }
5476
+ /** Resolve the Liveblocks family (exactly one of publicApiKey / authEndpoint). */
5477
+ function resolveLiveblocksFamily(candidate, authEndpointBaseUrl) {
5478
+ const documentId = normalizeNonEmptyString(candidate.documentId ?? candidate.roomId);
5479
+ if (!documentId) return {
5480
+ ok: false,
5481
+ reason: "invalid-document-id",
5482
+ message: "SuperDoc v2 collaboration requires a non-empty collaboration.documentId (or roomId) for the \"liveblocks\" provider."
5483
+ };
5484
+ const publicApiKey = normalizeNonEmptyString(candidate.publicApiKey);
5485
+ const roomMode = normalizeRoomMode(candidate.roomMode);
5486
+ if (!roomMode) return invalidRoomMode();
5487
+ const authEndpointRaw = candidate.authEndpoint;
5488
+ const hasAuthEndpoint = typeof authEndpointRaw === "string" && authEndpointRaw.length > 0;
5489
+ if (!publicApiKey && !hasAuthEndpoint) return {
5490
+ ok: false,
5491
+ reason: "missing-auth",
5492
+ message: "SuperDoc v2 Liveblocks collaboration requires exactly one auth mode: a publicApiKey or an authEndpoint. None was provided."
5493
+ };
5494
+ if (publicApiKey && hasAuthEndpoint) return {
5495
+ ok: false,
5496
+ reason: "mixed-auth",
5497
+ message: "SuperDoc v2 Liveblocks collaboration accepts exactly one auth mode; pass either publicApiKey or authEndpoint, not both."
5498
+ };
5499
+ if (publicApiKey) return {
5500
+ ok: true,
5501
+ target: {
5502
+ providerFamily: "liveblocks",
5503
+ documentId,
5504
+ roomMode,
5505
+ publicApiKey
5506
+ }
5507
+ };
5508
+ const authEndpoint = normalizeHttpUrl(authEndpointRaw, authEndpointBaseUrl);
5509
+ if (!authEndpoint) return {
5510
+ ok: false,
5511
+ reason: "invalid-auth-endpoint",
5512
+ message: "SuperDoc v2 Liveblocks collaboration requires a valid http(s) authEndpoint URL (received: <redacted>)."
5513
+ };
5514
+ return {
5515
+ ok: true,
5516
+ target: {
5517
+ providerFamily: "liveblocks",
5518
+ documentId,
5519
+ roomMode,
5520
+ authEndpoint
5521
+ }
5522
+ };
5523
+ }
5524
+ /**
5525
+ * Resolve a constructor-time or upgrade-time collaboration request into a
5526
+ * supported v2 room target, or a stable redacted diagnostic.
5527
+ */
5528
+ function resolveV2CollaborationTarget(input) {
5529
+ const { legacyCollaboration, documentType, documentCount, authEndpointBaseUrl } = input;
5530
+ const v2Collaboration = readCollaborationConfig(input);
5531
+ if (typeof documentCount === "number" && documentCount > 1) return {
5532
+ ok: false,
5533
+ reason: "unsupported-multi-document",
5534
+ message: `SuperDoc v2 collaboration supports exactly one document per room; received ${documentCount}.`
5535
+ };
5536
+ if (documentType != null && documentType !== "application/vnd.openxmlformats-officedocument.wordprocessingml.document") return {
5537
+ ok: false,
5538
+ reason: "unsupported-document-type",
5539
+ message: "SuperDoc v2 collaboration supports DOCX documents only."
5540
+ };
5541
+ if (!(v2Collaboration != null && typeof v2Collaboration === "object")) {
5542
+ const family = detectUnsupportedLegacyFamily(legacyCollaboration);
5543
+ if (family) {
5544
+ const reason = family === "external-ydoc-provider" ? "unsupported-legacy-provider" : "unsupported-provider-family";
5545
+ const redactedUrl = redactCollaborationUrl(legacyCollaboration?.url);
5546
+ return {
5547
+ ok: false,
5548
+ reason,
5549
+ message: family === "external-ydoc-provider" ? "SuperDoc v2 collaboration cannot use an external { ydoc, provider } pair. Provide a collaboration target (e.g. { providerType, documentId, url }) instead." : `SuperDoc v2 collaboration does not accept "${family}" through the legacy modules.collaboration block (server: ${redactedUrl}). Configure it as a document.collaboration target ({ providerType: "${family}", documentId, ... }) instead.`
5550
+ };
5551
+ }
5552
+ return {
5553
+ ok: false,
5554
+ reason: "missing-target",
5555
+ message: "SuperDoc v2 collaboration requires a collaboration target ({ documentId, serverUrl } or { providerType, ... }). None was provided."
5556
+ };
5557
+ }
5558
+ const candidate = v2Collaboration;
5559
+ if (Object.prototype.hasOwnProperty.call(candidate, "createIfMissing")) return {
5560
+ ok: false,
5561
+ reason: "invalid-room-mode",
5562
+ message: "SuperDoc v2 collaboration createIfMissing has been removed. Use roomMode: \"create\" for creation or roomMode: \"join\" for normal opens."
5563
+ };
5564
+ if (candidate.ydoc != null || candidate.provider != null) return {
5565
+ ok: false,
5566
+ reason: "unsupported-legacy-provider",
5567
+ message: "SuperDoc v2 collaboration cannot use an external { ydoc, provider } pair. v2 owns its provider; pass a collaboration target ({ providerType, documentId, serverUrl | publicApiKey | authEndpoint }) instead."
5568
+ };
5569
+ const providerType = readProviderType(candidate);
5570
+ if (providerType === null || providerType === "y-websocket") return resolveWebsocketFamily("y-websocket", candidate);
5571
+ if (providerType === "hocuspocus") return resolveWebsocketFamily("hocuspocus", candidate);
5572
+ if (providerType === "liveblocks") return resolveLiveblocksFamily(candidate, authEndpointBaseUrl);
5573
+ if (providerType === "extension") return resolveProviderExtension(candidate);
5574
+ return {
5575
+ ok: false,
5576
+ reason: "unsupported-provider-family",
5577
+ message: `SuperDoc v2 collaboration does not support the "${providerType}" provider family. Supported families are y-websocket, hocuspocus, liveblocks, and extension.`
5578
+ };
5579
+ }
5580
+ //#endregion
5313
5581
  //#region src/core/helpers/file.js
5314
5582
  /**
5315
5583
  * @typedef {Object} UploadWrapper
@@ -5433,6 +5701,14 @@ var GENERIC_BINARY_MIME = "application/octet-stream";
5433
5701
  * @returns {DocumentEntry|any} A normalized entry, or the original value when it is unsupported or unchanged
5434
5702
  */
5435
5703
  var normalizeDocumentEntry = (entry) => {
5704
+ if (entry && typeof entry === "object" && Object.prototype.hasOwnProperty.call(entry, "collaboration")) {
5705
+ const source = { ...entry };
5706
+ delete source.collaboration;
5707
+ entry = {
5708
+ ...source,
5709
+ v2Collaboration: readCollaborationConfig(entry)
5710
+ };
5711
+ }
5436
5712
  if (isDocumentByteSource(entry)) return {
5437
5713
  type: DOCX,
5438
5714
  data: documentByteSourceToUint8Array(entry),
@@ -5454,6 +5730,7 @@ var normalizeDocumentEntry = (entry) => {
5454
5730
  });
5455
5731
  else if (hasGenericType && inferredType && typeof Blob === "function" && maybeFile instanceof Blob) data = new Blob([maybeFile], { type });
5456
5732
  return {
5733
+ ...entry.v2Collaboration !== void 0 ? { v2Collaboration: entry.v2Collaboration } : {},
5457
5734
  type,
5458
5735
  data,
5459
5736
  name
@@ -20440,228 +20717,31 @@ function unmarkRuntimeRoot(root) {
20440
20717
  root.removeAttribute(RUNTIME_ROOT_ATTRIBUTE);
20441
20718
  }
20442
20719
  //#endregion
20443
- //#region src/core/collaboration/resolve-v2-collaboration-target.ts
20444
- /**
20445
- * Redact a connection URL for safe inclusion in diagnostics and artifacts.
20446
- *
20447
- * Strips the query string, fragment, and any embedded credentials (userinfo)
20448
- * because those commonly carry auth tokens. Falls back to a coarse string scrub
20449
- * when the value is not a parseable absolute URL so a malformed value with an
20450
- * inline `?token=...` still cannot leak.
20451
- */
20452
- function redactCollaborationUrl(url) {
20453
- if (typeof url !== "string" || url.length === 0) return "<none>";
20454
- try {
20455
- const parsed = new URL(url);
20456
- parsed.search = "";
20457
- parsed.hash = "";
20458
- parsed.username = "";
20459
- parsed.password = "";
20460
- const redactedQuery = url.includes("?") ? "?<redacted>" : "";
20461
- return `${parsed.toString().replace(/\?$/, "")}${redactedQuery}`;
20462
- } catch {
20463
- const withoutCredentials = url.replace(/\/\/[^/@]+@/, "//");
20464
- const cut = withoutCredentials.search(/[?#]/);
20465
- if (cut === -1) return withoutCredentials;
20466
- return `${withoutCredentials.slice(0, cut)}?<redacted>`;
20467
- }
20468
- }
20469
- function normalizeNonEmptyString(value) {
20470
- return typeof value === "string" && value.length > 0 ? value : null;
20471
- }
20472
- function normalizeWebsocketUrl(value) {
20473
- if (typeof value !== "string" || value.length === 0) return null;
20474
- try {
20475
- const parsed = new URL(value);
20476
- return parsed.protocol === "ws:" || parsed.protocol === "wss:" ? value : null;
20477
- } catch {
20478
- return null;
20479
- }
20480
- }
20481
- function normalizeHttpUrl(value, baseUrl) {
20482
- if (typeof value !== "string") return null;
20483
- const normalized = value.trim();
20484
- if (normalized.length === 0) return null;
20485
- try {
20486
- const parsed = new URL(normalized);
20487
- return parsed.protocol === "http:" || parsed.protocol === "https:" ? normalized : null;
20488
- } catch {
20489
- if (typeof baseUrl !== "string" || baseUrl.trim().length === 0) return null;
20490
- try {
20491
- const parsed = new URL(normalized, baseUrl);
20492
- return parsed.protocol === "http:" || parsed.protocol === "https:" ? parsed.href : null;
20493
- } catch {
20494
- return null;
20495
- }
20496
- }
20497
- }
20498
- function normalizeParams(value) {
20499
- if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
20500
- const params = {};
20501
- for (const [key, raw] of Object.entries(value)) if (typeof raw === "string") params[key] = raw;
20502
- return Object.keys(params).length > 0 ? params : void 0;
20503
- }
20504
- function normalizeRoomMode(value) {
20505
- if (value === void 0) return "join";
20506
- return value === "join" || value === "create" ? value : null;
20507
- }
20508
- function invalidRoomMode() {
20509
- return {
20510
- ok: false,
20511
- reason: "invalid-room-mode",
20512
- message: "SuperDoc v2 collaboration roomMode must be either \"join\" or \"create\"."
20513
- };
20514
- }
20515
- /** Provider-family token recognized on a v2Collaboration config object. */
20516
- function readProviderType(candidate) {
20517
- const raw = candidate.providerType;
20518
- return typeof raw === "string" && raw.length > 0 ? raw.toLowerCase() : null;
20519
- }
20520
- /**
20521
- * Detect whether a legacy collaboration block names a provider family that the
20522
- * shipped single-doc v2 runtime cannot drive. Returns the offending family name
20523
- * (for diagnostics) or `null` when the block carries no recognizable family.
20524
- */
20525
- function detectUnsupportedLegacyFamily(legacy) {
20526
- if (!legacy || typeof legacy !== "object") return null;
20527
- const providerType = typeof legacy.providerType === "string" ? legacy.providerType.toLowerCase() : "";
20528
- if (providerType === "hocuspocus") return "hocuspocus";
20529
- if (providerType === "liveblocks") return "liveblocks";
20530
- if (providerType === "superdoc") return "superdoc";
20531
- if (legacy.ydoc != null || legacy.provider != null) return "external-ydoc-provider";
20532
- return null;
20533
- }
20534
- /** Resolve a websocket-backed family (y-websocket / Hocuspocus). */
20535
- function resolveWebsocketFamily(family, candidate) {
20536
- const documentId = normalizeNonEmptyString(candidate.documentId);
20537
- if (!documentId) return {
20538
- ok: false,
20539
- reason: "invalid-document-id",
20540
- message: `SuperDoc v2 collaboration requires a non-empty v2Collaboration.documentId for the "${family}" provider.`
20541
- };
20542
- const rawUrl = candidate.url ?? candidate.serverUrl;
20543
- const serverUrl = normalizeWebsocketUrl(rawUrl);
20544
- if (!serverUrl) return {
20545
- ok: false,
20546
- reason: "invalid-server-url",
20547
- message: `SuperDoc v2 collaboration requires a valid ws:// or wss:// URL for the "${family}" provider (received: ${redactCollaborationUrl(rawUrl)}).`
20548
- };
20549
- const params = normalizeParams(candidate.params);
20550
- const token = family === "hocuspocus" ? normalizeNonEmptyString(candidate.token) : null;
20551
- const roomMode = normalizeRoomMode(candidate.roomMode);
20552
- if (!roomMode) return invalidRoomMode();
20553
- return {
20554
- ok: true,
20555
- target: {
20556
- providerFamily: family,
20557
- documentId,
20558
- roomMode,
20559
- serverUrl,
20560
- ...params ? { params } : {},
20561
- ...token ? { token } : {}
20562
- }
20563
- };
20564
- }
20565
- /** Resolve the Liveblocks family (exactly one of publicApiKey / authEndpoint). */
20566
- function resolveLiveblocksFamily(candidate, authEndpointBaseUrl) {
20567
- const documentId = normalizeNonEmptyString(candidate.documentId ?? candidate.roomId);
20568
- if (!documentId) return {
20569
- ok: false,
20570
- reason: "invalid-document-id",
20571
- message: "SuperDoc v2 collaboration requires a non-empty v2Collaboration.documentId (or roomId) for the \"liveblocks\" provider."
20572
- };
20573
- const publicApiKey = normalizeNonEmptyString(candidate.publicApiKey);
20574
- const roomMode = normalizeRoomMode(candidate.roomMode);
20575
- if (!roomMode) return invalidRoomMode();
20576
- const authEndpointRaw = candidate.authEndpoint;
20577
- const hasAuthEndpoint = typeof authEndpointRaw === "string" && authEndpointRaw.length > 0;
20578
- if (!publicApiKey && !hasAuthEndpoint) return {
20579
- ok: false,
20580
- reason: "missing-auth",
20581
- message: "SuperDoc v2 Liveblocks collaboration requires exactly one auth mode: a publicApiKey or an authEndpoint. None was provided."
20582
- };
20583
- if (publicApiKey && hasAuthEndpoint) return {
20584
- ok: false,
20585
- reason: "mixed-auth",
20586
- message: "SuperDoc v2 Liveblocks collaboration accepts exactly one auth mode; pass either publicApiKey or authEndpoint, not both."
20587
- };
20588
- if (publicApiKey) return {
20589
- ok: true,
20590
- target: {
20591
- providerFamily: "liveblocks",
20592
- documentId,
20593
- roomMode,
20594
- publicApiKey
20595
- }
20596
- };
20597
- const authEndpoint = normalizeHttpUrl(authEndpointRaw, authEndpointBaseUrl);
20598
- if (!authEndpoint) return {
20599
- ok: false,
20600
- reason: "invalid-auth-endpoint",
20601
- message: "SuperDoc v2 Liveblocks collaboration requires a valid http(s) authEndpoint URL (received: <redacted>)."
20602
- };
20603
- return {
20604
- ok: true,
20605
- target: {
20606
- providerFamily: "liveblocks",
20607
- documentId,
20608
- roomMode,
20609
- authEndpoint
20610
- }
20611
- };
20612
- }
20613
- /**
20614
- * Resolve a constructor-time or upgrade-time collaboration request into a
20615
- * supported v2 room target, or a stable redacted diagnostic.
20616
- */
20617
- function resolveV2CollaborationTarget(input) {
20618
- const { v2Collaboration, legacyCollaboration, documentType, documentCount, authEndpointBaseUrl } = input;
20619
- if (typeof documentCount === "number" && documentCount > 1) return {
20620
- ok: false,
20621
- reason: "unsupported-multi-document",
20622
- message: `SuperDoc v2 collaboration supports exactly one document per room; received ${documentCount}.`
20623
- };
20624
- if (documentType != null && documentType !== "application/vnd.openxmlformats-officedocument.wordprocessingml.document") return {
20625
- ok: false,
20626
- reason: "unsupported-document-type",
20627
- message: "SuperDoc v2 collaboration supports DOCX documents only."
20628
- };
20629
- if (!(v2Collaboration != null && typeof v2Collaboration === "object")) {
20630
- const family = detectUnsupportedLegacyFamily(legacyCollaboration);
20631
- if (family) {
20632
- const reason = family === "external-ydoc-provider" ? "unsupported-legacy-provider" : "unsupported-provider-family";
20633
- const redactedUrl = redactCollaborationUrl(legacyCollaboration?.url);
20634
- return {
20635
- ok: false,
20636
- reason,
20637
- message: family === "external-ydoc-provider" ? "SuperDoc v2 collaboration cannot use an external { ydoc, provider } pair. Provide a v2Collaboration target (e.g. { providerType, documentId, url }) instead." : `SuperDoc v2 collaboration does not accept "${family}" through the legacy modules.collaboration block (server: ${redactedUrl}). Configure it as a v2Collaboration target ({ providerType: "${family}", documentId, ... }) instead.`
20638
- };
20639
- }
20640
- return {
20641
- ok: false,
20642
- reason: "missing-target",
20643
- message: "SuperDoc v2 collaboration requires a v2Collaboration target ({ documentId, serverUrl } or { providerType, ... }). None was provided."
20644
- };
20720
+ //#region src/core/collaboration/collaboration-exception.ts
20721
+ function createCollaborationException(code, documentId) {
20722
+ let collaborationReason;
20723
+ let message;
20724
+ switch (code) {
20725
+ case "collaboration-access-denied":
20726
+ collaborationReason = "access-denied";
20727
+ message = "The collaboration server rejected access to this room.";
20728
+ break;
20729
+ case "collaboration-connection-failed":
20730
+ collaborationReason = "connection-failed";
20731
+ message = "The collaboration connection failed.";
20732
+ break;
20733
+ case "collaboration-sync-timeout":
20734
+ collaborationReason = "sync-timeout";
20735
+ message = "The collaboration room did not finish synchronizing in time.";
20736
+ break;
20737
+ default: return null;
20645
20738
  }
20646
- const candidate = v2Collaboration;
20647
- if (Object.prototype.hasOwnProperty.call(candidate, "createIfMissing")) return {
20648
- ok: false,
20649
- reason: "invalid-room-mode",
20650
- message: "SuperDoc v2 collaboration createIfMissing has been removed. Use roomMode: \"create\" for creation or roomMode: \"join\" for normal opens."
20651
- };
20652
- if (candidate.ydoc != null || candidate.provider != null) return {
20653
- ok: false,
20654
- reason: "unsupported-legacy-provider",
20655
- message: "SuperDoc v2 collaboration cannot use an external { ydoc, provider } pair. v2 owns its provider; pass a v2Collaboration target ({ providerType, documentId, url | publicApiKey | authEndpoint }) instead."
20656
- };
20657
- const providerType = readProviderType(candidate);
20658
- if (providerType === null || providerType === "y-websocket") return resolveWebsocketFamily("y-websocket", candidate);
20659
- if (providerType === "hocuspocus") return resolveWebsocketFamily("hocuspocus", candidate);
20660
- if (providerType === "liveblocks") return resolveLiveblocksFamily(candidate, authEndpointBaseUrl);
20661
20739
  return {
20662
- ok: false,
20663
- reason: "unsupported-provider-family",
20664
- message: `SuperDoc v2 collaboration does not support the "${providerType}" provider family. Supported families are y-websocket, hocuspocus, and liveblocks.`
20740
+ error: new Error(message),
20741
+ code,
20742
+ collaborationReason,
20743
+ documentId,
20744
+ editor: null
20665
20745
  };
20666
20746
  }
20667
20747
  //#endregion
@@ -21848,6 +21928,10 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
21848
21928
  const clearV2RuntimeRegistration = (documentId) => {
21849
21929
  clearV2CommandShortcutBinding(documentId);
21850
21930
  clearV2SessionShortcutBinding(documentId);
21931
+ const document = getDocument(documentId);
21932
+ const provider = document?.provider ?? null;
21933
+ if (provider && proxy.$superdoc.provider === provider) proxy.$superdoc.provider = void 0;
21934
+ if (document && provider?.sendStateless) document.provider = null;
21851
21935
  const entry = v2Runtimes.get(documentId);
21852
21936
  if (!entry) return;
21853
21937
  proxy.$superdoc.unregisterEditorRuntime(entry.runtimeId);
@@ -22036,7 +22120,7 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
22036
22120
  clearV2EditorFailure(payload.documentId ?? null);
22037
22121
  clearV2AuthorRequired(payload.documentId ?? null);
22038
22122
  clearV2EditRejected(payload.documentId ?? null);
22039
- const { host, mount, documentId, capabilities, editCommands, bindEditShortcuts, bindSessionShortcuts, commentsAdapter, trackedChangesAdapter, contextMenu, documentApi, documentMutationReadiness, documentApiUnavailableReason, pageMetrics, pageLayout, pageFurniture, presence, lock, fonts, replaceFile, upgradeToCollaboration, documentOpenToken } = payload;
22123
+ 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;
22040
22124
  documentOpenTelemetry?.trackDocumentOpen(documentOpenToken ?? null, documentId ?? null);
22041
22125
  const saveV2Bytes = async (saveOptions = {}) => {
22042
22126
  if (!host || typeof host.save !== "function") throw new Error("v2-editor: save unavailable");
@@ -22311,6 +22395,7 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
22311
22395
  pageFurniture: pageFurniture ?? null,
22312
22396
  presence: presence ?? null,
22313
22397
  lock: lock ?? null,
22398
+ provider: collaborationProvider ?? null,
22314
22399
  reviewWindow: {
22315
22400
  getDiagnostics: () => v2ReviewWindowController.getDiagnostics(),
22316
22401
  getSnapshot: () => v2ReviewWindowController.getSnapshot?.() ?? null,
@@ -22345,6 +22430,11 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
22345
22430
  proxy.$superdoc.setActiveEditor(facade);
22346
22431
  syncV2EditRejectedActiveDocument();
22347
22432
  }
22433
+ if (collaborationProvider) {
22434
+ const provider = markRaw(collaborationProvider);
22435
+ proxy.$superdoc.provider = provider;
22436
+ if (doc) doc.provider = provider;
22437
+ }
22348
22438
  proxy.$superdoc.broadcastEditorCreate(facade);
22349
22439
  installV2CommandShortcutBinding({
22350
22440
  documentId,
@@ -22862,7 +22952,7 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
22862
22952
  case "worker-init-failed": return "SuperDoc could not load the document editor because the browser worker failed to start.";
22863
22953
  case "input-too-large-for-inline-review": return "SuperDoc could not load the document editor because this document is too large to open without the browser worker.";
22864
22954
  case "collaboration-unsupported-huge-document": return "SuperDoc could not load the document editor because large documents cannot be opened with collaboration enabled yet.";
22865
- case "collaboration-v1-config-unsupported": return "SuperDoc v2 cannot use modules.collaboration because it is the SuperDoc v1 collaboration API. SuperDoc did not attach the provider or change the document. Configure Document.v2Collaboration with a v2 room instead.";
22955
+ case "collaboration-v1-config-unsupported": return "SuperDoc v2 cannot use modules.collaboration because it is the SuperDoc v1 collaboration API. SuperDoc did not attach the provider or change the document. Configure Document.collaboration with a v2 room instead.";
22866
22956
  case "collaboration-room-format-unsupported": return "SuperDoc v2 cannot open this collaboration state because it is not stored in the SuperDoc v2 room format. No changes were made.";
22867
22957
  case "collaboration-room-format-conflict": return "SuperDoc v2 found conflicting room formats in one collaboration document. No changes were made.";
22868
22958
  case "collaboration-room-corrupt": return "SuperDoc v2 found a structurally invalid collaboration room. No changes were made.";
@@ -22880,7 +22970,8 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
22880
22970
  const reason = typeof payload?.reason === "string" && payload.reason.length > 0 ? payload.reason : "open-failed";
22881
22971
  const detail = normalizeV2EditorFailureDetail(payload?.detail);
22882
22972
  const documentId = typeof payload?.documentId === "string" && payload.documentId.length > 0 ? payload.documentId : null;
22883
- const message = getV2EditorFailureMessage(reason);
22973
+ const collaborationException = createCollaborationException(reason, documentId);
22974
+ const message = collaborationException?.error.message ?? getV2EditorFailureMessage(reason);
22884
22975
  const workerFailure = payload?.workerFailure && typeof payload.workerFailure === "object" ? payload.workerFailure : null;
22885
22976
  setV2EditorFailure(documentId, {
22886
22977
  reason,
@@ -22896,7 +22987,7 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
22896
22987
  };
22897
22988
  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);
22898
22989
  else console.error(`[SuperDoc] ${message}`, logContext);
22899
- proxy.$superdoc.emit("exception", {
22990
+ proxy.$superdoc.emit("exception", collaborationException ?? {
22900
22991
  error: new Error(message),
22901
22992
  code: reason,
22902
22993
  ...documentId ? { documentId } : {},
@@ -24120,7 +24211,7 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
24120
24211
  ], 38);
24121
24212
  };
24122
24213
  }
24123
- }, [["__scopeId", "data-v-0d27f262"]]);
24214
+ }, [["__scopeId", "data-v-ebe9a1fb"]]);
24124
24215
  //#endregion
24125
24216
  //#region src/core/create-app.js
24126
24217
  var PINIA_DEVTOOLS_SETUP_EVENT = "devtools-plugin:setup";
@@ -39558,7 +39649,7 @@ var OverflowMenu_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
39558
39649
  const emit = __emit;
39559
39650
  const props = __props;
39560
39651
  const isOverflowMenuOpened = computed(() => props.toolbarItem.expand.value);
39561
- const hasOpenDropdown = ref(false);
39652
+ const hasOpenDropdown = computed(() => props.overflowItems.some((item) => item.type === "dropdown" && unref(item.expand)));
39562
39653
  const overflowToolbarItem = computed(() => ({
39563
39654
  ...props.toolbarItem,
39564
39655
  active: isOverflowMenuOpened.value
@@ -39604,8 +39695,7 @@ var OverflowMenu_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
39604
39695
  "ui-font-family": props.uiFontFamily,
39605
39696
  "from-overflow": "",
39606
39697
  onMousedown: unref(preventEditorFocusTransfer),
39607
- onCommand: handleCommand,
39608
- onDropdownUpdateShow: _cache[0] || (_cache[0] = ($event) => hasOpenDropdown.value = $event)
39698
+ onCommand: handleCommand
39609
39699
  }, null, 8, [
39610
39700
  "toolbar-items",
39611
39701
  "ui-font-family",
@@ -39620,7 +39710,7 @@ var OverflowMenu_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
39620
39710
  ]);
39621
39711
  };
39622
39712
  }
39623
- }, [["__scopeId", "data-v-975959f9"]]);
39713
+ }, [["__scopeId", "data-v-5f8ee279"]]);
39624
39714
  //#endregion
39625
39715
  //#region src/internal/toolbar/built-in/font-typeahead.js
39626
39716
  /**
@@ -44932,10 +45022,6 @@ function contentControlSelectionKey(selection) {
44932
45022
  function isV2ActiveEditorFacade(editor) {
44933
45023
  return Boolean(editor && typeof editor === "object" && editor.editorVersion === 2);
44934
45024
  }
44935
- function isV2FailClosedExportError(error) {
44936
- const code = error && typeof error === "object" ? error.code : null;
44937
- return code === "comment-export-missing-story-reference" || code === "v2-worker-comment-export-mode-unsupported";
44938
- }
44939
45025
  function normalizeActiveEditorDocumentId(documentId) {
44940
45026
  return typeof documentId === "string" && documentId.length > 0 ? documentId : null;
44941
45027
  }
@@ -45287,7 +45373,7 @@ var SuperDoc = class extends import_eventemitter3.default {
45287
45373
  this.config.colors = shuffleArray(this.config.colors);
45288
45374
  this.userColorMap = /* @__PURE__ */ new Map();
45289
45375
  this.colorIndex = 0;
45290
- this.version = "2.13.0-next.1";
45376
+ this.version = "2.13.0-next.10";
45291
45377
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
45292
45378
  this.superdocId = config.superdocId || v4();
45293
45379
  this.colors = this.config.colors ?? [];
@@ -45941,6 +46027,14 @@ var SuperDoc = class extends import_eventemitter3.default {
45941
46027
  storeDoc.v2Collaboration = value;
45942
46028
  }
45943
46029
  #toV2CollaborationConfig(target) {
46030
+ if (target.providerFamily === "extension") return {
46031
+ providerType: "extension",
46032
+ adapterId: target.adapterId,
46033
+ documentId: target.documentId,
46034
+ roomMode: target.roomMode,
46035
+ ...target.providerOptions !== void 0 ? { providerOptions: target.providerOptions } : {},
46036
+ ...target.token ? { token: target.token } : {}
46037
+ };
45944
46038
  if (target.providerFamily === "liveblocks") return {
45945
46039
  providerType: "liveblocks",
45946
46040
  documentId: target.documentId,
@@ -46149,8 +46243,10 @@ var SuperDoc = class extends import_eventemitter3.default {
46149
46243
  ydoc: options.ydoc,
46150
46244
  provider: options.provider
46151
46245
  } : collaborationModule ? { ...collaborationModule } : null;
46246
+ const v2Collaboration = options.v2Collaboration ?? this.#unwrapMaybeRef(configDoc.v2Collaboration) ?? collaborationModule?.v2Collaboration ?? collaborationModule?.v2 ?? null;
46152
46247
  const resolution = resolveV2CollaborationTarget({
46153
- v2Collaboration: options.v2Collaboration ?? this.#unwrapMaybeRef(configDoc.v2Collaboration) ?? collaborationModule?.v2Collaboration ?? collaborationModule?.v2 ?? null,
46248
+ collaboration: options.collaboration,
46249
+ v2Collaboration,
46154
46250
  legacyCollaboration,
46155
46251
  documentType: DOCX,
46156
46252
  documentCount: cfg.documents.length,
@@ -47362,7 +47458,7 @@ var SuperDoc = class extends import_eventemitter3.default {
47362
47458
  error,
47363
47459
  document: doc
47364
47460
  });
47365
- if (isV2Editor && (commentsType === "clean" || isV2FailClosedExportError(error))) throw error;
47461
+ if (isV2Editor) throw error;
47366
47462
  }
47367
47463
  return fallbackDocx();
47368
47464
  });