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
@@ -0,0 +1,175 @@
1
+ import type { ChangeMode, EditableFormat, EditReceipt, HistoryOptions, JsonSchema, OperationIssue, ReadItem, ReadOptions, ReadResult, TextRange } from "../types.js";
2
+ export interface OutlineOptions extends ReadOptions {
3
+ /** Inclusive 0-based page range; a node outside it is left out unless a descendant is inside. */
4
+ readonly pageRange?: readonly [number, number];
5
+ /** Element kinds to keep; a container of a kept node stays as its parent. */
6
+ readonly kinds?: readonly string[];
7
+ /** Characters of text kept per node; the rest is cut and `truncated` says so. Default 160. */
8
+ readonly maxTextChars?: number;
9
+ }
10
+ /** One element as a prompt sees it: no geometry, no styles, nested where the format nests. */
11
+ export interface OutlineNode {
12
+ /** The element id, as every operation takes it. */
13
+ readonly id: string;
14
+ /** The reading-order path: "3", "3.2" (a cell paragraph under its table). */
15
+ readonly ordinal: string;
16
+ /** The format's element kind. */
17
+ readonly kind: string;
18
+ /** −1 while the page is not laid out (a DOCX page the viewer has not cached). */
19
+ readonly pageIndex: number;
20
+ /** The first `maxTextChars` characters of the element's text. */
21
+ readonly text?: string;
22
+ /** Length of the whole text, in UTF-16 code units. */
23
+ readonly textLength: number;
24
+ /** True when `text` is shorter than the element's text. */
25
+ readonly truncated: boolean;
26
+ /** What a person calls it: "Title 1", "Heading 2", "Table (3×4)". */
27
+ readonly label?: string;
28
+ /** Why the element only accepts insertions next to it, when it does. */
29
+ readonly readOnlyReason?: string;
30
+ /** Listed and editable, but not drawn (a hidden PowerPoint shape). */
31
+ readonly hidden?: boolean;
32
+ /** Names of the operations that accept the element as their target. */
33
+ readonly operations: readonly string[];
34
+ /** A table's cell paragraphs, a group's members, a paragraph's inline pictures. */
35
+ readonly children?: readonly OutlineNode[];
36
+ }
37
+ /** `getOutline()`'s read: the nodes, how many there are and whether the limit cut them. */
38
+ export interface OutlineResult extends ReadResult<OutlineNode> {
39
+ /** Nodes in the result, nested ones included. */
40
+ readonly nodeCount: number;
41
+ /** True when `maxOutlineNodes` cut the outline. */
42
+ readonly truncated: boolean;
43
+ }
44
+ export interface DescribeOptions extends OutlineOptions {
45
+ /** Characters the description may take; the tail is cut and `truncated` says so. Default 50 000. */
46
+ readonly maxChars?: number;
47
+ }
48
+ /** The outline rendered as plain text for a prompt. */
49
+ export interface DocumentDescription {
50
+ readonly format: EditableFormat;
51
+ readonly pageCount: number;
52
+ /** Elements the description covers, nested ones included. */
53
+ readonly elementCount: number;
54
+ /**
55
+ * A header line, then one line per node in the documented grammar:
56
+ * `[sld2:7] slide 2 shape "Title 1": Quarterly review`.
57
+ */
58
+ readonly text: string;
59
+ /** True when `maxChars` or `maxOutlineNodes` cut the description. */
60
+ readonly truncated: boolean;
61
+ }
62
+ /** What a model names: a quoted text, a citation with its page, a kind, a place. */
63
+ export interface TargetQuery {
64
+ /** Text to find; whitespace-insensitive, case-insensitive, tolerant to small differences. */
65
+ readonly text?: string;
66
+ /** A citation as the viewer's `search()` gets them: the passage and the 1-based page it is expected on. */
67
+ readonly citation?: {
68
+ readonly text: string;
69
+ readonly pageNumber?: number;
70
+ };
71
+ readonly pageIndex?: number;
72
+ readonly kinds?: readonly string[];
73
+ /** Restrict to an element and its descendants (a table, a group). */
74
+ readonly within?: string;
75
+ /** Default 5. */
76
+ readonly maxResults?: number;
77
+ }
78
+ /** One way to read a query, with how it was found and how far to trust it. */
79
+ export interface TargetCandidate {
80
+ readonly elementId: string;
81
+ /** The matched part, for ranged operations; absent when the match is the element's whole text. */
82
+ readonly range?: TextRange;
83
+ readonly pageIndex: number;
84
+ /** 1 for an exact match, down to 0.5 for the loosest accepted one. */
85
+ readonly score: number;
86
+ /** The pass that matched: the engine's exact search, folded text, fuzzy alignment, or a kind lookup. */
87
+ readonly reason: "exact" | "normalized" | "fuzzy" | "kind-only";
88
+ /** The matched text with a little context, on one line. */
89
+ readonly snippet: string;
90
+ }
91
+ /** A state the host named, to come back to; session state, gone with the session. */
92
+ export interface EditCheckpoint {
93
+ /** 22 URL-safe characters, unique in the session. */
94
+ readonly id: string;
95
+ readonly label?: string;
96
+ /** The revision it names. */
97
+ readonly revision: number;
98
+ /** ISO 8601. */
99
+ readonly createdAt: string;
100
+ }
101
+ /** One tool as a model provider takes it: a name, a description and a JSON Schema (draft 2020-12). */
102
+ export interface ToolDefinition {
103
+ readonly name: string;
104
+ readonly description: string;
105
+ readonly inputSchema: JsonSchema;
106
+ }
107
+ /** The tools of a session; the same names on every format, the operations of its own. */
108
+ export interface ToolSet {
109
+ /** Raised when a tool's shape changes incompatibly. */
110
+ readonly version: number;
111
+ readonly format: EditableFormat;
112
+ readonly definitions: readonly ToolDefinition[];
113
+ }
114
+ /** A model's call: the tool's name and its JSON arguments, validated against the tool's schema. */
115
+ export interface ToolCall {
116
+ readonly name: string;
117
+ readonly arguments: unknown;
118
+ }
119
+ /** What a tool call produced, for the model and the chat. */
120
+ export interface ToolResult {
121
+ readonly ok: boolean;
122
+ /** JSON for the model: a description, an outline, candidates, a receipt, or the issues of a refused call. */
123
+ readonly content: unknown;
124
+ /** One or two sentences for the model and the chat: "Replaced the title of slide 2." */
125
+ readonly text: string;
126
+ /** Why a call was refused, in the shape `apply()` reports. */
127
+ readonly issues?: readonly OperationIssue[];
128
+ }
129
+ export interface ToolCallOptions {
130
+ /** Checked before any tool that changes the document, like `ApplyOptions.expectedRevision`. */
131
+ readonly expectedRevision?: number;
132
+ /** How `document_apply` writes: in place, or as tracked changes where the format has them. */
133
+ readonly changeMode?: ChangeMode;
134
+ /** The author of tracked changes; required with `changeMode: "tracked"`. */
135
+ readonly author?: string;
136
+ readonly signal?: AbortSignal;
137
+ }
138
+ /** The AI-facing reads, the checkpoints and the tools every edit session has. */
139
+ export interface EditSessionReads {
140
+ /** The body elements in reading order, shaped for a prompt. */
141
+ getOutline(options?: OutlineOptions): Promise<OutlineResult>;
142
+ /** The outline as plain text, one line per element, within a character budget. */
143
+ describe(options?: DescribeOptions): Promise<ReadItem<DocumentDescription>>;
144
+ /**
145
+ * Elements and ranges a query names, best first: an exact match, else a
146
+ * match with whitespace, case, quotes and compatibility forms folded,
147
+ * else the viewer's fuzzy citation match, else (without text) the
148
+ * elements of the asked kinds in reading order.
149
+ */
150
+ resolveTargets(query: TargetQuery, options?: ReadOptions): Promise<ReadResult<TargetCandidate>>;
151
+ /**
152
+ * Pins the current state under a new id. Rejects with `resource-limit`
153
+ * past `maxEditCheckpoints`.
154
+ */
155
+ createCheckpoint(label?: string): Promise<EditCheckpoint>;
156
+ /** Every checkpoint alive, in creation order. */
157
+ listCheckpoints(): readonly EditCheckpoint[];
158
+ /**
159
+ * Back to the checkpoint's content as one history entry: undoable, a new
160
+ * revision, `documentchange` with reason `restore`. Rejects with
161
+ * `invalid-operation` for an unknown id.
162
+ */
163
+ restoreCheckpoint(id: string, options?: HistoryOptions): Promise<EditReceipt>;
164
+ /** Forgets a checkpoint; unknown ids are ignored. */
165
+ dropCheckpoint(id: string): void;
166
+ /** The tool definitions of this session, for a model provider's tool list. */
167
+ readonly tools: ToolSet;
168
+ /**
169
+ * Runs one tool call. A model's mistake (an unknown tool, bad arguments, a
170
+ * refused batch, a stale revision) comes back as `ok: false` with issues
171
+ * and a text to act on; only the session's own errors (`lifecycle-error`,
172
+ * `aborted`) throw.
173
+ */
174
+ callTool(call: ToolCall, options?: ToolCallOptions): Promise<ToolResult>;
175
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,23 @@
1
+ import type { BinaryData, JsonSchema } from "./types.js";
2
+ export declare function isAssetReference(value: unknown): value is string;
3
+ /** The content-addressed id of `bytes`. */
4
+ export declare function assetIdOf(bytes: Uint8Array): Promise<string>;
5
+ /** Something that answers an asset reference with its bytes. */
6
+ export interface AssetSource {
7
+ get(id: string): Uint8Array | undefined;
8
+ }
9
+ export declare class AssetStore implements AssetSource {
10
+ #private;
11
+ get(id: string): Uint8Array | undefined;
12
+ has(id: string): boolean;
13
+ set(id: string, bytes: Uint8Array): void;
14
+ /** Bytes held, for limits. */
15
+ get byteLength(): number;
16
+ }
17
+ /**
18
+ * Bytes of a `BinaryData` value that passed schema validation: inline bytes,
19
+ * a base64 string, or an asset reference the store knows.
20
+ */
21
+ export declare function resolveBinary(data: BinaryData, assets: AssetSource): Uint8Array;
22
+ /** Names of an operation's top-level properties its schema marks as binary. */
23
+ export declare function binaryFields(schema: JsonSchema | undefined): string[];
@@ -0,0 +1,75 @@
1
+ import { ViewerError } from "../errors.js";
2
+ /*
3
+ * Binary payloads of operations live in a content-addressed store for the
4
+ * session: an operation refers to them as `asset:<sha-256 hex>`, so the
5
+ * history, undo, redo, dry runs and recovery never copy image bytes again.
6
+ */
7
+ const REFERENCE = /^asset:[0-9a-f]{64}$/;
8
+ export function isAssetReference(value) {
9
+ return typeof value === "string" && REFERENCE.test(value);
10
+ }
11
+ /** The content-addressed id of `bytes`. */
12
+ export async function assetIdOf(bytes) {
13
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", bytes.slice().buffer);
14
+ let hex = "";
15
+ for (const byte of new Uint8Array(digest))
16
+ hex += byte.toString(16).padStart(2, "0");
17
+ return `asset:${hex}`;
18
+ }
19
+ export class AssetStore {
20
+ #bytes = new Map();
21
+ #total = 0;
22
+ get(id) {
23
+ return this.#bytes.get(id);
24
+ }
25
+ has(id) {
26
+ return this.#bytes.has(id);
27
+ }
28
+ set(id, bytes) {
29
+ if (this.#bytes.has(id))
30
+ return;
31
+ this.#bytes.set(id, bytes);
32
+ this.#total += bytes.byteLength;
33
+ }
34
+ /** Bytes held, for limits. */
35
+ get byteLength() {
36
+ return this.#total;
37
+ }
38
+ }
39
+ /**
40
+ * Bytes of a `BinaryData` value that passed schema validation: inline bytes,
41
+ * a base64 string, or an asset reference the store knows.
42
+ */
43
+ export function resolveBinary(data, assets) {
44
+ if (data instanceof Uint8Array)
45
+ return data;
46
+ if (isAssetReference(data)) {
47
+ const bytes = assets.get(data);
48
+ if (!bytes)
49
+ throw new ViewerError("invalid-operation", `Unknown asset ${data}`, {
50
+ details: {
51
+ issues: [
52
+ {
53
+ operationIndex: -1,
54
+ path: "",
55
+ code: "unknown-asset",
56
+ message: `Unknown asset ${data}`,
57
+ },
58
+ ],
59
+ },
60
+ });
61
+ return bytes;
62
+ }
63
+ return Uint8Array.from(atob(data), (character) => character.charCodeAt(0));
64
+ }
65
+ /** Names of an operation's top-level properties its schema marks as binary. */
66
+ export function binaryFields(schema) {
67
+ const properties = schema?.properties;
68
+ if (!properties || typeof properties !== "object")
69
+ return [];
70
+ return Object.entries(properties)
71
+ .filter(([, property]) => typeof property === "object" &&
72
+ property !== null &&
73
+ property["x-binary"] === true)
74
+ .map(([name]) => name);
75
+ }
@@ -0,0 +1,6 @@
1
+ import type { PageRect } from "../types.js";
2
+ import { type AnyRecord, type DocxModel } from "./model.js";
3
+ import type { DocxElement } from "./types.js";
4
+ export declare const NO_PAGE = -1;
5
+ export declare const EMPTY_RECT: PageRect;
6
+ export declare function toElement(model: DocxModel, record: AnyRecord): DocxElement;
@@ -0,0 +1,90 @@
1
+ import { tableRows, tableText, } from "./model.js";
2
+ import { IMPLEMENTED_OPERATIONS } from "./schemas.js";
3
+ import { resolveParagraphStyle, resolveTextStyle } from "./style.js";
4
+ import { firstTextItem } from "./text.js";
5
+ /*
6
+ * `DocxElement` values from the model's records, without geometry: the
7
+ * engine never lays out, so `pageIndex` is −1 and `bounds` empty until
8
+ * the session joins the renderer's runs on the main thread.
9
+ */
10
+ export const NO_PAGE = -1;
11
+ export const EMPTY_RECT = { x: 0, y: 0, width: 0, height: 0 };
12
+ /** The operations each kind accepts once its handler ships. */
13
+ const OPERATIONS = {
14
+ paragraph: [
15
+ "replaceText",
16
+ "setTextStyle",
17
+ "setParagraphStyle",
18
+ "insertParagraph",
19
+ "insertTable",
20
+ "insertImage",
21
+ "moveElement",
22
+ "deleteElement",
23
+ ],
24
+ table: [
25
+ "setTableCell",
26
+ "insertParagraph",
27
+ "insertTable",
28
+ "insertImage",
29
+ "moveElement",
30
+ "deleteElement",
31
+ ],
32
+ image: ["deleteElement"],
33
+ other: [],
34
+ };
35
+ /** A read-only paragraph only accepts siblings placed next to it. */
36
+ const INSERTIONS = ["insertParagraph", "insertTable", "insertImage"];
37
+ function operationsOf(kind, readOnly) {
38
+ return OPERATIONS[kind].filter((name) => IMPLEMENTED_OPERATIONS.includes(name) &&
39
+ (!readOnly || INSERTIONS.includes(name)));
40
+ }
41
+ export function toElement(model, record) {
42
+ const base = {
43
+ pageIndex: NO_PAGE,
44
+ bounds: EMPTY_RECT,
45
+ fragments: [],
46
+ story: { kind: "body" },
47
+ };
48
+ if (record.kind === "paragraph")
49
+ return paragraphElement(model, record, base);
50
+ if (record.kind === "table")
51
+ return {
52
+ ...base,
53
+ id: record.elementId,
54
+ kind: "table",
55
+ text: tableText(record),
56
+ table: { rows: tableRows(record) },
57
+ operations: operationsOf("table", false),
58
+ };
59
+ return {
60
+ ...base,
61
+ id: record.elementId,
62
+ kind: record.kind,
63
+ parentId: record.paragraph.elementId,
64
+ ...(record.kind === "image" && record.extent
65
+ ? {
66
+ imageSize: {
67
+ width: record.extent.cx / EMU_PER_PX,
68
+ height: record.extent.cy / EMU_PER_PX,
69
+ },
70
+ }
71
+ : {}),
72
+ operations: operationsOf(record.kind, false),
73
+ };
74
+ }
75
+ /** EMU per CSS pixel at 96 dpi. */
76
+ const EMU_PER_PX = 9525;
77
+ function paragraphElement(model, record, base) {
78
+ const first = firstTextItem(record.text);
79
+ return {
80
+ ...base,
81
+ id: record.elementId,
82
+ kind: "paragraph",
83
+ text: record.text.text,
84
+ ...(record.table ? { parentId: record.table.elementId } : {}),
85
+ textStyle: resolveTextStyle(model.styles, record.pPr, first?.rPr),
86
+ paragraphStyle: resolveParagraphStyle(model.styles, record.pPr),
87
+ ...(record.readOnlyReason ? { readOnlyReason: record.readOnlyReason } : {}),
88
+ operations: operationsOf("paragraph", record.readOnlyReason !== undefined),
89
+ };
90
+ }
@@ -0,0 +1,57 @@
1
+ import type { ResourceLimits } from "../../contracts.js";
2
+ import type { BatchMode, EditEngine, EngineBatch, EngineChange, MaterializedDocument, MaterializeOptions, RestoreTarget } from "../engine.js";
3
+ import { OoxmlPackage } from "../ooxml/package.js";
4
+ import type { EditFindOptions, EditOperation, ElementQuery, OperationIssue, PagePoint, TextTarget } from "../types.js";
5
+ import { DocxModel, type AnyRecord } from "./model.js";
6
+ import type { DocxElement, DocxRevision } from "./types.js";
7
+ /** Reads the DOCX session adds on top of the core, served by the engine and the worker client alike. */
8
+ export interface DocxEngineReads {
9
+ revisions(id: string, signal: AbortSignal): Promise<readonly DocxRevision[]>;
10
+ }
11
+ export declare class DocxEditEngine implements EditEngine, DocxEngineReads {
12
+ #private;
13
+ readonly schemas: import("../types.js").OperationSchemaSet;
14
+ private constructor();
15
+ /** Opens the package and reads the block index, so a broken document fails here. */
16
+ static open(bytes: Uint8Array, limits: ResourceLimits, signal?: AbortSignal): Promise<DocxEditEngine>;
17
+ /** The package behind the engine, for tests and the operations. */
18
+ get package(): OoxmlPackage;
19
+ /** The engine has no pages of its own; the renderer counts them. */
20
+ get pageCount(): number;
21
+ /** The block index at the current revision. */
22
+ model(signal?: AbortSignal): Promise<DocxModel>;
23
+ validate(operations: readonly EditOperation[], signal: AbortSignal, mode?: BatchMode): Promise<readonly OperationIssue[]>;
24
+ /** Plain operation arrays, as the unit tests pass them, become the next batch. */
25
+ apply(input: EngineBatch | readonly EditOperation[], signal: AbortSignal): Promise<EngineChange>;
26
+ /** The revisions of a paragraph; none for another element or an unknown id. */
27
+ revisions(id: string, signal: AbortSignal): Promise<readonly DocxRevision[]>;
28
+ materialize(purposeOrSignal?: "show" | "save" | AbortSignal, options?: MaterializeOptions, signal?: AbortSignal): Promise<Uint8Array>;
29
+ /**
30
+ * `save` is the package as the session changed it: ids written only on
31
+ * the paragraphs the session rebuilt or created. `show` also stamps every
32
+ * other paragraph with the id the engine knows it by, in a copy, so the
33
+ * display pre-pass and the viewer's runs name the engine's paragraphs
34
+ * after edits that moved paragraphs around. Without changes both are
35
+ * the original bytes.
36
+ */
37
+ materializeDocument(purposeOrSignal?: "show" | "save" | AbortSignal, _options?: MaterializeOptions, signal?: AbortSignal): Promise<MaterializedDocument>;
38
+ restore(input: RestoreTarget | readonly (readonly EditOperation[])[], signal: AbortSignal): Promise<void>;
39
+ putAsset(id: string, data: Uint8Array, _signal: AbortSignal): Promise<void>;
40
+ /**
41
+ * Every element of the body story, in document order, without geometry.
42
+ * `pageIndex` and `intersects` are the session's to apply once the runs
43
+ * are joined; `kinds` filters here.
44
+ */
45
+ getElements(query: ElementQuery, signal: AbortSignal): Promise<readonly DocxElement[]>;
46
+ getElement(id: string, signal: AbortSignal): Promise<DocxElement | undefined>;
47
+ /** The record an element id names, at the current revision. */
48
+ locate(id: string, signal?: AbortSignal): Promise<AnyRecord | undefined>;
49
+ /** Hit-testing needs the renderer's geometry; the session answers it. */
50
+ elementsAt(_pageIndex: number, _point: PagePoint, _signal: AbortSignal): Promise<readonly DocxElement[]>;
51
+ /**
52
+ * Matches in paragraph text, in document order, without rectangles or
53
+ * pages: the session adds those from the renderer's runs.
54
+ */
55
+ findText(query: string, options: EditFindOptions, signal: AbortSignal): Promise<readonly TextTarget[]>;
56
+ dispose(): Promise<void>;
57
+ }