docxodus 12.6.4 → 13.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 (92) hide show
  1. package/README.md +8 -5
  2. package/dist/canonical.d.ts.map +1 -1
  3. package/dist/canonical.js +7 -3
  4. package/dist/canonical.js.map +1 -1
  5. package/dist/conversion-options.d.ts +16 -0
  6. package/dist/conversion-options.d.ts.map +1 -0
  7. package/dist/conversion-options.js +31 -0
  8. package/dist/conversion-options.js.map +1 -0
  9. package/dist/core.d.ts +17 -9
  10. package/dist/core.d.ts.map +1 -1
  11. package/dist/core.js +23 -24
  12. package/dist/core.js.map +1 -1
  13. package/dist/docxodus.worker.js +2 -1073
  14. package/dist/docxodus.worker.js.map +7 -1
  15. package/dist/editor.bundle.js +35 -14296
  16. package/dist/editor.bundle.js.map +7 -0
  17. package/dist/editor.d.ts +33 -2
  18. package/dist/editor.d.ts.map +1 -1
  19. package/dist/editor.js +6739 -4773
  20. package/dist/editor.js.map +7 -1
  21. package/dist/embed.bundle.js +159 -18703
  22. package/dist/embed.bundle.js.map +7 -0
  23. package/dist/embed.d.ts +1 -1
  24. package/dist/embed.iife.js +37 -18595
  25. package/dist/embed.iife.js.map +7 -0
  26. package/dist/embed.js +1 -1
  27. package/dist/export-assets.json +27 -27
  28. package/dist/export-browser.bundle.js +1388 -477
  29. package/dist/export-browser.d.ts +20 -0
  30. package/dist/export-browser.d.ts.map +1 -1
  31. package/dist/export-browser.js +132 -37
  32. package/dist/export-browser.js.map +1 -1
  33. package/dist/font-runtime.d.ts.map +1 -1
  34. package/dist/font-runtime.js +54 -0
  35. package/dist/font-runtime.js.map +1 -1
  36. package/dist/line-metrics.d.ts +60 -0
  37. package/dist/line-metrics.d.ts.map +1 -0
  38. package/dist/line-metrics.js +343 -0
  39. package/dist/line-metrics.js.map +1 -0
  40. package/dist/pagination.bundle.js +3 -3214
  41. package/dist/pagination.bundle.js.map +7 -0
  42. package/dist/pagination.d.ts +86 -9
  43. package/dist/pagination.d.ts.map +1 -1
  44. package/dist/pagination.js +358 -55
  45. package/dist/pagination.js.map +1 -1
  46. package/dist/react.d.ts.map +1 -1
  47. package/dist/react.js +63 -12
  48. package/dist/react.js.map +1 -1
  49. package/dist/render-report-v2.schema.json +29 -0
  50. package/dist/session.bundle.js +2 -2013
  51. package/dist/session.bundle.js.map +7 -0
  52. package/dist/session.d.ts +14 -5
  53. package/dist/session.d.ts.map +1 -1
  54. package/dist/session.js +62 -29
  55. package/dist/session.js.map +1 -1
  56. package/dist/types.d.ts +137 -21
  57. package/dist/types.d.ts.map +1 -1
  58. package/dist/types.js +14 -0
  59. package/dist/types.js.map +1 -1
  60. package/dist/wasm/_framework/Docxodus.wasm +0 -0
  61. package/dist/wasm/_framework/Docxodus.wasm.br +0 -0
  62. package/dist/wasm/_framework/DocxodusWasm.wasm +0 -0
  63. package/dist/wasm/_framework/DocxodusWasm.wasm.br +0 -0
  64. package/dist/wasm/_framework/System.Collections.wasm +0 -0
  65. package/dist/wasm/_framework/System.Collections.wasm.br +0 -0
  66. package/dist/wasm/_framework/System.IO.Compression.wasm +0 -0
  67. package/dist/wasm/_framework/System.IO.Compression.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.Private.CoreLib.wasm +0 -0
  73. package/dist/wasm/_framework/System.Private.CoreLib.wasm.br +0 -0
  74. package/dist/wasm/_framework/System.Private.Xml.Linq.wasm +0 -0
  75. package/dist/wasm/_framework/System.Private.Xml.Linq.wasm.br +0 -0
  76. package/dist/wasm/_framework/System.Text.RegularExpressions.wasm +0 -0
  77. package/dist/wasm/_framework/System.Text.RegularExpressions.wasm.br +0 -0
  78. package/dist/wasm/_framework/dotnet.boot.js +11 -11
  79. package/dist/wasm/_framework/dotnet.boot.js.br +0 -0
  80. package/dist/wasm/_framework/dotnet.native.wasm +0 -0
  81. package/dist/wasm/_framework/dotnet.native.wasm.br +0 -0
  82. package/dist/word-text.d.ts +14 -0
  83. package/dist/word-text.d.ts.map +1 -0
  84. package/dist/word-text.js +377 -0
  85. package/dist/word-text.js.map +1 -0
  86. package/dist/worker-proxy.bundle.js +2 -536
  87. package/dist/worker-proxy.bundle.js.map +7 -0
  88. package/dist/worker-proxy.d.ts +14 -1
  89. package/dist/worker-proxy.d.ts.map +1 -1
  90. package/dist/worker-proxy.js +357 -339
  91. package/dist/worker-proxy.js.map +1 -1
  92. package/package.json +13 -12
@@ -33,6 +33,24 @@ export class WorkerOperationError extends Error {
33
33
  function workerError(message, code) {
34
34
  return new WorkerOperationError(message || "Unknown error", code);
35
35
  }
36
+ /**
37
+ * Read a success response's payload, rejecting with `missing_result` when the worker reported
38
+ * success without it rather than handing the caller `undefined` typed as a value.
39
+ */
40
+ function requireField(response, field) {
41
+ const value = response[field];
42
+ if (value === undefined || value === null) {
43
+ throw workerError(`The worker's "${response.type ?? "unknown"}" response reported success without its ${String(field)}`, "missing_result");
44
+ }
45
+ return value;
46
+ }
47
+ /** A positive, finite timeout in milliseconds, or undefined; anything else is a caller error. */
48
+ function checkTimeout(timeoutMs, name) {
49
+ if (timeoutMs !== undefined && !(Number.isFinite(timeoutMs) && timeoutMs > 0)) {
50
+ throw new RangeError(`${name} must be a positive, finite number of milliseconds; got ${timeoutMs}`);
51
+ }
52
+ return timeoutMs;
53
+ }
36
54
  /** Reads a worker failure's machine-readable cause, or undefined for any other error. */
37
55
  export function workerErrorCode(error) {
38
56
  return error instanceof WorkerOperationError ? error.code : undefined;
@@ -97,6 +115,7 @@ export async function createWorkerDocxodus(options) {
97
115
  if (options?.signal?.aborted) {
98
116
  throw new Error("Worker creation aborted");
99
117
  }
118
+ const requestTimeoutMs = checkTimeout(options?.requestTimeoutMs, "requestTimeoutMs");
100
119
  // Determine WASM base path
101
120
  const wasmBasePath = options?.wasmBasePath ?? deriveWasmBasePath();
102
121
  // The worker bundle is packaged beside this module.
@@ -154,16 +173,58 @@ export async function createWorkerDocxodus(options) {
154
173
  worker.onerror = (error) => {
155
174
  stopWorker(`Worker error: ${error.message}`);
156
175
  };
176
+ // A response that cannot be deserialized arrives without its request id, so the request it
177
+ // answered cannot be identified. Rather than leave that request pending forever, reject every
178
+ // request in flight; the worker itself is unaffected and stays usable.
179
+ worker.onmessageerror = () => {
180
+ for (const pending of [...pendingRequests.values()]) {
181
+ pending.reject(workerError("A worker response could not be deserialized, so every request in flight was rejected", "message_error"));
182
+ }
183
+ };
157
184
  /**
158
- * Send a request to the worker and wait for response.
185
+ * Send a request to the worker and wait for its response. Every way a request ends (a
186
+ * response, a timeout, an abort, the worker stopping, or a failed post) goes through the
187
+ * pending entry's resolve/reject, which clear its timer and abort listener exactly once.
159
188
  */
160
- function sendRequest(request, transfer) {
189
+ function sendRequest(request, transfer, requestOptions) {
161
190
  return new Promise((resolve, reject) => {
162
191
  if (!isWorkerActive) {
163
192
  reject(new Error("Worker has been terminated"));
164
193
  return;
165
194
  }
166
- pendingRequests.set(request.id, { resolve, reject });
195
+ const signal = requestOptions?.signal;
196
+ if (signal?.aborted) {
197
+ reject(workerError(`The worker request "${request.type}" was aborted before it was sent`, "aborted"));
198
+ return;
199
+ }
200
+ const timeoutMs = requestOptions?.timeoutMs ?? requestTimeoutMs;
201
+ let timer;
202
+ let onAbort;
203
+ const finish = () => {
204
+ pendingRequests.delete(request.id);
205
+ if (timer !== undefined)
206
+ clearTimeout(timer);
207
+ if (onAbort)
208
+ signal?.removeEventListener("abort", onAbort);
209
+ };
210
+ pendingRequests.set(request.id, {
211
+ resolve: (value) => {
212
+ finish();
213
+ resolve(value);
214
+ },
215
+ reject: (error) => {
216
+ finish();
217
+ reject(error);
218
+ },
219
+ });
220
+ const fail = (error) => pendingRequests.get(request.id)?.reject(error);
221
+ if (timeoutMs !== undefined) {
222
+ timer = setTimeout(() => fail(workerError(`The worker request "${request.type}" timed out after ${timeoutMs} ms`, "timeout")), timeoutMs);
223
+ }
224
+ if (signal) {
225
+ onAbort = () => fail(workerError(`The worker request "${request.type}" was aborted`, "aborted"));
226
+ signal.addEventListener("abort", onAbort, { once: true });
227
+ }
167
228
  try {
168
229
  if (transfer && transfer.length > 0) {
169
230
  worker.postMessage(request, transfer);
@@ -173,8 +234,7 @@ export async function createWorkerDocxodus(options) {
173
234
  }
174
235
  }
175
236
  catch (error) {
176
- pendingRequests.delete(request.id);
177
- reject(error instanceof Error ? error : new Error(String(error)));
237
+ fail(error instanceof Error ? error : new Error(String(error)));
178
238
  }
179
239
  });
180
240
  }
@@ -190,342 +250,300 @@ export async function createWorkerDocxodus(options) {
190
250
  stopWorker("Worker initialization failed");
191
251
  throw error;
192
252
  }
193
- // Return the WorkerDocxodus instance
194
- return {
195
- async generatePackageManifest(document, limits) {
196
- const bytes = await toBytes(document);
197
- const response = await sendRequest({
198
- id: generateId(),
199
- type: "generatePackageManifest",
200
- documentBytes: bytes,
201
- limits,
202
- representation: "object",
203
- }, [bytes.buffer]);
204
- return response.manifest;
205
- },
206
- async verifyDeliverable(document, baseline, request) {
207
- const bytes = await toBytes(document);
208
- const baselineBytes = baseline === undefined ? undefined : await toBytes(baseline);
209
- const transfer = [bytes.buffer];
210
- if (baselineBytes !== undefined)
211
- transfer.push(baselineBytes.buffer);
212
- const response = await sendRequest({
213
- id: generateId(),
214
- type: "verifyDeliverable",
215
- documentBytes: bytes,
216
- baselineBytes,
217
- requestJson: request === undefined ? undefined : serializeVerificationRequest(request),
218
- }, transfer);
219
- if (!response.success || !response.verification) {
220
- throw new Error(response.error ?? "verifyDeliverable failed");
221
- }
222
- return response.verification;
223
- },
224
- async proveRedlineReversibility(baseline, intendedFinal, redline) {
225
- const baselineBytes = await toBytes(baseline);
226
- const intendedFinalBytes = await toBytes(intendedFinal);
227
- const redlineBytes = await toBytes(redline);
228
- const response = await sendRequest({
229
- id: generateId(),
230
- type: "proveRedlineReversibility",
231
- baselineBytes,
232
- intendedFinalBytes,
233
- redlineBytes,
234
- }, [baselineBytes.buffer, intendedFinalBytes.buffer, redlineBytes.buffer]);
235
- if (!response.success || !response.proof) {
236
- throw new Error(response.error ?? "proveRedlineReversibility failed");
237
- }
238
- return response.proof;
239
- },
240
- async getSemanticChanges(left, right, settings) {
241
- const leftBytes = await toBytes(left);
242
- const rightBytes = await toBytes(right);
243
- const response = await sendRequest({
244
- id: generateId(),
245
- type: "getSemanticChanges",
246
- leftBytes,
247
- rightBytes,
248
- settings,
249
- }, [leftBytes.buffer, rightBytes.buffer]);
250
- return response.semanticChanges;
251
- },
252
- async createExternalAnnotationSet(document, documentId) {
253
- const bytes = await toBytes(document);
254
- const response = await sendRequest({ id: generateId(), type: "createExternalAnnotationSet", documentBytes: bytes, documentId }, [bytes.buffer]);
255
- if (!response.success || !response.annotationSet) {
256
- throw new Error(response.error ?? "createExternalAnnotationSet failed");
257
- }
258
- return response.annotationSet;
259
- },
260
- async validateExternalAnnotations(document, annotationSet) {
261
- const bytes = await toBytes(document);
262
- const response = await sendRequest({ id: generateId(), type: "validateExternalAnnotations", documentBytes: bytes, annotationSet }, [bytes.buffer]);
263
- if (!response.success || !response.validation) {
264
- throw new Error(response.error ?? "validateExternalAnnotations failed");
265
- }
266
- return response.validation;
267
- },
268
- async projectAnnotationsOntoHtml(html, annotationSet, projectionOptions) {
269
- const response = await sendRequest({
270
- id: generateId(),
271
- type: "projectAnnotationsOntoHtml",
272
- html,
273
- annotationSet,
274
- projectionOptions,
275
- });
276
- if (!response.success || response.html === undefined) {
277
- throw new Error(response.error ?? "projectAnnotationsOntoHtml failed");
278
- }
279
- return response.html;
280
- },
281
- async convertDocxToHtmlWithExternalAnnotations(document, annotationSet, conversionOptions, projectionOptions) {
282
- const bytes = await toBytes(document);
283
- const response = await sendRequest({
284
- id: generateId(),
285
- type: "convertDocxToHtmlWithExternalAnnotations",
286
- documentBytes: bytes,
287
- annotationSet,
288
- conversionOptions,
289
- projectionOptions,
290
- }, [bytes.buffer]);
291
- if (!response.success || response.html === undefined) {
292
- throw new Error(response.error ?? "convertDocxToHtmlWithExternalAnnotations failed");
293
- }
294
- return response.html;
295
- },
296
- async exportToOpenContract(document) {
297
- const bytes = await toBytes(document);
298
- const response = await sendRequest({ id: generateId(), type: "exportToOpenContract", documentBytes: bytes }, [bytes.buffer]);
299
- if (!response.success || !response.export) {
300
- throw new Error(response.error ?? "exportToOpenContract failed");
301
- }
302
- return response.export;
303
- },
304
- async generatePackageManifestJson(document, limits) {
305
- const bytes = await toBytes(document);
306
- const response = await sendRequest({
307
- id: generateId(),
308
- type: "generatePackageManifest",
309
- documentBytes: bytes,
310
- limits,
311
- representation: "json",
312
- }, [bytes.buffer]);
313
- if (response.manifestJson === undefined) {
314
- throw new Error("Package manifest worker response omitted canonical JSON");
315
- }
316
- return response.manifestJson;
317
- },
318
- async projectReviewProfile(document, profile, maximumOutputBytes) {
319
- const bytes = await toBytes(document);
320
- const response = await sendRequest({
321
- id: generateId(),
322
- type: "projectReviewProfile",
323
- documentBytes: bytes,
324
- profile,
325
- maximumOutputBytes,
326
- }, [bytes.buffer]);
327
- if (!response.documentBytes || response.documentBytes.byteLength === 0) {
328
- throw new Error(`Failed to derive the ${profile} review profile`);
329
- }
330
- return response.documentBytes;
331
- },
332
- async convertDocxToHtml(document, options, maximumOutputBytes) {
333
- const bytes = await toBytes(document);
334
- const response = await sendRequest({
335
- id: generateId(),
336
- type: "convertDocxToHtml",
337
- documentBytes: bytes,
338
- options,
339
- maximumOutputBytes,
340
- }, [bytes.buffer]);
341
- return response.html;
342
- },
343
- async compareDocuments(original, modified, options) {
344
- const originalBytes = await toBytes(original);
345
- const modifiedBytes = await toBytes(modified);
346
- const response = await sendRequest({
347
- id: generateId(),
348
- type: "compareDocuments",
349
- originalBytes,
350
- modifiedBytes,
351
- options,
352
- }, [originalBytes.buffer, modifiedBytes.buffer]);
353
- return response.documentBytes;
354
- },
355
- async compareDocumentsToHtml(original, modified, options) {
356
- const originalBytes = await toBytes(original);
357
- const modifiedBytes = await toBytes(modified);
358
- const response = await sendRequest({
359
- id: generateId(),
360
- type: "compareDocumentsToHtml",
361
- originalBytes,
362
- modifiedBytes,
363
- options,
364
- }, [originalBytes.buffer, modifiedBytes.buffer]);
365
- return response.html;
366
- },
367
- async getRevisions(document) {
368
- const bytes = await toBytes(document);
369
- const response = await sendRequest({
370
- id: generateId(),
371
- type: "getRevisions",
372
- documentBytes: bytes,
373
- }, [bytes.buffer]);
374
- return response.revisions;
375
- },
376
- async getComments(document) {
377
- const bytes = await toBytes(document);
378
- const response = await sendRequest({ id: generateId(), type: "getComments", documentBytes: bytes }, [bytes.buffer]);
379
- return response.comments;
380
- },
381
- async getDocumentMetadata(document) {
382
- const bytes = await toBytes(document);
383
- const response = await sendRequest({
384
- id: generateId(),
385
- type: "getDocumentMetadata",
386
- documentBytes: bytes,
387
- }, [bytes.buffer]);
388
- return response.metadata;
389
- },
390
- async getVersion() {
391
- const response = await sendRequest({
392
- id: generateId(),
393
- type: "getVersion",
394
- });
395
- return response.version;
396
- },
397
- prepare() {
398
- // Idempotent: hand back the existing warmup if one is in flight or done.
399
- if (preparePromise) {
253
+ // The instance, and any withRequestOptions views of it, share this worker; each view's
254
+ // requests carry its options.
255
+ const createApi = (requestOptions) => {
256
+ const send = (request, transfer) => sendRequest(request, transfer, requestOptions);
257
+ return {
258
+ async generatePackageManifest(document, limits) {
259
+ const bytes = await toBytes(document);
260
+ const response = await send({
261
+ id: generateId(),
262
+ type: "generatePackageManifest",
263
+ documentBytes: bytes,
264
+ limits,
265
+ representation: "object",
266
+ }, [bytes.buffer]);
267
+ return requireField(response, "manifest");
268
+ },
269
+ async verifyDeliverable(document, baseline, request) {
270
+ const bytes = await toBytes(document);
271
+ const baselineBytes = baseline === undefined ? undefined : await toBytes(baseline);
272
+ const transfer = [bytes.buffer];
273
+ if (baselineBytes !== undefined)
274
+ transfer.push(baselineBytes.buffer);
275
+ const response = await send({
276
+ id: generateId(),
277
+ type: "verifyDeliverable",
278
+ documentBytes: bytes,
279
+ baselineBytes,
280
+ requestJson: request === undefined ? undefined : serializeVerificationRequest(request),
281
+ }, transfer);
282
+ return requireField(response, "verification");
283
+ },
284
+ async proveRedlineReversibility(baseline, intendedFinal, redline) {
285
+ const baselineBytes = await toBytes(baseline);
286
+ const intendedFinalBytes = await toBytes(intendedFinal);
287
+ const redlineBytes = await toBytes(redline);
288
+ const response = await send({
289
+ id: generateId(),
290
+ type: "proveRedlineReversibility",
291
+ baselineBytes,
292
+ intendedFinalBytes,
293
+ redlineBytes,
294
+ }, [baselineBytes.buffer, intendedFinalBytes.buffer, redlineBytes.buffer]);
295
+ return requireField(response, "proof");
296
+ },
297
+ async getSemanticChanges(left, right, settings) {
298
+ const leftBytes = await toBytes(left);
299
+ const rightBytes = await toBytes(right);
300
+ const response = await send({
301
+ id: generateId(),
302
+ type: "getSemanticChanges",
303
+ leftBytes,
304
+ rightBytes,
305
+ settings,
306
+ }, [leftBytes.buffer, rightBytes.buffer]);
307
+ return requireField(response, "semanticChanges");
308
+ },
309
+ async createExternalAnnotationSet(document, documentId) {
310
+ const bytes = await toBytes(document);
311
+ const response = await send({ id: generateId(), type: "createExternalAnnotationSet", documentBytes: bytes, documentId }, [bytes.buffer]);
312
+ return requireField(response, "annotationSet");
313
+ },
314
+ async validateExternalAnnotations(document, annotationSet) {
315
+ const bytes = await toBytes(document);
316
+ const response = await send({ id: generateId(), type: "validateExternalAnnotations", documentBytes: bytes, annotationSet }, [bytes.buffer]);
317
+ return requireField(response, "validation");
318
+ },
319
+ async projectAnnotationsOntoHtml(html, annotationSet, projectionOptions) {
320
+ const response = await send({
321
+ id: generateId(),
322
+ type: "projectAnnotationsOntoHtml",
323
+ html,
324
+ annotationSet,
325
+ projectionOptions,
326
+ });
327
+ return requireField(response, "html");
328
+ },
329
+ async convertDocxToHtmlWithExternalAnnotations(document, annotationSet, conversionOptions, projectionOptions) {
330
+ const bytes = await toBytes(document);
331
+ const response = await send({
332
+ id: generateId(),
333
+ type: "convertDocxToHtmlWithExternalAnnotations",
334
+ documentBytes: bytes,
335
+ annotationSet,
336
+ conversionOptions,
337
+ projectionOptions,
338
+ }, [bytes.buffer]);
339
+ return requireField(response, "html");
340
+ },
341
+ async exportToOpenContract(document) {
342
+ const bytes = await toBytes(document);
343
+ const response = await send({ id: generateId(), type: "exportToOpenContract", documentBytes: bytes }, [bytes.buffer]);
344
+ return requireField(response, "export");
345
+ },
346
+ async generatePackageManifestJson(document, limits) {
347
+ const bytes = await toBytes(document);
348
+ const response = await send({
349
+ id: generateId(),
350
+ type: "generatePackageManifest",
351
+ documentBytes: bytes,
352
+ limits,
353
+ representation: "json",
354
+ }, [bytes.buffer]);
355
+ return requireField(response, "manifestJson");
356
+ },
357
+ async projectReviewProfile(document, profile, maximumOutputBytes) {
358
+ const bytes = await toBytes(document);
359
+ const response = await send({
360
+ id: generateId(),
361
+ type: "projectReviewProfile",
362
+ documentBytes: bytes,
363
+ profile,
364
+ maximumOutputBytes,
365
+ }, [bytes.buffer]);
366
+ if (!response.documentBytes || response.documentBytes.byteLength === 0) {
367
+ throw new Error(`Failed to derive the ${profile} review profile`);
368
+ }
369
+ return response.documentBytes;
370
+ },
371
+ async convertDocxToHtml(document, options, maximumOutputBytes) {
372
+ const bytes = await toBytes(document);
373
+ const response = await send({
374
+ id: generateId(),
375
+ type: "convertDocxToHtml",
376
+ documentBytes: bytes,
377
+ options,
378
+ maximumOutputBytes,
379
+ }, [bytes.buffer]);
380
+ return requireField(response, "html");
381
+ },
382
+ async compareDocuments(original, modified, options) {
383
+ const originalBytes = await toBytes(original);
384
+ const modifiedBytes = await toBytes(modified);
385
+ const response = await send({
386
+ id: generateId(),
387
+ type: "compareDocuments",
388
+ originalBytes,
389
+ modifiedBytes,
390
+ options,
391
+ }, [originalBytes.buffer, modifiedBytes.buffer]);
392
+ return requireField(response, "documentBytes");
393
+ },
394
+ async compareDocumentsToHtml(original, modified, options) {
395
+ const originalBytes = await toBytes(original);
396
+ const modifiedBytes = await toBytes(modified);
397
+ const response = await send({
398
+ id: generateId(),
399
+ type: "compareDocumentsToHtml",
400
+ originalBytes,
401
+ modifiedBytes,
402
+ options,
403
+ }, [originalBytes.buffer, modifiedBytes.buffer]);
404
+ return requireField(response, "html");
405
+ },
406
+ async getRevisions(document) {
407
+ const bytes = await toBytes(document);
408
+ const response = await send({
409
+ id: generateId(),
410
+ type: "getRevisions",
411
+ documentBytes: bytes,
412
+ }, [bytes.buffer]);
413
+ return requireField(response, "revisions");
414
+ },
415
+ async getComments(document) {
416
+ const bytes = await toBytes(document);
417
+ const response = await send({ id: generateId(), type: "getComments", documentBytes: bytes }, [bytes.buffer]);
418
+ return requireField(response, "comments");
419
+ },
420
+ async getDocumentMetadata(document) {
421
+ const bytes = await toBytes(document);
422
+ const response = await send({
423
+ id: generateId(),
424
+ type: "getDocumentMetadata",
425
+ documentBytes: bytes,
426
+ }, [bytes.buffer]);
427
+ return requireField(response, "metadata");
428
+ },
429
+ async getVersion() {
430
+ const response = await send({
431
+ id: generateId(),
432
+ type: "getVersion",
433
+ });
434
+ return requireField(response, "version");
435
+ },
436
+ prepare() {
437
+ // Idempotent: hand back the existing warmup if one is in flight or done.
438
+ if (preparePromise) {
439
+ return preparePromise;
440
+ }
441
+ preparePromise = send({
442
+ id: generateId(),
443
+ type: "prepare",
444
+ }).then(() => undefined);
445
+ // On failure, clear the cache so a subsequent prepare() can retry.
446
+ preparePromise.catch(() => {
447
+ preparePromise = null;
448
+ });
400
449
  return preparePromise;
401
- }
402
- preparePromise = sendRequest({
403
- id: generateId(),
404
- type: "prepare",
405
- }).then(() => undefined);
406
- // On failure, clear the cache so a subsequent prepare() can retry.
407
- preparePromise.catch(() => {
408
- preparePromise = null;
409
- });
410
- return preparePromise;
411
- },
412
- async openDocxSession(document, settings) {
413
- const bytes = await toBytes(document);
414
- const settingsJson = settings ? JSON.stringify(settings) : "";
415
- const openResponse = await sendRequest({
416
- id: generateId(),
417
- type: "sessionOpen",
418
- documentBytes: bytes,
419
- settingsJson,
420
- }, [bytes.buffer]);
421
- if (!openResponse.success || openResponse.handle === undefined) {
422
- throw new Error(`Failed to open worker DocxSession: ${openResponse.error ?? "unknown error"}`);
423
- }
424
- const handle = openResponse.handle;
425
- return {
426
- async getPackageManifest() {
427
- const res = await sendRequest({
428
- id: generateId(),
429
- type: "sessionGetPackageManifest",
430
- handle,
431
- });
432
- if (!res.success || !res.manifest) {
433
- throw new Error(res.error ?? "sessionGetPackageManifest failed");
434
- }
435
- return res.manifest;
436
- },
437
- async getSemanticChanges() {
438
- const res = await sendRequest({
439
- id: generateId(),
440
- type: "sessionGetSemanticChanges",
441
- handle,
442
- });
443
- if (!res.success || !res.semanticChanges) {
444
- throw new Error(res.error ?? "sessionGetSemanticChanges failed");
445
- }
446
- return res.semanticChanges;
447
- },
448
- async verifyDeliverable(request) {
449
- const res = await sendRequest({
450
- id: generateId(),
451
- type: "sessionVerifyDeliverable",
452
- handle,
453
- requestJson: request === undefined ? undefined : serializeVerificationRequest(request),
454
- });
455
- if (!res.success || !res.verification) {
456
- throw new Error(res.error ?? "sessionVerifyDeliverable failed");
457
- }
458
- return res.verification;
459
- },
460
- async addAnnotation(anchorId, span, annotation) {
461
- const res = await sendRequest({
462
- id: generateId(),
463
- type: "sessionAddAnnotation",
464
- handle,
465
- anchorId,
466
- spanJson: span ? JSON.stringify(span) : "",
467
- annotationJson: JSON.stringify(annotation),
468
- });
469
- if (!res.success) {
470
- throw new Error(res.error ?? "sessionAddAnnotation failed");
471
- }
472
- return res.result;
473
- },
474
- async removeAnnotation(annotationId) {
475
- const res = await sendRequest({
476
- id: generateId(),
477
- type: "sessionRemoveAnnotation",
478
- handle,
479
- annotationId,
480
- });
481
- if (!res.success) {
482
- throw new Error(res.error ?? "sessionRemoveAnnotation failed");
483
- }
484
- return res.result;
485
- },
486
- async updateAnnotation(annotationId, update) {
487
- const res = await sendRequest({
488
- id: generateId(),
489
- type: "sessionUpdateAnnotation",
490
- handle,
491
- annotationId,
492
- updateJson: JSON.stringify(update),
493
- });
494
- if (!res.success) {
495
- throw new Error(res.error ?? "sessionUpdateAnnotation failed");
496
- }
497
- return res.result;
498
- },
499
- async moveAnnotation(annotationId, newAnchorId, newSpan) {
500
- const res = await sendRequest({
501
- id: generateId(),
502
- type: "sessionMoveAnnotation",
503
- handle,
504
- annotationId,
505
- newAnchorId,
506
- newSpanJson: newSpan ? JSON.stringify(newSpan) : "",
507
- });
508
- if (!res.success) {
509
- throw new Error(res.error ?? "sessionMoveAnnotation failed");
510
- }
511
- return res.result;
512
- },
513
- async close() {
514
- await sendRequest({
515
- id: generateId(),
516
- type: "sessionClose",
517
- handle,
518
- });
519
- },
520
- };
521
- },
522
- terminate() {
523
- stopWorker("Worker terminated");
524
- },
525
- isActive() {
526
- return isWorkerActive;
527
- },
450
+ },
451
+ async openDocxSession(document, settings) {
452
+ const bytes = await toBytes(document);
453
+ const settingsJson = settings ? JSON.stringify(settings) : "";
454
+ const openResponse = await send({
455
+ id: generateId(),
456
+ type: "sessionOpen",
457
+ documentBytes: bytes,
458
+ settingsJson,
459
+ }, [bytes.buffer]);
460
+ const handle = requireField(openResponse, "handle");
461
+ return {
462
+ async getPackageManifest() {
463
+ const res = await send({
464
+ id: generateId(),
465
+ type: "sessionGetPackageManifest",
466
+ handle,
467
+ });
468
+ return requireField(res, "manifest");
469
+ },
470
+ async getSemanticChanges() {
471
+ const res = await send({
472
+ id: generateId(),
473
+ type: "sessionGetSemanticChanges",
474
+ handle,
475
+ });
476
+ return requireField(res, "semanticChanges");
477
+ },
478
+ async verifyDeliverable(request) {
479
+ const res = await send({
480
+ id: generateId(),
481
+ type: "sessionVerifyDeliverable",
482
+ handle,
483
+ requestJson: request === undefined ? undefined : serializeVerificationRequest(request),
484
+ });
485
+ return requireField(res, "verification");
486
+ },
487
+ async addAnnotation(anchorId, span, annotation) {
488
+ const res = await send({
489
+ id: generateId(),
490
+ type: "sessionAddAnnotation",
491
+ handle,
492
+ anchorId,
493
+ spanJson: span ? JSON.stringify(span) : "",
494
+ annotationJson: JSON.stringify(annotation),
495
+ });
496
+ return requireField(res, "result");
497
+ },
498
+ async removeAnnotation(annotationId) {
499
+ const res = await send({
500
+ id: generateId(),
501
+ type: "sessionRemoveAnnotation",
502
+ handle,
503
+ annotationId,
504
+ });
505
+ return requireField(res, "result");
506
+ },
507
+ async updateAnnotation(annotationId, update) {
508
+ const res = await send({
509
+ id: generateId(),
510
+ type: "sessionUpdateAnnotation",
511
+ handle,
512
+ annotationId,
513
+ updateJson: JSON.stringify(update),
514
+ });
515
+ return requireField(res, "result");
516
+ },
517
+ async moveAnnotation(annotationId, newAnchorId, newSpan) {
518
+ const res = await send({
519
+ id: generateId(),
520
+ type: "sessionMoveAnnotation",
521
+ handle,
522
+ annotationId,
523
+ newAnchorId,
524
+ newSpanJson: newSpan ? JSON.stringify(newSpan) : "",
525
+ });
526
+ return requireField(res, "result");
527
+ },
528
+ async close() {
529
+ // Not abortable: an aborted view must still release the in-worker session handle.
530
+ await sendRequest({ id: generateId(), type: "sessionClose", handle }, undefined, { timeoutMs: requestOptions?.timeoutMs });
531
+ },
532
+ };
533
+ },
534
+ terminate() {
535
+ stopWorker("Worker terminated");
536
+ },
537
+ withRequestOptions(more) {
538
+ checkTimeout(more.timeoutMs, "timeoutMs");
539
+ return createApi({ ...requestOptions, ...more });
540
+ },
541
+ isActive() {
542
+ return isWorkerActive;
543
+ },
544
+ };
528
545
  };
546
+ return createApi();
529
547
  }
530
548
  /**
531
549
  * Check if Web Workers are supported in the current environment.