web-doc 0.6.2 → 0.8.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 (201) hide show
  1. package/THIRD_PARTY_NOTICES.md +33 -1
  2. package/dist/adapters/docx-images.d.ts +13 -4
  3. package/dist/adapters/docx-images.js +3 -0
  4. package/dist/adapters/docx-paragraphs.d.ts +65 -0
  5. package/dist/adapters/docx-paragraphs.js +165 -0
  6. package/dist/adapters/docx-prepass.d.ts +17 -0
  7. package/dist/adapters/docx-prepass.js +230 -0
  8. package/dist/adapters/office.d.ts +31 -5
  9. package/dist/adapters/office.js +60 -29
  10. package/dist/adapters/pdf.d.ts +9 -0
  11. package/dist/adapters/pdf.js +10 -0
  12. package/dist/assets/pdfium/pdfium.wasm +0 -0
  13. package/dist/contracts.d.ts +53 -2
  14. package/dist/edit/ai/outline.d.ts +47 -0
  15. package/dist/edit/ai/outline.js +338 -0
  16. package/dist/edit/ai/targets.d.ts +16 -0
  17. package/dist/edit/ai/targets.js +309 -0
  18. package/dist/edit/ai/tools.d.ts +28 -0
  19. package/dist/edit/ai/tools.js +605 -0
  20. package/dist/edit/ai/types.d.ts +175 -0
  21. package/dist/edit/ai/types.js +1 -0
  22. package/dist/edit/assets.d.ts +23 -0
  23. package/dist/edit/assets.js +75 -0
  24. package/dist/edit/docx/elements.d.ts +6 -0
  25. package/dist/edit/docx/elements.js +90 -0
  26. package/dist/edit/docx/engine.d.ts +57 -0
  27. package/dist/edit/docx/engine.js +547 -0
  28. package/dist/edit/docx/handlers.d.ts +3 -0
  29. package/dist/edit/docx/handlers.js +15 -0
  30. package/dist/edit/docx/ids.d.ts +45 -0
  31. package/dist/edit/docx/ids.js +101 -0
  32. package/dist/edit/docx/model.d.ts +94 -0
  33. package/dist/edit/docx/model.js +350 -0
  34. package/dist/edit/docx/operations.d.ts +47 -0
  35. package/dist/edit/docx/operations.js +3 -0
  36. package/dist/edit/docx/provider.d.ts +16 -0
  37. package/dist/edit/docx/provider.js +37 -0
  38. package/dist/edit/docx/schemas.d.ts +6 -0
  39. package/dist/edit/docx/schemas.js +192 -0
  40. package/dist/edit/docx/session.d.ts +48 -0
  41. package/dist/edit/docx/session.js +467 -0
  42. package/dist/edit/docx/structure-ops.d.ts +6 -0
  43. package/dist/edit/docx/structure-ops.js +529 -0
  44. package/dist/edit/docx/style.d.ts +45 -0
  45. package/dist/edit/docx/style.js +375 -0
  46. package/dist/edit/docx/table-ops.d.ts +4 -0
  47. package/dist/edit/docx/table-ops.js +241 -0
  48. package/dist/edit/docx/text-ops.d.ts +40 -0
  49. package/dist/edit/docx/text-ops.js +491 -0
  50. package/dist/edit/docx/text.d.ts +34 -0
  51. package/dist/edit/docx/text.js +284 -0
  52. package/dist/edit/docx/tracked.d.ts +52 -0
  53. package/dist/edit/docx/tracked.js +347 -0
  54. package/dist/edit/docx/types.d.ts +206 -0
  55. package/dist/edit/docx/types.js +1 -0
  56. package/dist/edit/docx/write.d.ts +64 -0
  57. package/dist/edit/docx/write.js +375 -0
  58. package/dist/edit/engine.d.ts +128 -0
  59. package/dist/edit/engine.js +1 -0
  60. package/dist/edit/history.d.ts +77 -0
  61. package/dist/edit/history.js +123 -0
  62. package/dist/edit/ooxml/names.d.ts +20 -0
  63. package/dist/edit/ooxml/names.js +61 -0
  64. package/dist/edit/ooxml/opc.d.ts +50 -0
  65. package/dist/edit/ooxml/opc.js +150 -0
  66. package/dist/edit/ooxml/package.d.ts +82 -0
  67. package/dist/edit/ooxml/package.js +233 -0
  68. package/dist/edit/ooxml/patch.d.ts +51 -0
  69. package/dist/edit/ooxml/patch.js +250 -0
  70. package/dist/edit/ooxml/transaction.d.ts +39 -0
  71. package/dist/edit/ooxml/transaction.js +316 -0
  72. package/dist/edit/ooxml/worker.d.ts +8 -0
  73. package/dist/edit/ooxml/worker.js +12 -0
  74. package/dist/edit/ooxml/writer.d.ts +21 -0
  75. package/dist/edit/ooxml/writer.js +187 -0
  76. package/dist/edit/ooxml/xml.d.ts +74 -0
  77. package/dist/edit/ooxml/xml.js +451 -0
  78. package/dist/edit/ooxml/zip.d.ts +54 -0
  79. package/dist/edit/ooxml/zip.js +280 -0
  80. package/dist/edit/operations.d.ts +19 -0
  81. package/dist/edit/operations.js +137 -0
  82. package/dist/edit/pdf/engine/compact.d.ts +6 -0
  83. package/dist/edit/pdf/engine/compact.js +442 -0
  84. package/dist/edit/pdf/engine/document.d.ts +95 -0
  85. package/dist/edit/pdf/engine/document.js +868 -0
  86. package/dist/edit/pdf/engine/elements.d.ts +45 -0
  87. package/dist/edit/pdf/engine/elements.js +313 -0
  88. package/dist/edit/pdf/engine/existing-text.d.ts +4 -0
  89. package/dist/edit/pdf/engine/existing-text.js +424 -0
  90. package/dist/edit/pdf/engine/fonts.d.ts +78 -0
  91. package/dist/edit/pdf/engine/fonts.js +466 -0
  92. package/dist/edit/pdf/engine/geometry.d.ts +36 -0
  93. package/dist/edit/pdf/engine/geometry.js +97 -0
  94. package/dist/edit/pdf/engine/handler.d.ts +21 -0
  95. package/dist/edit/pdf/engine/handler.js +108 -0
  96. package/dist/edit/pdf/engine/images.d.ts +33 -0
  97. package/dist/edit/pdf/engine/images.js +188 -0
  98. package/dist/edit/pdf/engine/layout.d.ts +23 -0
  99. package/dist/edit/pdf/engine/layout.js +177 -0
  100. package/dist/edit/pdf/engine/operations.d.ts +67 -0
  101. package/dist/edit/pdf/engine/operations.js +3 -0
  102. package/dist/edit/pdf/engine/pages.d.ts +6 -0
  103. package/dist/edit/pdf/engine/pages.js +98 -0
  104. package/dist/edit/pdf/engine/pdfium.d.ts +195 -0
  105. package/dist/edit/pdf/engine/pdfium.js +249 -0
  106. package/dist/edit/pdf/engine/shapes.d.ts +4 -0
  107. package/dist/edit/pdf/engine/shapes.js +183 -0
  108. package/dist/edit/pdf/engine/tables.d.ts +44 -0
  109. package/dist/edit/pdf/engine/tables.js +315 -0
  110. package/dist/edit/pdf/engine/text-box.d.ts +71 -0
  111. package/dist/edit/pdf/engine/text-box.js +317 -0
  112. package/dist/edit/pdf/engine/text-layout.d.ts +28 -0
  113. package/dist/edit/pdf/engine/text-layout.js +67 -0
  114. package/dist/edit/pdf/engine/transform.d.ts +5 -0
  115. package/dist/edit/pdf/engine/transform.js +137 -0
  116. package/dist/edit/pdf/provider.d.ts +35 -0
  117. package/dist/edit/pdf/provider.js +92 -0
  118. package/dist/edit/pdf/range-map.d.ts +16 -0
  119. package/dist/edit/pdf/range-map.js +107 -0
  120. package/dist/edit/pdf/schemas.d.ts +11 -0
  121. package/dist/edit/pdf/schemas.js +291 -0
  122. package/dist/edit/pdf/selection.d.ts +5 -0
  123. package/dist/edit/pdf/selection.js +152 -0
  124. package/dist/edit/pdf/session.d.ts +63 -0
  125. package/dist/edit/pdf/session.js +312 -0
  126. package/dist/edit/pdf/types.d.ts +336 -0
  127. package/dist/edit/pdf/types.js +1 -0
  128. package/dist/edit/pptx/elements.d.ts +74 -0
  129. package/dist/edit/pptx/elements.js +301 -0
  130. package/dist/edit/pptx/engine.d.ts +37 -0
  131. package/dist/edit/pptx/engine.js +466 -0
  132. package/dist/edit/pptx/geometry.d.ts +72 -0
  133. package/dist/edit/pptx/geometry.js +193 -0
  134. package/dist/edit/pptx/handler.d.ts +7 -0
  135. package/dist/edit/pptx/handler.js +99 -0
  136. package/dist/edit/pptx/handlers.d.ts +3 -0
  137. package/dist/edit/pptx/handlers.js +21 -0
  138. package/dist/edit/pptx/image-table-ops.d.ts +5 -0
  139. package/dist/edit/pptx/image-table-ops.js +233 -0
  140. package/dist/edit/pptx/model.d.ts +69 -0
  141. package/dist/edit/pptx/model.js +170 -0
  142. package/dist/edit/pptx/operations.d.ts +50 -0
  143. package/dist/edit/pptx/operations.js +11 -0
  144. package/dist/edit/pptx/provider.d.ts +17 -0
  145. package/dist/edit/pptx/provider.js +40 -0
  146. package/dist/edit/pptx/schemas.d.ts +6 -0
  147. package/dist/edit/pptx/schemas.js +220 -0
  148. package/dist/edit/pptx/session.d.ts +54 -0
  149. package/dist/edit/pptx/session.js +145 -0
  150. package/dist/edit/pptx/shape-ops.d.ts +10 -0
  151. package/dist/edit/pptx/shape-ops.js +486 -0
  152. package/dist/edit/pptx/slide-ops.d.ts +6 -0
  153. package/dist/edit/pptx/slide-ops.js +353 -0
  154. package/dist/edit/pptx/style.d.ts +31 -0
  155. package/dist/edit/pptx/style.js +181 -0
  156. package/dist/edit/pptx/text-ops.d.ts +13 -0
  157. package/dist/edit/pptx/text-ops.js +267 -0
  158. package/dist/edit/pptx/text-write.d.ts +67 -0
  159. package/dist/edit/pptx/text-write.js +293 -0
  160. package/dist/edit/pptx/text.d.ts +41 -0
  161. package/dist/edit/pptx/text.js +99 -0
  162. package/dist/edit/pptx/types.d.ts +232 -0
  163. package/dist/edit/pptx/types.js +1 -0
  164. package/dist/edit/schema.d.ts +11 -0
  165. package/dist/edit/schema.js +275 -0
  166. package/dist/edit/session.d.ts +77 -0
  167. package/dist/edit/session.js +943 -0
  168. package/dist/edit/sessions.d.ts +8 -0
  169. package/dist/edit/sessions.js +1 -0
  170. package/dist/edit/types.d.ts +290 -0
  171. package/dist/edit/types.js +1 -0
  172. package/dist/edit/worker-engine.d.ts +31 -0
  173. package/dist/edit/worker-engine.js +91 -0
  174. package/dist/fonts/THIRD_PARTY_NOTICES.md +3 -0
  175. package/dist/fonts/manifest.json +6 -1
  176. package/dist/fonts/noto-sans-latin-cyrillic.ttf +0 -0
  177. package/dist/fonts.d.ts +2 -0
  178. package/dist/fonts.js +4 -0
  179. package/dist/fuzzy-alignment.d.ts +11 -4
  180. package/dist/fuzzy-alignment.js +3 -9
  181. package/dist/headless.d.ts +5 -1
  182. package/dist/headless.js +8 -1
  183. package/dist/index.d.ts +10 -2
  184. package/dist/index.js +16 -2
  185. package/dist/limits.js +6 -0
  186. package/dist/ooxml-edit-worker.d.ts +1 -0
  187. package/dist/ooxml-edit-worker.js +8 -0
  188. package/dist/pdf-edit-worker.d.ts +1 -0
  189. package/dist/pdf-edit-worker.js +35 -0
  190. package/dist/spreadsheet-viewport.d.ts +5 -0
  191. package/dist/spreadsheet-viewport.js +11 -0
  192. package/dist/ui.js +7 -0
  193. package/dist/viewer.d.ts +6 -0
  194. package/dist/viewer.js +293 -19
  195. package/dist/viewport.d.ts +13 -0
  196. package/dist/viewport.js +126 -1
  197. package/dist/worker-protocol.d.ts +39 -2
  198. package/dist/workers/fuzzy-search-worker.js +1 -1
  199. package/dist/workers/ooxml-edit-worker.js +9212 -0
  200. package/dist/workers/pdf-edit-worker.js +10847 -0
  201. package/package.json +3 -3
@@ -1,5 +1,8 @@
1
1
  import { abortError, ViewerError } from "../errors.js";
2
- import { fitInlineImagesToPage } from "./docx-images.js";
2
+ import { DocxSession } from "../edit/docx/session.js";
3
+ import { PptxSession } from "../edit/pptx/session.js";
4
+ import { createDocxParagraphIdResolver, } from "./docx-paragraphs.js";
5
+ import { prepareDocxForDisplay } from "./docx-prepass.js";
3
6
  import { enforceContainerLimits } from "../limits.js";
4
7
  const MODERN_FORMATS = [
5
8
  "docx",
@@ -17,12 +20,38 @@ const ROW_HEADER_WIDTH = 50;
17
20
  const COLUMN_HEADER_HEIGHT = 22;
18
21
  export class OfficeDocumentAdapter {
19
22
  id = "office";
23
+ /**
24
+ * PPTX and DOCX editing on the OOXML package layer. The worker and the
25
+ * engine client are imported on the first `edit()`; viewing never loads
26
+ * them.
27
+ */
28
+ edit = {
29
+ formats: ["pptx", "pptm", "ppsx", "docx", "docm"],
30
+ load: async (original, context) => context.format === "docx"
31
+ ? (await import("../edit/docx/provider.js")).loadDocxEditEngine(original, context, this.#options.edit ?? {})
32
+ : (await import("../edit/pptx/provider.js")).loadPptxEditEngine(original, context, this.#options.edit ?? {}),
33
+ createSession: (core, access) => core.format === "docx"
34
+ ? new DocxSession(core, access)
35
+ : new PptxSession(core),
36
+ };
20
37
  formats = [...MODERN_FORMATS, ...LEGACY_FORMATS];
21
38
  #options;
22
39
  constructor(options = {}) {
23
40
  this.#options = options;
24
41
  }
25
42
  async open(input, context) {
43
+ return this.#open(input, context, false);
44
+ }
45
+ /**
46
+ * Edited bytes open as a fresh document (the engine owns no reusable
47
+ * state); a presentation lays its slides out progressively so the slide
48
+ * on screen paints without waiting for the whole deck — Firefox takes
49
+ * seconds for a 500-slide preflight. The viewer closes `previous`.
50
+ */
51
+ reopen(_previous, data, context) {
52
+ return this.#open(data, context, true);
53
+ }
54
+ async #open(input, context, reopening) {
26
55
  throwIfAborted(context.signal);
27
56
  let format = context.format;
28
57
  let data = input;
@@ -57,12 +86,16 @@ export class OfficeDocumentAdapter {
57
86
  useGoogleFonts: false,
58
87
  maxZipEntryBytes: context.limits.maxZipEntryBytes,
59
88
  mode: "main",
89
+ ...(reopening ? { progressiveLayout: true } : {}),
60
90
  };
61
- const buffer = exactArrayBuffer(data);
62
91
  try {
63
92
  const kind = kindFor(format);
64
93
  if (kind === "document") {
65
- const backend = await this.#loadDocx(buffer, engineOptions);
94
+ // What the renderer sees: oversized inline pictures fitted and every
95
+ // paragraph carrying an id; the bytes a session saves are the input.
96
+ const display = await prepareDocxForDisplay(data, context.limits, context.signal);
97
+ throwIfAborted(context.signal);
98
+ const backend = await this.#loadDocx(exactArrayBuffer(display.bytes), engineOptions);
66
99
  throwIfAborted(context.signal, backend);
67
100
  context.reportProgress({
68
101
  phase: "parsing",
@@ -70,8 +103,15 @@ export class OfficeDocumentAdapter {
70
103
  total: 1,
71
104
  ratio: 1,
72
105
  });
73
- return { kind, format: context.format, backend, warnings };
106
+ return {
107
+ kind,
108
+ format: context.format,
109
+ backend,
110
+ warnings,
111
+ paragraphIdOf: createDocxParagraphIdResolver(docxModelOf(backend)),
112
+ };
74
113
  }
114
+ const buffer = exactArrayBuffer(data);
75
115
  if (kind === "presentation") {
76
116
  const backend = await this.#loadPptx(buffer, engineOptions);
77
117
  throwIfAborted(context.signal, backend);
@@ -232,6 +272,7 @@ export class OfficeDocumentAdapter {
232
272
  return runs.map((run) => {
233
273
  const logicalStart = logicalOffset;
234
274
  logicalOffset += run.text.length;
275
+ const paragraphId = run.paragraphId ?? handle.paragraphIdOf(run.source);
235
276
  return {
236
277
  text: run.text,
237
278
  x: run.x,
@@ -240,6 +281,7 @@ export class OfficeDocumentAdapter {
240
281
  height: run.h,
241
282
  font: run.font,
242
283
  fontSize: run.fontSize,
284
+ ...(paragraphId === undefined ? {} : { paragraphId }),
243
285
  ...(run.letterSpacingPx === undefined
244
286
  ? {}
245
287
  : { letterSpacingPx: run.letterSpacingPx }),
@@ -326,11 +368,10 @@ export class OfficeDocumentAdapter {
326
368
  return convertInWorker(data, format, workerUrl, moduleUrl, context.signal, context.limits.maxOperationMs);
327
369
  }
328
370
  async #loadDocx(data, options) {
329
- const backend = this.#options.engines?.docx
330
- ? await this.#options.engines.docx(data, options)
331
- : await (await import("@silurus/ooxml/docx")).DocxDocument.load(data, options);
332
- fitDocxInlineImages(backend);
333
- return backend;
371
+ if (this.#options.engines?.docx)
372
+ return this.#options.engines.docx(data, options);
373
+ const { DocxDocument } = await import("@silurus/ooxml/docx");
374
+ return DocxDocument.load(data, options);
334
375
  }
335
376
  async #loadXlsx(data, options) {
336
377
  if (this.#options.engines?.xlsx)
@@ -341,13 +382,22 @@ export class OfficeDocumentAdapter {
341
382
  async #loadPptx(data, options) {
342
383
  if (this.#options.engines?.pptx)
343
384
  return this.#options.engines.pptx(data, options);
344
- const { PptxPresentation } = await import("@silurus/ooxml-pptx/pptx");
385
+ const { PptxPresentation } = await import("@silurus/ooxml/pptx");
345
386
  return PptxPresentation.load(data, options);
346
387
  }
347
388
  }
348
389
  export function createOfficeAdapter(options = {}) {
349
390
  return new OfficeDocumentAdapter(options);
350
391
  }
392
+ /** The engine's model when it is reachable; a worker-mode getter throws. */
393
+ function docxModelOf(backend) {
394
+ try {
395
+ return backend.document;
396
+ }
397
+ catch {
398
+ return undefined;
399
+ }
400
+ }
351
401
  export function sanitizeOfficeHyperlink(target) {
352
402
  if (!target)
353
403
  return undefined;
@@ -672,22 +722,3 @@ function normalizeOfficeError(error) {
672
722
  function textDirection(text) {
673
723
  return /[\u0590-\u08ff\ufb1d-\ufefc]/u.test(text) ? "rtl" : "ltr";
674
724
  }
675
- /**
676
- * Oversized inline pictures are shrunk to the section's content box before
677
- * the engine paginates (the layout is built lazily on first page access).
678
- * The model is reachable in `main` mode only; a worker-mode engine keeps
679
- * Word's geometry.
680
- */
681
- function fitDocxInlineImages(backend) {
682
- if (backend.mode === "worker")
683
- return;
684
- let model;
685
- try {
686
- model = backend.document;
687
- }
688
- catch {
689
- return;
690
- }
691
- if (model)
692
- fitInlineImagesToPage(model);
693
- }
@@ -1,4 +1,6 @@
1
1
  import type { AdapterOpenContext, DocumentAdapter, DocumentInfo, PageSize, RenderViewport, TextRun } from "../contracts.js";
2
+ import type { EditEngineProvider } from "../edit/engine.js";
3
+ import type { PdfEditProviderOptions } from "../edit/pdf/provider.js";
2
4
  export interface PdfBackend {
3
5
  readonly pageCount: number;
4
6
  pageSize?(pageIndex: number, signal?: AbortSignal): PageSize | Promise<PageSize>;
@@ -13,6 +15,8 @@ export interface PdfAdapterOptions {
13
15
  readonly wasmUrl?: string | URL;
14
16
  readonly iccUrl?: string | URL;
15
17
  readonly open?: (data: Uint8Array, context: AdapterOpenContext) => Promise<PdfBackend>;
18
+ /** Where the PDF edit worker and its WebAssembly live. */
19
+ readonly edit?: PdfEditProviderOptions;
16
20
  }
17
21
  interface PdfHandle {
18
22
  readonly backend: PdfBackend;
@@ -21,6 +25,11 @@ export declare class PdfDocumentAdapter implements DocumentAdapter<PdfHandle> {
21
25
  #private;
22
26
  readonly id = "pdf";
23
27
  readonly formats: readonly ["pdf"];
28
+ /**
29
+ * PDFium-backed editing. The worker, its WebAssembly and the engine client
30
+ * are imported on the first `edit()`; viewing never loads them.
31
+ */
32
+ readonly edit: EditEngineProvider;
24
33
  constructor(options?: PdfAdapterOptions);
25
34
  open(data: Uint8Array, context: AdapterOpenContext): Promise<PdfHandle>;
26
35
  getInfo(handle: PdfHandle): Promise<DocumentInfo>;
@@ -1,4 +1,5 @@
1
1
  import { abortError, ViewerError } from "../errors.js";
2
+ import { PdfSession } from "../edit/pdf/session.js";
2
3
  // Preserve the public zoom=1 contract: one PDF point maps to one renderer CSS
3
4
  // pixel. Per-page geometry still prevents the viewport from coercing pages to
4
5
  // A4 or changing their width while virtualizing.
@@ -7,6 +8,15 @@ export class PdfDocumentAdapter {
7
8
  id = "pdf";
8
9
  formats = ["pdf"];
9
10
  #options;
11
+ /**
12
+ * PDFium-backed editing. The worker, its WebAssembly and the engine client
13
+ * are imported on the first `edit()`; viewing never loads them.
14
+ */
15
+ edit = {
16
+ formats: ["pdf"],
17
+ load: async (original, context) => (await import("../edit/pdf/provider.js")).loadPdfEditEngine(original, context, this.#options.edit ?? {}),
18
+ createSession: (core) => new PdfSession(core),
19
+ };
10
20
  constructor(options = {}) {
11
21
  this.#options = options;
12
22
  }
Binary file
@@ -1,11 +1,22 @@
1
+ import type { EditEngineProvider } from "./edit/engine.js";
2
+ import type { EditSession } from "./edit/sessions.js";
3
+ import type { DocumentChange, LayoutChange, EditOptions, EditStateChange, PageHit, PageRect, ViewportRect } from "./edit/types.js";
1
4
  export declare const supportedFormats: readonly ["docx", "docm", "xlsx", "xlsm", "pptx", "pptm", "ppsx", "doc", "xls", "ppt", "pdf", "csv", "tsv", "png", "jpeg", "gif", "webp", "svg", "bmp", "tiff"];
2
5
  export type DocumentFormat = (typeof supportedFormats)[number];
3
6
  export type ViewerLocale = "en" | "ru";
4
7
  export type FitMode = "none" | "page" | "width";
5
8
  export type ViewerStatus = "idle" | "loading" | "ready" | "error" | "destroyed";
6
9
  export type RenderUnit = "page" | "slide" | "sheet" | "image";
7
- export type ViewerErrorCode = "unsupported-format" | "fidelity-unsupported" | "invalid-file" | "encrypted-document" | "resource-limit" | "network-error" | "aborted" | "font-unavailable" | "render-failed" | "worker-crashed" | "lifecycle-error" | "internal";
8
- export type ViewerWarningCode = "format-hint-mismatch" | "unsupported-feature" | "font-substitution" | "font-unavailable" | "external-resource-blocked" | "fidelity-degraded";
10
+ export type ViewerErrorCode = "unsupported-format" | "fidelity-unsupported" | "invalid-file" | "encrypted-document" | "resource-limit" | "network-error" | "aborted" | "font-unavailable" | "render-failed" | "worker-crashed" | "lifecycle-error" | "edit-unsupported" | "invalid-operation" | "edit-conflict" | "edit-failed"
11
+ /** An OOXML package the editing layer cannot open: ZIP64, encryption, an unknown method, several disks. */
12
+ | "unsupported-package"
13
+ /** An OOXML part that can be read but not patched: not UTF-8, or not byte-stable through decoding. */
14
+ | "unsupported-part"
15
+ /** An XML part the scanner cannot parse. */
16
+ | "malformed-xml"
17
+ /** A patch that overlaps, is stale, is not well-formed, or does not read back as expected. */
18
+ | "invalid-patch" | "internal";
19
+ export type ViewerWarningCode = "format-hint-mismatch" | "unsupported-feature" | "font-substitution" | "font-unavailable" | "external-resource-blocked" | "fidelity-degraded" | "privacy-not-guaranteed";
9
20
  export interface ViewerErrorData {
10
21
  readonly name: "ViewerError";
11
22
  readonly code: ViewerErrorCode;
@@ -34,6 +45,18 @@ export interface ResourceLimits {
34
45
  readonly maxDocumentUnits: number;
35
46
  readonly maxConcurrentRenders: number;
36
47
  readonly maxOperationMs: number;
48
+ /** Operations in one `EditSession.apply()` call. */
49
+ readonly maxEditOperations: number;
50
+ /** Undoable edit batches kept; older ones are folded into the starting point. */
51
+ readonly maxEditHistory: number;
52
+ /** Memory for retained edit checkpoints; fewer are kept when a file is big. */
53
+ readonly maxEditCheckpointBytes: number;
54
+ /** Nodes one `EditSession.getOutline()` returns; more is cut and reported. */
55
+ readonly maxOutlineNodes: number;
56
+ /** Upper bound of `describe()`'s character budget. */
57
+ readonly maxDescribeChars: number;
58
+ /** Named edit checkpoints alive at once in a session. */
59
+ readonly maxEditCheckpoints: number;
37
60
  }
38
61
  export type BinaryDocumentSource = ArrayBuffer | Uint8Array | Blob;
39
62
  export type DocumentSource = BinaryDocumentSource | URL | string;
@@ -164,6 +187,14 @@ export interface TextRun {
164
187
  readonly hyperlink?: HyperlinkTarget;
165
188
  readonly row?: number;
166
189
  readonly column?: number;
190
+ /**
191
+ * DOCX: the `w:p` of the source XML this run was laid out from, as the
192
+ * file's `w14:paraId` or the deterministic id the viewer assigns to a
193
+ * paragraph without one (eight hex digits). The runs of a paragraph that
194
+ * continues on the next page share it. Absent when the run belongs to no
195
+ * source paragraph.
196
+ */
197
+ readonly paragraphId?: string;
167
198
  }
168
199
  export type HyperlinkTarget = {
169
200
  readonly kind: "external";
@@ -216,6 +247,9 @@ export interface ViewerEventMap {
216
247
  };
217
248
  readonly viewchange: ViewerState;
218
249
  readonly searchchange: SearchResult | null;
250
+ readonly editstatechange: EditStateChange;
251
+ readonly documentchange: DocumentChange;
252
+ readonly layoutchange: LayoutChange;
219
253
  }
220
254
  /**
221
255
  * Tuning for the fuzzy fallback that runs when the exact search finds
@@ -389,6 +423,8 @@ export interface DocumentCapabilities {
389
423
  readonly cellSelection: boolean;
390
424
  readonly search: boolean;
391
425
  readonly thumbnails: boolean;
426
+ /** True when `edit()` is available for this document. */
427
+ readonly editing: boolean;
392
428
  }
393
429
  export type DocumentMetadata = DocumentInfo;
394
430
  export interface AdapterOpenContext {
@@ -410,6 +446,13 @@ export interface DocumentAdapter<THandle = unknown> {
410
446
  getTextMap?(handle: THandle, pageIndex: number, signal?: AbortSignal): Promise<readonly TextRun[]>;
411
447
  close(handle: THandle): void | Promise<void>;
412
448
  destroy?(): void | Promise<void>;
449
+ /** Editing support for some of this adapter's formats. */
450
+ readonly edit?: EditEngineProvider;
451
+ /**
452
+ * Opens edited bytes of a document, reusing what `previous` holds (for
453
+ * example a worker). `previous` stays open; the viewer closes it afterwards.
454
+ */
455
+ reopen?(previous: THandle, data: Uint8Array, context: AdapterOpenContext): Promise<THandle>;
413
456
  }
414
457
  export type ViewerEventListener<K extends keyof ViewerEventMap> = (event: ViewerEventMap[K]) => void;
415
458
  export interface ViewerApi {
@@ -445,6 +488,14 @@ export interface ViewerApi {
445
488
  copySelection(): Promise<string>;
446
489
  getOriginalBytes(): Uint8Array | undefined;
447
490
  downloadOriginal(fileName?: string): Blob;
491
+ /** Starts editing the loaded document, or returns the session already started. */
492
+ edit(options?: EditOptions): Promise<EditSession>;
493
+ /** The active session of the loaded document, if `edit()` was called. */
494
+ getEditSession(): EditSession | undefined;
495
+ /** Client-space rectangle of a page-space rectangle; undefined if the page is not mounted. */
496
+ pageToClient(pageIndex: number, rect: PageRect): ViewportRect | undefined;
497
+ /** Page under a client-space point and the point in page space; undefined outside pages. */
498
+ clientToPage(clientX: number, clientY: number): PageHit | undefined;
448
499
  on<K extends keyof ViewerEventMap>(type: K, listener: ViewerEventListener<K>): () => void;
449
500
  destroy(): Promise<void>;
450
501
  }
@@ -0,0 +1,47 @@
1
+ import type { ResourceLimits } from "../../contracts.js";
2
+ import type { EditableFormat, EditElement, EditState, ElementQuery, ReadItem, ReadOptions, ReadResult } from "../types.js";
3
+ import type { DescribeOptions, DocumentDescription, OutlineNode, OutlineOptions, OutlineResult } from "./types.js";
4
+ /** What the outline needs of a session: its format, its page count and its elements. */
5
+ export interface OutlineSource {
6
+ readonly format: EditableFormat;
7
+ readonly state: EditState;
8
+ getElements(query?: ElementQuery, options?: ReadOptions): Promise<ReadResult<EditElement>>;
9
+ }
10
+ /** The outline of a session's document; one `getElements()` read, reshaped. */
11
+ export declare function readOutline(session: OutlineSource, limits: ResourceLimits, options?: OutlineOptions): Promise<OutlineResult>;
12
+ /** The description of a session's document: the outline rendered within a character budget. */
13
+ export declare function readDescription(session: OutlineSource, limits: ResourceLimits, options?: DescribeOptions): Promise<ReadItem<DocumentDescription>>;
14
+ export interface BuiltOutline {
15
+ readonly nodes: readonly OutlineNode[];
16
+ readonly nodeCount: number;
17
+ readonly truncated: boolean;
18
+ }
19
+ /**
20
+ * Nests elements by `parentId`, numbers them in reading order, keeps the
21
+ * nodes the options ask for (a container stays when a descendant is kept)
22
+ * and cuts the result at `maxNodes`. Ordinals are assigned before any
23
+ * filtering, so "3.2" names the same paragraph whatever the query.
24
+ */
25
+ export declare function buildOutline(format: EditableFormat, elements: readonly EditElement[], options: Pick<OutlineOptions, "pageRange" | "kinds" | "maxTextChars">, maxNodes: number): BuiltOutline;
26
+ /**
27
+ * What a person calls the element, when the format knows: a shape's name
28
+ * or placeholder in a deck, a paragraph's style in a Word document, a
29
+ * table's size everywhere.
30
+ */
31
+ export declare function labelOf(format: EditableFormat, element: EditElement): string | undefined;
32
+ /**
33
+ * The description's grammar, one line per node:
34
+ *
35
+ * <format>: <n> pages|slides, <m> elements
36
+ * [<id>] page <p> <kind> "<label>" (<flags>): <text>…
37
+ * [<child id>] page <p> <kind>: <text>
38
+ *
39
+ * The page is left out while the node has none, the label and the flags
40
+ * while the node has none, the text while it is empty. Tabs in the text
41
+ * become ` | `, line breaks ` ⏎ `; a cut text ends in `…`. Children are
42
+ * indented two spaces per level. The budget cuts whole lines and the last
43
+ * line then says how many were left out.
44
+ */
45
+ export declare function renderDescription(format: EditableFormat, pageCount: number, outline: BuiltOutline | OutlineResult, maxChars: number, maxNodes: number): DocumentDescription;
46
+ /** One line of text: tabs as cell separators, breaks marked, other controls blanked. */
47
+ export declare function foldText(text: string): string;