docxodus 12.4.1 → 12.5.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 (59) hide show
  1. package/README.md +78 -0
  2. package/dist/core.d.ts +4 -4
  3. package/dist/core.d.ts.map +1 -1
  4. package/dist/core.js +21 -200
  5. package/dist/core.js.map +1 -1
  6. package/dist/docxodus.worker.js +280 -7
  7. package/dist/docxodus.worker.js.map +1 -1
  8. package/dist/editor-reconcile.d.ts +5 -0
  9. package/dist/editor-reconcile.d.ts.map +1 -1
  10. package/dist/editor-reconcile.js.map +1 -1
  11. package/dist/editor.bundle.js +157 -15
  12. package/dist/editor.d.ts +44 -0
  13. package/dist/editor.d.ts.map +1 -1
  14. package/dist/editor.js +209 -22
  15. package/dist/editor.js.map +1 -1
  16. package/dist/embed.bundle.js +560 -217
  17. package/dist/embed.iife.js +560 -217
  18. package/dist/export-assets.json +20 -20
  19. package/dist/export-browser.bundle.js +101 -4
  20. package/dist/external-annotation-wire.d.ts +19 -0
  21. package/dist/external-annotation-wire.d.ts.map +1 -0
  22. package/dist/external-annotation-wire.js +139 -0
  23. package/dist/external-annotation-wire.js.map +1 -0
  24. package/dist/session.bundle.js +258 -7
  25. package/dist/session.d.ts +61 -12
  26. package/dist/session.d.ts.map +1 -1
  27. package/dist/session.js +234 -7
  28. package/dist/session.js.map +1 -1
  29. package/dist/types.d.ts +371 -4
  30. package/dist/types.d.ts.map +1 -1
  31. package/dist/types.js.map +1 -1
  32. package/dist/verification-request.d.ts +9 -0
  33. package/dist/verification-request.d.ts.map +1 -0
  34. package/dist/verification-request.js +37 -0
  35. package/dist/verification-request.js.map +1 -0
  36. package/dist/wasm/_framework/Docxodus.wasm +0 -0
  37. package/dist/wasm/_framework/Docxodus.wasm.br +0 -0
  38. package/dist/wasm/_framework/DocxodusWasm.wasm +0 -0
  39. package/dist/wasm/_framework/DocxodusWasm.wasm.br +0 -0
  40. package/dist/wasm/_framework/System.Private.CoreLib.wasm +0 -0
  41. package/dist/wasm/_framework/System.Private.CoreLib.wasm.br +0 -0
  42. package/dist/wasm/_framework/System.Private.Xml.Linq.wasm +0 -0
  43. package/dist/wasm/_framework/System.Private.Xml.Linq.wasm.br +0 -0
  44. package/dist/wasm/_framework/System.Security.Cryptography.wasm +0 -0
  45. package/dist/wasm/_framework/System.Security.Cryptography.wasm.br +0 -0
  46. package/dist/wasm/_framework/System.Text.Encodings.Web.wasm +0 -0
  47. package/dist/wasm/_framework/System.Text.Encodings.Web.wasm.br +0 -0
  48. package/dist/wasm/_framework/System.Text.Json.wasm +0 -0
  49. package/dist/wasm/_framework/System.Text.Json.wasm.br +0 -0
  50. package/dist/wasm/_framework/dotnet.boot.js +9 -9
  51. package/dist/wasm/_framework/dotnet.boot.js.br +0 -0
  52. package/dist/wasm/_framework/dotnet.native.wasm +0 -0
  53. package/dist/wasm/_framework/dotnet.native.wasm.br +0 -0
  54. package/dist/worker-proxy.bundle.js +101 -4
  55. package/dist/worker-proxy.d.ts +21 -3
  56. package/dist/worker-proxy.d.ts.map +1 -1
  57. package/dist/worker-proxy.js +57 -2
  58. package/dist/worker-proxy.js.map +1 -1
  59. package/package.json +1 -1
@@ -251,6 +251,37 @@ var Docxodus = (() => {
251
251
  wasmBasePath: () => wasmBasePath
252
252
  });
253
253
 
254
+ // src/verification-request.ts
255
+ function serializeVerificationRequest(request) {
256
+ if (request === null || typeof request !== "object" || Array.isArray(request)) {
257
+ throw new RangeError("a verification request must be an object");
258
+ }
259
+ const { companionArtifacts, ...rest } = request;
260
+ const wire = { ...rest };
261
+ if (companionArtifacts !== void 0) {
262
+ wire.companionArtifacts = companionArtifacts.map(encodeCompanion);
263
+ }
264
+ return JSON.stringify(wire);
265
+ }
266
+ function encodeCompanion(artifact) {
267
+ const { bytes, ...rest } = artifact;
268
+ const wire = { ...rest };
269
+ if (bytes !== void 0) wire.bytesB64 = bytesToBase64(bytes);
270
+ return wire;
271
+ }
272
+ function bytesToBase64(bytes) {
273
+ if (typeof btoa === "function") {
274
+ let binary = "";
275
+ const chunkSize = 32768;
276
+ for (let i = 0; i < bytes.length; i += chunkSize) {
277
+ const chunk = bytes.subarray(i, i + chunkSize);
278
+ binary += String.fromCharCode.apply(null, chunk);
279
+ }
280
+ return btoa(binary);
281
+ }
282
+ return Buffer.from(bytes).toString("base64");
283
+ }
284
+
254
285
  // src/types.ts
255
286
  var ProjectionScopes = /* @__PURE__ */ ((ProjectionScopes2) => {
256
287
  ProjectionScopes2[ProjectionScopes2["Body"] = 1] = "Body";
@@ -520,9 +551,23 @@ var Docxodus = (() => {
520
551
  modified: after.filter((_, index) => modified[index])
521
552
  };
522
553
  }
554
+ var BATCH_REPLAY_CAVEATS = {
555
+ revisionDates: "Tracked-revision date attributes may use the execution clock; compare revision ids, authors, types, text, and anchors across separate executions.",
556
+ commentDates: "Comment date attributes may be generated from the execution clock; supply dates explicitly when byte-identical replay is required.",
557
+ annotationMetadata: "Auto-generated annotation ids or creation timestamps are execution metadata; supply id and created explicitly when byte-identical replay is required.",
558
+ createdAnchors: "Created anchors and related OOXML ids may be generated independently on replay; preview/apply equivalence is semantic and packageHash or anchor ids may differ."
559
+ };
560
+ var BATCH_REPLAY_CAVEAT_TEXTS = new Set(Object.values(BATCH_REPLAY_CAVEATS));
561
+ var RETAINED_PREVIEW_RECEIPTS = 8;
523
562
  var DocxSession = class _DocxSession {
524
563
  /** @internal */
525
564
  constructor(handle, wasm) {
565
+ /**
566
+ * The receipts this client composed for previews it retained, keyed by previewId. The host
567
+ * keeps the package and the binding; the step receipts live only here, so a commit can return
568
+ * the previewed steps and change sets without the host re-parsing a client-composed result.
569
+ */
570
+ this.retainedPreviewReceipts = /* @__PURE__ */ new Map();
526
571
  // ─── Raw escape hatch ────────────────────────────────────────────────
527
572
  this.raw = {
528
573
  getXml: (anchorId) => this.wasm.RawGetXml(this.handle, anchorId),
@@ -587,10 +632,152 @@ var Docxodus = (() => {
587
632
  * Execute synchronous mutations atomically by default. Atomic success is one undo/version
588
633
  * unit; any failed or thrown step restores the exact package and history checkpoint.
589
634
  */
590
- executeBatch(steps, mode = "atomic") {
635
+ executeBatch(steps, mode = "atomic", transaction) {
591
636
  if (mode !== "atomic" && mode !== "best_effort") {
592
637
  throw new RangeError(`unknown mutation batch mode: ${String(mode)}`);
593
638
  }
639
+ if (transaction === void 0) return this.recorded(steps, mode, void 0, () => this.runBatch(steps, mode));
640
+ return this.runTransactional(
641
+ transaction,
642
+ mode,
643
+ (identity) => this.recorded(steps, mode, identity, () => this.runBatch(steps, mode))
644
+ );
645
+ }
646
+ /**
647
+ * What the session's host-owned delivery evidence recorder holds (issue #748). `enabled` is
648
+ * false, with the reason, unless the session was opened with `captureDeliveryEvidence`.
649
+ */
650
+ getDeliveryEvidenceStatus() {
651
+ if (!this.wasm.GetDeliveryEvidenceStatus) {
652
+ throw new Error("This WASM bundle predates delivery evidence; rebuild docxodus.");
653
+ }
654
+ return JSON.parse(this.wasm.GetDeliveryEvidenceStatus(this.handle));
655
+ }
656
+ /**
657
+ * Build the receipt-bearing delivery of this session through the shared bundle service: the
658
+ * clean current package (`final-docx`), the source-to-delivered semantic delta, and the change
659
+ * receipt (`change-receipt`) minted from the captured evidence — verifiable with
660
+ * `verifyDeliveryReceipt` against the returned artifact bytes. A history that cannot be
661
+ * attested yields an `incomplete` bundle whose receipt artifact carries the reason, and
662
+ * `evidence.unavailableReason` says why.
663
+ */
664
+ buildDeliveryReceipt(options) {
665
+ if (!this.wasm.BuildDeliveryReceipt) {
666
+ throw new Error("This WASM bundle predates delivery evidence; rebuild docxodus.");
667
+ }
668
+ const wire = JSON.parse(this.wasm.BuildDeliveryReceipt(this.handle, JSON.stringify(options ?? {})));
669
+ const decode = (base64) => Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
670
+ return {
671
+ status: wire.status,
672
+ verified: wire.verified,
673
+ manifest: wire.manifest,
674
+ manifestBytes: decode(wire.manifestBytes),
675
+ artifacts: wire.artifacts.map((artifact) => {
676
+ const { bytes, ...rest } = artifact;
677
+ return bytes === void 0 ? rest : { ...rest, bytes: decode(bytes) };
678
+ }),
679
+ ...wire.evidence ? { evidence: wire.evidence } : {}
680
+ };
681
+ }
682
+ /**
683
+ * Describe a batch to the session's delivery evidence recorder before running it, and hand
684
+ * it the step results afterwards, so the version steps the batch produced are recorded under
685
+ * this description rather than as unlabeled mutations. A bundle without the recorder, or a
686
+ * session not capturing evidence, simply runs the batch.
687
+ */
688
+ recorded(steps, mode, identity, run) {
689
+ if (!this.wasm.BeginDeliveryEvidence || !this.wasm.CompleteDeliveryEvidence || !this.wasm.AbandonDeliveryEvidence) {
690
+ return run();
691
+ }
692
+ const described = this.wasm.BeginDeliveryEvidence(
693
+ this.handle,
694
+ JSON.stringify(steps.map((step) => step.args === void 0 ? { tool: step.tool, action: step.action } : { tool: step.tool, action: step.action, args: step.args })),
695
+ mode,
696
+ identity ? JSON.stringify({ transactionId: identity.transactionId, requestFingerprint: identity.requestFingerprint }) : ""
697
+ );
698
+ if (!described) return run();
699
+ let result;
700
+ try {
701
+ result = run();
702
+ return result;
703
+ } finally {
704
+ if (result) this.wasm.CompleteDeliveryEvidence(this.handle, JSON.stringify(result.steps));
705
+ else this.wasm.AbandonDeliveryEvidence(this.handle);
706
+ }
707
+ }
708
+ /**
709
+ * Make a preview retained by {@link previewBatch} (`retain: true`) the live document exactly
710
+ * as previewed: the previewed package is restored byte-for-byte as one undo step, so the
711
+ * generated anchor ids, timestamps and `packageHash` are exactly those the preview reported.
712
+ * The commit is guarded — it refuses with `preview_stale`, editing nothing, when the session's
713
+ * version, package content, tracked-changes mode or revision author moved since the preview,
714
+ * and with `preview_not_found` once the preview expired, was evicted, or was already
715
+ * committed. A `transaction` makes a retry after a lost response safe, as for
716
+ * {@link executeBatch}.
717
+ */
718
+ commitPreview(previewId, transaction) {
719
+ if (!this.wasm.CommitPreview) {
720
+ throw new Error("This WASM bundle predates retained previews; rebuild docxodus.");
721
+ }
722
+ const commit = () => {
723
+ const envelope = JSON.parse(this.wasm.CommitPreview(this.handle, previewId));
724
+ if (!envelope.success) {
725
+ if (envelope.failure?.error.code === "preview_not_found") this.retainedPreviewReceipts.delete(previewId);
726
+ return envelope;
727
+ }
728
+ const receipt = this.retainedPreviewReceipts.get(previewId);
729
+ this.retainedPreviewReceipts.delete(previewId);
730
+ if (!receipt) return envelope;
731
+ return {
732
+ ...receipt,
733
+ preview: false,
734
+ html: null,
735
+ baseVersion: envelope.baseVersion,
736
+ resultVersion: envelope.resultVersion,
737
+ packageHash: envelope.packageHash,
738
+ warnings: receipt.warnings.filter((warning) => !BATCH_REPLAY_CAVEAT_TEXTS.has(warning)),
739
+ retention: envelope.retention
740
+ };
741
+ };
742
+ if (transaction === void 0) return commit();
743
+ return this.runTransactional(transaction, "atomic", () => commit());
744
+ }
745
+ runTransactional(transaction, mode, body) {
746
+ if (!this.wasm.BeginMutationTransaction || !this.wasm.CompleteMutationTransaction || !this.wasm.AbandonMutationTransaction) {
747
+ throw new Error("This WASM bundle predates mutation transactions; rebuild docxodus.");
748
+ }
749
+ if (typeof transaction.transactionId !== "string") {
750
+ throw new RangeError("transactionId must be a string");
751
+ }
752
+ if (transaction.request === null || typeof transaction.request !== "object" || Array.isArray(transaction.request)) {
753
+ throw new RangeError("a mutation transaction needs a request object describing the batch");
754
+ }
755
+ const decision = JSON.parse(this.wasm.BeginMutationTransaction(
756
+ this.handle,
757
+ transaction.transactionId,
758
+ JSON.stringify({ ...transaction.request, mode })
759
+ ));
760
+ if (decision.response !== null) {
761
+ return JSON.parse(decision.response);
762
+ }
763
+ let completed = false;
764
+ try {
765
+ const result = {
766
+ ...body(decision.transaction),
767
+ transaction: decision.transaction
768
+ };
769
+ this.wasm.CompleteMutationTransaction(
770
+ this.handle,
771
+ transaction.transactionId,
772
+ JSON.stringify(result)
773
+ );
774
+ completed = true;
775
+ return result;
776
+ } finally {
777
+ if (!completed) this.wasm.AbandonMutationTransaction(this.handle, transaction.transactionId);
778
+ }
779
+ }
780
+ runBatch(steps, mode) {
594
781
  const baseVersion = this.getVersion();
595
782
  const observationWarnings = [];
596
783
  const inspect = (label, read, fallback) => {
@@ -628,16 +815,16 @@ var Docxodus = (() => {
628
815
  );
629
816
  const warnings = [...observationWarnings];
630
817
  if ([...revisionChanges.added, ...revisionChanges.modified].some((revision) => revision.date !== void 0 && revision.date !== null)) {
631
- warnings.push("Tracked-revision date attributes may use the execution clock; compare revision ids, authors, types, text, and anchors across separate executions.");
818
+ warnings.push(BATCH_REPLAY_CAVEATS.revisionDates);
632
819
  }
633
820
  if ([...commentChanges.added, ...commentChanges.modified].some((comment) => comment.date !== void 0 && comment.date !== null)) {
634
- warnings.push("Comment date attributes may be generated from the execution clock; supply dates explicitly when byte-identical replay is required.");
821
+ warnings.push(BATCH_REPLAY_CAVEATS.commentDates);
635
822
  }
636
823
  if (annotationChanges.added.some((annotation) => annotation.created !== void 0 && annotation.created !== null)) {
637
- warnings.push("Auto-generated annotation ids or creation timestamps are execution metadata; supply id and created explicitly when byte-identical replay is required.");
824
+ warnings.push(BATCH_REPLAY_CAVEATS.annotationMetadata);
638
825
  }
639
826
  if (result.steps.some((step) => step.results.some((edit) => edit.created.length > 0))) {
640
- warnings.push("Created anchors and related OOXML ids may be generated independently on replay; preview/apply equivalence is semantic and packageHash or anchor ids may differ.");
827
+ warnings.push(BATCH_REPLAY_CAVEATS.createdAnchors);
641
828
  }
642
829
  if (mode === "best_effort" && !result.success) {
643
830
  warnings.push("Best-effort execution retains every successful step despite later failures.");
@@ -861,7 +1048,27 @@ var Docxodus = (() => {
861
1048
  } catch (error) {
862
1049
  warnings.push(`Preview HTML could not be generated: ${error instanceof Error ? error.message : String(error)}`);
863
1050
  }
864
- return { ...result, preview: true, warnings, html };
1051
+ let retention;
1052
+ if (options?.retain) {
1053
+ if (!this.wasm.RetainPreview) {
1054
+ throw new Error("This WASM bundle predates retained previews; rebuild docxodus.");
1055
+ }
1056
+ if (!result.success) {
1057
+ warnings.push("The preview did not succeed, so it was not retained for commit.");
1058
+ } else {
1059
+ const retained = JSON.parse(this.wasm.RetainPreview(shadow.handle));
1060
+ warnings.push(...retained.warnings);
1061
+ retention = retained.retention ?? void 0;
1062
+ }
1063
+ }
1064
+ const preview = retention ? { ...result, preview: true, warnings, html, retention } : { ...result, preview: true, warnings, html };
1065
+ if (retention) {
1066
+ if (this.retainedPreviewReceipts.size >= RETAINED_PREVIEW_RECEIPTS) {
1067
+ this.retainedPreviewReceipts.delete(this.retainedPreviewReceipts.keys().next().value);
1068
+ }
1069
+ this.retainedPreviewReceipts.set(retention.previewId, { ...preview, html: null });
1070
+ }
1071
+ return preview;
865
1072
  } finally {
866
1073
  shadow.close();
867
1074
  }
@@ -1440,6 +1647,18 @@ var Docxodus = (() => {
1440
1647
  imageBytesToBase64(bytes)
1441
1648
  ));
1442
1649
  }
1650
+ /**
1651
+ * Convert an external linked picture into an embedded one using bytes the caller fetched;
1652
+ * the engine never reaches the network itself. Refused for pictures that already embed
1653
+ * their media — see `ImageOccurrence.operations`.
1654
+ */
1655
+ embedLinkedImage(imageId, bytes) {
1656
+ return JSON.parse(this.wasm.EmbedLinkedImage(
1657
+ this.handle,
1658
+ imageId,
1659
+ imageBytesToBase64(bytes)
1660
+ ));
1661
+ }
1443
1662
  setImageDimensions(imageId, dimensions) {
1444
1663
  return JSON.parse(this.wasm.SetImageDimensions(
1445
1664
  this.handle,
@@ -1570,6 +1789,28 @@ var Docxodus = (() => {
1570
1789
  listRevisions() {
1571
1790
  return JSON.parse(this.wasm.ListRevisions(this.handle));
1572
1791
  }
1792
+ /**
1793
+ * The explicit repairs the registry offers for entries it refuses to resolve (issues
1794
+ * #754–#758): which carriers are defective, whether a unique repair exists, and what it
1795
+ * would do. Read-only; listing, accept and reject never repair.
1796
+ */
1797
+ listRevisionRepairs() {
1798
+ if (!this.wasm.ListRevisionRepairs) {
1799
+ throw new Error("This WASM bundle predates revision repairs; rebuild docxodus.");
1800
+ }
1801
+ return JSON.parse(this.wasm.ListRevisionRepairs(this.handle));
1802
+ }
1803
+ /**
1804
+ * Perform requested repairs atomically as one undo step. A kind the registry did not offer,
1805
+ * a non-repairable proposal, or a wrap-as-deletion without author and date refuses the whole
1806
+ * call (`revision_repair_rejected`) with nothing mutated. Repaired entries get new ids.
1807
+ */
1808
+ repairRevisions(repairs) {
1809
+ if (!this.wasm.RepairRevisions) {
1810
+ throw new Error("This WASM bundle predates revision repairs; rebuild docxodus.");
1811
+ }
1812
+ return JSON.parse(this.wasm.RepairRevisions(this.handle, JSON.stringify(repairs)));
1813
+ }
1573
1814
  /** Accept ONE revision by the id {@link listRevisions} reported — insertions keep
1574
1815
  * their content, deletions are carried out, a move materializes at its destination,
1575
1816
  * a format change keeps the new properties. Undoable. */
@@ -1927,7 +2168,16 @@ var Docxodus = (() => {
1927
2168
  * With initial projection capture enabled (the default), exact opening bytes are the
1928
2169
  * baseline used for dispositions and semantic/package deltas.
1929
2170
  */
1930
- verifyDeliverable() {
2171
+ verifyDeliverable(request) {
2172
+ if (request !== void 0) {
2173
+ if (!this.wasm.VerifyDeliverableWithRequest) {
2174
+ throw new Error("This WASM bundle predates full verification requests; rebuild docxodus.");
2175
+ }
2176
+ return JSON.parse(this.wasm.VerifyDeliverableWithRequest(
2177
+ this.handle,
2178
+ serializeVerificationRequest(request)
2179
+ ));
2180
+ }
1931
2181
  return JSON.parse(
1932
2182
  this.wasm.VerifyDeliverable(this.handle)
1933
2183
  );
@@ -2156,6 +2406,7 @@ var Docxodus = (() => {
2156
2406
  return this.wasm.Save(this.handle);
2157
2407
  }
2158
2408
  close() {
2409
+ this.retainedPreviewReceipts.clear();
2159
2410
  this.wasm.CloseSession(this.handle);
2160
2411
  }
2161
2412
  // TypeScript 5.2+ disposable protocol
@@ -2176,6 +2427,129 @@ var Docxodus = (() => {
2176
2427
  return new DocxSession(handle, bridge);
2177
2428
  }
2178
2429
 
2430
+ // src/external-annotation-wire.ts
2431
+ function readPawlsPage(p) {
2432
+ return {
2433
+ page: {
2434
+ width: p.Page?.Width ?? p.page?.width,
2435
+ height: p.Page?.Height ?? p.page?.height,
2436
+ index: p.Page?.Index ?? p.page?.index
2437
+ },
2438
+ tokens: (p.Tokens || p.tokens || []).map((t) => ({
2439
+ x: t.X ?? t.x,
2440
+ y: t.Y ?? t.y,
2441
+ width: t.Width ?? t.width,
2442
+ height: t.Height ?? t.height,
2443
+ text: t.Text ?? t.text
2444
+ }))
2445
+ };
2446
+ }
2447
+ function readAnnotationJson(json) {
2448
+ if (!json) return void 0;
2449
+ if (json.Start !== void 0 || json.start !== void 0) {
2450
+ return {
2451
+ id: json.Id ?? json.id,
2452
+ start: json.Start ?? json.start,
2453
+ end: json.End ?? json.end,
2454
+ text: json.Text ?? json.text
2455
+ };
2456
+ }
2457
+ const result = {};
2458
+ for (const [key, value] of Object.entries(json)) {
2459
+ const v = value;
2460
+ result[key] = {
2461
+ bounds: {
2462
+ top: v.Bounds?.Top ?? v.bounds?.top,
2463
+ bottom: v.Bounds?.Bottom ?? v.bounds?.bottom,
2464
+ left: v.Bounds?.Left ?? v.bounds?.left,
2465
+ right: v.Bounds?.Right ?? v.bounds?.right
2466
+ },
2467
+ tokensJsons: (v.TokensJsons || v.tokensJsons || []).map((t) => ({
2468
+ pageIndex: t.PageIndex ?? t.pageIndex,
2469
+ tokenIndex: t.TokenIndex ?? t.tokenIndex
2470
+ })),
2471
+ rawText: v.RawText ?? v.rawText
2472
+ };
2473
+ }
2474
+ return result;
2475
+ }
2476
+ function readAnnotation(a) {
2477
+ return {
2478
+ id: a.Id ?? a.id,
2479
+ annotationLabel: a.AnnotationLabel ?? a.annotationLabel,
2480
+ rawText: a.RawText ?? a.rawText,
2481
+ page: a.Page ?? a.page,
2482
+ annotationJson: readAnnotationJson(a.AnnotationJson ?? a.annotationJson),
2483
+ parentId: a.ParentId ?? a.parentId,
2484
+ annotationType: a.AnnotationType ?? a.annotationType,
2485
+ structural: a.Structural ?? a.structural
2486
+ };
2487
+ }
2488
+ function readRelationship(r) {
2489
+ return {
2490
+ id: r.Id ?? r.id,
2491
+ relationshipLabel: r.RelationshipLabel ?? r.relationshipLabel,
2492
+ sourceAnnotationIds: r.SourceAnnotationIds ?? r.sourceAnnotationIds ?? [],
2493
+ targetAnnotationIds: r.TargetAnnotationIds ?? r.targetAnnotationIds ?? [],
2494
+ structural: r.Structural ?? r.structural
2495
+ };
2496
+ }
2497
+ function readLabel(l) {
2498
+ return {
2499
+ id: l.Id ?? l.id,
2500
+ color: l.Color ?? l.color,
2501
+ description: l.Description ?? l.description ?? "",
2502
+ icon: l.Icon ?? l.icon ?? "",
2503
+ text: l.Text ?? l.text,
2504
+ labelType: l.LabelType ?? l.labelType ?? "text"
2505
+ };
2506
+ }
2507
+ function readLabels(raw) {
2508
+ const labels = {};
2509
+ for (const [key, value] of Object.entries(raw || {})) labels[key] = readLabel(value);
2510
+ return labels;
2511
+ }
2512
+ function readOpenContractExport(parsed) {
2513
+ return {
2514
+ title: parsed.Title ?? parsed.title,
2515
+ content: parsed.Content ?? parsed.content,
2516
+ description: parsed.Description ?? parsed.description,
2517
+ pageCount: parsed.PageCount ?? parsed.pageCount,
2518
+ pawlsFileContent: (parsed.PawlsFileContent || parsed.pawlsFileContent || []).map(readPawlsPage),
2519
+ docLabels: parsed.DocLabels ?? parsed.docLabels ?? [],
2520
+ labelledText: (parsed.LabelledText || parsed.labelledText || []).map(readAnnotation),
2521
+ relationships: (parsed.Relationships || parsed.relationships)?.map(readRelationship)
2522
+ };
2523
+ }
2524
+ function readExternalAnnotationSet(parsed) {
2525
+ return {
2526
+ documentId: parsed.DocumentId ?? parsed.documentId,
2527
+ documentHash: parsed.DocumentHash ?? parsed.documentHash,
2528
+ createdAt: parsed.CreatedAt ?? parsed.createdAt,
2529
+ updatedAt: parsed.UpdatedAt ?? parsed.updatedAt,
2530
+ version: parsed.Version ?? parsed.version,
2531
+ ...readOpenContractExport(parsed),
2532
+ textLabels: readLabels(parsed.TextLabels || parsed.textLabels),
2533
+ docLabelDefinitions: readLabels(parsed.DocLabelDefinitions || parsed.docLabelDefinitions)
2534
+ };
2535
+ }
2536
+ function readExternalAnnotationValidation(parsed) {
2537
+ return {
2538
+ isValid: parsed.IsValid ?? parsed.isValid,
2539
+ hashMismatch: parsed.HashMismatch ?? parsed.hashMismatch,
2540
+ issues: (parsed.Issues || parsed.issues || []).map((i) => ({
2541
+ annotationId: i.AnnotationId ?? i.annotationId,
2542
+ issueType: i.IssueType ?? i.issueType,
2543
+ description: i.Description ?? i.description,
2544
+ expectedText: i.ExpectedText ?? i.expectedText,
2545
+ actualText: i.ActualText ?? i.actualText
2546
+ }))
2547
+ };
2548
+ }
2549
+ function readProjectedHtml(parsed) {
2550
+ return parsed.Html ?? parsed.html;
2551
+ }
2552
+
2179
2553
  // src/history.ts
2180
2554
  var MAX_HISTORY_ARCHIVE_BYTES = 64 * 1024 * 1024;
2181
2555
  var DocxHistoryError = class extends Error {
@@ -6565,11 +6939,21 @@ Your current draft and all later versions will be kept.`);
6565
6939
  exports.DocumentConverter.GeneratePackageManifest(bytes)
6566
6940
  );
6567
6941
  }
6568
- async function verifyDeliverable(document2, baseline) {
6942
+ async function verifyDeliverable(document2, baseline, request) {
6569
6943
  const exports = ensureInitialized();
6570
6944
  const bytes = await toBytes(document2);
6571
6945
  const baselineBytes = baseline === void 0 ? void 0 : await toBytes(baseline);
6572
6946
  await yieldToMain();
6947
+ if (request !== void 0) {
6948
+ const requestJson = serializeVerificationRequest(request);
6949
+ const converter = exports.DocumentConverter;
6950
+ if (!converter.VerifyDeliverableWithRequest || !converter.VerifyDeliverableWithBaselineAndRequest) {
6951
+ throw new Error("This WASM bundle predates full verification requests; rebuild docxodus.");
6952
+ }
6953
+ return JSON.parse(
6954
+ baselineBytes === void 0 ? converter.VerifyDeliverableWithRequest(bytes, requestJson) : converter.VerifyDeliverableWithBaselineAndRequest(baselineBytes, bytes, requestJson)
6955
+ );
6956
+ }
6573
6957
  return JSON.parse(
6574
6958
  baselineBytes === void 0 ? exports.DocumentConverter.VerifyDeliverable(bytes) : exports.DocumentConverter.VerifyDeliverableWithBaseline(
6575
6959
  baselineBytes,
@@ -6583,7 +6967,7 @@ Your current draft and all later versions will be kept.`);
6583
6967
  Object.fromEntries(
6584
6968
  Object.entries(artifacts).map(([artifactId, bytes]) => [
6585
6969
  artifactId,
6586
- bytesToBase64(bytes)
6970
+ bytesToBase642(bytes)
6587
6971
  ])
6588
6972
  )
6589
6973
  );
@@ -6814,7 +7198,7 @@ Your current draft and all later versions will be kept.`);
6814
7198
  const bytes = await toBytes(candidates[i].document);
6815
7199
  payload.push({
6816
7200
  name: candidates[i].name ?? String(i),
6817
- docB64: bytesToBase64(bytes)
7201
+ docB64: bytesToBase642(bytes)
6818
7202
  });
6819
7203
  }
6820
7204
  await yieldToMain();
@@ -6890,7 +7274,7 @@ Your current draft and all later versions will be kept.`);
6890
7274
  }
6891
7275
  return result;
6892
7276
  }
6893
- function bytesToBase64(bytes) {
7277
+ function bytesToBase642(bytes) {
6894
7278
  if (typeof btoa === "function") {
6895
7279
  let binary = "";
6896
7280
  const chunkSize = 32768;
@@ -6906,7 +7290,7 @@ Your current draft and all later versions will be kept.`);
6906
7290
  const arr = await Promise.all(
6907
7291
  reviewers.map(async (r) => ({
6908
7292
  author: r.author,
6909
- docB64: bytesToBase64(await toBytes(r.document))
7293
+ docB64: bytesToBase642(await toBytes(r.document))
6910
7294
  }))
6911
7295
  );
6912
7296
  return JSON.stringify(arr);
@@ -7216,77 +7600,7 @@ Your current draft and all later versions will be kept.`);
7216
7600
  const error = parseError(result);
7217
7601
  throw new Error(`Failed to export to OpenContract format: ${error.error}`);
7218
7602
  }
7219
- const parsed = JSON.parse(result);
7220
- const convertPawlsPage = (p) => ({
7221
- page: {
7222
- width: p.Page?.Width ?? p.page?.width,
7223
- height: p.Page?.Height ?? p.page?.height,
7224
- index: p.Page?.Index ?? p.page?.index
7225
- },
7226
- tokens: (p.Tokens || p.tokens || []).map((t) => ({
7227
- x: t.X ?? t.x,
7228
- y: t.Y ?? t.y,
7229
- width: t.Width ?? t.width,
7230
- height: t.Height ?? t.height,
7231
- text: t.Text ?? t.text
7232
- }))
7233
- });
7234
- const convertAnnotation = (a) => ({
7235
- id: a.Id ?? a.id,
7236
- annotationLabel: a.AnnotationLabel ?? a.annotationLabel,
7237
- rawText: a.RawText ?? a.rawText,
7238
- page: a.Page ?? a.page,
7239
- annotationJson: convertAnnotationJson(a.AnnotationJson ?? a.annotationJson),
7240
- parentId: a.ParentId ?? a.parentId,
7241
- annotationType: a.AnnotationType ?? a.annotationType,
7242
- structural: a.Structural ?? a.structural
7243
- });
7244
- const convertAnnotationJson = (json) => {
7245
- if (!json) return void 0;
7246
- if (json.Start !== void 0 || json.start !== void 0) {
7247
- return {
7248
- id: json.Id ?? json.id,
7249
- start: json.Start ?? json.start,
7250
- end: json.End ?? json.end,
7251
- text: json.Text ?? json.text
7252
- };
7253
- }
7254
- const result2 = {};
7255
- for (const [key, value] of Object.entries(json)) {
7256
- const v = value;
7257
- result2[key] = {
7258
- bounds: {
7259
- top: v.Bounds?.Top ?? v.bounds?.top,
7260
- bottom: v.Bounds?.Bottom ?? v.bounds?.bottom,
7261
- left: v.Bounds?.Left ?? v.bounds?.left,
7262
- right: v.Bounds?.Right ?? v.bounds?.right
7263
- },
7264
- tokensJsons: (v.TokensJsons || v.tokensJsons || []).map((t) => ({
7265
- pageIndex: t.PageIndex ?? t.pageIndex,
7266
- tokenIndex: t.TokenIndex ?? t.tokenIndex
7267
- })),
7268
- rawText: v.RawText ?? v.rawText
7269
- };
7270
- }
7271
- return result2;
7272
- };
7273
- const convertRelationship = (r) => ({
7274
- id: r.Id ?? r.id,
7275
- relationshipLabel: r.RelationshipLabel ?? r.relationshipLabel,
7276
- sourceAnnotationIds: r.SourceAnnotationIds ?? r.sourceAnnotationIds ?? [],
7277
- targetAnnotationIds: r.TargetAnnotationIds ?? r.targetAnnotationIds ?? [],
7278
- structural: r.Structural ?? r.structural
7279
- });
7280
- return {
7281
- title: parsed.Title ?? parsed.title,
7282
- content: parsed.Content ?? parsed.content,
7283
- description: parsed.Description ?? parsed.description,
7284
- pageCount: parsed.PageCount ?? parsed.pageCount,
7285
- pawlsFileContent: (parsed.PawlsFileContent || parsed.pawlsFileContent || []).map(convertPawlsPage),
7286
- docLabels: parsed.DocLabels ?? parsed.docLabels ?? [],
7287
- labelledText: (parsed.LabelledText || parsed.labelledText || []).map(convertAnnotation),
7288
- relationships: (parsed.Relationships || parsed.relationships)?.map(convertRelationship)
7289
- };
7603
+ return readOpenContractExport(JSON.parse(result));
7290
7604
  }
7291
7605
  async function convertWmlToMarkdown(document2, settings = {}) {
7292
7606
  const exports = ensureInitialized();
@@ -7392,8 +7706,7 @@ Your current draft and all later versions will be kept.`);
7392
7706
  const error = parseError(result);
7393
7707
  throw new Error(`Failed to create external annotation set: ${error.error}`);
7394
7708
  }
7395
- const parsed = JSON.parse(result);
7396
- return convertExternalAnnotationSet(parsed);
7709
+ return readExternalAnnotationSet(JSON.parse(result));
7397
7710
  }
7398
7711
  async function validateExternalAnnotations(document2, annotationSet) {
7399
7712
  const exports = ensureInitialized();
@@ -7405,18 +7718,7 @@ Your current draft and all later versions will be kept.`);
7405
7718
  const error = parseError(result);
7406
7719
  throw new Error(`Failed to validate external annotations: ${error.error}`);
7407
7720
  }
7408
- const parsed = JSON.parse(result);
7409
- return {
7410
- isValid: parsed.IsValid ?? parsed.isValid,
7411
- hashMismatch: parsed.HashMismatch ?? parsed.hashMismatch,
7412
- issues: (parsed.Issues || parsed.issues || []).map((i) => ({
7413
- annotationId: i.AnnotationId ?? i.annotationId,
7414
- issueType: i.IssueType ?? i.issueType,
7415
- description: i.Description ?? i.description,
7416
- expectedText: i.ExpectedText ?? i.expectedText,
7417
- actualText: i.ActualText ?? i.actualText
7418
- }))
7419
- };
7721
+ return readExternalAnnotationValidation(JSON.parse(result));
7420
7722
  }
7421
7723
  async function convertDocxToHtmlWithExternalAnnotations(document2, annotationSet, conversionOptions, projectionOptions) {
7422
7724
  const exports = ensureInitialized();
@@ -7437,8 +7739,7 @@ Your current draft and all later versions will be kept.`);
7437
7739
  const error = parseError(result);
7438
7740
  throw new Error(`Failed to convert with external annotations: ${error.error}`);
7439
7741
  }
7440
- const parsed = JSON.parse(result);
7441
- return parsed.Html ?? parsed.html;
7742
+ return readProjectedHtml(JSON.parse(result));
7442
7743
  }
7443
7744
  async function searchTextOffsets(document2, searchText, maxResults = 100) {
7444
7745
  const exports = ensureInitialized();
@@ -7506,103 +7807,6 @@ Your current draft and all later versions will be kept.`);
7506
7807
  }
7507
7808
  return results;
7508
7809
  }
7509
- function convertExternalAnnotationSet(parsed) {
7510
- const convertLabel = (l) => ({
7511
- id: l.Id ?? l.id,
7512
- color: l.Color ?? l.color,
7513
- description: l.Description ?? l.description ?? "",
7514
- icon: l.Icon ?? l.icon ?? "",
7515
- text: l.Text ?? l.text,
7516
- labelType: l.LabelType ?? l.labelType ?? "text"
7517
- });
7518
- const convertPawlsPage = (p) => ({
7519
- page: {
7520
- width: p.Page?.Width ?? p.page?.width,
7521
- height: p.Page?.Height ?? p.page?.height,
7522
- index: p.Page?.Index ?? p.page?.index
7523
- },
7524
- tokens: (p.Tokens || p.tokens || []).map((t) => ({
7525
- x: t.X ?? t.x,
7526
- y: t.Y ?? t.y,
7527
- width: t.Width ?? t.width,
7528
- height: t.Height ?? t.height,
7529
- text: t.Text ?? t.text
7530
- }))
7531
- });
7532
- const convertAnnotation = (a) => ({
7533
- id: a.Id ?? a.id,
7534
- annotationLabel: a.AnnotationLabel ?? a.annotationLabel,
7535
- rawText: a.RawText ?? a.rawText,
7536
- page: a.Page ?? a.page,
7537
- annotationJson: convertAnnotationJson(a.AnnotationJson ?? a.annotationJson),
7538
- parentId: a.ParentId ?? a.parentId,
7539
- annotationType: a.AnnotationType ?? a.annotationType,
7540
- structural: a.Structural ?? a.structural
7541
- });
7542
- const convertAnnotationJson = (json) => {
7543
- if (!json) return void 0;
7544
- if (json.Start !== void 0 || json.start !== void 0) {
7545
- return {
7546
- id: json.Id ?? json.id,
7547
- start: json.Start ?? json.start,
7548
- end: json.End ?? json.end,
7549
- text: json.Text ?? json.text
7550
- };
7551
- }
7552
- const result = {};
7553
- for (const [key, value] of Object.entries(json)) {
7554
- const v = value;
7555
- result[key] = {
7556
- bounds: {
7557
- top: v.Bounds?.Top ?? v.bounds?.top,
7558
- bottom: v.Bounds?.Bottom ?? v.bounds?.bottom,
7559
- left: v.Bounds?.Left ?? v.bounds?.left,
7560
- right: v.Bounds?.Right ?? v.bounds?.right
7561
- },
7562
- tokensJsons: (v.TokensJsons || v.tokensJsons || []).map((t) => ({
7563
- pageIndex: t.PageIndex ?? t.pageIndex,
7564
- tokenIndex: t.TokenIndex ?? t.tokenIndex
7565
- })),
7566
- rawText: v.RawText ?? v.rawText
7567
- };
7568
- }
7569
- return result;
7570
- };
7571
- const convertRelationship = (r) => ({
7572
- id: r.Id ?? r.id,
7573
- relationshipLabel: r.RelationshipLabel ?? r.relationshipLabel,
7574
- sourceAnnotationIds: r.SourceAnnotationIds ?? r.sourceAnnotationIds ?? [],
7575
- targetAnnotationIds: r.TargetAnnotationIds ?? r.targetAnnotationIds ?? [],
7576
- structural: r.Structural ?? r.structural
7577
- });
7578
- const textLabels = {};
7579
- const rawTextLabels = parsed.TextLabels || parsed.textLabels || {};
7580
- for (const [key, value] of Object.entries(rawTextLabels)) {
7581
- textLabels[key] = convertLabel(value);
7582
- }
7583
- const docLabelDefinitions = {};
7584
- const rawDocLabelDefs = parsed.DocLabelDefinitions || parsed.docLabelDefinitions || {};
7585
- for (const [key, value] of Object.entries(rawDocLabelDefs)) {
7586
- docLabelDefinitions[key] = convertLabel(value);
7587
- }
7588
- return {
7589
- documentId: parsed.DocumentId ?? parsed.documentId,
7590
- documentHash: parsed.DocumentHash ?? parsed.documentHash,
7591
- createdAt: parsed.CreatedAt ?? parsed.createdAt,
7592
- updatedAt: parsed.UpdatedAt ?? parsed.updatedAt,
7593
- version: parsed.Version ?? parsed.version,
7594
- title: parsed.Title ?? parsed.title,
7595
- content: parsed.Content ?? parsed.content,
7596
- description: parsed.Description ?? parsed.description,
7597
- pageCount: parsed.PageCount ?? parsed.pageCount,
7598
- pawlsFileContent: (parsed.PawlsFileContent || parsed.pawlsFileContent || []).map(convertPawlsPage),
7599
- docLabels: parsed.DocLabels ?? parsed.docLabels ?? [],
7600
- labelledText: (parsed.LabelledText || parsed.labelledText || []).map(convertAnnotation),
7601
- relationships: (parsed.Relationships || parsed.relationships)?.map(convertRelationship),
7602
- textLabels,
7603
- docLabelDefinitions
7604
- };
7605
- }
7606
7810
  async function projectAnnotationsOntoHtml(html, annotationSet, projectionOptions) {
7607
7811
  const exports = ensureInitialized();
7608
7812
  await yieldToMain();
@@ -7617,8 +7821,7 @@ Your current draft and all later versions will be kept.`);
7617
7821
  const error = parseError(result);
7618
7822
  throw new Error(`Failed to project annotations: ${error.error}`);
7619
7823
  }
7620
- const parsed = JSON.parse(result);
7621
- return parsed.Html ?? parsed.html;
7824
+ return readProjectedHtml(JSON.parse(result));
7622
7825
  }
7623
7826
  async function addAnnotationToHtml(html, annotation, label, projectionOptions) {
7624
7827
  const exports = ensureInitialized();
@@ -7636,8 +7839,7 @@ Your current draft and all later versions will be kept.`);
7636
7839
  const error = parseError(result);
7637
7840
  throw new Error(`Failed to add annotation to HTML: ${error.error}`);
7638
7841
  }
7639
- const parsed = JSON.parse(result);
7640
- return parsed.Html ?? parsed.html;
7842
+ return readProjectedHtml(JSON.parse(result));
7641
7843
  }
7642
7844
  async function removeAnnotationFromHtml(html, annotationId, cssClassPrefix) {
7643
7845
  const exports = ensureInitialized();
@@ -7651,8 +7853,7 @@ Your current draft and all later versions will be kept.`);
7651
7853
  const error = parseError(result);
7652
7854
  throw new Error(`Failed to remove annotation from HTML: ${error.error}`);
7653
7855
  }
7654
- const parsed = JSON.parse(result);
7655
- return parsed.Html ?? parsed.html;
7856
+ return readProjectedHtml(JSON.parse(result));
7656
7857
  }
7657
7858
  async function generateAnnotationVisibilityCss(hiddenLabelIds, cssClassPrefix) {
7658
7859
  const exports = ensureInitialized();
@@ -11819,6 +12020,16 @@ span.comment-highlight.docx-comment-active { background: hsl(var(--docx-comment-
11819
12020
  `;
11820
12021
  (doc.head ?? doc.documentElement).appendChild(style);
11821
12022
  }
12023
+ var CHROME_CARRIER_ANCHOR = "chrome-carrier";
12024
+ function yieldToEventLoop() {
12025
+ return new Promise((resolve) => {
12026
+ const settle = () => {
12027
+ setTimeout(resolve, 0);
12028
+ };
12029
+ if (typeof requestAnimationFrame === "function") requestAnimationFrame(settle);
12030
+ else settle();
12031
+ });
12032
+ }
11822
12033
  function trackedChangeWireName(mode) {
11823
12034
  if (mode === 1 /* RenderInline */) return "render_inline";
11824
12035
  if (mode === 2 /* StripDeletions */) return "strip_deletions";
@@ -12486,7 +12697,64 @@ span.comment-highlight.docx-comment-active { background: hsl(var(--docx-comment-
12486
12697
  }
12487
12698
  /** Open a document, render it into `container`, and wire up editing. */
12488
12699
  static open(container, bytes, exports, options = {}) {
12489
- const opts = {
12700
+ const opts = _DocxEditor.resolveOptions(options);
12701
+ const editor = _DocxEditor.openSession(container, bytes, exports, opts);
12702
+ try {
12703
+ editor.refreshAnchorMap();
12704
+ if (opts.headerFooter) editor.createRegion();
12705
+ const fullHtml = editor.renderFullHtml(bytes);
12706
+ if (opts.paginated) editor.mountPaginated(fullHtml);
12707
+ else editor.mountHtml(fullHtml);
12708
+ editor.finishMount();
12709
+ return editor;
12710
+ } catch (error) {
12711
+ editor.close();
12712
+ throw error;
12713
+ }
12714
+ }
12715
+ /**
12716
+ * Open a document without holding the main thread for the whole mount (issue #776).
12717
+ *
12718
+ * {@link open} renders and wires the entire document in one synchronous task, which on a
12719
+ * long document is the largest single block of a reading-and-editing session. This variant
12720
+ * pays only the session open up front, then mounts the document in windows of body units,
12721
+ * yielding to the event loop between them: the chrome — stylesheet, section wrappers with
12722
+ * their page geometry, footnote and endnote sections — comes from one cheap engine render
12723
+ * that sees no body content, and each window from the engine's block renderer, which lays
12724
+ * units out exactly as the full render does (the plan's border-box grouping is never split).
12725
+ * The DOM that results is the one {@link open} produces; blocks already mounted are editable
12726
+ * while later windows are still landing, and edits made meanwhile are honoured because every
12727
+ * window renders from the live session.
12728
+ *
12729
+ * Paginated mounts assemble the windows off-screen and paginate once at the end, since
12730
+ * pagination is a one-shot flow over the whole document; the main thread is still free
12731
+ * between windows, and `onProgress` lets a host show the fill.
12732
+ *
12733
+ * A bundle that predates the windowed renders mounts synchronously, exactly like {@link open}.
12734
+ */
12735
+ static async openAsync(container, bytes, exports, options = {}) {
12736
+ const bridge = exports.DocxSessionBridge;
12737
+ if (typeof bridge.RenderEditorChromeHtml !== "function" || typeof bridge.RenderEditorRangeHtml !== "function" || typeof bridge.ListRenderedBlocks !== "function") {
12738
+ return _DocxEditor.open(container, bytes, exports, options);
12739
+ }
12740
+ const opts = _DocxEditor.resolveOptions(options);
12741
+ const editor = _DocxEditor.openSession(container, bytes, exports, opts);
12742
+ try {
12743
+ editor.refreshAnchorMap();
12744
+ if (opts.headerFooter) editor.createRegion();
12745
+ await editor.mountWindowed(
12746
+ Math.max(1, Math.floor(options.windowSize ?? 24)),
12747
+ options.onProgress
12748
+ );
12749
+ editor.finishMount();
12750
+ return editor;
12751
+ } catch (error) {
12752
+ editor.close();
12753
+ throw error;
12754
+ }
12755
+ }
12756
+ static resolveOptions(options) {
12757
+ return {
12490
12758
  cssPrefix: options.cssPrefix ?? "docx-",
12491
12759
  fabricateClasses: options.fabricateClasses ?? false,
12492
12760
  editable: options.editable ?? true,
@@ -12505,25 +12773,100 @@ span.comment-highlight.docx-comment-active { background: hsl(var(--docx-comment-
12505
12773
  onStoryChange: options.onStoryChange,
12506
12774
  onCommentsChange: options.onCommentsChange
12507
12775
  };
12776
+ }
12777
+ static openSession(container, bytes, exports, opts) {
12508
12778
  const handle = exports.DocxSessionBridge.OpenSession(bytes, JSON.stringify({
12509
12779
  emitMarkdownPatch: false,
12510
12780
  trackedChanges: trackedChangeWireName(opts.trackedChanges),
12511
12781
  revisionAuthor: opts.revisionAuthor
12512
12782
  }));
12513
- const editor = new _DocxEditor(container, exports, handle, opts);
12514
- try {
12515
- editor.refreshAnchorMap();
12516
- if (opts.headerFooter) editor.createRegion();
12517
- const fullHtml = editor.renderFullHtml(bytes);
12518
- if (opts.paginated) editor.mountPaginated(fullHtml);
12519
- else editor.mountHtml(fullHtml);
12520
- editor.syncRegionToBody();
12521
- editor.setupBlockDrag();
12522
- if (opts.comments) editor.createGutter();
12523
- return editor;
12524
- } catch (error) {
12525
- editor.close();
12526
- throw error;
12783
+ return new _DocxEditor(container, exports, handle, opts);
12784
+ }
12785
+ /** The steps every mount ends with once the body is in the DOM. */
12786
+ finishMount() {
12787
+ this.syncRegionToBody();
12788
+ this.setupBlockDrag();
12789
+ if (this.options.comments) this.createGutter();
12790
+ }
12791
+ /**
12792
+ * The windowed mount behind {@link openAsync}: chrome first, then body units in plan order,
12793
+ * a group-aligned window per task. See {@link openAsync} for the contract.
12794
+ */
12795
+ async mountWindowed(windowSize, onProgress) {
12796
+ const bridge = this.exports.DocxSessionBridge;
12797
+ const profile = JSON.stringify({ ...JSON.parse(this.editorRenderProfile()), stampAnchors: true });
12798
+ const chrome = bridge.RenderEditorChromeHtml(this.handle, profile);
12799
+ if (chrome.trimStart().startsWith("{")) {
12800
+ throw new Error(JSON.parse(chrome).error ?? "chrome render failed");
12801
+ }
12802
+ const parsed = new DOMParser().parseFromString(chrome, "text/html");
12803
+ parsed.body.querySelectorAll(`[data-section-index] > [data-anchor="${CHROME_CARRIER_ANCHOR}"]`).forEach((el) => el.remove());
12804
+ const styles = Array.from(parsed.querySelectorAll("style")).map((s) => s.outerHTML).join("");
12805
+ const flow = document.createElement("div");
12806
+ flow.className = "docx-body-flow";
12807
+ flow.innerHTML = parsed.body.innerHTML;
12808
+ const hosts = /* @__PURE__ */ new Map();
12809
+ flow.querySelectorAll("[data-section-index]").forEach((el) => hosts.set(Number(el.getAttribute("data-section-index")), el));
12810
+ const attachNow = !this.options.paginated;
12811
+ const wireNow = attachNow && this.options.editable;
12812
+ if (wireNow) this.wireBlocks(flow);
12813
+ if (attachNow) {
12814
+ this.region?.detachPages();
12815
+ this.container.innerHTML = styles;
12816
+ this.readoptGutter();
12817
+ this.container.appendChild(flow);
12818
+ this.editRoot = flow;
12819
+ }
12820
+ const plan = JSON.parse(this.renderPlanJson());
12821
+ if (plan.error) throw new Error(plan.error);
12822
+ const units = plan.body;
12823
+ const sectionOf = new Map(units.map((u) => [unidOf(u.id), u.section ?? 0]));
12824
+ const mounted = /* @__PURE__ */ new Set();
12825
+ const place = (el, sameHostAs) => {
12826
+ el.removeAttribute("xmlns");
12827
+ const unit = el.hasAttribute("data-anchor") ? el : el.querySelector("[data-anchor]");
12828
+ const unid = unit?.getAttribute("data-anchor") ?? "";
12829
+ const host = sameHostAs ?? hosts.get(sectionOf.get(unid) ?? 0) ?? hosts.values().next().value ?? flow;
12830
+ host.insertBefore(el, host.querySelector(":scope > section.endnotes"));
12831
+ if (wireNow) {
12832
+ if (el.hasAttribute("data-anchor")) this.wireBlock(el);
12833
+ this.wireBlocks(el);
12834
+ }
12835
+ unit && mounted.add(unid);
12836
+ el.querySelectorAll("[data-anchor]").forEach((n) => mounted.add(n.getAttribute("data-anchor")));
12837
+ return host;
12838
+ };
12839
+ for (let start2 = 0; start2 < units.length; ) {
12840
+ let end = Math.min(start2 + windowSize, units.length);
12841
+ while (end < units.length && units[end].group !== void 0 && units[end].group === units[end - 1].group) end++;
12842
+ const window2 = units.slice(start2, end);
12843
+ const rendered = JSON.parse(bridge.RenderEditorRangeHtml(
12844
+ this.handle,
12845
+ JSON.stringify(window2.map((u) => u.id)),
12846
+ profile
12847
+ ));
12848
+ if (!Array.isArray(rendered)) throw new Error(rendered.error ?? "window render failed");
12849
+ for (const html of rendered) {
12850
+ let host;
12851
+ for (const el of Array.from(new DOMParser().parseFromString(html, "text/html").body.children)) {
12852
+ host = place(el, host);
12853
+ }
12854
+ }
12855
+ for (const unit of window2) {
12856
+ if (mounted.has(unidOf(unit.id))) continue;
12857
+ const el = this.renderInto(unit.id);
12858
+ if (el) place(el);
12859
+ }
12860
+ start2 = end;
12861
+ onProgress?.(start2, units.length);
12862
+ if (start2 < units.length) await yieldToEventLoop();
12863
+ }
12864
+ if (attachNow) {
12865
+ this.stampPlanState();
12866
+ if (this.region) this.dockBands(flow);
12867
+ this.viewport.attach(flow, true);
12868
+ } else {
12869
+ this.mountPaginated(parsed.head.innerHTML + flow.innerHTML);
12527
12870
  }
12528
12871
  }
12529
12872
  /**