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
package/dist/superdoc.cjs CHANGED
@@ -4,7 +4,7 @@ const require_blank_docx = require("./chunks/blank-docx-BuFAbRjs.cjs");
4
4
  const require_eventemitter3 = require("./chunks/eventemitter3-C_TAnXOl.cjs");
5
5
  const require_uuid = require("./chunks/uuid-BhG0ngwk.cjs");
6
6
  const require_jszip = require("./chunks/jszip-D8mAFF-r.cjs");
7
- const require_create_super_doc_ui = require("./chunks/create-super-doc-ui-BWWWNPP8.cjs");
7
+ const require_create_super_doc_ui = require("./chunks/create-super-doc-ui-mHK2pqj3.cjs");
8
8
  const require__plugin_vue_export_helper = require("./chunks/_plugin-vue_export-helper-SDR04tiH.cjs");
9
9
  const require_constants = require("./chunks/constants-DpXuDx_g.cjs");
10
10
  let vue = require("vue");
@@ -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.13.0-next.1";
319
+ return "2.13.0-next.10";
320
320
  } catch {
321
321
  return "unknown";
322
322
  }
@@ -5311,6 +5311,274 @@ function storeToRefs(store) {
5311
5311
  return refs;
5312
5312
  }
5313
5313
  //#endregion
5314
+ //#region src/core/collaboration/resolve-v2-collaboration-target.ts
5315
+ /** Select the public spelling before validation; do not merge settings from different rooms. */
5316
+ function readCollaborationConfig(input) {
5317
+ return input.collaboration !== void 0 ? input.collaboration : input.v2Collaboration;
5318
+ }
5319
+ /**
5320
+ * Redact a connection URL for safe inclusion in diagnostics and artifacts.
5321
+ *
5322
+ * Strips the query string, fragment, and any embedded credentials (userinfo)
5323
+ * because those commonly carry auth tokens. Falls back to a coarse string scrub
5324
+ * when the value is not a parseable absolute URL so a malformed value with an
5325
+ * inline `?token=...` still cannot leak.
5326
+ */
5327
+ function redactCollaborationUrl(url) {
5328
+ if (typeof url !== "string" || url.length === 0) return "<none>";
5329
+ try {
5330
+ const parsed = new URL(url);
5331
+ parsed.search = "";
5332
+ parsed.hash = "";
5333
+ parsed.username = "";
5334
+ parsed.password = "";
5335
+ const redactedQuery = url.includes("?") ? "?<redacted>" : "";
5336
+ return `${parsed.toString().replace(/\?$/, "")}${redactedQuery}`;
5337
+ } catch {
5338
+ const withoutCredentials = url.replace(/\/\/[^/@]+@/, "//");
5339
+ const cut = withoutCredentials.search(/[?#]/);
5340
+ if (cut === -1) return withoutCredentials;
5341
+ return `${withoutCredentials.slice(0, cut)}?<redacted>`;
5342
+ }
5343
+ }
5344
+ function normalizeNonEmptyString(value) {
5345
+ return typeof value === "string" && value.length > 0 ? value : null;
5346
+ }
5347
+ function normalizeWebsocketUrl(value) {
5348
+ if (typeof value !== "string" || value.length === 0) return null;
5349
+ try {
5350
+ const parsed = new URL(value);
5351
+ return parsed.protocol === "ws:" || parsed.protocol === "wss:" ? value : null;
5352
+ } catch {
5353
+ return null;
5354
+ }
5355
+ }
5356
+ function normalizeHttpUrl(value, baseUrl) {
5357
+ if (typeof value !== "string") return null;
5358
+ const normalized = value.trim();
5359
+ if (normalized.length === 0) return null;
5360
+ try {
5361
+ const parsed = new URL(normalized);
5362
+ return parsed.protocol === "http:" || parsed.protocol === "https:" ? normalized : null;
5363
+ } catch {
5364
+ if (typeof baseUrl !== "string" || baseUrl.trim().length === 0) return null;
5365
+ try {
5366
+ const parsed = new URL(normalized, baseUrl);
5367
+ return parsed.protocol === "http:" || parsed.protocol === "https:" ? parsed.href : null;
5368
+ } catch {
5369
+ return null;
5370
+ }
5371
+ }
5372
+ }
5373
+ function normalizeParams(value) {
5374
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
5375
+ const params = {};
5376
+ for (const [key, raw] of Object.entries(value)) if (typeof raw === "string") params[key] = raw;
5377
+ return Object.keys(params).length > 0 ? params : void 0;
5378
+ }
5379
+ function normalizeRoomMode(value) {
5380
+ if (value === void 0) return "join";
5381
+ return value === "join" || value === "create" ? value : null;
5382
+ }
5383
+ function invalidRoomMode() {
5384
+ return {
5385
+ ok: false,
5386
+ reason: "invalid-room-mode",
5387
+ message: "SuperDoc v2 collaboration roomMode must be either \"join\" or \"create\"."
5388
+ };
5389
+ }
5390
+ /** Provider-family token recognized on a v2Collaboration config object. */
5391
+ function readProviderType(candidate) {
5392
+ const raw = candidate.providerType;
5393
+ return typeof raw === "string" && raw.length > 0 ? raw.toLowerCase() : null;
5394
+ }
5395
+ /**
5396
+ * Detect whether a legacy collaboration block names a provider family that the
5397
+ * shipped single-doc v2 runtime cannot drive. Returns the offending family name
5398
+ * (for diagnostics) or `null` when the block carries no recognizable family.
5399
+ */
5400
+ function detectUnsupportedLegacyFamily(legacy) {
5401
+ if (!legacy || typeof legacy !== "object") return null;
5402
+ const providerType = typeof legacy.providerType === "string" ? legacy.providerType.toLowerCase() : "";
5403
+ if (providerType === "hocuspocus") return "hocuspocus";
5404
+ if (providerType === "liveblocks") return "liveblocks";
5405
+ if (providerType === "superdoc") return "superdoc";
5406
+ if (legacy.ydoc != null || legacy.provider != null) return "external-ydoc-provider";
5407
+ return null;
5408
+ }
5409
+ /** Resolve a websocket-backed family (y-websocket / Hocuspocus). */
5410
+ function resolveWebsocketFamily(family, candidate) {
5411
+ const documentId = normalizeNonEmptyString(candidate.documentId);
5412
+ if (!documentId) return {
5413
+ ok: false,
5414
+ reason: "invalid-document-id",
5415
+ message: `SuperDoc v2 collaboration requires a non-empty collaboration.documentId for the "${family}" provider.`
5416
+ };
5417
+ const rawUrl = candidate.url ?? candidate.serverUrl;
5418
+ const serverUrl = normalizeWebsocketUrl(rawUrl);
5419
+ if (!serverUrl) return {
5420
+ ok: false,
5421
+ reason: "invalid-server-url",
5422
+ message: `SuperDoc v2 collaboration requires a valid ws:// or wss:// URL for the "${family}" provider (received: ${redactCollaborationUrl(rawUrl)}).`
5423
+ };
5424
+ const params = normalizeParams(candidate.params);
5425
+ const token = family === "hocuspocus" && typeof candidate.token === "function" ? candidate.token : family === "hocuspocus" ? normalizeNonEmptyString(candidate.token) : null;
5426
+ const roomMode = normalizeRoomMode(candidate.roomMode);
5427
+ if (!roomMode) return invalidRoomMode();
5428
+ return {
5429
+ ok: true,
5430
+ target: {
5431
+ providerFamily: family,
5432
+ documentId,
5433
+ roomMode,
5434
+ serverUrl,
5435
+ ...params ? { params } : {},
5436
+ ...token ? { token } : {}
5437
+ }
5438
+ };
5439
+ }
5440
+ function resolveProviderExtension(candidate) {
5441
+ const adapterId = normalizeNonEmptyString(candidate.adapterId);
5442
+ if (!adapterId) return {
5443
+ ok: false,
5444
+ reason: "invalid-adapter-id",
5445
+ message: "SuperDoc v2 provider extensions require a non-empty v2Collaboration.adapterId."
5446
+ };
5447
+ const documentId = normalizeNonEmptyString(candidate.documentId);
5448
+ if (!documentId) return {
5449
+ ok: false,
5450
+ reason: "invalid-document-id",
5451
+ message: "SuperDoc v2 provider extensions require a non-empty v2Collaboration.documentId."
5452
+ };
5453
+ const roomMode = normalizeRoomMode(candidate.roomMode);
5454
+ if (!roomMode) return invalidRoomMode();
5455
+ if (Object.prototype.hasOwnProperty.call(candidate, "providerOptions")) try {
5456
+ structuredClone(candidate.providerOptions);
5457
+ } catch {
5458
+ return {
5459
+ ok: false,
5460
+ reason: "invalid-provider-options",
5461
+ message: "SuperDoc v2 provider extension options must be structured-clone-safe."
5462
+ };
5463
+ }
5464
+ const token = typeof candidate.token === "function" ? candidate.token : normalizeNonEmptyString(candidate.token);
5465
+ return {
5466
+ ok: true,
5467
+ target: {
5468
+ providerFamily: "extension",
5469
+ adapterId,
5470
+ documentId,
5471
+ roomMode,
5472
+ ...Object.prototype.hasOwnProperty.call(candidate, "providerOptions") ? { providerOptions: candidate.providerOptions } : {},
5473
+ ...token ? { token } : {}
5474
+ }
5475
+ };
5476
+ }
5477
+ /** Resolve the Liveblocks family (exactly one of publicApiKey / authEndpoint). */
5478
+ function resolveLiveblocksFamily(candidate, authEndpointBaseUrl) {
5479
+ const documentId = normalizeNonEmptyString(candidate.documentId ?? candidate.roomId);
5480
+ if (!documentId) return {
5481
+ ok: false,
5482
+ reason: "invalid-document-id",
5483
+ message: "SuperDoc v2 collaboration requires a non-empty collaboration.documentId (or roomId) for the \"liveblocks\" provider."
5484
+ };
5485
+ const publicApiKey = normalizeNonEmptyString(candidate.publicApiKey);
5486
+ const roomMode = normalizeRoomMode(candidate.roomMode);
5487
+ if (!roomMode) return invalidRoomMode();
5488
+ const authEndpointRaw = candidate.authEndpoint;
5489
+ const hasAuthEndpoint = typeof authEndpointRaw === "string" && authEndpointRaw.length > 0;
5490
+ if (!publicApiKey && !hasAuthEndpoint) return {
5491
+ ok: false,
5492
+ reason: "missing-auth",
5493
+ message: "SuperDoc v2 Liveblocks collaboration requires exactly one auth mode: a publicApiKey or an authEndpoint. None was provided."
5494
+ };
5495
+ if (publicApiKey && hasAuthEndpoint) return {
5496
+ ok: false,
5497
+ reason: "mixed-auth",
5498
+ message: "SuperDoc v2 Liveblocks collaboration accepts exactly one auth mode; pass either publicApiKey or authEndpoint, not both."
5499
+ };
5500
+ if (publicApiKey) return {
5501
+ ok: true,
5502
+ target: {
5503
+ providerFamily: "liveblocks",
5504
+ documentId,
5505
+ roomMode,
5506
+ publicApiKey
5507
+ }
5508
+ };
5509
+ const authEndpoint = normalizeHttpUrl(authEndpointRaw, authEndpointBaseUrl);
5510
+ if (!authEndpoint) return {
5511
+ ok: false,
5512
+ reason: "invalid-auth-endpoint",
5513
+ message: "SuperDoc v2 Liveblocks collaboration requires a valid http(s) authEndpoint URL (received: <redacted>)."
5514
+ };
5515
+ return {
5516
+ ok: true,
5517
+ target: {
5518
+ providerFamily: "liveblocks",
5519
+ documentId,
5520
+ roomMode,
5521
+ authEndpoint
5522
+ }
5523
+ };
5524
+ }
5525
+ /**
5526
+ * Resolve a constructor-time or upgrade-time collaboration request into a
5527
+ * supported v2 room target, or a stable redacted diagnostic.
5528
+ */
5529
+ function resolveV2CollaborationTarget(input) {
5530
+ const { legacyCollaboration, documentType, documentCount, authEndpointBaseUrl } = input;
5531
+ const v2Collaboration = readCollaborationConfig(input);
5532
+ if (typeof documentCount === "number" && documentCount > 1) return {
5533
+ ok: false,
5534
+ reason: "unsupported-multi-document",
5535
+ message: `SuperDoc v2 collaboration supports exactly one document per room; received ${documentCount}.`
5536
+ };
5537
+ if (documentType != null && documentType !== "application/vnd.openxmlformats-officedocument.wordprocessingml.document") return {
5538
+ ok: false,
5539
+ reason: "unsupported-document-type",
5540
+ message: "SuperDoc v2 collaboration supports DOCX documents only."
5541
+ };
5542
+ if (!(v2Collaboration != null && typeof v2Collaboration === "object")) {
5543
+ const family = detectUnsupportedLegacyFamily(legacyCollaboration);
5544
+ if (family) {
5545
+ const reason = family === "external-ydoc-provider" ? "unsupported-legacy-provider" : "unsupported-provider-family";
5546
+ const redactedUrl = redactCollaborationUrl(legacyCollaboration?.url);
5547
+ return {
5548
+ ok: false,
5549
+ reason,
5550
+ 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.`
5551
+ };
5552
+ }
5553
+ return {
5554
+ ok: false,
5555
+ reason: "missing-target",
5556
+ message: "SuperDoc v2 collaboration requires a collaboration target ({ documentId, serverUrl } or { providerType, ... }). None was provided."
5557
+ };
5558
+ }
5559
+ const candidate = v2Collaboration;
5560
+ if (Object.prototype.hasOwnProperty.call(candidate, "createIfMissing")) return {
5561
+ ok: false,
5562
+ reason: "invalid-room-mode",
5563
+ message: "SuperDoc v2 collaboration createIfMissing has been removed. Use roomMode: \"create\" for creation or roomMode: \"join\" for normal opens."
5564
+ };
5565
+ if (candidate.ydoc != null || candidate.provider != null) return {
5566
+ ok: false,
5567
+ reason: "unsupported-legacy-provider",
5568
+ 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."
5569
+ };
5570
+ const providerType = readProviderType(candidate);
5571
+ if (providerType === null || providerType === "y-websocket") return resolveWebsocketFamily("y-websocket", candidate);
5572
+ if (providerType === "hocuspocus") return resolveWebsocketFamily("hocuspocus", candidate);
5573
+ if (providerType === "liveblocks") return resolveLiveblocksFamily(candidate, authEndpointBaseUrl);
5574
+ if (providerType === "extension") return resolveProviderExtension(candidate);
5575
+ return {
5576
+ ok: false,
5577
+ reason: "unsupported-provider-family",
5578
+ message: `SuperDoc v2 collaboration does not support the "${providerType}" provider family. Supported families are y-websocket, hocuspocus, liveblocks, and extension.`
5579
+ };
5580
+ }
5581
+ //#endregion
5314
5582
  //#region src/core/helpers/file.js
5315
5583
  /**
5316
5584
  * @typedef {Object} UploadWrapper
@@ -5434,6 +5702,14 @@ var GENERIC_BINARY_MIME = "application/octet-stream";
5434
5702
  * @returns {DocumentEntry|any} A normalized entry, or the original value when it is unsupported or unchanged
5435
5703
  */
5436
5704
  var normalizeDocumentEntry = (entry) => {
5705
+ if (entry && typeof entry === "object" && Object.prototype.hasOwnProperty.call(entry, "collaboration")) {
5706
+ const source = { ...entry };
5707
+ delete source.collaboration;
5708
+ entry = {
5709
+ ...source,
5710
+ v2Collaboration: readCollaborationConfig(entry)
5711
+ };
5712
+ }
5437
5713
  if (isDocumentByteSource(entry)) return {
5438
5714
  type: DOCX,
5439
5715
  data: documentByteSourceToUint8Array(entry),
@@ -5455,6 +5731,7 @@ var normalizeDocumentEntry = (entry) => {
5455
5731
  });
5456
5732
  else if (hasGenericType && inferredType && typeof Blob === "function" && maybeFile instanceof Blob) data = new Blob([maybeFile], { type });
5457
5733
  return {
5734
+ ...entry.v2Collaboration !== void 0 ? { v2Collaboration: entry.v2Collaboration } : {},
5458
5735
  type,
5459
5736
  data,
5460
5737
  name
@@ -20472,228 +20749,31 @@ function unmarkRuntimeRoot(root) {
20472
20749
  root.removeAttribute(RUNTIME_ROOT_ATTRIBUTE);
20473
20750
  }
20474
20751
  //#endregion
20475
- //#region src/core/collaboration/resolve-v2-collaboration-target.ts
20476
- /**
20477
- * Redact a connection URL for safe inclusion in diagnostics and artifacts.
20478
- *
20479
- * Strips the query string, fragment, and any embedded credentials (userinfo)
20480
- * because those commonly carry auth tokens. Falls back to a coarse string scrub
20481
- * when the value is not a parseable absolute URL so a malformed value with an
20482
- * inline `?token=...` still cannot leak.
20483
- */
20484
- function redactCollaborationUrl(url) {
20485
- if (typeof url !== "string" || url.length === 0) return "<none>";
20486
- try {
20487
- const parsed = new URL(url);
20488
- parsed.search = "";
20489
- parsed.hash = "";
20490
- parsed.username = "";
20491
- parsed.password = "";
20492
- const redactedQuery = url.includes("?") ? "?<redacted>" : "";
20493
- return `${parsed.toString().replace(/\?$/, "")}${redactedQuery}`;
20494
- } catch {
20495
- const withoutCredentials = url.replace(/\/\/[^/@]+@/, "//");
20496
- const cut = withoutCredentials.search(/[?#]/);
20497
- if (cut === -1) return withoutCredentials;
20498
- return `${withoutCredentials.slice(0, cut)}?<redacted>`;
20499
- }
20500
- }
20501
- function normalizeNonEmptyString(value) {
20502
- return typeof value === "string" && value.length > 0 ? value : null;
20503
- }
20504
- function normalizeWebsocketUrl(value) {
20505
- if (typeof value !== "string" || value.length === 0) return null;
20506
- try {
20507
- const parsed = new URL(value);
20508
- return parsed.protocol === "ws:" || parsed.protocol === "wss:" ? value : null;
20509
- } catch {
20510
- return null;
20511
- }
20512
- }
20513
- function normalizeHttpUrl(value, baseUrl) {
20514
- if (typeof value !== "string") return null;
20515
- const normalized = value.trim();
20516
- if (normalized.length === 0) return null;
20517
- try {
20518
- const parsed = new URL(normalized);
20519
- return parsed.protocol === "http:" || parsed.protocol === "https:" ? normalized : null;
20520
- } catch {
20521
- if (typeof baseUrl !== "string" || baseUrl.trim().length === 0) return null;
20522
- try {
20523
- const parsed = new URL(normalized, baseUrl);
20524
- return parsed.protocol === "http:" || parsed.protocol === "https:" ? parsed.href : null;
20525
- } catch {
20526
- return null;
20527
- }
20528
- }
20529
- }
20530
- function normalizeParams(value) {
20531
- if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
20532
- const params = {};
20533
- for (const [key, raw] of Object.entries(value)) if (typeof raw === "string") params[key] = raw;
20534
- return Object.keys(params).length > 0 ? params : void 0;
20535
- }
20536
- function normalizeRoomMode(value) {
20537
- if (value === void 0) return "join";
20538
- return value === "join" || value === "create" ? value : null;
20539
- }
20540
- function invalidRoomMode() {
20541
- return {
20542
- ok: false,
20543
- reason: "invalid-room-mode",
20544
- message: "SuperDoc v2 collaboration roomMode must be either \"join\" or \"create\"."
20545
- };
20546
- }
20547
- /** Provider-family token recognized on a v2Collaboration config object. */
20548
- function readProviderType(candidate) {
20549
- const raw = candidate.providerType;
20550
- return typeof raw === "string" && raw.length > 0 ? raw.toLowerCase() : null;
20551
- }
20552
- /**
20553
- * Detect whether a legacy collaboration block names a provider family that the
20554
- * shipped single-doc v2 runtime cannot drive. Returns the offending family name
20555
- * (for diagnostics) or `null` when the block carries no recognizable family.
20556
- */
20557
- function detectUnsupportedLegacyFamily(legacy) {
20558
- if (!legacy || typeof legacy !== "object") return null;
20559
- const providerType = typeof legacy.providerType === "string" ? legacy.providerType.toLowerCase() : "";
20560
- if (providerType === "hocuspocus") return "hocuspocus";
20561
- if (providerType === "liveblocks") return "liveblocks";
20562
- if (providerType === "superdoc") return "superdoc";
20563
- if (legacy.ydoc != null || legacy.provider != null) return "external-ydoc-provider";
20564
- return null;
20565
- }
20566
- /** Resolve a websocket-backed family (y-websocket / Hocuspocus). */
20567
- function resolveWebsocketFamily(family, candidate) {
20568
- const documentId = normalizeNonEmptyString(candidate.documentId);
20569
- if (!documentId) return {
20570
- ok: false,
20571
- reason: "invalid-document-id",
20572
- message: `SuperDoc v2 collaboration requires a non-empty v2Collaboration.documentId for the "${family}" provider.`
20573
- };
20574
- const rawUrl = candidate.url ?? candidate.serverUrl;
20575
- const serverUrl = normalizeWebsocketUrl(rawUrl);
20576
- if (!serverUrl) return {
20577
- ok: false,
20578
- reason: "invalid-server-url",
20579
- message: `SuperDoc v2 collaboration requires a valid ws:// or wss:// URL for the "${family}" provider (received: ${redactCollaborationUrl(rawUrl)}).`
20580
- };
20581
- const params = normalizeParams(candidate.params);
20582
- const token = family === "hocuspocus" ? normalizeNonEmptyString(candidate.token) : null;
20583
- const roomMode = normalizeRoomMode(candidate.roomMode);
20584
- if (!roomMode) return invalidRoomMode();
20585
- return {
20586
- ok: true,
20587
- target: {
20588
- providerFamily: family,
20589
- documentId,
20590
- roomMode,
20591
- serverUrl,
20592
- ...params ? { params } : {},
20593
- ...token ? { token } : {}
20594
- }
20595
- };
20596
- }
20597
- /** Resolve the Liveblocks family (exactly one of publicApiKey / authEndpoint). */
20598
- function resolveLiveblocksFamily(candidate, authEndpointBaseUrl) {
20599
- const documentId = normalizeNonEmptyString(candidate.documentId ?? candidate.roomId);
20600
- if (!documentId) return {
20601
- ok: false,
20602
- reason: "invalid-document-id",
20603
- message: "SuperDoc v2 collaboration requires a non-empty v2Collaboration.documentId (or roomId) for the \"liveblocks\" provider."
20604
- };
20605
- const publicApiKey = normalizeNonEmptyString(candidate.publicApiKey);
20606
- const roomMode = normalizeRoomMode(candidate.roomMode);
20607
- if (!roomMode) return invalidRoomMode();
20608
- const authEndpointRaw = candidate.authEndpoint;
20609
- const hasAuthEndpoint = typeof authEndpointRaw === "string" && authEndpointRaw.length > 0;
20610
- if (!publicApiKey && !hasAuthEndpoint) return {
20611
- ok: false,
20612
- reason: "missing-auth",
20613
- message: "SuperDoc v2 Liveblocks collaboration requires exactly one auth mode: a publicApiKey or an authEndpoint. None was provided."
20614
- };
20615
- if (publicApiKey && hasAuthEndpoint) return {
20616
- ok: false,
20617
- reason: "mixed-auth",
20618
- message: "SuperDoc v2 Liveblocks collaboration accepts exactly one auth mode; pass either publicApiKey or authEndpoint, not both."
20619
- };
20620
- if (publicApiKey) return {
20621
- ok: true,
20622
- target: {
20623
- providerFamily: "liveblocks",
20624
- documentId,
20625
- roomMode,
20626
- publicApiKey
20627
- }
20628
- };
20629
- const authEndpoint = normalizeHttpUrl(authEndpointRaw, authEndpointBaseUrl);
20630
- if (!authEndpoint) return {
20631
- ok: false,
20632
- reason: "invalid-auth-endpoint",
20633
- message: "SuperDoc v2 Liveblocks collaboration requires a valid http(s) authEndpoint URL (received: <redacted>)."
20634
- };
20635
- return {
20636
- ok: true,
20637
- target: {
20638
- providerFamily: "liveblocks",
20639
- documentId,
20640
- roomMode,
20641
- authEndpoint
20642
- }
20643
- };
20644
- }
20645
- /**
20646
- * Resolve a constructor-time or upgrade-time collaboration request into a
20647
- * supported v2 room target, or a stable redacted diagnostic.
20648
- */
20649
- function resolveV2CollaborationTarget(input) {
20650
- const { v2Collaboration, legacyCollaboration, documentType, documentCount, authEndpointBaseUrl } = input;
20651
- if (typeof documentCount === "number" && documentCount > 1) return {
20652
- ok: false,
20653
- reason: "unsupported-multi-document",
20654
- message: `SuperDoc v2 collaboration supports exactly one document per room; received ${documentCount}.`
20655
- };
20656
- if (documentType != null && documentType !== "application/vnd.openxmlformats-officedocument.wordprocessingml.document") return {
20657
- ok: false,
20658
- reason: "unsupported-document-type",
20659
- message: "SuperDoc v2 collaboration supports DOCX documents only."
20660
- };
20661
- if (!(v2Collaboration != null && typeof v2Collaboration === "object")) {
20662
- const family = detectUnsupportedLegacyFamily(legacyCollaboration);
20663
- if (family) {
20664
- const reason = family === "external-ydoc-provider" ? "unsupported-legacy-provider" : "unsupported-provider-family";
20665
- const redactedUrl = redactCollaborationUrl(legacyCollaboration?.url);
20666
- return {
20667
- ok: false,
20668
- reason,
20669
- 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.`
20670
- };
20671
- }
20672
- return {
20673
- ok: false,
20674
- reason: "missing-target",
20675
- message: "SuperDoc v2 collaboration requires a v2Collaboration target ({ documentId, serverUrl } or { providerType, ... }). None was provided."
20676
- };
20752
+ //#region src/core/collaboration/collaboration-exception.ts
20753
+ function createCollaborationException(code, documentId) {
20754
+ let collaborationReason;
20755
+ let message;
20756
+ switch (code) {
20757
+ case "collaboration-access-denied":
20758
+ collaborationReason = "access-denied";
20759
+ message = "The collaboration server rejected access to this room.";
20760
+ break;
20761
+ case "collaboration-connection-failed":
20762
+ collaborationReason = "connection-failed";
20763
+ message = "The collaboration connection failed.";
20764
+ break;
20765
+ case "collaboration-sync-timeout":
20766
+ collaborationReason = "sync-timeout";
20767
+ message = "The collaboration room did not finish synchronizing in time.";
20768
+ break;
20769
+ default: return null;
20677
20770
  }
20678
- const candidate = v2Collaboration;
20679
- if (Object.prototype.hasOwnProperty.call(candidate, "createIfMissing")) return {
20680
- ok: false,
20681
- reason: "invalid-room-mode",
20682
- message: "SuperDoc v2 collaboration createIfMissing has been removed. Use roomMode: \"create\" for creation or roomMode: \"join\" for normal opens."
20683
- };
20684
- if (candidate.ydoc != null || candidate.provider != null) return {
20685
- ok: false,
20686
- reason: "unsupported-legacy-provider",
20687
- 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."
20688
- };
20689
- const providerType = readProviderType(candidate);
20690
- if (providerType === null || providerType === "y-websocket") return resolveWebsocketFamily("y-websocket", candidate);
20691
- if (providerType === "hocuspocus") return resolveWebsocketFamily("hocuspocus", candidate);
20692
- if (providerType === "liveblocks") return resolveLiveblocksFamily(candidate, authEndpointBaseUrl);
20693
20771
  return {
20694
- ok: false,
20695
- reason: "unsupported-provider-family",
20696
- message: `SuperDoc v2 collaboration does not support the "${providerType}" provider family. Supported families are y-websocket, hocuspocus, and liveblocks.`
20772
+ error: new Error(message),
20773
+ code,
20774
+ collaborationReason,
20775
+ documentId,
20776
+ editor: null
20697
20777
  };
20698
20778
  }
20699
20779
  //#endregion
@@ -21888,6 +21968,10 @@ var SuperDoc_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_v
21888
21968
  const clearV2RuntimeRegistration = (documentId) => {
21889
21969
  clearV2CommandShortcutBinding(documentId);
21890
21970
  clearV2SessionShortcutBinding(documentId);
21971
+ const document = getDocument(documentId);
21972
+ const provider = document?.provider ?? null;
21973
+ if (provider && proxy.$superdoc.provider === provider) proxy.$superdoc.provider = void 0;
21974
+ if (document && provider?.sendStateless) document.provider = null;
21891
21975
  const entry = v2Runtimes.get(documentId);
21892
21976
  if (!entry) return;
21893
21977
  proxy.$superdoc.unregisterEditorRuntime(entry.runtimeId);
@@ -22076,7 +22160,7 @@ var SuperDoc_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_v
22076
22160
  clearV2EditorFailure(payload.documentId ?? null);
22077
22161
  clearV2AuthorRequired(payload.documentId ?? null);
22078
22162
  clearV2EditRejected(payload.documentId ?? null);
22079
- const { host, mount, documentId, capabilities, editCommands, bindEditShortcuts, bindSessionShortcuts, commentsAdapter, trackedChangesAdapter, contextMenu, documentApi, documentMutationReadiness, documentApiUnavailableReason, pageMetrics, pageLayout, pageFurniture, presence, lock, fonts, replaceFile, upgradeToCollaboration, documentOpenToken } = payload;
22163
+ 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;
22080
22164
  documentOpenTelemetry?.trackDocumentOpen(documentOpenToken ?? null, documentId ?? null);
22081
22165
  const saveV2Bytes = async (saveOptions = {}) => {
22082
22166
  if (!host || typeof host.save !== "function") throw new Error("v2-editor: save unavailable");
@@ -22351,6 +22435,7 @@ var SuperDoc_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_v
22351
22435
  pageFurniture: pageFurniture ?? null,
22352
22436
  presence: presence ?? null,
22353
22437
  lock: lock ?? null,
22438
+ provider: collaborationProvider ?? null,
22354
22439
  reviewWindow: {
22355
22440
  getDiagnostics: () => v2ReviewWindowController.getDiagnostics(),
22356
22441
  getSnapshot: () => v2ReviewWindowController.getSnapshot?.() ?? null,
@@ -22385,6 +22470,11 @@ var SuperDoc_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_v
22385
22470
  proxy.$superdoc.setActiveEditor(facade);
22386
22471
  syncV2EditRejectedActiveDocument();
22387
22472
  }
22473
+ if (collaborationProvider) {
22474
+ const provider = (0, vue.markRaw)(collaborationProvider);
22475
+ proxy.$superdoc.provider = provider;
22476
+ if (doc) doc.provider = provider;
22477
+ }
22388
22478
  proxy.$superdoc.broadcastEditorCreate(facade);
22389
22479
  installV2CommandShortcutBinding({
22390
22480
  documentId,
@@ -22902,7 +22992,7 @@ var SuperDoc_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_v
22902
22992
  case "worker-init-failed": return "SuperDoc could not load the document editor because the browser worker failed to start.";
22903
22993
  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.";
22904
22994
  case "collaboration-unsupported-huge-document": return "SuperDoc could not load the document editor because large documents cannot be opened with collaboration enabled yet.";
22905
- 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.";
22995
+ 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.";
22906
22996
  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.";
22907
22997
  case "collaboration-room-format-conflict": return "SuperDoc v2 found conflicting room formats in one collaboration document. No changes were made.";
22908
22998
  case "collaboration-room-corrupt": return "SuperDoc v2 found a structurally invalid collaboration room. No changes were made.";
@@ -22920,7 +23010,8 @@ var SuperDoc_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_v
22920
23010
  const reason = typeof payload?.reason === "string" && payload.reason.length > 0 ? payload.reason : "open-failed";
22921
23011
  const detail = normalizeV2EditorFailureDetail(payload?.detail);
22922
23012
  const documentId = typeof payload?.documentId === "string" && payload.documentId.length > 0 ? payload.documentId : null;
22923
- const message = getV2EditorFailureMessage(reason);
23013
+ const collaborationException = createCollaborationException(reason, documentId);
23014
+ const message = collaborationException?.error.message ?? getV2EditorFailureMessage(reason);
22924
23015
  const workerFailure = payload?.workerFailure && typeof payload.workerFailure === "object" ? payload.workerFailure : null;
22925
23016
  setV2EditorFailure(documentId, {
22926
23017
  reason,
@@ -22936,7 +23027,7 @@ var SuperDoc_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_v
22936
23027
  };
22937
23028
  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);
22938
23029
  else console.error(`[SuperDoc] ${message}`, logContext);
22939
- proxy.$superdoc.emit("exception", {
23030
+ proxy.$superdoc.emit("exception", collaborationException ?? {
22940
23031
  error: new Error(message),
22941
23032
  code: reason,
22942
23033
  ...documentId ? { documentId } : {},
@@ -24160,7 +24251,7 @@ var SuperDoc_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_v
24160
24251
  ], 38);
24161
24252
  };
24162
24253
  }
24163
- }, [["__scopeId", "data-v-0d27f262"]]);
24254
+ }, [["__scopeId", "data-v-ebe9a1fb"]]);
24164
24255
  //#endregion
24165
24256
  //#region src/core/create-app.js
24166
24257
  var PINIA_DEVTOOLS_SETUP_EVENT = "devtools-plugin:setup";
@@ -39604,7 +39695,7 @@ var _sfc_main$15 = {
39604
39695
  const emit = __emit;
39605
39696
  const props = __props;
39606
39697
  const isOverflowMenuOpened = (0, vue.computed)(() => props.toolbarItem.expand.value);
39607
- const hasOpenDropdown = (0, vue.ref)(false);
39698
+ const hasOpenDropdown = (0, vue.computed)(() => props.overflowItems.some((item) => item.type === "dropdown" && (0, vue.unref)(item.expand)));
39608
39699
  const overflowToolbarItem = (0, vue.computed)(() => ({
39609
39700
  ...props.toolbarItem,
39610
39701
  active: isOverflowMenuOpened.value
@@ -39650,8 +39741,7 @@ var _sfc_main$15 = {
39650
39741
  "ui-font-family": props.uiFontFamily,
39651
39742
  "from-overflow": "",
39652
39743
  onMousedown: (0, vue.unref)(preventEditorFocusTransfer),
39653
- onCommand: handleCommand,
39654
- onDropdownUpdateShow: _cache[0] || (_cache[0] = ($event) => hasOpenDropdown.value = $event)
39744
+ onCommand: handleCommand
39655
39745
  }, null, 8, [
39656
39746
  "toolbar-items",
39657
39747
  "ui-font-family",
@@ -39667,7 +39757,7 @@ var _sfc_main$15 = {
39667
39757
  };
39668
39758
  }
39669
39759
  };
39670
- var OverflowMenu_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_vue_export_helper_default(_sfc_main$15, [["__scopeId", "data-v-975959f9"]]);
39760
+ var OverflowMenu_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_vue_export_helper_default(_sfc_main$15, [["__scopeId", "data-v-5f8ee279"]]);
39671
39761
  //#endregion
39672
39762
  //#region src/internal/toolbar/built-in/font-typeahead.js
39673
39763
  /**
@@ -45001,10 +45091,6 @@ function contentControlSelectionKey(selection) {
45001
45091
  function isV2ActiveEditorFacade(editor) {
45002
45092
  return Boolean(editor && typeof editor === "object" && editor.editorVersion === 2);
45003
45093
  }
45004
- function isV2FailClosedExportError(error) {
45005
- const code = error && typeof error === "object" ? error.code : null;
45006
- return code === "comment-export-missing-story-reference" || code === "v2-worker-comment-export-mode-unsupported";
45007
- }
45008
45094
  function normalizeActiveEditorDocumentId(documentId) {
45009
45095
  return typeof documentId === "string" && documentId.length > 0 ? documentId : null;
45010
45096
  }
@@ -45356,7 +45442,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
45356
45442
  this.config.colors = shuffleArray(this.config.colors);
45357
45443
  this.userColorMap = /* @__PURE__ */ new Map();
45358
45444
  this.colorIndex = 0;
45359
- this.version = "2.13.0-next.1";
45445
+ this.version = "2.13.0-next.10";
45360
45446
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
45361
45447
  this.superdocId = config.superdocId || require_uuid.v4();
45362
45448
  this.colors = this.config.colors ?? [];
@@ -46010,6 +46096,14 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
46010
46096
  storeDoc.v2Collaboration = value;
46011
46097
  }
46012
46098
  #toV2CollaborationConfig(target) {
46099
+ if (target.providerFamily === "extension") return {
46100
+ providerType: "extension",
46101
+ adapterId: target.adapterId,
46102
+ documentId: target.documentId,
46103
+ roomMode: target.roomMode,
46104
+ ...target.providerOptions !== void 0 ? { providerOptions: target.providerOptions } : {},
46105
+ ...target.token ? { token: target.token } : {}
46106
+ };
46013
46107
  if (target.providerFamily === "liveblocks") return {
46014
46108
  providerType: "liveblocks",
46015
46109
  documentId: target.documentId,
@@ -46218,8 +46312,10 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
46218
46312
  ydoc: options.ydoc,
46219
46313
  provider: options.provider
46220
46314
  } : collaborationModule ? { ...collaborationModule } : null;
46315
+ const v2Collaboration = options.v2Collaboration ?? this.#unwrapMaybeRef(configDoc.v2Collaboration) ?? collaborationModule?.v2Collaboration ?? collaborationModule?.v2 ?? null;
46221
46316
  const resolution = resolveV2CollaborationTarget({
46222
- v2Collaboration: options.v2Collaboration ?? this.#unwrapMaybeRef(configDoc.v2Collaboration) ?? collaborationModule?.v2Collaboration ?? collaborationModule?.v2 ?? null,
46317
+ collaboration: options.collaboration,
46318
+ v2Collaboration,
46223
46319
  legacyCollaboration,
46224
46320
  documentType: DOCX,
46225
46321
  documentCount: cfg.documents.length,
@@ -47431,7 +47527,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
47431
47527
  error,
47432
47528
  document: doc
47433
47529
  });
47434
- if (isV2Editor && (commentsType === "clean" || isV2FailClosedExportError(error))) throw error;
47530
+ if (isV2Editor) throw error;
47435
47531
  }
47436
47532
  return fallbackDocx();
47437
47533
  });