docxodus 9.9.0 → 10.0.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 (111) hide show
  1. package/README.md +178 -0
  2. package/dist/canonical.d.ts +7 -0
  3. package/dist/canonical.d.ts.map +1 -0
  4. package/dist/canonical.js +56 -0
  5. package/dist/canonical.js.map +1 -0
  6. package/dist/docxodus.worker.d.ts +2 -1
  7. package/dist/docxodus.worker.d.ts.map +1 -1
  8. package/dist/docxodus.worker.js +244 -3
  9. package/dist/docxodus.worker.js.map +1 -1
  10. package/dist/editor.bundle.js +1914 -419
  11. package/dist/editor.d.ts +22 -2
  12. package/dist/editor.d.ts.map +1 -1
  13. package/dist/editor.js +94 -9
  14. package/dist/editor.js.map +1 -1
  15. package/dist/embed.bundle.js +2803 -469
  16. package/dist/embed.iife.js +2801 -467
  17. package/dist/export-assets.json +283 -0
  18. package/dist/export-browser.bundle.js +7990 -0
  19. package/dist/export-browser.d.ts +266 -0
  20. package/dist/export-browser.d.ts.map +1 -0
  21. package/dist/export-browser.js +2915 -0
  22. package/dist/export-browser.js.map +1 -0
  23. package/dist/export-resource-limits-v1.json +57 -0
  24. package/dist/font-contract.d.ts +150 -0
  25. package/dist/font-contract.d.ts.map +1 -0
  26. package/dist/font-contract.js +59 -0
  27. package/dist/font-contract.js.map +1 -0
  28. package/dist/font-runtime.d.ts +33 -0
  29. package/dist/font-runtime.d.ts.map +1 -0
  30. package/dist/font-runtime.js +1100 -0
  31. package/dist/font-runtime.js.map +1 -0
  32. package/dist/index.d.ts +62 -5
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +130 -16
  35. package/dist/index.js.map +1 -1
  36. package/dist/page-geometry.d.ts +8 -1
  37. package/dist/page-geometry.d.ts.map +1 -1
  38. package/dist/page-geometry.js +37 -11
  39. package/dist/page-geometry.js.map +1 -1
  40. package/dist/pagination.bundle.js +1827 -410
  41. package/dist/pagination.d.ts +249 -15
  42. package/dist/pagination.d.ts.map +1 -1
  43. package/dist/pagination.js +1942 -453
  44. package/dist/pagination.js.map +1 -1
  45. package/dist/react.d.ts +11 -4
  46. package/dist/react.d.ts.map +1 -1
  47. package/dist/react.js +38 -5
  48. package/dist/react.js.map +1 -1
  49. package/dist/render-report-v2.schema.json +1581 -0
  50. package/dist/ribbon-chrome.d.ts +1 -1
  51. package/dist/ribbon-chrome.d.ts.map +1 -1
  52. package/dist/ribbon-chrome.js +45 -0
  53. package/dist/ribbon-chrome.js.map +1 -1
  54. package/dist/ribbon.js +70 -0
  55. package/dist/ribbon.js.map +1 -1
  56. package/dist/session.bundle.js +695 -29
  57. package/dist/session.d.ts +134 -19
  58. package/dist/session.d.ts.map +1 -1
  59. package/dist/session.js +562 -25
  60. package/dist/session.js.map +1 -1
  61. package/dist/types.d.ts +1207 -16
  62. package/dist/types.d.ts.map +1 -1
  63. package/dist/types.js.map +1 -1
  64. package/dist/wasm/_framework/DocumentFormat.OpenXml.Framework.wasm +0 -0
  65. package/dist/wasm/_framework/DocumentFormat.OpenXml.Framework.wasm.br +0 -0
  66. package/dist/wasm/_framework/DocumentFormat.OpenXml.wasm +0 -0
  67. package/dist/wasm/_framework/DocumentFormat.OpenXml.wasm.br +0 -0
  68. package/dist/wasm/_framework/Docxodus.wasm +0 -0
  69. package/dist/wasm/_framework/Docxodus.wasm.br +0 -0
  70. package/dist/wasm/_framework/DocxodusWasm.wasm +0 -0
  71. package/dist/wasm/_framework/DocxodusWasm.wasm.br +0 -0
  72. package/dist/wasm/_framework/System.Collections.Concurrent.wasm +0 -0
  73. package/dist/wasm/_framework/System.Collections.Concurrent.wasm.br +0 -0
  74. package/dist/wasm/_framework/System.Collections.Immutable.wasm +0 -0
  75. package/dist/wasm/_framework/System.Collections.Immutable.wasm.br +0 -0
  76. package/dist/wasm/_framework/System.Collections.wasm +0 -0
  77. package/dist/wasm/_framework/System.Collections.wasm.br +0 -0
  78. package/dist/wasm/_framework/System.IO.Compression.wasm +0 -0
  79. package/dist/wasm/_framework/System.IO.Compression.wasm.br +0 -0
  80. package/dist/wasm/_framework/System.IO.Packaging.wasm +0 -0
  81. package/dist/wasm/_framework/System.IO.Packaging.wasm.br +0 -0
  82. package/dist/wasm/_framework/System.Linq.wasm +0 -0
  83. package/dist/wasm/_framework/System.Linq.wasm.br +0 -0
  84. package/dist/wasm/_framework/System.Private.CoreLib.wasm +0 -0
  85. package/dist/wasm/_framework/System.Private.CoreLib.wasm.br +0 -0
  86. package/dist/wasm/_framework/System.Private.Uri.wasm +0 -0
  87. package/dist/wasm/_framework/System.Private.Uri.wasm.br +0 -0
  88. package/dist/wasm/_framework/System.Private.Xml.Linq.wasm +0 -0
  89. package/dist/wasm/_framework/System.Private.Xml.Linq.wasm.br +0 -0
  90. package/dist/wasm/_framework/System.Private.Xml.wasm +0 -0
  91. package/dist/wasm/_framework/System.Private.Xml.wasm.br +0 -0
  92. package/dist/wasm/_framework/System.Runtime.InteropServices.JavaScript.wasm +0 -0
  93. package/dist/wasm/_framework/System.Runtime.InteropServices.JavaScript.wasm.br +0 -0
  94. package/dist/wasm/_framework/System.Runtime.wasm +0 -0
  95. package/dist/wasm/_framework/System.Runtime.wasm.br +0 -0
  96. package/dist/wasm/_framework/System.Security.Cryptography.wasm +0 -0
  97. package/dist/wasm/_framework/System.Security.Cryptography.wasm.br +0 -0
  98. package/dist/wasm/_framework/System.Text.Json.wasm +0 -0
  99. package/dist/wasm/_framework/System.Text.Json.wasm.br +0 -0
  100. package/dist/wasm/_framework/System.Text.RegularExpressions.wasm +0 -0
  101. package/dist/wasm/_framework/System.Text.RegularExpressions.wasm.br +0 -0
  102. package/dist/wasm/_framework/dotnet.boot.js +21 -21
  103. package/dist/wasm/_framework/dotnet.boot.js.br +0 -0
  104. package/dist/wasm/_framework/dotnet.native.wasm +0 -0
  105. package/dist/wasm/_framework/dotnet.native.wasm.br +0 -0
  106. package/dist/worker-proxy.bundle.js +196 -29
  107. package/dist/worker-proxy.d.ts +36 -3
  108. package/dist/worker-proxy.d.ts.map +1 -1
  109. package/dist/worker-proxy.js +186 -33
  110. package/dist/worker-proxy.js.map +1 -1
  111. package/package.json +22 -6
@@ -1,10 +1,23 @@
1
1
  // src/worker-proxy.ts
2
+ var WorkerOperationError = class extends Error {
3
+ constructor(message, code) {
4
+ super(message);
5
+ this.name = "WorkerOperationError";
6
+ this.code = code;
7
+ }
8
+ };
9
+ function workerError(message, code) {
10
+ return new WorkerOperationError(message || "Unknown error", code);
11
+ }
12
+ function workerErrorCode(error) {
13
+ return error instanceof WorkerOperationError ? error.code : void 0;
14
+ }
2
15
  function generateId() {
3
16
  return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
4
17
  }
5
18
  async function toBytes(document2) {
6
19
  if (document2 instanceof Uint8Array) {
7
- return document2;
20
+ return new Uint8Array(document2);
8
21
  }
9
22
  const buffer = await document2.arrayBuffer();
10
23
  return new Uint8Array(buffer);
@@ -21,12 +34,32 @@ function deriveWasmBasePath() {
21
34
  return "/wasm/";
22
35
  }
23
36
  async function createWorkerDocxodus(options) {
37
+ if (options?.signal?.aborted) {
38
+ throw new Error("Worker creation aborted");
39
+ }
24
40
  const wasmBasePath = options?.wasmBasePath ?? deriveWasmBasePath();
25
- let workerUrl;
26
41
  const workerScriptPath = new URL("./docxodus.worker.js", import.meta.url).href;
27
42
  const worker = new Worker(workerScriptPath, { type: "module" });
28
43
  const pendingRequests = /* @__PURE__ */ new Map();
29
44
  let isWorkerActive = true;
45
+ let abortListener;
46
+ const stopWorker = (message) => {
47
+ if (!isWorkerActive) return;
48
+ isWorkerActive = false;
49
+ worker.terminate();
50
+ for (const pending of pendingRequests.values()) {
51
+ pending.reject(new Error(message));
52
+ }
53
+ pendingRequests.clear();
54
+ if (abortListener && options?.signal) {
55
+ options.signal.removeEventListener("abort", abortListener);
56
+ abortListener = void 0;
57
+ }
58
+ };
59
+ if (options?.signal) {
60
+ abortListener = () => stopWorker("Worker creation or operation aborted");
61
+ options.signal.addEventListener("abort", abortListener, { once: true });
62
+ }
30
63
  let preparePromise = null;
31
64
  worker.onmessage = (event) => {
32
65
  const response = event.data;
@@ -39,16 +72,12 @@ async function createWorkerDocxodus(options) {
39
72
  if (response.success) {
40
73
  pending.resolve(response);
41
74
  } else {
42
- pending.reject(new Error(response.error || "Unknown error"));
75
+ pending.reject(workerError(response.error, response.errorCode));
43
76
  }
44
77
  }
45
78
  };
46
79
  worker.onerror = (error) => {
47
- for (const pending of pendingRequests.values()) {
48
- pending.reject(new Error(`Worker error: ${error.message}`));
49
- }
50
- pendingRequests.clear();
51
- isWorkerActive = false;
80
+ stopWorker(`Worker error: ${error.message}`);
52
81
  };
53
82
  function sendRequest(request, transfer) {
54
83
  return new Promise((resolve, reject) => {
@@ -57,31 +86,139 @@ async function createWorkerDocxodus(options) {
57
86
  return;
58
87
  }
59
88
  pendingRequests.set(request.id, { resolve, reject });
60
- if (transfer && transfer.length > 0) {
61
- worker.postMessage(request, transfer);
62
- } else {
63
- worker.postMessage(request);
89
+ try {
90
+ if (transfer && transfer.length > 0) {
91
+ worker.postMessage(request, transfer);
92
+ } else {
93
+ worker.postMessage(request);
94
+ }
95
+ } catch (error) {
96
+ pendingRequests.delete(request.id);
97
+ reject(error instanceof Error ? error : new Error(String(error)));
64
98
  }
65
99
  });
66
100
  }
67
- const initResponse = await sendRequest({
68
- id: generateId(),
69
- type: "init",
70
- wasmBasePath
71
- });
72
- if (!initResponse.success) {
73
- worker.terminate();
74
- throw new Error(`Failed to initialize worker: ${initResponse.error}`);
101
+ try {
102
+ await sendRequest({
103
+ id: generateId(),
104
+ type: "init",
105
+ wasmBasePath
106
+ });
107
+ } catch (error) {
108
+ stopWorker("Worker initialization failed");
109
+ throw error;
75
110
  }
76
111
  return {
77
- async convertDocxToHtml(document2, options2) {
112
+ async generatePackageManifest(document2, limits) {
113
+ const bytes = await toBytes(document2);
114
+ const response = await sendRequest(
115
+ {
116
+ id: generateId(),
117
+ type: "generatePackageManifest",
118
+ documentBytes: bytes,
119
+ limits,
120
+ representation: "object"
121
+ },
122
+ [bytes.buffer]
123
+ );
124
+ return response.manifest;
125
+ },
126
+ async verifyDeliverable(document2, baseline) {
127
+ const bytes = await toBytes(document2);
128
+ const baselineBytes = baseline === void 0 ? void 0 : await toBytes(baseline);
129
+ const transfer = [bytes.buffer];
130
+ if (baselineBytes !== void 0) transfer.push(baselineBytes.buffer);
131
+ const response = await sendRequest(
132
+ {
133
+ id: generateId(),
134
+ type: "verifyDeliverable",
135
+ documentBytes: bytes,
136
+ baselineBytes
137
+ },
138
+ transfer
139
+ );
140
+ if (!response.success || !response.verification) {
141
+ throw new Error(response.error ?? "verifyDeliverable failed");
142
+ }
143
+ return response.verification;
144
+ },
145
+ async proveRedlineReversibility(baseline, intendedFinal, redline) {
146
+ const baselineBytes = await toBytes(baseline);
147
+ const intendedFinalBytes = await toBytes(intendedFinal);
148
+ const redlineBytes = await toBytes(redline);
149
+ const response = await sendRequest(
150
+ {
151
+ id: generateId(),
152
+ type: "proveRedlineReversibility",
153
+ baselineBytes,
154
+ intendedFinalBytes,
155
+ redlineBytes
156
+ },
157
+ [baselineBytes.buffer, intendedFinalBytes.buffer, redlineBytes.buffer]
158
+ );
159
+ if (!response.success || !response.proof) {
160
+ throw new Error(response.error ?? "proveRedlineReversibility failed");
161
+ }
162
+ return response.proof;
163
+ },
164
+ async getSemanticChanges(left, right, settings) {
165
+ const leftBytes = await toBytes(left);
166
+ const rightBytes = await toBytes(right);
167
+ const response = await sendRequest(
168
+ {
169
+ id: generateId(),
170
+ type: "getSemanticChanges",
171
+ leftBytes,
172
+ rightBytes,
173
+ settings
174
+ },
175
+ [leftBytes.buffer, rightBytes.buffer]
176
+ );
177
+ return response.semanticChanges;
178
+ },
179
+ async generatePackageManifestJson(document2, limits) {
180
+ const bytes = await toBytes(document2);
181
+ const response = await sendRequest(
182
+ {
183
+ id: generateId(),
184
+ type: "generatePackageManifest",
185
+ documentBytes: bytes,
186
+ limits,
187
+ representation: "json"
188
+ },
189
+ [bytes.buffer]
190
+ );
191
+ if (response.manifestJson === void 0) {
192
+ throw new Error("Package manifest worker response omitted canonical JSON");
193
+ }
194
+ return response.manifestJson;
195
+ },
196
+ async projectReviewProfile(document2, profile, maximumOutputBytes) {
197
+ const bytes = await toBytes(document2);
198
+ const response = await sendRequest(
199
+ {
200
+ id: generateId(),
201
+ type: "projectReviewProfile",
202
+ documentBytes: bytes,
203
+ profile,
204
+ maximumOutputBytes
205
+ },
206
+ [bytes.buffer]
207
+ );
208
+ if (!response.documentBytes || response.documentBytes.byteLength === 0) {
209
+ throw new Error(`Failed to derive the ${profile} review profile`);
210
+ }
211
+ return response.documentBytes;
212
+ },
213
+ async convertDocxToHtml(document2, options2, maximumOutputBytes) {
78
214
  const bytes = await toBytes(document2);
79
215
  const response = await sendRequest(
80
216
  {
81
217
  id: generateId(),
82
218
  type: "convertDocxToHtml",
83
219
  documentBytes: bytes,
84
- options: options2
220
+ options: options2,
221
+ maximumOutputBytes
85
222
  },
86
223
  [bytes.buffer]
87
224
  );
@@ -181,6 +318,39 @@ async function createWorkerDocxodus(options) {
181
318
  }
182
319
  const handle = openResponse.handle;
183
320
  return {
321
+ async getPackageManifest() {
322
+ const res = await sendRequest({
323
+ id: generateId(),
324
+ type: "sessionGetPackageManifest",
325
+ handle
326
+ });
327
+ if (!res.success || !res.manifest) {
328
+ throw new Error(res.error ?? "sessionGetPackageManifest failed");
329
+ }
330
+ return res.manifest;
331
+ },
332
+ async getSemanticChanges() {
333
+ const res = await sendRequest({
334
+ id: generateId(),
335
+ type: "sessionGetSemanticChanges",
336
+ handle
337
+ });
338
+ if (!res.success || !res.semanticChanges) {
339
+ throw new Error(res.error ?? "sessionGetSemanticChanges failed");
340
+ }
341
+ return res.semanticChanges;
342
+ },
343
+ async verifyDeliverable() {
344
+ const res = await sendRequest({
345
+ id: generateId(),
346
+ type: "sessionVerifyDeliverable",
347
+ handle
348
+ });
349
+ if (!res.success || !res.verification) {
350
+ throw new Error(res.error ?? "sessionVerifyDeliverable failed");
351
+ }
352
+ return res.verification;
353
+ },
184
354
  async addAnnotation(anchorId, span, annotation) {
185
355
  const res = await sendRequest({
186
356
  id: generateId(),
@@ -244,12 +414,7 @@ async function createWorkerDocxodus(options) {
244
414
  };
245
415
  },
246
416
  terminate() {
247
- isWorkerActive = false;
248
- worker.terminate();
249
- for (const pending of pendingRequests.values()) {
250
- pending.reject(new Error("Worker terminated"));
251
- }
252
- pendingRequests.clear();
417
+ stopWorker("Worker terminated");
253
418
  },
254
419
  isActive() {
255
420
  return isWorkerActive;
@@ -260,6 +425,8 @@ function isWorkerSupported() {
260
425
  return typeof Worker !== "undefined";
261
426
  }
262
427
  export {
428
+ WorkerOperationError,
263
429
  createWorkerDocxodus,
264
- isWorkerSupported
430
+ isWorkerSupported,
431
+ workerErrorCode
265
432
  };
@@ -18,7 +18,17 @@
18
18
  * docxodus.terminate();
19
19
  * ```
20
20
  */
21
- import type { WorkerDocxodusOptions, ConversionOptions, CompareOptions, GetRevisionsOptions, Revision, VersionInfo, DocumentMetadata, DocxSessionSettings, DocumentAnnotation, AnnotationUpdate, CharSpan, EditResult } from "./types.js";
21
+ import type { WorkerDocxodusOptions, ConversionOptions, CompareOptions, DocxDiffSettings, GetRevisionsOptions, Revision, VersionInfo, DocumentMetadata, DocxSessionSettings, DocumentAnnotation, AnnotationUpdate, CharSpan, EditResult, PackageManifest, DeliverableVerificationResult, RedlineReversibilityProof, SemanticChangeSet, PackageManifestInspectionLimits, WorkerErrorCode } from "./types.js";
22
+ /**
23
+ * Rejection carrying the worker's machine-readable cause. Callers classify failures with
24
+ * {@link workerErrorCode}; `message` is diagnostic text whose wording is not a contract.
25
+ */
26
+ export declare class WorkerOperationError extends Error {
27
+ readonly code?: WorkerErrorCode;
28
+ constructor(message: string, code?: WorkerErrorCode);
29
+ }
30
+ /** Reads a worker failure's machine-readable cause, or undefined for any other error. */
31
+ export declare function workerErrorCode(error: unknown): WorkerErrorCode | undefined;
22
32
  /**
23
33
  * A worker-proxied DocxSession. Mirrors the main-thread {@link DocxSession}
24
34
  * annotation write surface but each call returns a Promise, since the actual
@@ -28,6 +38,12 @@ import type { WorkerDocxodusOptions, ConversionOptions, CompareOptions, GetRevis
28
38
  * {@link close} when finished to free the in-worker handle.
29
39
  */
30
40
  export interface WorkerDocxSession {
41
+ /** Generate a deterministic manifest of the session's current logical checkpoint. */
42
+ getPackageManifest(): Promise<PackageManifest>;
43
+ /** Run the default deliverable gate over the session's clean-save checkpoint. */
44
+ verifyDeliverable(): Promise<DeliverableVerificationResult>;
45
+ /** Compare the current logical checkpoint with the exact opening package. */
46
+ getSemanticChanges(): Promise<SemanticChangeSet>;
31
47
  /**
32
48
  * Add an annotation to the document at the given anchor.
33
49
  * @param anchorId - Markdown-projection anchor id of the target block
@@ -70,13 +86,29 @@ export interface WorkerDocxSession {
70
86
  * in a Web Worker for non-blocking UI.
71
87
  */
72
88
  export interface WorkerDocxodus {
89
+ /** Generate a deterministic, non-mutating verification manifest. */
90
+ generatePackageManifest(document: File | Uint8Array, limits?: PackageManifestInspectionLimits): Promise<PackageManifest>;
91
+ /** Generate the exact canonical manifest JSON for strict boundary validation. */
92
+ generatePackageManifestJson(document: File | Uint8Array, limits?: PackageManifestInspectionLimits): Promise<string>;
93
+ /** Derive an isolated final/original package; the source bytes remain caller-owned. */
94
+ projectReviewProfile(document: File | Uint8Array, profile: "final" | "original", maximumOutputBytes?: number): Promise<Uint8Array>;
95
+ /** Run the default bounded deliverable gate, optionally against an exact baseline. */
96
+ verifyDeliverable(document: File | Uint8Array, baseline?: File | Uint8Array): Promise<DeliverableVerificationResult>;
97
+ /**
98
+ * Prove that a redline's generated revisions accept to the intended final and reject to the
99
+ * baseline. Three packages are inspected and two rebuilt, so this always runs off the main
100
+ * thread; the returned proof carries digests and divergences rather than the rebuilt bytes.
101
+ */
102
+ proveRedlineReversibility(baseline: File | Uint8Array, intendedFinal: File | Uint8Array, redline: File | Uint8Array): Promise<RedlineReversibilityProof>;
103
+ /** Compare two DOCX packages into the stable, versioned semantic-change schema. */
104
+ getSemanticChanges(left: File | Uint8Array, right: File | Uint8Array, settings?: DocxDiffSettings): Promise<SemanticChangeSet>;
73
105
  /**
74
106
  * Convert a DOCX document to HTML.
75
107
  * @param document - DOCX file as File object or Uint8Array
76
108
  * @param options - Conversion options
77
109
  * @returns HTML string
78
110
  */
79
- convertDocxToHtml(document: File | Uint8Array, options?: ConversionOptions): Promise<string>;
111
+ convertDocxToHtml(document: File | Uint8Array, options?: ConversionOptions, maximumOutputBytes?: number): Promise<string>;
80
112
  /**
81
113
  * Compare two DOCX documents and return the redlined result.
82
114
  * @param original - Original DOCX document
@@ -137,7 +169,8 @@ export interface WorkerDocxodus {
137
169
  prepare(): Promise<void>;
138
170
  /**
139
171
  * Open a {@link WorkerDocxSession} for surgical annotation editing inside
140
- * the worker. The document bytes are transferred to the worker (zero-copy).
172
+ * the worker. Uint8Array inputs are copied once so the caller's buffer remains attached and
173
+ * subarray boundaries are preserved; the private copy is then transferred.
141
174
  *
142
175
  * Always call {@link WorkerDocxSession.close} when you are done to release
143
176
  * the in-worker session handle.
@@ -1 +1 @@
1
- {"version":3,"file":"worker-proxy.d.ts","sourceRoot":"","sources":["../src/worker-proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAYV,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,QAAQ,EACR,WAAW,EACX,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,QAAQ,EACR,UAAU,EACX,MAAM,YAAY,CAAC;AAuCpB;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;;;OAMG;IACH,aAAa,CACX,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,QAAQ,GAAG,IAAI,EACrB,UAAU,EAAE,kBAAkB,GAC7B,OAAO,CAAC,UAAU,CAAC,CAAC;IAEvB;;;;OAIG;IACH,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAE5D;;;;;OAKG;IACH,gBAAgB,CACd,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,UAAU,CAAC,CAAC;IAEvB;;;;;;OAMG;IACH,cAAc,CACZ,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,QAAQ,GAAG,IAAI,GACvB,OAAO,CAAC,UAAU,CAAC,CAAC;IAEvB;;;OAGG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,iBAAiB,CACf,QAAQ,EAAE,IAAI,GAAG,UAAU,EAC3B,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnB;;;;;;OAMG;IACH,gBAAgB,CACd,QAAQ,EAAE,IAAI,GAAG,UAAU,EAC3B,QAAQ,EAAE,IAAI,GAAG,UAAU,EAC3B,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,UAAU,CAAC,CAAC;IAEvB;;;;;;OAMG;IACH,sBAAsB,CACpB,QAAQ,EAAE,IAAI,GAAG,UAAU,EAC3B,QAAQ,EAAE,IAAI,GAAG,UAAU,EAC3B,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnB;;;;;OAKG;IACH,YAAY,CACV,QAAQ,EAAE,IAAI,GAAG,UAAU,EAC3B,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAEvB;;;;;OAKG;IACH,mBAAmB,CAAC,QAAQ,EAAE,IAAI,GAAG,UAAU,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAE5E;;;OAGG;IACH,UAAU,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;IAEnC;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzB;;;;;;;;;;OAUG;IACH,eAAe,CACb,QAAQ,EAAE,IAAI,GAAG,UAAU,EAC3B,QAAQ,CAAC,EAAE,mBAAmB,GAC7B,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAE9B;;;OAGG;IACH,SAAS,IAAI,IAAI,CAAC;IAElB;;OAEG;IACH,QAAQ,IAAI,OAAO,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,cAAc,CAAC,CA6UzB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C"}
1
+ {"version":3,"file":"worker-proxy.d.ts","sourceRoot":"","sources":["../src/worker-proxy.ts"],"names":[],"mappings":"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"}
@@ -18,6 +18,24 @@
18
18
  * docxodus.terminate();
19
19
  * ```
20
20
  */
21
+ /**
22
+ * Rejection carrying the worker's machine-readable cause. Callers classify failures with
23
+ * {@link workerErrorCode}; `message` is diagnostic text whose wording is not a contract.
24
+ */
25
+ export class WorkerOperationError extends Error {
26
+ constructor(message, code) {
27
+ super(message);
28
+ this.name = "WorkerOperationError";
29
+ this.code = code;
30
+ }
31
+ }
32
+ function workerError(message, code) {
33
+ return new WorkerOperationError(message || "Unknown error", code);
34
+ }
35
+ /** Reads a worker failure's machine-readable cause, or undefined for any other error. */
36
+ export function workerErrorCode(error) {
37
+ return error instanceof WorkerOperationError ? error.code : undefined;
38
+ }
21
39
  /**
22
40
  * Generate a unique request ID.
23
41
  */
@@ -29,7 +47,9 @@ function generateId() {
29
47
  */
30
48
  async function toBytes(document) {
31
49
  if (document instanceof Uint8Array) {
32
- return document;
50
+ // Transfer only an exact-view clone. Transferring the caller's buffer would detach it,
51
+ // and transferring a subarray's backing buffer would also send unrelated prefix/suffix bytes.
52
+ return new Uint8Array(document);
33
53
  }
34
54
  const buffer = await document.arrayBuffer();
35
55
  return new Uint8Array(buffer);
@@ -73,13 +93,12 @@ function deriveWasmBasePath() {
73
93
  * ```
74
94
  */
75
95
  export async function createWorkerDocxodus(options) {
96
+ if (options?.signal?.aborted) {
97
+ throw new Error("Worker creation aborted");
98
+ }
76
99
  // Determine WASM base path
77
100
  const wasmBasePath = options?.wasmBasePath ?? deriveWasmBasePath();
78
- // Determine worker script path
79
- // The worker bundle should be in the same directory as this module
80
- let workerUrl;
81
- // Try to create worker from bundled script or blob
82
- // For now, we'll use a blob URL to inline the worker path
101
+ // The worker bundle is packaged beside this module.
83
102
  const workerScriptPath = new URL("./docxodus.worker.js", import.meta.url)
84
103
  .href;
85
104
  // Create the worker
@@ -88,6 +107,25 @@ export async function createWorkerDocxodus(options) {
88
107
  const pendingRequests = new Map();
89
108
  // Track if worker is active
90
109
  let isWorkerActive = true;
110
+ let abortListener;
111
+ const stopWorker = (message) => {
112
+ if (!isWorkerActive)
113
+ return;
114
+ isWorkerActive = false;
115
+ worker.terminate();
116
+ for (const pending of pendingRequests.values()) {
117
+ pending.reject(new Error(message));
118
+ }
119
+ pendingRequests.clear();
120
+ if (abortListener && options?.signal) {
121
+ options.signal.removeEventListener("abort", abortListener);
122
+ abortListener = undefined;
123
+ }
124
+ };
125
+ if (options?.signal) {
126
+ abortListener = () => stopWorker("Worker creation or operation aborted");
127
+ options.signal.addEventListener("abort", abortListener, { once: true });
128
+ }
91
129
  // Cached warmup promise. Set on the first prepare() and reused thereafter so
92
130
  // repeated/concurrent calls share a single in-flight (or completed) warmup.
93
131
  // Reset to null on failure so a later prepare() can retry.
@@ -107,18 +145,13 @@ export async function createWorkerDocxodus(options) {
107
145
  pending.resolve(response);
108
146
  }
109
147
  else {
110
- pending.reject(new Error(response.error || "Unknown error"));
148
+ pending.reject(workerError(response.error, response.errorCode));
111
149
  }
112
150
  }
113
151
  };
114
152
  // Handle worker errors
115
153
  worker.onerror = (error) => {
116
- // Reject all pending requests
117
- for (const pending of pendingRequests.values()) {
118
- pending.reject(new Error(`Worker error: ${error.message}`));
119
- }
120
- pendingRequests.clear();
121
- isWorkerActive = false;
154
+ stopWorker(`Worker error: ${error.message}`);
122
155
  };
123
156
  /**
124
157
  * Send a request to the worker and wait for response.
@@ -130,33 +163,126 @@ export async function createWorkerDocxodus(options) {
130
163
  return;
131
164
  }
132
165
  pendingRequests.set(request.id, { resolve, reject });
133
- if (transfer && transfer.length > 0) {
134
- worker.postMessage(request, transfer);
166
+ try {
167
+ if (transfer && transfer.length > 0) {
168
+ worker.postMessage(request, transfer);
169
+ }
170
+ else {
171
+ worker.postMessage(request);
172
+ }
135
173
  }
136
- else {
137
- worker.postMessage(request);
174
+ catch (error) {
175
+ pendingRequests.delete(request.id);
176
+ reject(error instanceof Error ? error : new Error(String(error)));
138
177
  }
139
178
  });
140
179
  }
141
180
  // Initialize the worker
142
- const initResponse = await sendRequest({
143
- id: generateId(),
144
- type: "init",
145
- wasmBasePath,
146
- });
147
- if (!initResponse.success) {
148
- worker.terminate();
149
- throw new Error(`Failed to initialize worker: ${initResponse.error}`);
181
+ try {
182
+ await sendRequest({
183
+ id: generateId(),
184
+ type: "init",
185
+ wasmBasePath,
186
+ });
187
+ }
188
+ catch (error) {
189
+ stopWorker("Worker initialization failed");
190
+ throw error;
150
191
  }
151
192
  // Return the WorkerDocxodus instance
152
193
  return {
153
- async convertDocxToHtml(document, options) {
194
+ async generatePackageManifest(document, limits) {
195
+ const bytes = await toBytes(document);
196
+ const response = await sendRequest({
197
+ id: generateId(),
198
+ type: "generatePackageManifest",
199
+ documentBytes: bytes,
200
+ limits,
201
+ representation: "object",
202
+ }, [bytes.buffer]);
203
+ return response.manifest;
204
+ },
205
+ async verifyDeliverable(document, baseline) {
206
+ const bytes = await toBytes(document);
207
+ const baselineBytes = baseline === undefined ? undefined : await toBytes(baseline);
208
+ const transfer = [bytes.buffer];
209
+ if (baselineBytes !== undefined)
210
+ transfer.push(baselineBytes.buffer);
211
+ const response = await sendRequest({
212
+ id: generateId(),
213
+ type: "verifyDeliverable",
214
+ documentBytes: bytes,
215
+ baselineBytes,
216
+ }, transfer);
217
+ if (!response.success || !response.verification) {
218
+ throw new Error(response.error ?? "verifyDeliverable failed");
219
+ }
220
+ return response.verification;
221
+ },
222
+ async proveRedlineReversibility(baseline, intendedFinal, redline) {
223
+ const baselineBytes = await toBytes(baseline);
224
+ const intendedFinalBytes = await toBytes(intendedFinal);
225
+ const redlineBytes = await toBytes(redline);
226
+ const response = await sendRequest({
227
+ id: generateId(),
228
+ type: "proveRedlineReversibility",
229
+ baselineBytes,
230
+ intendedFinalBytes,
231
+ redlineBytes,
232
+ }, [baselineBytes.buffer, intendedFinalBytes.buffer, redlineBytes.buffer]);
233
+ if (!response.success || !response.proof) {
234
+ throw new Error(response.error ?? "proveRedlineReversibility failed");
235
+ }
236
+ return response.proof;
237
+ },
238
+ async getSemanticChanges(left, right, settings) {
239
+ const leftBytes = await toBytes(left);
240
+ const rightBytes = await toBytes(right);
241
+ const response = await sendRequest({
242
+ id: generateId(),
243
+ type: "getSemanticChanges",
244
+ leftBytes,
245
+ rightBytes,
246
+ settings,
247
+ }, [leftBytes.buffer, rightBytes.buffer]);
248
+ return response.semanticChanges;
249
+ },
250
+ async generatePackageManifestJson(document, limits) {
251
+ const bytes = await toBytes(document);
252
+ const response = await sendRequest({
253
+ id: generateId(),
254
+ type: "generatePackageManifest",
255
+ documentBytes: bytes,
256
+ limits,
257
+ representation: "json",
258
+ }, [bytes.buffer]);
259
+ if (response.manifestJson === undefined) {
260
+ throw new Error("Package manifest worker response omitted canonical JSON");
261
+ }
262
+ return response.manifestJson;
263
+ },
264
+ async projectReviewProfile(document, profile, maximumOutputBytes) {
265
+ const bytes = await toBytes(document);
266
+ const response = await sendRequest({
267
+ id: generateId(),
268
+ type: "projectReviewProfile",
269
+ documentBytes: bytes,
270
+ profile,
271
+ maximumOutputBytes,
272
+ }, [bytes.buffer]);
273
+ if (!response.documentBytes || response.documentBytes.byteLength === 0) {
274
+ throw new Error(`Failed to derive the ${profile} review profile`);
275
+ }
276
+ return response.documentBytes;
277
+ },
278
+ async convertDocxToHtml(document, options, maximumOutputBytes) {
154
279
  const bytes = await toBytes(document);
155
280
  const response = await sendRequest({
156
281
  id: generateId(),
157
282
  type: "convertDocxToHtml",
158
283
  documentBytes: bytes,
159
284
  options,
285
+ maximumOutputBytes,
160
286
  }, [bytes.buffer]);
161
287
  return response.html;
162
288
  },
@@ -239,6 +365,39 @@ export async function createWorkerDocxodus(options) {
239
365
  }
240
366
  const handle = openResponse.handle;
241
367
  return {
368
+ async getPackageManifest() {
369
+ const res = await sendRequest({
370
+ id: generateId(),
371
+ type: "sessionGetPackageManifest",
372
+ handle,
373
+ });
374
+ if (!res.success || !res.manifest) {
375
+ throw new Error(res.error ?? "sessionGetPackageManifest failed");
376
+ }
377
+ return res.manifest;
378
+ },
379
+ async getSemanticChanges() {
380
+ const res = await sendRequest({
381
+ id: generateId(),
382
+ type: "sessionGetSemanticChanges",
383
+ handle,
384
+ });
385
+ if (!res.success || !res.semanticChanges) {
386
+ throw new Error(res.error ?? "sessionGetSemanticChanges failed");
387
+ }
388
+ return res.semanticChanges;
389
+ },
390
+ async verifyDeliverable() {
391
+ const res = await sendRequest({
392
+ id: generateId(),
393
+ type: "sessionVerifyDeliverable",
394
+ handle,
395
+ });
396
+ if (!res.success || !res.verification) {
397
+ throw new Error(res.error ?? "sessionVerifyDeliverable failed");
398
+ }
399
+ return res.verification;
400
+ },
242
401
  async addAnnotation(anchorId, span, annotation) {
243
402
  const res = await sendRequest({
244
403
  id: generateId(),
@@ -302,13 +461,7 @@ export async function createWorkerDocxodus(options) {
302
461
  };
303
462
  },
304
463
  terminate() {
305
- isWorkerActive = false;
306
- worker.terminate();
307
- // Reject any pending requests
308
- for (const pending of pendingRequests.values()) {
309
- pending.reject(new Error("Worker terminated"));
310
- }
311
- pendingRequests.clear();
464
+ stopWorker("Worker terminated");
312
465
  },
313
466
  isActive() {
314
467
  return isWorkerActive;