docxodus 12.1.0 → 12.2.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 (75) hide show
  1. package/README.md +9 -4
  2. package/dist/editor.bundle.js +135 -22
  3. package/dist/editor.d.ts +25 -3
  4. package/dist/editor.d.ts.map +1 -1
  5. package/dist/editor.js +132 -13
  6. package/dist/editor.js.map +1 -1
  7. package/dist/embed.bundle.js +573 -47
  8. package/dist/embed.d.ts +30 -1
  9. package/dist/embed.d.ts.map +1 -1
  10. package/dist/embed.iife.js +573 -47
  11. package/dist/embed.js +124 -13
  12. package/dist/embed.js.map +1 -1
  13. package/dist/export-assets.json +33 -33
  14. package/dist/history.d.ts +265 -0
  15. package/dist/history.d.ts.map +1 -0
  16. package/dist/history.js +307 -0
  17. package/dist/history.js.map +1 -0
  18. package/dist/index.d.ts +7 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +20 -2
  21. package/dist/index.js.map +1 -1
  22. package/dist/ribbon-chrome.d.ts +2 -2
  23. package/dist/ribbon-chrome.d.ts.map +1 -1
  24. package/dist/ribbon-chrome.js +6 -4
  25. package/dist/ribbon-chrome.js.map +1 -1
  26. package/dist/ribbon.js +39 -8
  27. package/dist/ribbon.js.map +1 -1
  28. package/dist/session.js +1 -1
  29. package/dist/session.js.map +1 -1
  30. package/dist/types.d.ts +2 -0
  31. package/dist/types.d.ts.map +1 -1
  32. package/dist/types.js.map +1 -1
  33. package/dist/wasm/_framework/DocumentFormat.OpenXml.Framework.wasm +0 -0
  34. package/dist/wasm/_framework/DocumentFormat.OpenXml.Framework.wasm.br +0 -0
  35. package/dist/wasm/_framework/DocumentFormat.OpenXml.wasm +0 -0
  36. package/dist/wasm/_framework/DocumentFormat.OpenXml.wasm.br +0 -0
  37. package/dist/wasm/_framework/Docxodus.wasm +0 -0
  38. package/dist/wasm/_framework/Docxodus.wasm.br +0 -0
  39. package/dist/wasm/_framework/DocxodusWasm.wasm +0 -0
  40. package/dist/wasm/_framework/DocxodusWasm.wasm.br +0 -0
  41. package/dist/wasm/_framework/System.Collections.Concurrent.wasm +0 -0
  42. package/dist/wasm/_framework/System.Collections.Concurrent.wasm.br +0 -0
  43. package/dist/wasm/_framework/System.Collections.wasm +0 -0
  44. package/dist/wasm/_framework/System.Collections.wasm.br +0 -0
  45. package/dist/wasm/_framework/System.IO.Compression.wasm +0 -0
  46. package/dist/wasm/_framework/System.IO.Compression.wasm.br +0 -0
  47. package/dist/wasm/_framework/System.IO.Packaging.wasm +0 -0
  48. package/dist/wasm/_framework/System.IO.Packaging.wasm.br +0 -0
  49. package/dist/wasm/_framework/System.Linq.Expressions.wasm +0 -0
  50. package/dist/wasm/_framework/System.Linq.Expressions.wasm.br +0 -0
  51. package/dist/wasm/_framework/System.Memory.wasm +0 -0
  52. package/dist/wasm/_framework/System.Memory.wasm.br +0 -0
  53. package/dist/wasm/_framework/System.Net.Http.wasm +0 -0
  54. package/dist/wasm/_framework/System.Net.Http.wasm.br +0 -0
  55. package/dist/wasm/_framework/System.Private.CoreLib.wasm +0 -0
  56. package/dist/wasm/_framework/System.Private.CoreLib.wasm.br +0 -0
  57. package/dist/wasm/_framework/System.Private.Xml.Linq.wasm +0 -0
  58. package/dist/wasm/_framework/System.Private.Xml.Linq.wasm.br +0 -0
  59. package/dist/wasm/_framework/System.Private.Xml.wasm +0 -0
  60. package/dist/wasm/_framework/System.Private.Xml.wasm.br +0 -0
  61. package/dist/wasm/_framework/System.Runtime.InteropServices.JavaScript.wasm +0 -0
  62. package/dist/wasm/_framework/System.Runtime.InteropServices.JavaScript.wasm.br +0 -0
  63. package/dist/wasm/_framework/System.Runtime.wasm +0 -0
  64. package/dist/wasm/_framework/System.Runtime.wasm.br +0 -0
  65. package/dist/wasm/_framework/System.Security.Cryptography.wasm +0 -0
  66. package/dist/wasm/_framework/System.Security.Cryptography.wasm.br +0 -0
  67. package/dist/wasm/_framework/System.Text.Json.wasm +0 -0
  68. package/dist/wasm/_framework/System.Text.Json.wasm.br +0 -0
  69. package/dist/wasm/_framework/System.Text.RegularExpressions.wasm +0 -0
  70. package/dist/wasm/_framework/System.Text.RegularExpressions.wasm.br +0 -0
  71. package/dist/wasm/_framework/dotnet.boot.js +21 -21
  72. package/dist/wasm/_framework/dotnet.boot.js.br +0 -0
  73. package/dist/wasm/_framework/dotnet.native.wasm +0 -0
  74. package/dist/wasm/_framework/dotnet.native.wasm.br +0 -0
  75. package/package.json +4 -3
@@ -2038,6 +2038,288 @@ function openDocxSession(bytes, wasmExports2, settings) {
2038
2038
  return new DocxSession(handle, bridge);
2039
2039
  }
2040
2040
 
2041
+ // src/history.ts
2042
+ var MAX_HISTORY_ARCHIVE_BYTES = 64 * 1024 * 1024;
2043
+ var DocxHistoryError = class extends Error {
2044
+ constructor(code, message) {
2045
+ super(message);
2046
+ this.code = code;
2047
+ this.name = "DocxHistoryError";
2048
+ }
2049
+ };
2050
+ var adapters = /* @__PURE__ */ new Map();
2051
+ var nextAdapter = 0;
2052
+ function adapter(id) {
2053
+ const store = adapters.get(id);
2054
+ if (!store) throw new DocxHistoryError("Closed", "History storage adapter is closed.");
2055
+ return store;
2056
+ }
2057
+ function toBase64(bytes) {
2058
+ let binary = "";
2059
+ for (let offset = 0; offset < bytes.length; offset += 32768)
2060
+ binary += String.fromCharCode(...bytes.subarray(offset, offset + 32768));
2061
+ return btoa(binary);
2062
+ }
2063
+ function fromBase64(encoded) {
2064
+ const binary = atob(encoded);
2065
+ return Uint8Array.from(binary, (c) => c.charCodeAt(0));
2066
+ }
2067
+ function installHistoryStorageImports(setModuleImports) {
2068
+ setModuleImports("docxodus.history", {
2069
+ readBlob: async (id, json) => {
2070
+ const reference = JSON.parse(json);
2071
+ const bytes = await adapter(id).readBlob(reference);
2072
+ if (bytes === null) return "";
2073
+ if (bytes.length !== reference.length) throw new DocxHistoryError("PayloadMismatch", "Stored blob length differs from its reference.");
2074
+ return bytes.length === 0 ? "=" : toBase64(bytes);
2075
+ },
2076
+ putBlob: async (id, json, bytes) => adapter(id).putBlob(JSON.parse(json), bytes.slice()),
2077
+ readHead: async (id, documentId) => JSON.stringify(await adapter(id).readHead(documentId)),
2078
+ advanceHead: async (id, documentId, expected, state) => JSON.stringify(await adapter(id).advanceHead(documentId, JSON.parse(expected), JSON.parse(state))),
2079
+ initializeHead: async (id, documentId, head) => {
2080
+ const storage = adapter(id);
2081
+ if (!storage.initializeHead) throw new DocxHistoryError("InitializationUnsupported", "Storage cannot import an exact head.");
2082
+ return JSON.stringify(await storage.initializeHead(documentId, JSON.parse(head)));
2083
+ }
2084
+ });
2085
+ }
2086
+ var DocxHistoryClient = class {
2087
+ constructor(bridge, storage) {
2088
+ this.bridge = bridge;
2089
+ this.closed = false;
2090
+ if (nextAdapter >= 2147483647) throw new Error("History adapter identifiers exhausted.");
2091
+ this.adapterId = ++nextAdapter;
2092
+ adapters.set(this.adapterId, storage);
2093
+ try {
2094
+ this.handle = storage.initializeHead && bridge.OpenWithInitialization ? bridge.OpenWithInitialization(this.adapterId) : bridge.Open(this.adapterId);
2095
+ } catch (error) {
2096
+ adapters.delete(this.adapterId);
2097
+ throw error;
2098
+ }
2099
+ }
2100
+ close() {
2101
+ if (this.closed) return;
2102
+ this.bridge.Close(this.handle);
2103
+ adapters.delete(this.adapterId);
2104
+ this.closed = true;
2105
+ }
2106
+ /** Bind an identity without reading, creating a version, or taking ownership of this client. */
2107
+ document(documentId) {
2108
+ return new DocxHistoryDocument(documentId, (operation, fields, bytes) => this.call(operation, documentId, fields, bytes));
2109
+ }
2110
+ async exportHistoryArchive(documentId) {
2111
+ return fromBase64((await this.call("exportArchive", documentId)).bytes);
2112
+ }
2113
+ async importHistoryArchive(bytes) {
2114
+ checkArchiveSize(bytes);
2115
+ return (await this.call("importArchive", "", {}, bytes)).import;
2116
+ }
2117
+ async read(documentId) {
2118
+ return (await this.call("read", documentId)).view;
2119
+ }
2120
+ /** Host-triggered validated metadata tail; first join starts at the latest checkpoint. */
2121
+ async readChangesSince(documentId, after, maxEntriesToScan = 1e4) {
2122
+ return (await this.call("updates", documentId, { expectedHead: after, maxEntriesToScan })).update;
2123
+ }
2124
+ async readOperationsSince(documentId, after, maxEntriesToScan = 1e4) {
2125
+ return (await this.call("operations", documentId, { expectedHead: after, maxEntriesToScan })).operationUpdate;
2126
+ }
2127
+ async getOperation(documentId, operationId) {
2128
+ return (await this.call("getOperation", documentId, { operationId })).operation;
2129
+ }
2130
+ async exportOperationProposal(documentId, operationId) {
2131
+ return fromBase64((await this.call("exportOperationProposal", documentId, { operationId })).bytes);
2132
+ }
2133
+ async compareVersions(documentId, beforeVersionId, afterVersionId) {
2134
+ return fromBase64((await this.call("compare", documentId, { beforeVersionId, afterVersionId })).bytes);
2135
+ }
2136
+ async createVersion(documentId, expectedHead, bytes, metadata, requestId) {
2137
+ return (await this.call("create", documentId, { expectedHead, metadata, requestId }, bytes)).view;
2138
+ }
2139
+ async listVersions(documentId, cursor = null, limit = 25) {
2140
+ return (await this.call("list", documentId, { versionId: cursor, limit })).page;
2141
+ }
2142
+ async getVersion(documentId, versionId) {
2143
+ return (await this.call("get", documentId, { versionId })).version;
2144
+ }
2145
+ async exportVersion(documentId, versionId) {
2146
+ return fromBase64((await this.call("export", documentId, { versionId })).bytes);
2147
+ }
2148
+ async materialize(documentId, sequence, maxEntriesToScan = 1e4) {
2149
+ return fromBase64((await this.call("materialize", documentId, { sequence, maxEntriesToScan })).bytes);
2150
+ }
2151
+ async replay(documentId, sequence, maxEntriesToScan = 1e4) {
2152
+ return fromBase64((await this.call("replay", documentId, { sequence, maxEntriesToScan })).bytes);
2153
+ }
2154
+ async resolveSequenceAtTime(documentId, cutoff, maxEntriesToScan = 1e4) {
2155
+ return (await this.call("resolveTime", documentId, { cutoff, maxEntriesToScan })).sequence;
2156
+ }
2157
+ async restoreVersion(documentId, expectedHead, versionId, metadata, requestId) {
2158
+ return (await this.call("restore", documentId, { expectedHead, versionId, metadata, requestId })).view;
2159
+ }
2160
+ async call(operation, documentId, fields = {}, bytes = new Uint8Array()) {
2161
+ if (this.closed) throw new DocxHistoryError("Closed", "History client is closed.");
2162
+ return parseResult(await this.bridge.Invoke(
2163
+ this.handle,
2164
+ JSON.stringify({ schemaVersion: 1, operation, documentId, ...fields }),
2165
+ bytes
2166
+ ));
2167
+ }
2168
+ };
2169
+ var DocxHistoryReader = class {
2170
+ /** @internal Obtain through client.document() or openDocxHistoryArchive(). */
2171
+ constructor(documentId, call) {
2172
+ this.call = call;
2173
+ this.#documentId = documentId;
2174
+ }
2175
+ #documentId;
2176
+ get documentId() {
2177
+ return this.#documentId;
2178
+ }
2179
+ async read() {
2180
+ return (await this.call("read")).view;
2181
+ }
2182
+ async listVersions(cursor = null, limit = 25) {
2183
+ return (await this.call("list", { versionId: cursor, limit })).page;
2184
+ }
2185
+ async getVersion(versionId) {
2186
+ return (await this.call("get", { versionId })).version;
2187
+ }
2188
+ /** Omit versionId for latest; pass an ID to keep a UI operation pinned to a captured version. */
2189
+ async exportDocx(versionId = null) {
2190
+ return fromBase64((await this.call("exportDocx", { versionId })).bytes);
2191
+ }
2192
+ async exportHistoryArchive() {
2193
+ return fromBase64((await this.call("exportArchive")).bytes);
2194
+ }
2195
+ async materialize(sequence, maxEntriesToScan = 1e4) {
2196
+ return fromBase64((await this.call("materialize", { sequence, maxEntriesToScan })).bytes);
2197
+ }
2198
+ async replay(sequence, maxEntriesToScan = 1e4) {
2199
+ return fromBase64((await this.call("replay", { sequence, maxEntriesToScan })).bytes);
2200
+ }
2201
+ async resolveSequenceAtTime(cutoff, maxEntriesToScan = 1e4) {
2202
+ return (await this.call("resolveTime", { cutoff, maxEntriesToScan })).sequence;
2203
+ }
2204
+ async readChangesSince(after, maxEntriesToScan = 1e4) {
2205
+ return (await this.call("updates", { expectedHead: after, maxEntriesToScan })).update;
2206
+ }
2207
+ async readOperationsSince(after, maxEntriesToScan = 1e4) {
2208
+ return (await this.call("operations", { expectedHead: after, maxEntriesToScan })).operationUpdate;
2209
+ }
2210
+ async getOperation(operationId) {
2211
+ return (await this.call("getOperation", { operationId })).operation;
2212
+ }
2213
+ async exportOperationProposal(operationId) {
2214
+ return fromBase64((await this.call("exportOperationProposal", { operationId })).bytes);
2215
+ }
2216
+ /** Redlined DOCX through DocxCompare's existing accepted-input revision policy. */
2217
+ async compareVersions(beforeVersionId, afterVersionId) {
2218
+ return fromBase64((await this.call("compare", { beforeVersionId, afterVersionId })).bytes);
2219
+ }
2220
+ };
2221
+ var DocxHistoryDocument = class extends DocxHistoryReader {
2222
+ async createVersion(expectedHead, bytes, metadata, requestId) {
2223
+ requireRequestId(requestId);
2224
+ return (await this.call("create", { expectedHead, metadata, requestId }, bytes)).view;
2225
+ }
2226
+ async restoreVersion(expectedHead, versionId, metadata, requestId) {
2227
+ requireRequestId(requestId);
2228
+ return (await this.call("restore", { expectedHead, versionId, metadata, requestId })).view;
2229
+ }
2230
+ };
2231
+ var DocxHistoryArchive = class _DocxHistoryArchive extends DocxHistoryReader {
2232
+ constructor(bridge, handle, info) {
2233
+ super(info.documentId, async (operation, fields = {}, bytes = new Uint8Array()) => {
2234
+ if (this.closed) throw new DocxHistoryError("Closed", "History archive is closed.");
2235
+ return parseResult(await bridge.Invoke(
2236
+ handle,
2237
+ JSON.stringify({ schemaVersion: 1, operation, documentId: this.documentId, ...fields }),
2238
+ bytes
2239
+ ));
2240
+ });
2241
+ this.bridge = bridge;
2242
+ this.handle = handle;
2243
+ this.info = info;
2244
+ this.closed = false;
2245
+ }
2246
+ /** For custom loaders; normal callers use openDocxHistoryArchive(). */
2247
+ static async open(bridge, bytes) {
2248
+ checkArchiveSize(bytes);
2249
+ if (!bridge.OpenArchive) throw new Error("This WASM build does not include portable history.");
2250
+ const result = parseResult(await bridge.OpenArchive(bytes));
2251
+ return new _DocxHistoryArchive(bridge, result.handle, result.archive);
2252
+ }
2253
+ close() {
2254
+ if (this.closed) return;
2255
+ this.bridge.Close(this.handle);
2256
+ this.closed = true;
2257
+ }
2258
+ };
2259
+ function parseResult(json) {
2260
+ const result = JSON.parse(json);
2261
+ if (!result.success) throw new DocxHistoryError(result.errorCode, result.message);
2262
+ return result;
2263
+ }
2264
+ function checkArchiveSize(bytes) {
2265
+ if (bytes.length > MAX_HISTORY_ARCHIVE_BYTES) throw new DocxHistoryError("ResourceLimit", "History archive exceeds 64 MiB.");
2266
+ }
2267
+ function requireRequestId(requestId) {
2268
+ if (typeof requestId !== "string" || !requestId.trim()) throw new DocxHistoryError("InvalidRequest", "A durable requestId is required.");
2269
+ }
2270
+ function createMemoryHistoryStorage(maxBlobBytes = 256 * 1024 * 1024) {
2271
+ if (!Number.isSafeInteger(maxBlobBytes) || maxBlobBytes <= 0) throw new RangeError("Invalid blob byte limit.");
2272
+ const blobs = /* @__PURE__ */ new Map();
2273
+ const heads = /* @__PURE__ */ new Map();
2274
+ const copy = (value) => JSON.parse(JSON.stringify(value));
2275
+ const key = (reference) => {
2276
+ if (reference.digest.algorithm !== "SHA-256" || !/^[a-f0-9]{64}$/.test(reference.digest.value) || !Number.isSafeInteger(reference.length) || reference.length < 0 || reference.length > maxBlobBytes)
2277
+ throw new DocxHistoryError("InvalidRequest", "Invalid blob reference or byte limit.");
2278
+ return `${reference.digest.value}:${reference.length}`;
2279
+ };
2280
+ const equalReference = (a, b) => a.length === b.length && a.digest.algorithm === b.digest.algorithm && a.digest.value === b.digest.value;
2281
+ const equalHead = (a, b) => a === null || b === null ? a === b : a.revision === b.revision && equalReference(a.state, b.state);
2282
+ return {
2283
+ async readBlob(reference) {
2284
+ return blobs.get(key(reference))?.slice() ?? null;
2285
+ },
2286
+ async putBlob(reference, bytes) {
2287
+ const blobKey = key(reference);
2288
+ const captured = bytes.slice();
2289
+ if (captured.length !== reference.length) throw new DocxHistoryError("PayloadMismatch", "Blob length mismatch.");
2290
+ const digest = Array.from(
2291
+ new Uint8Array(await crypto.subtle.digest("SHA-256", captured)),
2292
+ (n) => n.toString(16).padStart(2, "0")
2293
+ ).join("");
2294
+ if (digest !== blobKey.split(":")[0]) throw new DocxHistoryError("PayloadMismatch", "Blob digest mismatch.");
2295
+ if (!blobs.has(blobKey)) blobs.set(blobKey, captured);
2296
+ },
2297
+ async readHead(documentId) {
2298
+ return copy(heads.get(documentId) ?? null);
2299
+ },
2300
+ async advanceHead(documentId, expected, state) {
2301
+ key(state);
2302
+ const current = heads.get(documentId) ?? null;
2303
+ if (!equalHead(current, expected)) return null;
2304
+ const revision = BigInt(current?.revision ?? "0") + 1n;
2305
+ if (revision > 9223372036854775807n) throw new RangeError("History revision exhausted.");
2306
+ const head = { revision: String(revision), state: copy(state) };
2307
+ heads.set(documentId, head);
2308
+ return copy(head);
2309
+ },
2310
+ async initializeHead(documentId, head) {
2311
+ key(head.state);
2312
+ if (typeof head.revision !== "string" || !/^[1-9][0-9]*$/.test(head.revision) || BigInt(head.revision) > 9223372036854775807n)
2313
+ throw new DocxHistoryError("InvalidRequest", "Imported head revision must be a positive Int64 string.");
2314
+ const existing = heads.get(documentId);
2315
+ if (existing) return { initialized: false, head: copy(existing) };
2316
+ const captured = copy(head);
2317
+ heads.set(documentId, captured);
2318
+ return { initialized: true, head: copy(captured) };
2319
+ }
2320
+ };
2321
+ }
2322
+
2041
2323
  // src/page-number-format.ts
2042
2324
  var ROMAN_ONES = ["", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix"];
2043
2325
  var ROMAN_TENS = ["", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc"];
@@ -5487,11 +5769,11 @@ var HeaderFooterRegion = class {
5487
5769
  if (!this.partUriFor(which, "default")) this.seedStory(which, "default");
5488
5770
  if (!this.partUriFor(which, kind)) this.seedStory(which, kind);
5489
5771
  }
5490
- const res = parseResult(this.bridge.EnsureHeaderFooterVisible(this.handle, this.bodyAnchorId, kind));
5772
+ const res = parseResult2(this.bridge.EnsureHeaderFooterVisible(this.handle, this.bodyAnchorId, kind));
5491
5773
  if (!res.success) return false;
5492
5774
  } else {
5493
5775
  if (!this.bridge.SetHeaderFooterKindEnabled) return false;
5494
- const res = parseResult(this.bridge.SetHeaderFooterKindEnabled(this.handle, this.bodyAnchorId, kind, false));
5776
+ const res = parseResult2(this.bridge.SetHeaderFooterKindEnabled(this.handle, this.bodyAnchorId, kind, false));
5495
5777
  if (!res.success) return false;
5496
5778
  for (const which of ["header", "footer"]) {
5497
5779
  if (this.kinds[which] === kind) this.kinds[which] = "default";
@@ -5516,7 +5798,7 @@ var HeaderFooterRegion = class {
5516
5798
  * Deliberately a PLAIN field (no `\*` switch), exactly as Word inserts one, so it follows the
5517
5799
  * section's page-number format — see {@link setPageNumbering}. */
5518
5800
  insertPageNumber(which, anchorId, field) {
5519
- const res = parseResult(this.bridge.InsertPageNumberField(this.handle, anchorId, field, ""));
5801
+ const res = parseResult2(this.bridge.InsertPageNumberField(this.handle, anchorId, field, ""));
5520
5802
  if (!res.success) return false;
5521
5803
  this.refresh(which);
5522
5804
  return true;
@@ -5539,7 +5821,7 @@ var HeaderFooterRegion = class {
5539
5821
  /** Set this section's page numbering (`w:pgNumType`) — Word's *Format Page Numbers…*. */
5540
5822
  setPageNumbering(op) {
5541
5823
  if (!this.bodyAnchorId) return false;
5542
- const res = parseResult(this.bridge.SetPageNumbering(this.handle, this.bodyAnchorId, JSON.stringify(op)));
5824
+ const res = parseResult2(this.bridge.SetPageNumbering(this.handle, this.bodyAnchorId, JSON.stringify(op)));
5543
5825
  if (!res.success) return false;
5544
5826
  this.reloadSection();
5545
5827
  return true;
@@ -5551,7 +5833,7 @@ var HeaderFooterRegion = class {
5551
5833
  /** Remove this section's page-numbering start/format. */
5552
5834
  clearPageNumbering() {
5553
5835
  if (!this.bodyAnchorId) return false;
5554
- const res = parseResult(this.bridge.ClearPageNumbering(this.handle, this.bodyAnchorId));
5836
+ const res = parseResult2(this.bridge.ClearPageNumbering(this.handle, this.bodyAnchorId));
5555
5837
  if (!res.success) return false;
5556
5838
  this.reloadSection();
5557
5839
  return true;
@@ -5862,7 +6144,7 @@ var HeaderFooterRegion = class {
5862
6144
  seedStory(which, kind) {
5863
6145
  if (!this.bodyAnchorId) return;
5864
6146
  const set = which === "header" ? this.bridge.SetHeaderText : this.bridge.SetFooterText;
5865
- const res = parseResult(set(this.handle, this.bodyAnchorId, kind, ""));
6147
+ const res = parseResult2(set(this.handle, this.bodyAnchorId, kind, ""));
5866
6148
  if (!res.success) return;
5867
6149
  this.callbacks.refreshAnchorMap();
5868
6150
  this.sectionInfo = this.readSectionInfo(this.bodyAnchorId);
@@ -6018,7 +6300,7 @@ function caretFromPoint(doc, x, y) {
6018
6300
  const range = d.caretRangeFromPoint?.(x, y);
6019
6301
  return range ? { node: range.startContainer, offset: range.startOffset } : null;
6020
6302
  }
6021
- function parseResult(json) {
6303
+ function parseResult2(json) {
6022
6304
  try {
6023
6305
  return JSON.parse(json);
6024
6306
  } catch {
@@ -8251,7 +8533,7 @@ function addToRegistry(args) {
8251
8533
  };
8252
8534
  }
8253
8535
  var honeyPotFix = makeHoneyPotFix();
8254
- var adapter = makeAdapter({
8536
+ var adapter2 = makeAdapter({
8255
8537
  typeKey: "element",
8256
8538
  defaultDropEffect: "move",
8257
8539
  mount: function mount(api2) {
@@ -8340,8 +8622,8 @@ var adapter = makeAdapter({
8340
8622
  },
8341
8623
  onPostDispatch: honeyPotFix.getOnPostDispatch()
8342
8624
  });
8343
- var dropTargetForElements = adapter.dropTarget;
8344
- var monitorForElements = adapter.monitor;
8625
+ var dropTargetForElements = adapter2.dropTarget;
8626
+ var monitorForElements = adapter2.monitor;
8345
8627
  function draggable(args) {
8346
8628
  if (true) {
8347
8629
  if (args.dragHandle && !args.element.contains(args.dragHandle)) {
@@ -8365,7 +8647,7 @@ function draggable(args) {
8365
8647
  // this is because you *must* have a draggable element to start a drag
8366
8648
  // but you _might_ not have any drop targets immediately
8367
8649
  // (You might create drop targets async)
8368
- adapter.registerUsage(),
8650
+ adapter2.registerUsage(),
8369
8651
  addToRegistry(args),
8370
8652
  addAttribute(args.element, {
8371
8653
  attribute: "draggable",
@@ -9812,22 +10094,55 @@ function selectionSpanIn(block) {
9812
10094
  const span = trimmedSpan(block, { start: Math.min(start2, end), length: Math.abs(end - start2) });
9813
10095
  return span.length > 0 ? span : null;
9814
10096
  }
9815
- function selectRange(el, start2, length) {
9816
- const sel = typeof window !== "undefined" ? window.getSelection() : null;
9817
- if (!sel || !el.isConnected) return;
9818
- el.focus();
9819
- const range = document.createRange();
10097
+ function contentRangeIn(el, start2, length) {
10098
+ if (!el.isConnected) return null;
10099
+ const doc = el.ownerDocument;
10100
+ const range = doc.createRange();
9820
10101
  const from = contentPositionIn(el, start2);
9821
10102
  const to = contentPositionIn(el, start2 + length);
9822
10103
  try {
9823
10104
  range.setStart(from.node, from.offset);
9824
10105
  range.setEnd(to.node, to.offset);
9825
10106
  } catch {
9826
- return;
10107
+ return null;
9827
10108
  }
10109
+ return range;
10110
+ }
10111
+ function selectRange(el, start2, length) {
10112
+ const sel = typeof window !== "undefined" ? window.getSelection() : null;
10113
+ if (!sel || !el.isConnected) return;
10114
+ el.focus();
10115
+ const range = contentRangeIn(el, start2, length);
10116
+ if (!range) return;
9828
10117
  sel.removeAllRanges();
9829
10118
  sel.addRange(range);
9830
10119
  }
10120
+ var FIND_HIGHLIGHT = "docxodus-find";
10121
+ var FIND_HIGHLIGHT_ACTIVE = "docxodus-find-active";
10122
+ var FIND_PAINT_LIMIT = 500;
10123
+ var findHighlightStyledDocuments = /* @__PURE__ */ new WeakSet();
10124
+ var findPaintOwner = null;
10125
+ function ensureFindHighlightStyles(doc) {
10126
+ if (findHighlightStyledDocuments.has(doc)) return;
10127
+ findHighlightStyledDocuments.add(doc);
10128
+ const style = doc.createElement("style");
10129
+ style.dataset.docxodusFindHighlight = "true";
10130
+ style.textContent = `
10131
+ ::highlight(${FIND_HIGHLIGHT}) { background-color: rgba(15, 118, 110, .16); }
10132
+ ::highlight(${FIND_HIGHLIGHT_ACTIVE}) { background-color: rgba(15, 118, 110, .38); }
10133
+ `;
10134
+ (doc.head ?? doc.documentElement).appendChild(style);
10135
+ }
10136
+ function highlightRegistry() {
10137
+ if (typeof CSS === "undefined") return null;
10138
+ const registry = CSS.highlights;
10139
+ const ctor = globalThis.Highlight;
10140
+ return registry && typeof ctor === "function" ? registry : null;
10141
+ }
10142
+ function makeHighlight(ranges) {
10143
+ const ctor = globalThis.Highlight;
10144
+ return new ctor(...ranges);
10145
+ }
9831
10146
  function inBorderWrapper(el) {
9832
10147
  const style = el.parentElement?.getAttribute("style") ?? "";
9833
10148
  return /border-(top|bottom|left|right):\s*(?!none)[^;]+/i.test(style);
@@ -10198,6 +10513,7 @@ var DocxEditor = class _DocxEditor {
10198
10513
  document.removeEventListener("mouseup", this.onMouseUp, true);
10199
10514
  }
10200
10515
  this.clearDragSelection();
10516
+ this.clearFindMatches();
10201
10517
  this.teardownBlockDrag();
10202
10518
  this.gutter?.dispose();
10203
10519
  this.gutter = null;
@@ -12596,15 +12912,65 @@ var DocxEditor = class _DocxEditor {
12596
12912
  }
12597
12913
  return out;
12598
12914
  }
12599
- /** Select a match and scroll it into view. */
12915
+ /**
12916
+ * Select a match, focus its block and scroll it into view — the caret lands on the hit, so
12917
+ * typing continues in the document. A find box that is still being typed into wants
12918
+ * `showFindMatches` instead; this is the commit step (closing the bar, jumping in to edit).
12919
+ */
12600
12920
  selectMatch(match) {
12601
12921
  if (!match.block.isConnected) return;
12922
+ this.clearFindMatches();
12602
12923
  this.activeBlock = match.block;
12603
12924
  selectRange(match.block, match.start, match.length);
12604
12925
  match.block.scrollIntoView({ block: "center", behavior: "smooth" });
12605
12926
  }
12606
- /** Replace one match's text (formatting of the surrounding run is inherited). */
12607
- replaceMatch(match, replacement) {
12927
+ /**
12928
+ * Paint `matches` and scroll the one at `activeIndex` into view WITHOUT moving focus or the
12929
+ * caret. This is what a find field calls on every keystroke: the document shows where the hits
12930
+ * are and rides to the current one, while the keyboard stays in the search box.
12931
+ *
12932
+ * Falls back to the document selection where the CSS Custom Highlight API is missing — still
12933
+ * without focusing the block, so the next character typed goes to the search field either way.
12934
+ */
12935
+ showFindMatches(matches, activeIndex) {
12936
+ const active = matches[activeIndex];
12937
+ this.clearFindMatches();
12938
+ if (!active || !active.block.isConnected) return;
12939
+ this.activeBlock = active.block;
12940
+ const activeRange = contentRangeIn(active.block, active.start, active.length);
12941
+ const registry = highlightRegistry();
12942
+ if (registry && activeRange) {
12943
+ ensureFindHighlightStyles(this.container.ownerDocument);
12944
+ const rest = [];
12945
+ for (let i = 0; i < matches.length && rest.length < FIND_PAINT_LIMIT; i++) {
12946
+ if (i === activeIndex) continue;
12947
+ const range = contentRangeIn(matches[i].block, matches[i].start, matches[i].length);
12948
+ if (range) rest.push(range);
12949
+ }
12950
+ if (rest.length > 0) registry.set(FIND_HIGHLIGHT, makeHighlight(rest));
12951
+ registry.set(FIND_HIGHLIGHT_ACTIVE, makeHighlight([activeRange]));
12952
+ findPaintOwner = this;
12953
+ } else if (activeRange) {
12954
+ const sel = this.container.ownerDocument.defaultView?.getSelection();
12955
+ sel?.removeAllRanges();
12956
+ sel?.addRange(activeRange);
12957
+ }
12958
+ active.block.scrollIntoView({ block: "center", behavior: "smooth" });
12959
+ }
12960
+ /** Drop the find painting (closing the find bar, or committing a match to the caret). */
12961
+ clearFindMatches() {
12962
+ if (findPaintOwner !== this) return;
12963
+ const registry = highlightRegistry();
12964
+ registry?.delete(FIND_HIGHLIGHT);
12965
+ registry?.delete(FIND_HIGHLIGHT_ACTIVE);
12966
+ findPaintOwner = null;
12967
+ }
12968
+ /**
12969
+ * Replace one match's text (formatting of the surrounding run is inherited). `focus: false`
12970
+ * leaves the keyboard where it is — a Replace button pressed from the find bar must not drag
12971
+ * the caret into the document mid-search.
12972
+ */
12973
+ replaceMatch(match, replacement, options = {}) {
12608
12974
  const block = match.block;
12609
12975
  if (this.closed || !block.isConnected) return false;
12610
12976
  const unid = block.getAttribute("data-anchor");
@@ -12625,7 +12991,7 @@ var DocxEditor = class _DocxEditor {
12625
12991
  );
12626
12992
  if (!res.success) return false;
12627
12993
  const fresh = this.swapBlock(block, unid, res.modified?.[0]);
12628
- if (fresh) selectRange(fresh, span.start, replacement.length);
12994
+ if (fresh && options.focus !== false) selectRange(fresh, span.start, replacement.length);
12629
12995
  return true;
12630
12996
  }
12631
12997
  /** Replace every occurrence; returns how many were replaced. */
@@ -12644,7 +13010,11 @@ var DocxEditor = class _DocxEditor {
12644
13010
  for (const m of list.slice().sort((a, b) => b.start - a.start)) {
12645
13011
  if (!current.isConnected) break;
12646
13012
  const before = current;
12647
- if (this.replaceMatch({ block: current, start: m.start, length: m.length }, replacement)) {
13013
+ if (this.replaceMatch(
13014
+ { block: current, start: m.start, length: m.length },
13015
+ replacement,
13016
+ { focus: options.focus }
13017
+ )) {
12648
13018
  count++;
12649
13019
  current = this.activeBlock && this.activeBlock !== before ? this.activeBlock : current;
12650
13020
  }
@@ -13326,7 +13696,7 @@ function ensureCommentGutterStyles(doc) {
13326
13696
  }
13327
13697
 
13328
13698
  // src/ribbon-chrome.ts
13329
- var RIBBON_STYLE_VERSION = "10";
13699
+ var RIBBON_STYLE_VERSION = "11";
13330
13700
  var RIBBON_STYLE_ATTR = "data-docxodus-ribbon-styles";
13331
13701
  var COMMENT_GUTTER_WIDTH = 264;
13332
13702
  var RIBBON_CSS = `
@@ -13759,9 +14129,11 @@ var RIBBON_CSS = `
13759
14129
  background: linear-gradient(to top, var(--dxr-desk), transparent);
13760
14130
  }
13761
14131
  .dxr[data-chrome] .dxr-surface { position: relative; margin: 26px auto; padding: 0 16px 96px; }
13762
- /* The comment gutter sits to the right of the sheet; the surface reserves its width so the
13763
- page shifts left rather than the bubbles covering it \u2014 Word's markup area. */
13764
- .dxr[data-chrome="full"] .dxr-surface[data-comments="on"] { padding-right: calc(var(--dxr-gutter) + 8px); }
14132
+ /* Reserve the markup area only while a visible comment or draft needs it. The gutter owns
14133
+ its empty/hidden state, so ordinary documents stay centered without disabling comments. */
14134
+ .dxr[data-chrome="full"] .dxr-surface[data-comments="on"]:has(> .docx-comment-gutter:not([data-empty]):not([hidden])) {
14135
+ padding-right: calc(var(--dxr-gutter) + 8px);
14136
+ }
13765
14137
  .dxr-surface [contenteditable="true"]:focus {
13766
14138
  outline: 2px solid var(--dxr-accent);
13767
14139
  outline-offset: 2px;
@@ -15912,11 +16284,18 @@ var RibbonSurface = class {
15912
16284
  if (!this.live || !text.value) return;
15913
16285
  let count = 0;
15914
16286
  this.run("replace all", () => {
15915
- count = this.live.replaceAll(text.value, replace.value, { matchCase: matchCase.checked });
16287
+ count = this.live.replaceAll(text.value, replace.value, {
16288
+ matchCase: matchCase.checked,
16289
+ focus: false
16290
+ });
15916
16291
  });
15917
16292
  this.setStatus(`Replaced ${count} occurrence${count === 1 ? "" : "s"}`);
15918
16293
  this.refreshFind(true);
15919
16294
  });
16295
+ for (const id of ["findprev", "findnext", "replaceone", "replaceall"]) {
16296
+ const button = this.control(id);
16297
+ if (button) this.keepSelection(button);
16298
+ }
15920
16299
  bar.hidden = true;
15921
16300
  }
15922
16301
  openFindBar(withReplace) {
@@ -15927,28 +16306,44 @@ var RibbonSurface = class {
15927
16306
  const text = this.require("findtext");
15928
16307
  text.focus();
15929
16308
  text.select();
15930
- this.refreshFind(false);
16309
+ this.refreshFind(true);
15931
16310
  }
16311
+ /**
16312
+ * Close the bar and hand the current hit over to the caret: the document is where the user is
16313
+ * going next, and Word leaves the insertion point on the match it stopped at. Until this runs
16314
+ * the match is only PAINTED (see `showFindMatches`), so the search field keeps the keyboard for
16315
+ * as long as the bar is open.
16316
+ */
15932
16317
  closeFindBar() {
15933
16318
  const bar = this.control("findbar");
15934
16319
  if (bar) bar.hidden = true;
16320
+ const match = this.findMatches[this.findIndex];
16321
+ if (match) this.live?.selectMatch(match);
16322
+ else this.live?.clearFindMatches();
15935
16323
  this.findMatches = [];
15936
16324
  this.findIndex = -1;
15937
16325
  }
15938
- refreshFind(select) {
16326
+ /**
16327
+ * Re-scan for the current query. `show` paints the hits and rides to the first one — it never
16328
+ * focuses the document, so typing the second character of a query that already matched goes on
16329
+ * refining the search instead of being typed into the document.
16330
+ */
16331
+ refreshFind(show) {
15939
16332
  const text = this.require("findtext");
15940
16333
  const matchCase = this.require("findcase").checked;
15941
16334
  this.findMatches = this.live && text.value ? this.live.find(text.value, { matchCase }) : [];
15942
16335
  this.findIndex = this.findMatches.length > 0 ? 0 : -1;
15943
16336
  this.updateFindCount();
15944
- if (select && this.findIndex >= 0) this.live?.selectMatch(this.findMatches[this.findIndex]);
16337
+ if (!show) return;
16338
+ if (this.findIndex >= 0) this.live?.showFindMatches(this.findMatches, this.findIndex);
16339
+ else this.live?.clearFindMatches();
15945
16340
  }
15946
16341
  stepFind(direction) {
15947
16342
  if (!this.live) return;
15948
16343
  if (this.findMatches.length === 0) this.refreshFind(false);
15949
16344
  if (this.findMatches.length === 0) return;
15950
16345
  this.findIndex = (this.findIndex + direction + this.findMatches.length) % this.findMatches.length;
15951
- this.live.selectMatch(this.findMatches[this.findIndex]);
16346
+ this.live.showFindMatches(this.findMatches, this.findIndex);
15952
16347
  this.updateFindCount();
15953
16348
  }
15954
16349
  replaceCurrent() {
@@ -15957,12 +16352,12 @@ var RibbonSurface = class {
15957
16352
  const match = this.findMatches[this.findIndex];
15958
16353
  if (!match) return;
15959
16354
  const replacement = this.require("replacetext").value;
15960
- this.run("replace", () => this.live.replaceMatch(match, replacement));
16355
+ this.run("replace", () => this.live.replaceMatch(match, replacement, { focus: false }));
15961
16356
  const keep = this.findIndex;
15962
16357
  this.refreshFind(false);
15963
16358
  if (this.findMatches.length > 0) {
15964
16359
  this.findIndex = Math.min(keep, this.findMatches.length - 1);
15965
- this.live.selectMatch(this.findMatches[this.findIndex]);
16360
+ this.live.showFindMatches(this.findMatches, this.findIndex);
15966
16361
  this.updateFindCount();
15967
16362
  }
15968
16363
  }
@@ -16393,6 +16788,16 @@ var RibbonSurface = class {
16393
16788
  };
16394
16789
 
16395
16790
  // src/index.ts
16791
+ function openDocxHistory(storage) {
16792
+ const bridge = ensureInitialized().HistoryBridge;
16793
+ if (!bridge) throw new Error("This WASM build does not include history bindings.");
16794
+ return new DocxHistoryClient(bridge, storage);
16795
+ }
16796
+ function openDocxHistoryArchive(bytes) {
16797
+ const bridge = ensureInitialized().HistoryBridge;
16798
+ if (!bridge) throw new Error("This WASM build does not include history bindings.");
16799
+ return DocxHistoryArchive.open(bridge, bytes);
16800
+ }
16396
16801
  function openDocxSession2(bytes, settings) {
16397
16802
  const wasm = ensureInitialized();
16398
16803
  return openDocxSession(bytes, wasm, settings);
@@ -16447,14 +16852,16 @@ async function tryLoadFromPath(basePath) {
16447
16852
  /* @vite-ignore */
16448
16853
  dotnetPath
16449
16854
  );
16450
- const { getAssemblyExports, getConfig } = await dotnet.withDiagnosticTracing(false).create();
16855
+ const { getAssemblyExports, getConfig, setModuleImports } = await dotnet.withDiagnosticTracing(false).create();
16856
+ installHistoryStorageImports(setModuleImports);
16451
16857
  const config = getConfig();
16452
16858
  const exports = await getAssemblyExports(config.mainAssemblyName);
16453
16859
  wasmExports = {
16454
16860
  DocumentConverter: exports.DocxodusWasm.DocumentConverter,
16455
16861
  DocumentComparer: exports.DocxodusWasm.DocumentComparer,
16456
16862
  DocxDiffBridge: exports.DocxodusWasm.DocxDiffBridge,
16457
- DocxSessionBridge: exports.DocxodusWasm.DocxSessionBridge
16863
+ DocxSessionBridge: exports.DocxodusWasm.DocxSessionBridge,
16864
+ HistoryBridge: exports.DocxodusWasm.HistoryBridge
16458
16865
  };
16459
16866
  return true;
16460
16867
  } catch {
@@ -17828,6 +18235,20 @@ async function toDocumentBytes(source) {
17828
18235
  }
17829
18236
  throw new Error("Docxodus embed: unsupported document source");
17830
18237
  }
18238
+ function scopedDocumentFragment(mount2, html) {
18239
+ const parsed = new DOMParser().parseFromString(html, "text/html");
18240
+ const fragment = document.createDocumentFragment();
18241
+ parsed.querySelectorAll("style").forEach((sourceStyle) => {
18242
+ const style = document.createElement("style");
18243
+ style.textContent = sourceStyle.textContent;
18244
+ scopeStyleElement(style, mount2.selector);
18245
+ fragment.appendChild(style);
18246
+ });
18247
+ const body = document.createElement("template");
18248
+ body.innerHTML = parsed.body.innerHTML;
18249
+ fragment.appendChild(body.content);
18250
+ return fragment;
18251
+ }
17831
18252
  async function createViewer(container, source, options = {}) {
17832
18253
  const el = resolveContainer2(container);
17833
18254
  const { wasmBasePath: wasmBasePath2, ...conversion } = options;
@@ -17840,18 +18261,7 @@ async function createViewer(container, source, options = {}) {
17840
18261
  renderFootnotesAndEndnotes: true,
17841
18262
  ...opts
17842
18263
  });
17843
- const parsed = new DOMParser().parseFromString(lastHtml, "text/html");
17844
- const fragment = document.createDocumentFragment();
17845
- parsed.querySelectorAll("style").forEach((sourceStyle) => {
17846
- const style = document.createElement("style");
17847
- style.textContent = sourceStyle.textContent;
17848
- scopeStyleElement(style, mount2.selector);
17849
- fragment.appendChild(style);
17850
- });
17851
- const body = document.createElement("template");
17852
- body.innerHTML = parsed.body.innerHTML;
17853
- fragment.appendChild(body.content);
17854
- mount2.root.replaceChildren(fragment);
18264
+ mount2.root.replaceChildren(scopedDocumentFragment(mount2, lastHtml));
17855
18265
  };
17856
18266
  await render(source, conversion);
17857
18267
  return {
@@ -17865,6 +18275,111 @@ async function createViewer(container, source, options = {}) {
17865
18275
  }
17866
18276
  };
17867
18277
  }
18278
+ async function createHistoryViewer(container, history, documentId, options = {}) {
18279
+ const el = resolveContainer2(container);
18280
+ const { wasmBasePath: wasmBasePath2, maxEntriesToScan = 1e4, ...conversion } = options;
18281
+ if (!Number.isSafeInteger(maxEntriesToScan) || maxEntriesToScan <= 0 || maxEntriesToScan > 2147483647)
18282
+ throw new RangeError("Invalid history scan budget.");
18283
+ await ensureWasm(wasmBasePath2);
18284
+ const mount2 = createScopedMount(el);
18285
+ let accepted = null;
18286
+ let acceptedBytes = null;
18287
+ let displayedBytes = null;
18288
+ let shownSequence = "0";
18289
+ let following = true;
18290
+ let closed = false;
18291
+ let html = "";
18292
+ let queue = Promise.resolve();
18293
+ const clone = (value) => JSON.parse(JSON.stringify(value));
18294
+ const assertOpen = () => {
18295
+ if (closed) throw new DocxHistoryError("Closed", "History viewer is destroyed.");
18296
+ };
18297
+ const enqueue = (action) => {
18298
+ const result = queue.then(() => {
18299
+ assertOpen();
18300
+ return action();
18301
+ });
18302
+ queue = result.then(() => void 0, () => void 0);
18303
+ return result;
18304
+ };
18305
+ const sameHead = (a, b) => a.revision === b.revision && a.state.length === b.state.length && a.state.digest.algorithm === b.state.digest.algorithm && a.state.digest.value === b.state.digest.value;
18306
+ const paint = async (bytes, sequence) => {
18307
+ const nextHtml = await convertDocxToHtml(bytes, { renderFootnotesAndEndnotes: true, ...conversion });
18308
+ assertOpen();
18309
+ const fragment = scopedDocumentFragment(mount2, nextHtml);
18310
+ mount2.root.replaceChildren(fragment);
18311
+ html = nextHtml;
18312
+ displayedBytes = bytes;
18313
+ shownSequence = sequence;
18314
+ };
18315
+ const refresh = async (resume = false) => {
18316
+ const update = await history.readChangesSince(documentId, accepted?.view.head ?? null, maxEntriesToScan);
18317
+ assertOpen();
18318
+ const duplicate = accepted !== null && sameHead(accepted.view.head, update.view.head);
18319
+ const bytes = duplicate ? acceptedBytes : await history.exportVersion(documentId, update.view.version.id);
18320
+ assertOpen();
18321
+ const wantLive = following || resume;
18322
+ const changedContent = accepted === null || accepted.view.state.snapshot.contentDigest.value !== update.view.state.snapshot.contentDigest.value || accepted.view.state.epoch !== update.view.state.epoch;
18323
+ if (wantLive && (changedContent || !following)) await paint(bytes, update.view.state.sequence);
18324
+ else if (wantLive) {
18325
+ displayedBytes = bytes;
18326
+ shownSequence = update.view.state.sequence;
18327
+ }
18328
+ assertOpen();
18329
+ accepted = update;
18330
+ acceptedBytes = bytes;
18331
+ if (wantLive) following = true;
18332
+ return clone(update);
18333
+ };
18334
+ const showSequence = async (sequence) => {
18335
+ const bytes = await history.materialize(documentId, sequence, maxEntriesToScan);
18336
+ assertOpen();
18337
+ await paint(bytes, sequence);
18338
+ following = false;
18339
+ };
18340
+ const viewer = {
18341
+ element: el,
18342
+ get html() {
18343
+ return html;
18344
+ },
18345
+ get head() {
18346
+ assertOpen();
18347
+ return clone(accepted.view.head);
18348
+ },
18349
+ get sequence() {
18350
+ return shownSequence;
18351
+ },
18352
+ get following() {
18353
+ return following;
18354
+ },
18355
+ refresh: () => enqueue(() => refresh()),
18356
+ showSequence: (sequence) => enqueue(() => showSequence(sequence)),
18357
+ showTime: (cutoff) => enqueue(async () => {
18358
+ const sequence = await history.resolveSequenceAtTime(documentId, cutoff, maxEntriesToScan);
18359
+ assertOpen();
18360
+ await showSequence(sequence);
18361
+ }),
18362
+ resume: () => enqueue(() => refresh(true)),
18363
+ exportDisplayed: () => {
18364
+ assertOpen();
18365
+ return displayedBytes.slice();
18366
+ },
18367
+ destroy: () => {
18368
+ if (closed) return;
18369
+ closed = true;
18370
+ acceptedBytes = null;
18371
+ displayedBytes = null;
18372
+ mount2.root.remove();
18373
+ }
18374
+ };
18375
+ try {
18376
+ await viewer.refresh();
18377
+ return viewer;
18378
+ } catch (error) {
18379
+ viewer.destroy();
18380
+ throw error;
18381
+ }
18382
+ }
17868
18383
  async function createEditor(container, source, options = {}) {
17869
18384
  const el = resolveContainer2(container);
17870
18385
  const { wasmBasePath: wasmBasePath2, ...editorOptions } = options;
@@ -17946,8 +18461,14 @@ export {
17946
18461
  DocxDiffFormatComparison,
17947
18462
  DocxDiffRevisionGranularity,
17948
18463
  DocxEditor,
18464
+ DocxHistoryArchive,
18465
+ DocxHistoryClient,
18466
+ DocxHistoryDocument,
18467
+ DocxHistoryError,
18468
+ DocxHistoryReader,
17949
18469
  DocxSession,
17950
18470
  EmptyParagraphMode,
18471
+ MAX_HISTORY_ARCHIVE_BYTES,
17951
18472
  PaginationEngine,
17952
18473
  PaginationMode,
17953
18474
  PlaceholderKinds,
@@ -17971,6 +18492,8 @@ export {
17971
18492
  createBlankDocx,
17972
18493
  createEditor,
17973
18494
  createExternalAnnotationSet,
18495
+ createHistoryViewer,
18496
+ createMemoryHistoryStorage,
17974
18497
  createRibbonEditor,
17975
18498
  createUnavailablePageMap,
17976
18499
  createViewer,
@@ -18005,6 +18528,7 @@ export {
18005
18528
  getWasmExports,
18006
18529
  hasAnnotations,
18007
18530
  initialize,
18531
+ installHistoryStorageImports,
18008
18532
  isDeletion,
18009
18533
  isFormatChange,
18010
18534
  isInitialized,
@@ -18012,6 +18536,8 @@ export {
18012
18536
  isMove,
18013
18537
  mountRibbon,
18014
18538
  navigateToPageCitation,
18539
+ openDocxHistory,
18540
+ openDocxHistoryArchive,
18015
18541
  openDocxSession2 as openDocxSession,
18016
18542
  paginateHtml,
18017
18543
  parseSectionDimensions,