docxodus 12.4.0 → 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 (119) hide show
  1. package/README.md +101 -0
  2. package/dist/core.d.ts +924 -0
  3. package/dist/core.d.ts.map +1 -0
  4. package/dist/core.js +1915 -0
  5. package/dist/core.js.map +1 -0
  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 +12565 -12222
  17. package/dist/embed.iife.js +12532 -12189
  18. package/dist/export-assets.json +48 -48
  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/index.d.ts +2 -922
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +2 -2093
  27. package/dist/index.js.map +1 -1
  28. package/dist/session.bundle.js +258 -7
  29. package/dist/session.d.ts +61 -12
  30. package/dist/session.d.ts.map +1 -1
  31. package/dist/session.js +234 -7
  32. package/dist/session.js.map +1 -1
  33. package/dist/types.d.ts +371 -4
  34. package/dist/types.d.ts.map +1 -1
  35. package/dist/types.js.map +1 -1
  36. package/dist/verification-request.d.ts +9 -0
  37. package/dist/verification-request.d.ts.map +1 -0
  38. package/dist/verification-request.js +37 -0
  39. package/dist/verification-request.js.map +1 -0
  40. package/dist/wasm/_framework/Docxodus.wasm +0 -0
  41. package/dist/wasm/_framework/Docxodus.wasm.br +0 -0
  42. package/dist/wasm/_framework/DocxodusWasm.wasm +0 -0
  43. package/dist/wasm/_framework/DocxodusWasm.wasm.br +0 -0
  44. package/dist/wasm/_framework/System.Collections.Concurrent.wasm +0 -0
  45. package/dist/wasm/_framework/System.Collections.Concurrent.wasm.br +0 -0
  46. package/dist/wasm/_framework/System.Collections.Immutable.wasm +0 -0
  47. package/dist/wasm/_framework/System.Collections.Immutable.wasm.br +0 -0
  48. package/dist/wasm/_framework/System.Collections.NonGeneric.wasm +0 -0
  49. package/dist/wasm/_framework/System.Collections.NonGeneric.wasm.br +0 -0
  50. package/dist/wasm/_framework/System.Collections.Specialized.wasm +0 -0
  51. package/dist/wasm/_framework/System.Collections.Specialized.wasm.br +0 -0
  52. package/dist/wasm/_framework/System.Collections.wasm +0 -0
  53. package/dist/wasm/_framework/System.Collections.wasm.br +0 -0
  54. package/dist/wasm/_framework/System.ComponentModel.Primitives.wasm +0 -0
  55. package/dist/wasm/_framework/System.ComponentModel.Primitives.wasm.br +0 -0
  56. package/dist/wasm/_framework/System.ComponentModel.TypeConverter.wasm +0 -0
  57. package/dist/wasm/_framework/System.ComponentModel.TypeConverter.wasm.br +0 -0
  58. package/dist/wasm/_framework/System.ComponentModel.wasm +0 -0
  59. package/dist/wasm/_framework/System.ComponentModel.wasm.br +0 -0
  60. package/dist/wasm/_framework/System.Console.wasm +0 -0
  61. package/dist/wasm/_framework/System.Console.wasm.br +0 -0
  62. package/dist/wasm/_framework/System.IO.Compression.wasm +0 -0
  63. package/dist/wasm/_framework/System.IO.Compression.wasm.br +0 -0
  64. package/dist/wasm/_framework/System.IO.Pipelines.wasm +0 -0
  65. package/dist/wasm/_framework/System.IO.Pipelines.wasm.br +0 -0
  66. package/dist/wasm/_framework/System.Linq.Expressions.wasm +0 -0
  67. package/dist/wasm/_framework/System.Linq.Expressions.wasm.br +0 -0
  68. package/dist/wasm/_framework/System.Linq.wasm +0 -0
  69. package/dist/wasm/_framework/System.Linq.wasm.br +0 -0
  70. package/dist/wasm/_framework/System.Memory.wasm +0 -0
  71. package/dist/wasm/_framework/System.Memory.wasm.br +0 -0
  72. package/dist/wasm/_framework/System.Net.Http.wasm +0 -0
  73. package/dist/wasm/_framework/System.Net.Http.wasm.br +0 -0
  74. package/dist/wasm/_framework/System.Net.Primitives.wasm +0 -0
  75. package/dist/wasm/_framework/System.Net.Primitives.wasm.br +0 -0
  76. package/dist/wasm/_framework/System.ObjectModel.wasm +0 -0
  77. package/dist/wasm/_framework/System.ObjectModel.wasm.br +0 -0
  78. package/dist/wasm/_framework/System.Private.CoreLib.wasm +0 -0
  79. package/dist/wasm/_framework/System.Private.CoreLib.wasm.br +0 -0
  80. package/dist/wasm/_framework/System.Private.Uri.wasm +0 -0
  81. package/dist/wasm/_framework/System.Private.Uri.wasm.br +0 -0
  82. package/dist/wasm/_framework/System.Private.Xml.Linq.wasm +0 -0
  83. package/dist/wasm/_framework/System.Private.Xml.Linq.wasm.br +0 -0
  84. package/dist/wasm/_framework/System.Private.Xml.wasm +0 -0
  85. package/dist/wasm/_framework/System.Private.Xml.wasm.br +0 -0
  86. package/dist/wasm/_framework/System.Runtime.InteropServices.JavaScript.wasm +0 -0
  87. package/dist/wasm/_framework/System.Runtime.InteropServices.JavaScript.wasm.br +0 -0
  88. package/dist/wasm/_framework/System.Runtime.wasm +0 -0
  89. package/dist/wasm/_framework/System.Runtime.wasm.br +0 -0
  90. package/dist/wasm/_framework/System.Security.Cryptography.wasm +0 -0
  91. package/dist/wasm/_framework/System.Security.Cryptography.wasm.br +0 -0
  92. package/dist/wasm/_framework/System.Text.Encodings.Web.wasm +0 -0
  93. package/dist/wasm/_framework/System.Text.Encodings.Web.wasm.br +0 -0
  94. package/dist/wasm/_framework/System.Text.Json.wasm +0 -0
  95. package/dist/wasm/_framework/System.Text.Json.wasm.br +0 -0
  96. package/dist/wasm/_framework/System.Text.RegularExpressions.wasm +0 -0
  97. package/dist/wasm/_framework/System.Text.RegularExpressions.wasm.br +0 -0
  98. package/dist/wasm/_framework/System.Xml.Linq.wasm +0 -0
  99. package/dist/wasm/_framework/System.Xml.Linq.wasm.br +0 -0
  100. package/dist/wasm/_framework/System.Xml.XDocument.wasm +0 -0
  101. package/dist/wasm/_framework/System.Xml.XDocument.wasm.br +0 -0
  102. package/dist/wasm/_framework/System.wasm +0 -0
  103. package/dist/wasm/_framework/System.wasm.br +0 -0
  104. package/dist/wasm/_framework/dotnet.boot.js +34 -34
  105. package/dist/wasm/_framework/dotnet.boot.js.br +0 -0
  106. package/dist/wasm/_framework/dotnet.js +1 -1
  107. package/dist/wasm/_framework/dotnet.js.br +0 -0
  108. package/dist/wasm/_framework/dotnet.native.js +3 -3
  109. package/dist/wasm/_framework/dotnet.native.js.br +0 -0
  110. package/dist/wasm/_framework/dotnet.native.wasm +0 -0
  111. package/dist/wasm/_framework/dotnet.native.wasm.br +0 -0
  112. package/dist/wasm/_framework/dotnet.runtime.js +1 -1
  113. package/dist/wasm/_framework/dotnet.runtime.js.br +0 -0
  114. package/dist/worker-proxy.bundle.js +101 -4
  115. package/dist/worker-proxy.d.ts +21 -3
  116. package/dist/worker-proxy.d.ts.map +1 -1
  117. package/dist/worker-proxy.js +57 -2
  118. package/dist/worker-proxy.js.map +1 -1
  119. package/package.json +8 -1
package/README.md CHANGED
@@ -72,6 +72,13 @@ Two layers, so you can take as much UI as you want:
72
72
  import { DocxEditor } from 'docxodus';
73
73
  const editor = DocxEditor.open(container, docxBytes, exports);
74
74
 
75
+ // Long document? Mount it in windows instead, yielding to the event loop between them, so the
76
+ // tab stays responsive and you can show progress. The result is the same editor and the same DOM.
77
+ const editor = await DocxEditor.openAsync(container, docxBytes, exports, {
78
+ windowSize: 24,
79
+ onProgress: (mounted, total) => console.log(`${mounted}/${total} blocks`),
80
+ });
81
+
75
82
  // Or the whole surface: Word's tabbed ribbon (fonts, colour, styles, find & replace, links,
76
83
  // pictures, tables, page setup, tracked changes), Word-style comment bubbles beside the page,
77
84
  // in-place header/footer editing, a status bar with zoom, and the loading overlay.
@@ -125,6 +132,19 @@ if (!result.success) console.error(result.failure);
125
132
 
126
133
  Pass `'best_effort'` explicitly only when partial successes should be retained.
127
134
 
135
+ A retry after a lost response must not apply the edit twice. Give the batch a transaction id
136
+ and a serializable description of what it does; an identical retry returns the original result
137
+ without executing again, and reusing the id for a different request fails with
138
+ `transaction_conflict`:
139
+
140
+ ```ts
141
+ const result = session.executeBatch(steps, 'atomic', {
142
+ transactionId: 'plan-42-step-3',
143
+ request: { replace: firstAnchor, header: 'Confidential' },
144
+ });
145
+ result.transaction; // { schemaVersion: 1, transactionId, requestFingerprint }
146
+ ```
147
+
128
148
  `previewBatch` answers "what would this do?" without touching the live session. It runs the
129
149
  same steps against a complete isolated clone — each callback is handed the shadow session to
130
150
  mutate — and returns the same receipt plus optional predicted HTML:
@@ -144,6 +164,53 @@ the batch would produce, matching what the Python and MCP clients render for the
144
164
  `packageHash` is `null` when it could not be computed, so never assert replay equality
145
165
  without checking for it.
146
166
 
167
+ A preview predicts generated values (new anchor ids, comment ids, revision timestamps), but a
168
+ later `executeBatch` runs afresh and may generate them differently. `retain: true` keeps the
169
+ successful preview's exact result package, and `commitPreview` makes it the live document as
170
+ previewed — one undo step, same ids, same `packageHash`:
171
+
172
+ ```ts
173
+ const preview = session.previewBatch(steps, 'atomic', { html: 'full', retain: true });
174
+ showToReviewer(preview.html, preview.revisionChanges);
175
+ const commit = session.commitPreview(preview.retention!.previewId, {
176
+ transactionId: 'plan-42-commit', request: { commit: preview.retention!.previewId },
177
+ });
178
+ commit.packageHash === preview.packageHash; // true
179
+ ```
180
+
181
+ The commit refuses with `preview_stale`, editing nothing, if the session's version, package
182
+ content, tracked-changes mode or revision author moved since the preview, and with
183
+ `preview_not_found` once the preview expired, was evicted (8 previews, 64 MiB, 15 minutes per
184
+ session) or was already committed.
185
+
186
+ ### Delivery receipts from captured evidence
187
+
188
+ A session opened with `captureDeliveryEvidence: true` records the evidence a delivery change
189
+ receipt needs as its edits execute — the exact package before and after every mutation, each
190
+ `executeBatch` step's `tool`/`action`/`args`, transaction ids, and undo/redo lineage — and
191
+ `buildDeliveryReceipt` mints a receipt the portable verifier accepts:
192
+
193
+ ```ts
194
+ const session = openDocxSession(bytes, { captureDeliveryEvidence: true });
195
+ session.executeBatch([
196
+ { tool: 'docx_edit', action: 'replace_text', args: { anchorId: firstAnchor, markdown: 'Final wording' },
197
+ mutation: () => session.replaceText(firstAnchor, 'Final wording') },
198
+ ], 'atomic', { transactionId: 'plan-42', request: { replace: firstAnchor } });
199
+
200
+ const bundle = session.buildDeliveryReceipt({ privacyProfile: 'hashAndSummary' });
201
+ const receipt = bundle.artifacts.find(a => a.artifactId === 'change-receipt')!;
202
+ const artifacts = Object.fromEntries(bundle.artifacts
203
+ .filter(a => a.bytes && a.artifactId !== 'change-receipt')
204
+ .map(a => [a.artifactId, a.bytes!]));
205
+ await verifyDeliveryReceipt(new TextDecoder().decode(receipt.bytes!), artifacts); // isValid
206
+ ```
207
+
208
+ Deliver the bundle's `final-docx` artifact: it is the bytes the receipt attests. A direct call
209
+ outside `executeBatch` is still captured exactly but recorded as an unlabeled mutation;
210
+ `getDeliveryEvidenceStatus()` counts those and names the first reason a receipt cannot be
211
+ minted (capture off, retention of 256 states / 512 MiB exceeded), in which case the bundle is
212
+ `incomplete` and the receipt artifact carries the reason instead of claiming a history.
213
+
147
214
  ![Markdown projection beside the rendered document](https://raw.githubusercontent.com/JSv4/Docxodus/main/docs/images/projection.png)
148
215
 
149
216
  Native links and bookmarks use the same stable anchors and exact character spans:
@@ -275,6 +342,29 @@ function DocumentComparer() {
275
342
  }
276
343
  ```
277
344
 
345
+ ## Node.js (ES modules)
346
+
347
+ Import the engine from `docxodus/core` for server-side conversion, comparison, annotations,
348
+ and document sessions. It loads without a bundler or a custom Node loader:
349
+
350
+ ```js
351
+ import { readFile, writeFile } from 'node:fs/promises';
352
+ import { initialize, convertDocxToHtml, compareDocuments } from 'docxodus/core';
353
+
354
+ await initialize(); // Finds the WASM runtime included in the installed package.
355
+ const original = await readFile('original.docx');
356
+ const revised = await readFile('revised.docx');
357
+ await writeFile('original.html', await convertDocxToHtml(original));
358
+ await writeFile('redline.docx', await compareDocuments(original, revised));
359
+ ```
360
+
361
+ `docxodus/core` exposes the engine functions, types, enums, annotation helpers, and history
362
+ APIs from `docxodus`, excluding `DocxEditor`, `CommentGutter`, `mountRibbon`, and their editor
363
+ types. The existing `docxodus` entry includes those browser editor APIs and requires a browser
364
+ bundler; use `docxodus/core` in plain Node ESM. Both entries share the same engine state.
365
+ Browser helpers retained in `core`, such as pagination, the document viewport, IndexedDB
366
+ storage, and history controls, still require their browser APIs when called.
367
+
278
368
  ## API Reference
279
369
 
280
370
  ### Package verification
@@ -505,10 +595,21 @@ const redlined = await docxodus.compareDocuments(original, modified, options);
505
595
  const revisions = await docxodus.getRevisions(docxFile);
506
596
  const metadata = await docxodus.getDocumentMetadata(docxFile);
507
597
 
598
+ // The external annotation family runs there too, so a read-only viewer that renders
599
+ // through the worker can annotate without booting a second runtime on the main thread.
600
+ const set = await docxodus.createExternalAnnotationSet(docxFile, 'doc-1');
601
+ const annotated = await docxodus.projectAnnotationsOntoHtml(html, set);
602
+ const validation = await docxodus.validateExternalAnnotations(docxFile, set);
603
+ const exported = await docxodus.exportToOpenContract(docxFile);
604
+
508
605
  // Terminate when done
509
606
  docxodus.terminate();
510
607
  ```
511
608
 
609
+ `projectAnnotationsOntoHtml` parses its input as XML: hand it the converter's output (or
610
+ another well-formed serialization), not a live DOM's `innerHTML`, which leaves `<br>` and
611
+ `<img>` unclosed. `DocxEditor.open()` stays main-thread only — it writes into a live container.
612
+
512
613
  #### First-call warmup
513
614
 
514
615
  `createWorkerDocxodus()` warms the .NET WASM runtime, but the **comparison code