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
@@ -113,6 +113,37 @@ var require_dist = __commonJS({
113
113
  }
114
114
  });
115
115
 
116
+ // src/verification-request.ts
117
+ function serializeVerificationRequest(request) {
118
+ if (request === null || typeof request !== "object" || Array.isArray(request)) {
119
+ throw new RangeError("a verification request must be an object");
120
+ }
121
+ const { companionArtifacts, ...rest } = request;
122
+ const wire = { ...rest };
123
+ if (companionArtifacts !== void 0) {
124
+ wire.companionArtifacts = companionArtifacts.map(encodeCompanion);
125
+ }
126
+ return JSON.stringify(wire);
127
+ }
128
+ function encodeCompanion(artifact) {
129
+ const { bytes, ...rest } = artifact;
130
+ const wire = { ...rest };
131
+ if (bytes !== void 0) wire.bytesB64 = bytesToBase64(bytes);
132
+ return wire;
133
+ }
134
+ function bytesToBase64(bytes) {
135
+ if (typeof btoa === "function") {
136
+ let binary = "";
137
+ const chunkSize = 32768;
138
+ for (let i = 0; i < bytes.length; i += chunkSize) {
139
+ const chunk = bytes.subarray(i, i + chunkSize);
140
+ binary += String.fromCharCode.apply(null, chunk);
141
+ }
142
+ return btoa(binary);
143
+ }
144
+ return Buffer.from(bytes).toString("base64");
145
+ }
146
+
116
147
  // src/types.ts
117
148
  var ProjectionScopes = /* @__PURE__ */ ((ProjectionScopes2) => {
118
149
  ProjectionScopes2[ProjectionScopes2["Body"] = 1] = "Body";
@@ -382,9 +413,23 @@ function mutationBatchChangeSet(before, after, key) {
382
413
  modified: after.filter((_, index) => modified[index])
383
414
  };
384
415
  }
416
+ var BATCH_REPLAY_CAVEATS = {
417
+ revisionDates: "Tracked-revision date attributes may use the execution clock; compare revision ids, authors, types, text, and anchors across separate executions.",
418
+ commentDates: "Comment date attributes may be generated from the execution clock; supply dates explicitly when byte-identical replay is required.",
419
+ annotationMetadata: "Auto-generated annotation ids or creation timestamps are execution metadata; supply id and created explicitly when byte-identical replay is required.",
420
+ 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."
421
+ };
422
+ var BATCH_REPLAY_CAVEAT_TEXTS = new Set(Object.values(BATCH_REPLAY_CAVEATS));
423
+ var RETAINED_PREVIEW_RECEIPTS = 8;
385
424
  var DocxSession = class _DocxSession {
386
425
  /** @internal */
387
426
  constructor(handle, wasm) {
427
+ /**
428
+ * The receipts this client composed for previews it retained, keyed by previewId. The host
429
+ * keeps the package and the binding; the step receipts live only here, so a commit can return
430
+ * the previewed steps and change sets without the host re-parsing a client-composed result.
431
+ */
432
+ this.retainedPreviewReceipts = /* @__PURE__ */ new Map();
388
433
  // ─── Raw escape hatch ────────────────────────────────────────────────
389
434
  this.raw = {
390
435
  getXml: (anchorId) => this.wasm.RawGetXml(this.handle, anchorId),
@@ -449,10 +494,152 @@ var DocxSession = class _DocxSession {
449
494
  * Execute synchronous mutations atomically by default. Atomic success is one undo/version
450
495
  * unit; any failed or thrown step restores the exact package and history checkpoint.
451
496
  */
452
- executeBatch(steps, mode = "atomic") {
497
+ executeBatch(steps, mode = "atomic", transaction) {
453
498
  if (mode !== "atomic" && mode !== "best_effort") {
454
499
  throw new RangeError(`unknown mutation batch mode: ${String(mode)}`);
455
500
  }
501
+ if (transaction === void 0) return this.recorded(steps, mode, void 0, () => this.runBatch(steps, mode));
502
+ return this.runTransactional(
503
+ transaction,
504
+ mode,
505
+ (identity) => this.recorded(steps, mode, identity, () => this.runBatch(steps, mode))
506
+ );
507
+ }
508
+ /**
509
+ * What the session's host-owned delivery evidence recorder holds (issue #748). `enabled` is
510
+ * false, with the reason, unless the session was opened with `captureDeliveryEvidence`.
511
+ */
512
+ getDeliveryEvidenceStatus() {
513
+ if (!this.wasm.GetDeliveryEvidenceStatus) {
514
+ throw new Error("This WASM bundle predates delivery evidence; rebuild docxodus.");
515
+ }
516
+ return JSON.parse(this.wasm.GetDeliveryEvidenceStatus(this.handle));
517
+ }
518
+ /**
519
+ * Build the receipt-bearing delivery of this session through the shared bundle service: the
520
+ * clean current package (`final-docx`), the source-to-delivered semantic delta, and the change
521
+ * receipt (`change-receipt`) minted from the captured evidence — verifiable with
522
+ * `verifyDeliveryReceipt` against the returned artifact bytes. A history that cannot be
523
+ * attested yields an `incomplete` bundle whose receipt artifact carries the reason, and
524
+ * `evidence.unavailableReason` says why.
525
+ */
526
+ buildDeliveryReceipt(options) {
527
+ if (!this.wasm.BuildDeliveryReceipt) {
528
+ throw new Error("This WASM bundle predates delivery evidence; rebuild docxodus.");
529
+ }
530
+ const wire = JSON.parse(this.wasm.BuildDeliveryReceipt(this.handle, JSON.stringify(options ?? {})));
531
+ const decode = (base64) => Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
532
+ return {
533
+ status: wire.status,
534
+ verified: wire.verified,
535
+ manifest: wire.manifest,
536
+ manifestBytes: decode(wire.manifestBytes),
537
+ artifacts: wire.artifacts.map((artifact) => {
538
+ const { bytes, ...rest } = artifact;
539
+ return bytes === void 0 ? rest : { ...rest, bytes: decode(bytes) };
540
+ }),
541
+ ...wire.evidence ? { evidence: wire.evidence } : {}
542
+ };
543
+ }
544
+ /**
545
+ * Describe a batch to the session's delivery evidence recorder before running it, and hand
546
+ * it the step results afterwards, so the version steps the batch produced are recorded under
547
+ * this description rather than as unlabeled mutations. A bundle without the recorder, or a
548
+ * session not capturing evidence, simply runs the batch.
549
+ */
550
+ recorded(steps, mode, identity, run) {
551
+ if (!this.wasm.BeginDeliveryEvidence || !this.wasm.CompleteDeliveryEvidence || !this.wasm.AbandonDeliveryEvidence) {
552
+ return run();
553
+ }
554
+ const described = this.wasm.BeginDeliveryEvidence(
555
+ this.handle,
556
+ JSON.stringify(steps.map((step) => step.args === void 0 ? { tool: step.tool, action: step.action } : { tool: step.tool, action: step.action, args: step.args })),
557
+ mode,
558
+ identity ? JSON.stringify({ transactionId: identity.transactionId, requestFingerprint: identity.requestFingerprint }) : ""
559
+ );
560
+ if (!described) return run();
561
+ let result;
562
+ try {
563
+ result = run();
564
+ return result;
565
+ } finally {
566
+ if (result) this.wasm.CompleteDeliveryEvidence(this.handle, JSON.stringify(result.steps));
567
+ else this.wasm.AbandonDeliveryEvidence(this.handle);
568
+ }
569
+ }
570
+ /**
571
+ * Make a preview retained by {@link previewBatch} (`retain: true`) the live document exactly
572
+ * as previewed: the previewed package is restored byte-for-byte as one undo step, so the
573
+ * generated anchor ids, timestamps and `packageHash` are exactly those the preview reported.
574
+ * The commit is guarded — it refuses with `preview_stale`, editing nothing, when the session's
575
+ * version, package content, tracked-changes mode or revision author moved since the preview,
576
+ * and with `preview_not_found` once the preview expired, was evicted, or was already
577
+ * committed. A `transaction` makes a retry after a lost response safe, as for
578
+ * {@link executeBatch}.
579
+ */
580
+ commitPreview(previewId, transaction) {
581
+ if (!this.wasm.CommitPreview) {
582
+ throw new Error("This WASM bundle predates retained previews; rebuild docxodus.");
583
+ }
584
+ const commit = () => {
585
+ const envelope = JSON.parse(this.wasm.CommitPreview(this.handle, previewId));
586
+ if (!envelope.success) {
587
+ if (envelope.failure?.error.code === "preview_not_found") this.retainedPreviewReceipts.delete(previewId);
588
+ return envelope;
589
+ }
590
+ const receipt = this.retainedPreviewReceipts.get(previewId);
591
+ this.retainedPreviewReceipts.delete(previewId);
592
+ if (!receipt) return envelope;
593
+ return {
594
+ ...receipt,
595
+ preview: false,
596
+ html: null,
597
+ baseVersion: envelope.baseVersion,
598
+ resultVersion: envelope.resultVersion,
599
+ packageHash: envelope.packageHash,
600
+ warnings: receipt.warnings.filter((warning) => !BATCH_REPLAY_CAVEAT_TEXTS.has(warning)),
601
+ retention: envelope.retention
602
+ };
603
+ };
604
+ if (transaction === void 0) return commit();
605
+ return this.runTransactional(transaction, "atomic", () => commit());
606
+ }
607
+ runTransactional(transaction, mode, body) {
608
+ if (!this.wasm.BeginMutationTransaction || !this.wasm.CompleteMutationTransaction || !this.wasm.AbandonMutationTransaction) {
609
+ throw new Error("This WASM bundle predates mutation transactions; rebuild docxodus.");
610
+ }
611
+ if (typeof transaction.transactionId !== "string") {
612
+ throw new RangeError("transactionId must be a string");
613
+ }
614
+ if (transaction.request === null || typeof transaction.request !== "object" || Array.isArray(transaction.request)) {
615
+ throw new RangeError("a mutation transaction needs a request object describing the batch");
616
+ }
617
+ const decision = JSON.parse(this.wasm.BeginMutationTransaction(
618
+ this.handle,
619
+ transaction.transactionId,
620
+ JSON.stringify({ ...transaction.request, mode })
621
+ ));
622
+ if (decision.response !== null) {
623
+ return JSON.parse(decision.response);
624
+ }
625
+ let completed = false;
626
+ try {
627
+ const result = {
628
+ ...body(decision.transaction),
629
+ transaction: decision.transaction
630
+ };
631
+ this.wasm.CompleteMutationTransaction(
632
+ this.handle,
633
+ transaction.transactionId,
634
+ JSON.stringify(result)
635
+ );
636
+ completed = true;
637
+ return result;
638
+ } finally {
639
+ if (!completed) this.wasm.AbandonMutationTransaction(this.handle, transaction.transactionId);
640
+ }
641
+ }
642
+ runBatch(steps, mode) {
456
643
  const baseVersion = this.getVersion();
457
644
  const observationWarnings = [];
458
645
  const inspect = (label, read, fallback) => {
@@ -490,16 +677,16 @@ var DocxSession = class _DocxSession {
490
677
  );
491
678
  const warnings = [...observationWarnings];
492
679
  if ([...revisionChanges.added, ...revisionChanges.modified].some((revision) => revision.date !== void 0 && revision.date !== null)) {
493
- warnings.push("Tracked-revision date attributes may use the execution clock; compare revision ids, authors, types, text, and anchors across separate executions.");
680
+ warnings.push(BATCH_REPLAY_CAVEATS.revisionDates);
494
681
  }
495
682
  if ([...commentChanges.added, ...commentChanges.modified].some((comment) => comment.date !== void 0 && comment.date !== null)) {
496
- warnings.push("Comment date attributes may be generated from the execution clock; supply dates explicitly when byte-identical replay is required.");
683
+ warnings.push(BATCH_REPLAY_CAVEATS.commentDates);
497
684
  }
498
685
  if (annotationChanges.added.some((annotation) => annotation.created !== void 0 && annotation.created !== null)) {
499
- warnings.push("Auto-generated annotation ids or creation timestamps are execution metadata; supply id and created explicitly when byte-identical replay is required.");
686
+ warnings.push(BATCH_REPLAY_CAVEATS.annotationMetadata);
500
687
  }
501
688
  if (result.steps.some((step) => step.results.some((edit) => edit.created.length > 0))) {
502
- 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.");
689
+ warnings.push(BATCH_REPLAY_CAVEATS.createdAnchors);
503
690
  }
504
691
  if (mode === "best_effort" && !result.success) {
505
692
  warnings.push("Best-effort execution retains every successful step despite later failures.");
@@ -723,7 +910,27 @@ var DocxSession = class _DocxSession {
723
910
  } catch (error) {
724
911
  warnings.push(`Preview HTML could not be generated: ${error instanceof Error ? error.message : String(error)}`);
725
912
  }
726
- return { ...result, preview: true, warnings, html };
913
+ let retention;
914
+ if (options?.retain) {
915
+ if (!this.wasm.RetainPreview) {
916
+ throw new Error("This WASM bundle predates retained previews; rebuild docxodus.");
917
+ }
918
+ if (!result.success) {
919
+ warnings.push("The preview did not succeed, so it was not retained for commit.");
920
+ } else {
921
+ const retained = JSON.parse(this.wasm.RetainPreview(shadow.handle));
922
+ warnings.push(...retained.warnings);
923
+ retention = retained.retention ?? void 0;
924
+ }
925
+ }
926
+ const preview = retention ? { ...result, preview: true, warnings, html, retention } : { ...result, preview: true, warnings, html };
927
+ if (retention) {
928
+ if (this.retainedPreviewReceipts.size >= RETAINED_PREVIEW_RECEIPTS) {
929
+ this.retainedPreviewReceipts.delete(this.retainedPreviewReceipts.keys().next().value);
930
+ }
931
+ this.retainedPreviewReceipts.set(retention.previewId, { ...preview, html: null });
932
+ }
933
+ return preview;
727
934
  } finally {
728
935
  shadow.close();
729
936
  }
@@ -1302,6 +1509,18 @@ var DocxSession = class _DocxSession {
1302
1509
  imageBytesToBase64(bytes)
1303
1510
  ));
1304
1511
  }
1512
+ /**
1513
+ * Convert an external linked picture into an embedded one using bytes the caller fetched;
1514
+ * the engine never reaches the network itself. Refused for pictures that already embed
1515
+ * their media — see `ImageOccurrence.operations`.
1516
+ */
1517
+ embedLinkedImage(imageId, bytes) {
1518
+ return JSON.parse(this.wasm.EmbedLinkedImage(
1519
+ this.handle,
1520
+ imageId,
1521
+ imageBytesToBase64(bytes)
1522
+ ));
1523
+ }
1305
1524
  setImageDimensions(imageId, dimensions) {
1306
1525
  return JSON.parse(this.wasm.SetImageDimensions(
1307
1526
  this.handle,
@@ -1432,6 +1651,28 @@ var DocxSession = class _DocxSession {
1432
1651
  listRevisions() {
1433
1652
  return JSON.parse(this.wasm.ListRevisions(this.handle));
1434
1653
  }
1654
+ /**
1655
+ * The explicit repairs the registry offers for entries it refuses to resolve (issues
1656
+ * #754–#758): which carriers are defective, whether a unique repair exists, and what it
1657
+ * would do. Read-only; listing, accept and reject never repair.
1658
+ */
1659
+ listRevisionRepairs() {
1660
+ if (!this.wasm.ListRevisionRepairs) {
1661
+ throw new Error("This WASM bundle predates revision repairs; rebuild docxodus.");
1662
+ }
1663
+ return JSON.parse(this.wasm.ListRevisionRepairs(this.handle));
1664
+ }
1665
+ /**
1666
+ * Perform requested repairs atomically as one undo step. A kind the registry did not offer,
1667
+ * a non-repairable proposal, or a wrap-as-deletion without author and date refuses the whole
1668
+ * call (`revision_repair_rejected`) with nothing mutated. Repaired entries get new ids.
1669
+ */
1670
+ repairRevisions(repairs) {
1671
+ if (!this.wasm.RepairRevisions) {
1672
+ throw new Error("This WASM bundle predates revision repairs; rebuild docxodus.");
1673
+ }
1674
+ return JSON.parse(this.wasm.RepairRevisions(this.handle, JSON.stringify(repairs)));
1675
+ }
1435
1676
  /** Accept ONE revision by the id {@link listRevisions} reported — insertions keep
1436
1677
  * their content, deletions are carried out, a move materializes at its destination,
1437
1678
  * a format change keeps the new properties. Undoable. */
@@ -1789,7 +2030,16 @@ var DocxSession = class _DocxSession {
1789
2030
  * With initial projection capture enabled (the default), exact opening bytes are the
1790
2031
  * baseline used for dispositions and semantic/package deltas.
1791
2032
  */
1792
- verifyDeliverable() {
2033
+ verifyDeliverable(request) {
2034
+ if (request !== void 0) {
2035
+ if (!this.wasm.VerifyDeliverableWithRequest) {
2036
+ throw new Error("This WASM bundle predates full verification requests; rebuild docxodus.");
2037
+ }
2038
+ return JSON.parse(this.wasm.VerifyDeliverableWithRequest(
2039
+ this.handle,
2040
+ serializeVerificationRequest(request)
2041
+ ));
2042
+ }
1793
2043
  return JSON.parse(
1794
2044
  this.wasm.VerifyDeliverable(this.handle)
1795
2045
  );
@@ -2018,6 +2268,7 @@ var DocxSession = class _DocxSession {
2018
2268
  return this.wasm.Save(this.handle);
2019
2269
  }
2020
2270
  close() {
2271
+ this.retainedPreviewReceipts.clear();
2021
2272
  this.wasm.CloseSession(this.handle);
2022
2273
  }
2023
2274
  // TypeScript 5.2+ disposable protocol
@@ -2038,6 +2289,129 @@ function openDocxSession(bytes, wasmExports2, settings) {
2038
2289
  return new DocxSession(handle, bridge);
2039
2290
  }
2040
2291
 
2292
+ // src/external-annotation-wire.ts
2293
+ function readPawlsPage(p) {
2294
+ return {
2295
+ page: {
2296
+ width: p.Page?.Width ?? p.page?.width,
2297
+ height: p.Page?.Height ?? p.page?.height,
2298
+ index: p.Page?.Index ?? p.page?.index
2299
+ },
2300
+ tokens: (p.Tokens || p.tokens || []).map((t) => ({
2301
+ x: t.X ?? t.x,
2302
+ y: t.Y ?? t.y,
2303
+ width: t.Width ?? t.width,
2304
+ height: t.Height ?? t.height,
2305
+ text: t.Text ?? t.text
2306
+ }))
2307
+ };
2308
+ }
2309
+ function readAnnotationJson(json) {
2310
+ if (!json) return void 0;
2311
+ if (json.Start !== void 0 || json.start !== void 0) {
2312
+ return {
2313
+ id: json.Id ?? json.id,
2314
+ start: json.Start ?? json.start,
2315
+ end: json.End ?? json.end,
2316
+ text: json.Text ?? json.text
2317
+ };
2318
+ }
2319
+ const result = {};
2320
+ for (const [key, value] of Object.entries(json)) {
2321
+ const v = value;
2322
+ result[key] = {
2323
+ bounds: {
2324
+ top: v.Bounds?.Top ?? v.bounds?.top,
2325
+ bottom: v.Bounds?.Bottom ?? v.bounds?.bottom,
2326
+ left: v.Bounds?.Left ?? v.bounds?.left,
2327
+ right: v.Bounds?.Right ?? v.bounds?.right
2328
+ },
2329
+ tokensJsons: (v.TokensJsons || v.tokensJsons || []).map((t) => ({
2330
+ pageIndex: t.PageIndex ?? t.pageIndex,
2331
+ tokenIndex: t.TokenIndex ?? t.tokenIndex
2332
+ })),
2333
+ rawText: v.RawText ?? v.rawText
2334
+ };
2335
+ }
2336
+ return result;
2337
+ }
2338
+ function readAnnotation(a) {
2339
+ return {
2340
+ id: a.Id ?? a.id,
2341
+ annotationLabel: a.AnnotationLabel ?? a.annotationLabel,
2342
+ rawText: a.RawText ?? a.rawText,
2343
+ page: a.Page ?? a.page,
2344
+ annotationJson: readAnnotationJson(a.AnnotationJson ?? a.annotationJson),
2345
+ parentId: a.ParentId ?? a.parentId,
2346
+ annotationType: a.AnnotationType ?? a.annotationType,
2347
+ structural: a.Structural ?? a.structural
2348
+ };
2349
+ }
2350
+ function readRelationship(r) {
2351
+ return {
2352
+ id: r.Id ?? r.id,
2353
+ relationshipLabel: r.RelationshipLabel ?? r.relationshipLabel,
2354
+ sourceAnnotationIds: r.SourceAnnotationIds ?? r.sourceAnnotationIds ?? [],
2355
+ targetAnnotationIds: r.TargetAnnotationIds ?? r.targetAnnotationIds ?? [],
2356
+ structural: r.Structural ?? r.structural
2357
+ };
2358
+ }
2359
+ function readLabel(l) {
2360
+ return {
2361
+ id: l.Id ?? l.id,
2362
+ color: l.Color ?? l.color,
2363
+ description: l.Description ?? l.description ?? "",
2364
+ icon: l.Icon ?? l.icon ?? "",
2365
+ text: l.Text ?? l.text,
2366
+ labelType: l.LabelType ?? l.labelType ?? "text"
2367
+ };
2368
+ }
2369
+ function readLabels(raw) {
2370
+ const labels = {};
2371
+ for (const [key, value] of Object.entries(raw || {})) labels[key] = readLabel(value);
2372
+ return labels;
2373
+ }
2374
+ function readOpenContractExport(parsed) {
2375
+ return {
2376
+ title: parsed.Title ?? parsed.title,
2377
+ content: parsed.Content ?? parsed.content,
2378
+ description: parsed.Description ?? parsed.description,
2379
+ pageCount: parsed.PageCount ?? parsed.pageCount,
2380
+ pawlsFileContent: (parsed.PawlsFileContent || parsed.pawlsFileContent || []).map(readPawlsPage),
2381
+ docLabels: parsed.DocLabels ?? parsed.docLabels ?? [],
2382
+ labelledText: (parsed.LabelledText || parsed.labelledText || []).map(readAnnotation),
2383
+ relationships: (parsed.Relationships || parsed.relationships)?.map(readRelationship)
2384
+ };
2385
+ }
2386
+ function readExternalAnnotationSet(parsed) {
2387
+ return {
2388
+ documentId: parsed.DocumentId ?? parsed.documentId,
2389
+ documentHash: parsed.DocumentHash ?? parsed.documentHash,
2390
+ createdAt: parsed.CreatedAt ?? parsed.createdAt,
2391
+ updatedAt: parsed.UpdatedAt ?? parsed.updatedAt,
2392
+ version: parsed.Version ?? parsed.version,
2393
+ ...readOpenContractExport(parsed),
2394
+ textLabels: readLabels(parsed.TextLabels || parsed.textLabels),
2395
+ docLabelDefinitions: readLabels(parsed.DocLabelDefinitions || parsed.docLabelDefinitions)
2396
+ };
2397
+ }
2398
+ function readExternalAnnotationValidation(parsed) {
2399
+ return {
2400
+ isValid: parsed.IsValid ?? parsed.isValid,
2401
+ hashMismatch: parsed.HashMismatch ?? parsed.hashMismatch,
2402
+ issues: (parsed.Issues || parsed.issues || []).map((i) => ({
2403
+ annotationId: i.AnnotationId ?? i.annotationId,
2404
+ issueType: i.IssueType ?? i.issueType,
2405
+ description: i.Description ?? i.description,
2406
+ expectedText: i.ExpectedText ?? i.expectedText,
2407
+ actualText: i.ActualText ?? i.actualText
2408
+ }))
2409
+ };
2410
+ }
2411
+ function readProjectedHtml(parsed) {
2412
+ return parsed.Html ?? parsed.html;
2413
+ }
2414
+
2041
2415
  // src/history.ts
2042
2416
  var MAX_HISTORY_ARCHIVE_BYTES = 64 * 1024 * 1024;
2043
2417
  var DocxHistoryError = class extends Error {
@@ -6426,11 +6800,21 @@ async function generatePackageManifest(document2) {
6426
6800
  exports.DocumentConverter.GeneratePackageManifest(bytes)
6427
6801
  );
6428
6802
  }
6429
- async function verifyDeliverable(document2, baseline) {
6803
+ async function verifyDeliverable(document2, baseline, request) {
6430
6804
  const exports = ensureInitialized();
6431
6805
  const bytes = await toBytes(document2);
6432
6806
  const baselineBytes = baseline === void 0 ? void 0 : await toBytes(baseline);
6433
6807
  await yieldToMain();
6808
+ if (request !== void 0) {
6809
+ const requestJson = serializeVerificationRequest(request);
6810
+ const converter = exports.DocumentConverter;
6811
+ if (!converter.VerifyDeliverableWithRequest || !converter.VerifyDeliverableWithBaselineAndRequest) {
6812
+ throw new Error("This WASM bundle predates full verification requests; rebuild docxodus.");
6813
+ }
6814
+ return JSON.parse(
6815
+ baselineBytes === void 0 ? converter.VerifyDeliverableWithRequest(bytes, requestJson) : converter.VerifyDeliverableWithBaselineAndRequest(baselineBytes, bytes, requestJson)
6816
+ );
6817
+ }
6434
6818
  return JSON.parse(
6435
6819
  baselineBytes === void 0 ? exports.DocumentConverter.VerifyDeliverable(bytes) : exports.DocumentConverter.VerifyDeliverableWithBaseline(
6436
6820
  baselineBytes,
@@ -6444,7 +6828,7 @@ async function verifyDeliveryReceipt(receiptJson, artifacts) {
6444
6828
  Object.fromEntries(
6445
6829
  Object.entries(artifacts).map(([artifactId, bytes]) => [
6446
6830
  artifactId,
6447
- bytesToBase64(bytes)
6831
+ bytesToBase642(bytes)
6448
6832
  ])
6449
6833
  )
6450
6834
  );
@@ -6675,7 +7059,7 @@ async function docxDiffCompareBatch(baseline, candidates, settings, products) {
6675
7059
  const bytes = await toBytes(candidates[i].document);
6676
7060
  payload.push({
6677
7061
  name: candidates[i].name ?? String(i),
6678
- docB64: bytesToBase64(bytes)
7062
+ docB64: bytesToBase642(bytes)
6679
7063
  });
6680
7064
  }
6681
7065
  await yieldToMain();
@@ -6751,7 +7135,7 @@ async function docxDiffRejectRevisions(redline) {
6751
7135
  }
6752
7136
  return result;
6753
7137
  }
6754
- function bytesToBase64(bytes) {
7138
+ function bytesToBase642(bytes) {
6755
7139
  if (typeof btoa === "function") {
6756
7140
  let binary = "";
6757
7141
  const chunkSize = 32768;
@@ -6767,7 +7151,7 @@ async function reviewersJson(reviewers) {
6767
7151
  const arr = await Promise.all(
6768
7152
  reviewers.map(async (r) => ({
6769
7153
  author: r.author,
6770
- docB64: bytesToBase64(await toBytes(r.document))
7154
+ docB64: bytesToBase642(await toBytes(r.document))
6771
7155
  }))
6772
7156
  );
6773
7157
  return JSON.stringify(arr);
@@ -7077,77 +7461,7 @@ async function exportToOpenContract(document2) {
7077
7461
  const error = parseError(result);
7078
7462
  throw new Error(`Failed to export to OpenContract format: ${error.error}`);
7079
7463
  }
7080
- const parsed = JSON.parse(result);
7081
- const convertPawlsPage = (p) => ({
7082
- page: {
7083
- width: p.Page?.Width ?? p.page?.width,
7084
- height: p.Page?.Height ?? p.page?.height,
7085
- index: p.Page?.Index ?? p.page?.index
7086
- },
7087
- tokens: (p.Tokens || p.tokens || []).map((t) => ({
7088
- x: t.X ?? t.x,
7089
- y: t.Y ?? t.y,
7090
- width: t.Width ?? t.width,
7091
- height: t.Height ?? t.height,
7092
- text: t.Text ?? t.text
7093
- }))
7094
- });
7095
- const convertAnnotation = (a) => ({
7096
- id: a.Id ?? a.id,
7097
- annotationLabel: a.AnnotationLabel ?? a.annotationLabel,
7098
- rawText: a.RawText ?? a.rawText,
7099
- page: a.Page ?? a.page,
7100
- annotationJson: convertAnnotationJson(a.AnnotationJson ?? a.annotationJson),
7101
- parentId: a.ParentId ?? a.parentId,
7102
- annotationType: a.AnnotationType ?? a.annotationType,
7103
- structural: a.Structural ?? a.structural
7104
- });
7105
- const convertAnnotationJson = (json) => {
7106
- if (!json) return void 0;
7107
- if (json.Start !== void 0 || json.start !== void 0) {
7108
- return {
7109
- id: json.Id ?? json.id,
7110
- start: json.Start ?? json.start,
7111
- end: json.End ?? json.end,
7112
- text: json.Text ?? json.text
7113
- };
7114
- }
7115
- const result2 = {};
7116
- for (const [key, value] of Object.entries(json)) {
7117
- const v = value;
7118
- result2[key] = {
7119
- bounds: {
7120
- top: v.Bounds?.Top ?? v.bounds?.top,
7121
- bottom: v.Bounds?.Bottom ?? v.bounds?.bottom,
7122
- left: v.Bounds?.Left ?? v.bounds?.left,
7123
- right: v.Bounds?.Right ?? v.bounds?.right
7124
- },
7125
- tokensJsons: (v.TokensJsons || v.tokensJsons || []).map((t) => ({
7126
- pageIndex: t.PageIndex ?? t.pageIndex,
7127
- tokenIndex: t.TokenIndex ?? t.tokenIndex
7128
- })),
7129
- rawText: v.RawText ?? v.rawText
7130
- };
7131
- }
7132
- return result2;
7133
- };
7134
- const convertRelationship = (r) => ({
7135
- id: r.Id ?? r.id,
7136
- relationshipLabel: r.RelationshipLabel ?? r.relationshipLabel,
7137
- sourceAnnotationIds: r.SourceAnnotationIds ?? r.sourceAnnotationIds ?? [],
7138
- targetAnnotationIds: r.TargetAnnotationIds ?? r.targetAnnotationIds ?? [],
7139
- structural: r.Structural ?? r.structural
7140
- });
7141
- return {
7142
- title: parsed.Title ?? parsed.title,
7143
- content: parsed.Content ?? parsed.content,
7144
- description: parsed.Description ?? parsed.description,
7145
- pageCount: parsed.PageCount ?? parsed.pageCount,
7146
- pawlsFileContent: (parsed.PawlsFileContent || parsed.pawlsFileContent || []).map(convertPawlsPage),
7147
- docLabels: parsed.DocLabels ?? parsed.docLabels ?? [],
7148
- labelledText: (parsed.LabelledText || parsed.labelledText || []).map(convertAnnotation),
7149
- relationships: (parsed.Relationships || parsed.relationships)?.map(convertRelationship)
7150
- };
7464
+ return readOpenContractExport(JSON.parse(result));
7151
7465
  }
7152
7466
  async function convertWmlToMarkdown(document2, settings = {}) {
7153
7467
  const exports = ensureInitialized();
@@ -7253,8 +7567,7 @@ async function createExternalAnnotationSet(document2, documentId) {
7253
7567
  const error = parseError(result);
7254
7568
  throw new Error(`Failed to create external annotation set: ${error.error}`);
7255
7569
  }
7256
- const parsed = JSON.parse(result);
7257
- return convertExternalAnnotationSet(parsed);
7570
+ return readExternalAnnotationSet(JSON.parse(result));
7258
7571
  }
7259
7572
  async function validateExternalAnnotations(document2, annotationSet) {
7260
7573
  const exports = ensureInitialized();
@@ -7266,18 +7579,7 @@ async function validateExternalAnnotations(document2, annotationSet) {
7266
7579
  const error = parseError(result);
7267
7580
  throw new Error(`Failed to validate external annotations: ${error.error}`);
7268
7581
  }
7269
- const parsed = JSON.parse(result);
7270
- return {
7271
- isValid: parsed.IsValid ?? parsed.isValid,
7272
- hashMismatch: parsed.HashMismatch ?? parsed.hashMismatch,
7273
- issues: (parsed.Issues || parsed.issues || []).map((i) => ({
7274
- annotationId: i.AnnotationId ?? i.annotationId,
7275
- issueType: i.IssueType ?? i.issueType,
7276
- description: i.Description ?? i.description,
7277
- expectedText: i.ExpectedText ?? i.expectedText,
7278
- actualText: i.ActualText ?? i.actualText
7279
- }))
7280
- };
7582
+ return readExternalAnnotationValidation(JSON.parse(result));
7281
7583
  }
7282
7584
  async function convertDocxToHtmlWithExternalAnnotations(document2, annotationSet, conversionOptions, projectionOptions) {
7283
7585
  const exports = ensureInitialized();
@@ -7298,8 +7600,7 @@ async function convertDocxToHtmlWithExternalAnnotations(document2, annotationSet
7298
7600
  const error = parseError(result);
7299
7601
  throw new Error(`Failed to convert with external annotations: ${error.error}`);
7300
7602
  }
7301
- const parsed = JSON.parse(result);
7302
- return parsed.Html ?? parsed.html;
7603
+ return readProjectedHtml(JSON.parse(result));
7303
7604
  }
7304
7605
  async function searchTextOffsets(document2, searchText, maxResults = 100) {
7305
7606
  const exports = ensureInitialized();
@@ -7367,103 +7668,6 @@ function findTextOccurrences(documentText, searchText, maxResults = 100) {
7367
7668
  }
7368
7669
  return results;
7369
7670
  }
7370
- function convertExternalAnnotationSet(parsed) {
7371
- const convertLabel = (l) => ({
7372
- id: l.Id ?? l.id,
7373
- color: l.Color ?? l.color,
7374
- description: l.Description ?? l.description ?? "",
7375
- icon: l.Icon ?? l.icon ?? "",
7376
- text: l.Text ?? l.text,
7377
- labelType: l.LabelType ?? l.labelType ?? "text"
7378
- });
7379
- const convertPawlsPage = (p) => ({
7380
- page: {
7381
- width: p.Page?.Width ?? p.page?.width,
7382
- height: p.Page?.Height ?? p.page?.height,
7383
- index: p.Page?.Index ?? p.page?.index
7384
- },
7385
- tokens: (p.Tokens || p.tokens || []).map((t) => ({
7386
- x: t.X ?? t.x,
7387
- y: t.Y ?? t.y,
7388
- width: t.Width ?? t.width,
7389
- height: t.Height ?? t.height,
7390
- text: t.Text ?? t.text
7391
- }))
7392
- });
7393
- const convertAnnotation = (a) => ({
7394
- id: a.Id ?? a.id,
7395
- annotationLabel: a.AnnotationLabel ?? a.annotationLabel,
7396
- rawText: a.RawText ?? a.rawText,
7397
- page: a.Page ?? a.page,
7398
- annotationJson: convertAnnotationJson(a.AnnotationJson ?? a.annotationJson),
7399
- parentId: a.ParentId ?? a.parentId,
7400
- annotationType: a.AnnotationType ?? a.annotationType,
7401
- structural: a.Structural ?? a.structural
7402
- });
7403
- const convertAnnotationJson = (json) => {
7404
- if (!json) return void 0;
7405
- if (json.Start !== void 0 || json.start !== void 0) {
7406
- return {
7407
- id: json.Id ?? json.id,
7408
- start: json.Start ?? json.start,
7409
- end: json.End ?? json.end,
7410
- text: json.Text ?? json.text
7411
- };
7412
- }
7413
- const result = {};
7414
- for (const [key, value] of Object.entries(json)) {
7415
- const v = value;
7416
- result[key] = {
7417
- bounds: {
7418
- top: v.Bounds?.Top ?? v.bounds?.top,
7419
- bottom: v.Bounds?.Bottom ?? v.bounds?.bottom,
7420
- left: v.Bounds?.Left ?? v.bounds?.left,
7421
- right: v.Bounds?.Right ?? v.bounds?.right
7422
- },
7423
- tokensJsons: (v.TokensJsons || v.tokensJsons || []).map((t) => ({
7424
- pageIndex: t.PageIndex ?? t.pageIndex,
7425
- tokenIndex: t.TokenIndex ?? t.tokenIndex
7426
- })),
7427
- rawText: v.RawText ?? v.rawText
7428
- };
7429
- }
7430
- return result;
7431
- };
7432
- const convertRelationship = (r) => ({
7433
- id: r.Id ?? r.id,
7434
- relationshipLabel: r.RelationshipLabel ?? r.relationshipLabel,
7435
- sourceAnnotationIds: r.SourceAnnotationIds ?? r.sourceAnnotationIds ?? [],
7436
- targetAnnotationIds: r.TargetAnnotationIds ?? r.targetAnnotationIds ?? [],
7437
- structural: r.Structural ?? r.structural
7438
- });
7439
- const textLabels = {};
7440
- const rawTextLabels = parsed.TextLabels || parsed.textLabels || {};
7441
- for (const [key, value] of Object.entries(rawTextLabels)) {
7442
- textLabels[key] = convertLabel(value);
7443
- }
7444
- const docLabelDefinitions = {};
7445
- const rawDocLabelDefs = parsed.DocLabelDefinitions || parsed.docLabelDefinitions || {};
7446
- for (const [key, value] of Object.entries(rawDocLabelDefs)) {
7447
- docLabelDefinitions[key] = convertLabel(value);
7448
- }
7449
- return {
7450
- documentId: parsed.DocumentId ?? parsed.documentId,
7451
- documentHash: parsed.DocumentHash ?? parsed.documentHash,
7452
- createdAt: parsed.CreatedAt ?? parsed.createdAt,
7453
- updatedAt: parsed.UpdatedAt ?? parsed.updatedAt,
7454
- version: parsed.Version ?? parsed.version,
7455
- title: parsed.Title ?? parsed.title,
7456
- content: parsed.Content ?? parsed.content,
7457
- description: parsed.Description ?? parsed.description,
7458
- pageCount: parsed.PageCount ?? parsed.pageCount,
7459
- pawlsFileContent: (parsed.PawlsFileContent || parsed.pawlsFileContent || []).map(convertPawlsPage),
7460
- docLabels: parsed.DocLabels ?? parsed.docLabels ?? [],
7461
- labelledText: (parsed.LabelledText || parsed.labelledText || []).map(convertAnnotation),
7462
- relationships: (parsed.Relationships || parsed.relationships)?.map(convertRelationship),
7463
- textLabels,
7464
- docLabelDefinitions
7465
- };
7466
- }
7467
7671
  async function projectAnnotationsOntoHtml(html, annotationSet, projectionOptions) {
7468
7672
  const exports = ensureInitialized();
7469
7673
  await yieldToMain();
@@ -7478,8 +7682,7 @@ async function projectAnnotationsOntoHtml(html, annotationSet, projectionOptions
7478
7682
  const error = parseError(result);
7479
7683
  throw new Error(`Failed to project annotations: ${error.error}`);
7480
7684
  }
7481
- const parsed = JSON.parse(result);
7482
- return parsed.Html ?? parsed.html;
7685
+ return readProjectedHtml(JSON.parse(result));
7483
7686
  }
7484
7687
  async function addAnnotationToHtml(html, annotation, label, projectionOptions) {
7485
7688
  const exports = ensureInitialized();
@@ -7497,8 +7700,7 @@ async function addAnnotationToHtml(html, annotation, label, projectionOptions) {
7497
7700
  const error = parseError(result);
7498
7701
  throw new Error(`Failed to add annotation to HTML: ${error.error}`);
7499
7702
  }
7500
- const parsed = JSON.parse(result);
7501
- return parsed.Html ?? parsed.html;
7703
+ return readProjectedHtml(JSON.parse(result));
7502
7704
  }
7503
7705
  async function removeAnnotationFromHtml(html, annotationId, cssClassPrefix) {
7504
7706
  const exports = ensureInitialized();
@@ -7512,8 +7714,7 @@ async function removeAnnotationFromHtml(html, annotationId, cssClassPrefix) {
7512
7714
  const error = parseError(result);
7513
7715
  throw new Error(`Failed to remove annotation from HTML: ${error.error}`);
7514
7716
  }
7515
- const parsed = JSON.parse(result);
7516
- return parsed.Html ?? parsed.html;
7717
+ return readProjectedHtml(JSON.parse(result));
7517
7718
  }
7518
7719
  async function generateAnnotationVisibilityCss(hiddenLabelIds, cssClassPrefix) {
7519
7720
  const exports = ensureInitialized();
@@ -11680,6 +11881,16 @@ function ensureBlockDragStyles(doc) {
11680
11881
  `;
11681
11882
  (doc.head ?? doc.documentElement).appendChild(style);
11682
11883
  }
11884
+ var CHROME_CARRIER_ANCHOR = "chrome-carrier";
11885
+ function yieldToEventLoop() {
11886
+ return new Promise((resolve) => {
11887
+ const settle = () => {
11888
+ setTimeout(resolve, 0);
11889
+ };
11890
+ if (typeof requestAnimationFrame === "function") requestAnimationFrame(settle);
11891
+ else settle();
11892
+ });
11893
+ }
11683
11894
  function trackedChangeWireName(mode) {
11684
11895
  if (mode === 1 /* RenderInline */) return "render_inline";
11685
11896
  if (mode === 2 /* StripDeletions */) return "strip_deletions";
@@ -12347,7 +12558,64 @@ var DocxEditor = class _DocxEditor {
12347
12558
  }
12348
12559
  /** Open a document, render it into `container`, and wire up editing. */
12349
12560
  static open(container, bytes, exports, options = {}) {
12350
- const opts = {
12561
+ const opts = _DocxEditor.resolveOptions(options);
12562
+ const editor = _DocxEditor.openSession(container, bytes, exports, opts);
12563
+ try {
12564
+ editor.refreshAnchorMap();
12565
+ if (opts.headerFooter) editor.createRegion();
12566
+ const fullHtml = editor.renderFullHtml(bytes);
12567
+ if (opts.paginated) editor.mountPaginated(fullHtml);
12568
+ else editor.mountHtml(fullHtml);
12569
+ editor.finishMount();
12570
+ return editor;
12571
+ } catch (error) {
12572
+ editor.close();
12573
+ throw error;
12574
+ }
12575
+ }
12576
+ /**
12577
+ * Open a document without holding the main thread for the whole mount (issue #776).
12578
+ *
12579
+ * {@link open} renders and wires the entire document in one synchronous task, which on a
12580
+ * long document is the largest single block of a reading-and-editing session. This variant
12581
+ * pays only the session open up front, then mounts the document in windows of body units,
12582
+ * yielding to the event loop between them: the chrome — stylesheet, section wrappers with
12583
+ * their page geometry, footnote and endnote sections — comes from one cheap engine render
12584
+ * that sees no body content, and each window from the engine's block renderer, which lays
12585
+ * units out exactly as the full render does (the plan's border-box grouping is never split).
12586
+ * The DOM that results is the one {@link open} produces; blocks already mounted are editable
12587
+ * while later windows are still landing, and edits made meanwhile are honoured because every
12588
+ * window renders from the live session.
12589
+ *
12590
+ * Paginated mounts assemble the windows off-screen and paginate once at the end, since
12591
+ * pagination is a one-shot flow over the whole document; the main thread is still free
12592
+ * between windows, and `onProgress` lets a host show the fill.
12593
+ *
12594
+ * A bundle that predates the windowed renders mounts synchronously, exactly like {@link open}.
12595
+ */
12596
+ static async openAsync(container, bytes, exports, options = {}) {
12597
+ const bridge = exports.DocxSessionBridge;
12598
+ if (typeof bridge.RenderEditorChromeHtml !== "function" || typeof bridge.RenderEditorRangeHtml !== "function" || typeof bridge.ListRenderedBlocks !== "function") {
12599
+ return _DocxEditor.open(container, bytes, exports, options);
12600
+ }
12601
+ const opts = _DocxEditor.resolveOptions(options);
12602
+ const editor = _DocxEditor.openSession(container, bytes, exports, opts);
12603
+ try {
12604
+ editor.refreshAnchorMap();
12605
+ if (opts.headerFooter) editor.createRegion();
12606
+ await editor.mountWindowed(
12607
+ Math.max(1, Math.floor(options.windowSize ?? 24)),
12608
+ options.onProgress
12609
+ );
12610
+ editor.finishMount();
12611
+ return editor;
12612
+ } catch (error) {
12613
+ editor.close();
12614
+ throw error;
12615
+ }
12616
+ }
12617
+ static resolveOptions(options) {
12618
+ return {
12351
12619
  cssPrefix: options.cssPrefix ?? "docx-",
12352
12620
  fabricateClasses: options.fabricateClasses ?? false,
12353
12621
  editable: options.editable ?? true,
@@ -12366,25 +12634,100 @@ var DocxEditor = class _DocxEditor {
12366
12634
  onStoryChange: options.onStoryChange,
12367
12635
  onCommentsChange: options.onCommentsChange
12368
12636
  };
12637
+ }
12638
+ static openSession(container, bytes, exports, opts) {
12369
12639
  const handle = exports.DocxSessionBridge.OpenSession(bytes, JSON.stringify({
12370
12640
  emitMarkdownPatch: false,
12371
12641
  trackedChanges: trackedChangeWireName(opts.trackedChanges),
12372
12642
  revisionAuthor: opts.revisionAuthor
12373
12643
  }));
12374
- const editor = new _DocxEditor(container, exports, handle, opts);
12375
- try {
12376
- editor.refreshAnchorMap();
12377
- if (opts.headerFooter) editor.createRegion();
12378
- const fullHtml = editor.renderFullHtml(bytes);
12379
- if (opts.paginated) editor.mountPaginated(fullHtml);
12380
- else editor.mountHtml(fullHtml);
12381
- editor.syncRegionToBody();
12382
- editor.setupBlockDrag();
12383
- if (opts.comments) editor.createGutter();
12384
- return editor;
12385
- } catch (error) {
12386
- editor.close();
12387
- throw error;
12644
+ return new _DocxEditor(container, exports, handle, opts);
12645
+ }
12646
+ /** The steps every mount ends with once the body is in the DOM. */
12647
+ finishMount() {
12648
+ this.syncRegionToBody();
12649
+ this.setupBlockDrag();
12650
+ if (this.options.comments) this.createGutter();
12651
+ }
12652
+ /**
12653
+ * The windowed mount behind {@link openAsync}: chrome first, then body units in plan order,
12654
+ * a group-aligned window per task. See {@link openAsync} for the contract.
12655
+ */
12656
+ async mountWindowed(windowSize, onProgress) {
12657
+ const bridge = this.exports.DocxSessionBridge;
12658
+ const profile = JSON.stringify({ ...JSON.parse(this.editorRenderProfile()), stampAnchors: true });
12659
+ const chrome = bridge.RenderEditorChromeHtml(this.handle, profile);
12660
+ if (chrome.trimStart().startsWith("{")) {
12661
+ throw new Error(JSON.parse(chrome).error ?? "chrome render failed");
12662
+ }
12663
+ const parsed = new DOMParser().parseFromString(chrome, "text/html");
12664
+ parsed.body.querySelectorAll(`[data-section-index] > [data-anchor="${CHROME_CARRIER_ANCHOR}"]`).forEach((el) => el.remove());
12665
+ const styles = Array.from(parsed.querySelectorAll("style")).map((s) => s.outerHTML).join("");
12666
+ const flow = document.createElement("div");
12667
+ flow.className = "docx-body-flow";
12668
+ flow.innerHTML = parsed.body.innerHTML;
12669
+ const hosts = /* @__PURE__ */ new Map();
12670
+ flow.querySelectorAll("[data-section-index]").forEach((el) => hosts.set(Number(el.getAttribute("data-section-index")), el));
12671
+ const attachNow = !this.options.paginated;
12672
+ const wireNow = attachNow && this.options.editable;
12673
+ if (wireNow) this.wireBlocks(flow);
12674
+ if (attachNow) {
12675
+ this.region?.detachPages();
12676
+ this.container.innerHTML = styles;
12677
+ this.readoptGutter();
12678
+ this.container.appendChild(flow);
12679
+ this.editRoot = flow;
12680
+ }
12681
+ const plan = JSON.parse(this.renderPlanJson());
12682
+ if (plan.error) throw new Error(plan.error);
12683
+ const units = plan.body;
12684
+ const sectionOf = new Map(units.map((u) => [unidOf(u.id), u.section ?? 0]));
12685
+ const mounted = /* @__PURE__ */ new Set();
12686
+ const place = (el, sameHostAs) => {
12687
+ el.removeAttribute("xmlns");
12688
+ const unit = el.hasAttribute("data-anchor") ? el : el.querySelector("[data-anchor]");
12689
+ const unid = unit?.getAttribute("data-anchor") ?? "";
12690
+ const host = sameHostAs ?? hosts.get(sectionOf.get(unid) ?? 0) ?? hosts.values().next().value ?? flow;
12691
+ host.insertBefore(el, host.querySelector(":scope > section.endnotes"));
12692
+ if (wireNow) {
12693
+ if (el.hasAttribute("data-anchor")) this.wireBlock(el);
12694
+ this.wireBlocks(el);
12695
+ }
12696
+ unit && mounted.add(unid);
12697
+ el.querySelectorAll("[data-anchor]").forEach((n) => mounted.add(n.getAttribute("data-anchor")));
12698
+ return host;
12699
+ };
12700
+ for (let start2 = 0; start2 < units.length; ) {
12701
+ let end = Math.min(start2 + windowSize, units.length);
12702
+ while (end < units.length && units[end].group !== void 0 && units[end].group === units[end - 1].group) end++;
12703
+ const window2 = units.slice(start2, end);
12704
+ const rendered = JSON.parse(bridge.RenderEditorRangeHtml(
12705
+ this.handle,
12706
+ JSON.stringify(window2.map((u) => u.id)),
12707
+ profile
12708
+ ));
12709
+ if (!Array.isArray(rendered)) throw new Error(rendered.error ?? "window render failed");
12710
+ for (const html of rendered) {
12711
+ let host;
12712
+ for (const el of Array.from(new DOMParser().parseFromString(html, "text/html").body.children)) {
12713
+ host = place(el, host);
12714
+ }
12715
+ }
12716
+ for (const unit of window2) {
12717
+ if (mounted.has(unidOf(unit.id))) continue;
12718
+ const el = this.renderInto(unit.id);
12719
+ if (el) place(el);
12720
+ }
12721
+ start2 = end;
12722
+ onProgress?.(start2, units.length);
12723
+ if (start2 < units.length) await yieldToEventLoop();
12724
+ }
12725
+ if (attachNow) {
12726
+ this.stampPlanState();
12727
+ if (this.region) this.dockBands(flow);
12728
+ this.viewport.attach(flow, true);
12729
+ } else {
12730
+ this.mountPaginated(parsed.head.innerHTML + flow.innerHTML);
12388
12731
  }
12389
12732
  }
12390
12733
  /**