@stll/folio-core 0.10.0 → 0.12.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 (217) hide show
  1. package/dist/ai-edits/apply.js +602 -50
  2. package/dist/ai-edits/block-identity.d.ts +4 -0
  3. package/dist/ai-edits/block-identity.js +9 -0
  4. package/dist/ai-edits/blockRange.d.ts +28 -1
  5. package/dist/ai-edits/blockRange.js +67 -1
  6. package/dist/ai-edits/headless.d.ts +4 -4
  7. package/dist/ai-edits/headless.js +9 -9
  8. package/dist/ai-edits/index.d.ts +2 -2
  9. package/dist/ai-edits/index.js +2 -2
  10. package/dist/ai-edits/read.d.ts +7 -7
  11. package/dist/ai-edits/read.js +110 -3
  12. package/dist/ai-edits/table-cell-mutations.d.ts +48 -0
  13. package/dist/ai-edits/table-cell-mutations.js +237 -0
  14. package/dist/ai-edits/table-mutation-plan.d.ts +38 -0
  15. package/dist/ai-edits/table-mutation-plan.js +90 -0
  16. package/dist/ai-edits/table-row-column-mutations.d.ts +100 -0
  17. package/dist/ai-edits/table-row-column-mutations.js +300 -0
  18. package/dist/ai-edits/table-targets.d.ts +32 -0
  19. package/dist/ai-edits/table-targets.js +70 -0
  20. package/dist/ai-edits/types.d.ts +34 -0
  21. package/dist/compat/eigenpal.js +1 -1
  22. package/dist/content-controls/mutateContentControls.js +1 -1
  23. package/dist/controller/activeEditorStory.d.ts +36 -0
  24. package/dist/controller/activeEditorStory.js +30 -0
  25. package/dist/controller/collaborationModules.d.ts +7 -0
  26. package/dist/controller/collaborationModules.js +15 -0
  27. package/dist/controller/contentControlWidgetController.d.ts +55 -0
  28. package/dist/controller/contentControlWidgetController.js +141 -0
  29. package/dist/controller/folioEditor.d.ts +1 -1
  30. package/dist/controller/fontReadiness.js +2 -0
  31. package/dist/controller/headerFooterEditorManager.d.ts +41 -0
  32. package/dist/controller/headerFooterEditorManager.js +182 -0
  33. package/dist/controller/hiddenEditorApi.js +2 -2
  34. package/dist/controller/hiddenEditorManager.d.ts +13 -2
  35. package/dist/controller/hiddenEditorManager.js +32 -11
  36. package/dist/controller/layoutPipeline.d.ts +2 -0
  37. package/dist/controller/layoutPipeline.js +16 -1
  38. package/dist/controller/noteEditorManager.d.ts +36 -0
  39. package/dist/controller/noteEditorManager.js +210 -0
  40. package/dist/document-operations.d.ts +35 -3
  41. package/dist/document-operations.js +161 -3
  42. package/dist/docx/blockContentParser.js +2 -2
  43. package/dist/docx/commentParser.js +6 -1
  44. package/dist/docx/conformance.js +8 -1
  45. package/dist/docx/documentGrid.d.ts +8 -0
  46. package/dist/docx/documentGrid.js +8 -0
  47. package/dist/docx/drawingUtils.js +1 -1
  48. package/dist/docx/ensureParaIds.js +1 -1
  49. package/dist/docx/fieldParser.js +1 -1
  50. package/dist/docx/notePropertiesParser.js +1 -1
  51. package/dist/docx/numberingParser.js +1 -1
  52. package/dist/docx/paragraphParser.js +63 -58
  53. package/dist/docx/paragraphTextBoxEnrichment.d.ts +2 -1
  54. package/dist/docx/paragraphTextBoxEnrichment.js +67 -13
  55. package/dist/docx/paragraphTraversal.js +1 -1
  56. package/dist/docx/parser.js +3 -3
  57. package/dist/docx/rezip.js +1 -1
  58. package/dist/docx/runParser.js +4 -2
  59. package/dist/docx/sdtProperties.js +1 -1
  60. package/dist/docx/sectionParser.js +1 -1
  61. package/dist/docx/selectiveSave.js +1 -1
  62. package/dist/docx/serializer/commentSerializer.js +1 -2
  63. package/dist/docx/serializer/documentSerializer.js +2 -2
  64. package/dist/docx/serializer/headerFooterSerializer.js +2 -2
  65. package/dist/docx/serializer/noteSerializer.js +2 -2
  66. package/dist/docx/serializer/paragraphSerializer.js +7 -1
  67. package/dist/docx/serializer/runSerializer.js +4 -2
  68. package/dist/docx/serializer/stylesSerializer.js +1 -1
  69. package/dist/docx/serializer/tableSerializer.d.ts +5 -4
  70. package/dist/docx/serializer/tableSerializer.js +17 -13
  71. package/dist/docx/server/applyDocxXmlPatchProposal.d.ts +87 -0
  72. package/dist/docx/server/applyDocxXmlPatchProposal.js +204 -0
  73. package/dist/docx/server/boundedArchive.d.ts +14 -3
  74. package/dist/docx/server/boundedArchive.js +56 -11
  75. package/dist/docx/server/evaluateDocxXmlPatchProposal.d.ts +85 -0
  76. package/dist/docx/server/evaluateDocxXmlPatchProposal.js +361 -0
  77. package/dist/docx/server/inspectDocxPackage.d.ts +70 -0
  78. package/dist/docx/server/inspectDocxPackage.js +217 -0
  79. package/dist/docx/server/validateDocxConformance.d.ts +41 -0
  80. package/dist/docx/server/validateDocxConformance.js +336 -0
  81. package/dist/docx/settingsParser.js +11 -1
  82. package/dist/docx/shapeParser.js +1 -1
  83. package/dist/docx/styleParser.js +4 -2
  84. package/dist/docx/tableParser.js +18 -7
  85. package/dist/docx/textBoxParser.d.ts +3 -3
  86. package/dist/docx/textBoxParser.js +16 -12
  87. package/dist/docx/xmlSafety.d.ts +5 -0
  88. package/dist/docx/xmlSafety.js +9 -0
  89. package/dist/fields/resolveFieldValues.js +1 -3
  90. package/dist/i18n/messages/catalogs.gen.d.ts +17 -0
  91. package/dist/i18n/messages/catalogs.gen.js +17 -0
  92. package/dist/i18n/messages/messages.gen.d.ts +1 -0
  93. package/dist/index.js +1 -1
  94. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  95. package/dist/layout-bridge/convert/footnoteLayout.js +47 -40
  96. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  97. package/dist/layout-bridge/convert/headerFooterLayout.js +3 -0
  98. package/dist/layout-bridge/convert/templatePreviewFlow.js +3 -3
  99. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -2
  100. package/dist/layout-bridge/convert/toFlowBlocks.js +136 -20
  101. package/dist/layout-bridge/dom/noteStoryDom.d.ts +6 -0
  102. package/dist/layout-bridge/dom/noteStoryDom.js +17 -0
  103. package/dist/layout-bridge/engine/clickToPosition.js +2 -2
  104. package/dist/layout-engine/index.d.ts +2 -2
  105. package/dist/layout-engine/index.js +43 -28
  106. package/dist/layout-engine/justificationCompatibility.d.ts +6 -0
  107. package/dist/layout-engine/justificationCompatibility.js +8 -0
  108. package/dist/layout-engine/keep-together.js +11 -1
  109. package/dist/layout-engine/measure/cache.js +21 -5
  110. package/dist/layout-engine/measure/lineBreakProvider.js +53 -34
  111. package/dist/layout-engine/measure/measureBlocks.js +6 -3
  112. package/dist/layout-engine/measure/measureContainer.js +1 -1
  113. package/dist/layout-engine/measure/measureHelpers.d.ts +1 -1
  114. package/dist/layout-engine/measure/measureHelpers.js +3 -3
  115. package/dist/layout-engine/measure/measureParagraph.js +69 -25
  116. package/dist/layout-engine/measure/measureProvider.js +4 -3
  117. package/dist/layout-engine/measure/tableCellFlow.js +5 -2
  118. package/dist/layout-engine/measure/textBoxParagraphLayout.d.ts +9 -7
  119. package/dist/layout-engine/measure/textBoxParagraphLayout.js +22 -6
  120. package/dist/layout-engine/measure/textMeasurementPolicy.d.ts +3 -1
  121. package/dist/layout-engine/measure/textMeasurementPolicy.js +7 -1
  122. package/dist/layout-engine/paginator.js +5 -1
  123. package/dist/layout-engine/paragraphSpacing.d.ts +28 -4
  124. package/dist/layout-engine/paragraphSpacing.js +107 -13
  125. package/dist/layout-engine/renderedBreakReconciliation.js +1 -1
  126. package/dist/layout-engine/types.d.ts +26 -13
  127. package/dist/layout-painter/registry/modules/textBox.js +5 -1
  128. package/dist/layout-painter/renderPage.d.ts +5 -2
  129. package/dist/layout-painter/renderPage.js +56 -12
  130. package/dist/layout-painter/renderParagraph.js +22 -6
  131. package/dist/layout-painter/renderTable.d.ts +5 -1
  132. package/dist/layout-painter/renderTable.js +5 -2
  133. package/dist/layout-painter/renderTextBox.d.ts +2 -1
  134. package/dist/layout-painter/renderTextBox.js +25 -14
  135. package/dist/managers/DocumentLoaderManager.js +1 -1
  136. package/dist/managers/FindReplaceManager.d.ts +8 -0
  137. package/dist/managers/FindReplaceManager.js +18 -0
  138. package/dist/managers/TableSelectionManager.d.ts +6 -0
  139. package/dist/managers/TableSelectionManager.js +14 -0
  140. package/dist/model.js +1 -1
  141. package/dist/prosemirror/attrs/index.d.ts +4 -2
  142. package/dist/prosemirror/attrs/index.js +154 -18
  143. package/dist/prosemirror/commands/comments.d.ts +3 -3
  144. package/dist/prosemirror/commands/comments.js +248 -12
  145. package/dist/prosemirror/commands/contentControls.js +1 -1
  146. package/dist/prosemirror/commands/index.js +1 -1
  147. package/dist/prosemirror/commands/pageBreak.js +1 -1
  148. package/dist/prosemirror/commands/propertyChangeScope.d.ts +2 -2
  149. package/dist/prosemirror/commands/propertyChangeScope.js +3 -2
  150. package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +9 -0
  151. package/dist/prosemirror/commands/tableCellMergeResolution.js +181 -0
  152. package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -1
  153. package/dist/prosemirror/conversion/fromProseDoc.js +286 -61
  154. package/dist/prosemirror/conversion/sdtAttrs.d.ts +9 -0
  155. package/dist/prosemirror/conversion/sdtAttrs.js +49 -0
  156. package/dist/prosemirror/conversion/toProseDoc.d.ts +2 -1
  157. package/dist/prosemirror/conversion/toProseDoc.js +347 -98
  158. package/dist/prosemirror/extensions/ExtensionManager.js +1 -1
  159. package/dist/prosemirror/extensions/StarterKit.js +6 -1
  160. package/dist/prosemirror/extensions/core/ParagraphExtension.js +4 -1
  161. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +1 -0
  162. package/dist/prosemirror/extensions/features/ListExtension.js +1 -1
  163. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +10 -1
  164. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +93 -2
  165. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +2 -1
  166. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +6 -2
  167. package/dist/prosemirror/extensions/marks/CharacterSpacingExtension.js +1 -1
  168. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.d.ts +9 -1
  169. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +24 -1
  170. package/dist/prosemirror/extensions/nodes/FieldExtension.js +1 -1
  171. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.d.ts +7 -0
  172. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.js +22 -0
  173. package/dist/prosemirror/extensions/nodes/TableExtension.js +9 -3
  174. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +13 -0
  175. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +41 -0
  176. package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +5 -2
  177. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +4 -1
  178. package/dist/prosemirror/findReplaceSelection.d.ts +6 -1
  179. package/dist/prosemirror/findReplaceSelection.js +57 -13
  180. package/dist/prosemirror/plugins/contentControlWidgets.d.ts +34 -8
  181. package/dist/prosemirror/plugins/contentControlWidgets.js +125 -91
  182. package/dist/prosemirror/plugins/selectionTracker.js +1 -0
  183. package/dist/prosemirror/plugins/suggestionMode.js +1 -1
  184. package/dist/prosemirror/schema/index.d.ts +2 -2
  185. package/dist/prosemirror/schema/marks.d.ts +5 -1
  186. package/dist/prosemirror/schema/nodes.d.ts +64 -7
  187. package/dist/prosemirror/selectionState.js +1 -0
  188. package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
  189. package/dist/prosemirror/tableCellMergeRevision.d.ts +9 -0
  190. package/dist/prosemirror/tableCellMergeRevision.js +22 -0
  191. package/dist/prosemirror/textBoxAnchorAttrs.d.ts +9 -0
  192. package/dist/prosemirror/textBoxAnchorAttrs.js +33 -0
  193. package/dist/prosemirror/utils/extractTrackedChanges.d.ts +1 -1
  194. package/dist/prosemirror/utils/extractTrackedChanges.js +62 -14
  195. package/dist/prosemirror/validation.js +9 -1
  196. package/dist/render-dom/BodySelectionOverlay.d.ts +31 -0
  197. package/dist/render-dom/BodySelectionOverlay.js +76 -0
  198. package/dist/render-dom/HeaderFooterSelectionOverlay.d.ts +28 -0
  199. package/dist/render-dom/HeaderFooterSelectionOverlay.js +121 -0
  200. package/dist/render-dom/RemoteSelectionOverlay.d.ts +30 -0
  201. package/dist/render-dom/RemoteSelectionOverlay.js +67 -0
  202. package/dist/render-dom/RenderedDomContext.d.ts +40 -0
  203. package/dist/render-dom/RenderedDomContext.js +126 -0
  204. package/dist/render-dom/resolveSidebarItemPositions.d.ts +33 -0
  205. package/dist/render-dom/resolveSidebarItemPositions.js +45 -0
  206. package/dist/server.d.ts +6 -2
  207. package/dist/server.js +5 -1
  208. package/dist/utils/findReplace.d.ts +32 -0
  209. package/dist/utils/findReplace.js +118 -0
  210. package/dist/utils/fontFamilyMerge.js +9 -11
  211. package/dist/utils/fontLoader.js +3 -2
  212. package/dist/utils/fontResolver.js +22 -4
  213. package/dist/utils/fontWeights.d.ts +1 -1
  214. package/dist/utils/fontWeights.js +1 -1
  215. package/dist/utils/headerFooter.js +24 -1
  216. package/dist/utils/paragraphFormattingMerge.js +1 -0
  217. package/package.json +1 -1
@@ -1,6 +1,5 @@
1
1
  import { escapeXml, intAttr } from "./xmlUtils.js";
2
2
  import { serializeBorder } from "./borderSerializer.js";
3
- import { serializeParagraph } from "./paragraphSerializer.js";
4
3
  //#region src/docx/serializer/tableSerializer.ts
5
4
  function normalizeTrackedChangeInfo(info) {
6
5
  const normalizedId = Number.isInteger(info.id) && info.id >= 0 ? info.id : 0;
@@ -247,12 +246,17 @@ function serializeTableCellFormatting(formatting, propertyChanges, structuralCha
247
246
  if (formatting.textDirection) parts.push(`<w:textDirection w:val="${formatting.textDirection}"/>`);
248
247
  if (formatting.fitText) parts.push("<w:tcFitText/>");
249
248
  if (formatting.verticalAlign) parts.push(`<w:vAlign w:val="${formatting.verticalAlign}"/>`);
250
- if (formatting.hideMark) parts.push("<w:hideMark/>");
249
+ if (formatting.hideMark !== void 0) parts.push(formatting.hideMark ? "<w:hideMark/>" : "<w:hideMark w:val=\"false\"/>");
251
250
  }
252
251
  if (structuralChange) {
253
252
  if (structuralChange.type === "tableCellInsertion") parts.push(`<w:cellIns ${serializeTrackedChangeAttributes(structuralChange.info)}/>`);
254
253
  else if (structuralChange.type === "tableCellDeletion") parts.push(`<w:cellDel ${serializeTrackedChangeAttributes(structuralChange.info)}/>`);
255
- else if (structuralChange.type === "tableCellMerge") parts.push(`<w:cellMerge ${serializeTrackedChangeAttributes(structuralChange.info)}/>`);
254
+ else if (structuralChange.type === "tableCellMerge") {
255
+ const attrs = [serializeTrackedChangeAttributes(structuralChange.info)];
256
+ if (structuralChange.verticalMerge) attrs.push(`w:vMerge="${structuralChange.verticalMerge === "continue" ? "cont" : "rest"}"`);
257
+ if (structuralChange.verticalMergeOriginal) attrs.push(`w:vMergeOrig="${structuralChange.verticalMergeOriginal === "continue" ? "cont" : "rest"}"`);
258
+ parts.push(`<w:cellMerge ${attrs.join(" ")}/>`);
259
+ }
256
260
  }
257
261
  if (propertyChanges && propertyChanges.length > 0) parts.push(...propertyChanges.map((change) => serializeTableCellPropertyChange(change)));
258
262
  if (parts.length === 0) return "";
@@ -277,31 +281,31 @@ function serializeTableGrid(columnWidths) {
277
281
  /**
278
282
  * Serialize cell content (paragraphs, nested tables)
279
283
  */
280
- function serializeCellContent(content) {
284
+ function serializeCellContent(content, serializeParagraph) {
281
285
  const parts = [];
282
286
  for (const item of content) if (item.type === "paragraph") parts.push(serializeParagraph(item));
283
- else parts.push(serializeTable(item));
287
+ else parts.push(serializeTable(item, serializeParagraph));
284
288
  if (parts.length === 0) parts.push("<w:p/>");
285
289
  return parts.join("");
286
290
  }
287
291
  /**
288
292
  * Serialize a table cell (w:tc)
289
293
  */
290
- function serializeTableCell(cell) {
294
+ function serializeTableCell(cell, serializeParagraph) {
291
295
  const parts = [];
292
296
  const tcPrXml = serializeTableCellFormatting(cell.formatting, cell.propertyChanges, cell.structuralChange);
293
297
  if (tcPrXml) parts.push(tcPrXml);
294
- parts.push(serializeCellContent(cell.content));
298
+ parts.push(serializeCellContent(cell.content, serializeParagraph));
295
299
  return `<w:tc>${parts.join("")}</w:tc>`;
296
300
  }
297
301
  /**
298
302
  * Serialize a table row (w:tr)
299
303
  */
300
- function serializeTableRow(row) {
304
+ function serializeTableRow(row, serializeParagraph) {
301
305
  const parts = [];
302
306
  const trPrXml = serializeTableRowFormatting(row.formatting, row.propertyChanges, row.structuralChange);
303
307
  if (trPrXml) parts.push(trPrXml);
304
- for (const cell of row.cells) parts.push(serializeTableCell(cell));
308
+ for (const cell of row.cells) parts.push(serializeTableCell(cell, serializeParagraph));
305
309
  return `<w:tr>${parts.join("")}</w:tr>`;
306
310
  }
307
311
  /**
@@ -310,13 +314,13 @@ function serializeTableRow(row) {
310
314
  * @param table - The table to serialize
311
315
  * @returns XML string for the table
312
316
  */
313
- function serializeTable(table) {
317
+ function serializeTable(table, serializeParagraph) {
314
318
  const parts = [];
315
319
  const tblPrXml = serializeTableFormatting(table.formatting, table.propertyChanges);
316
320
  if (tblPrXml) parts.push(tblPrXml);
317
321
  const tblGridXml = serializeTableGrid(table.columnWidths);
318
322
  if (tblGridXml) parts.push(tblGridXml);
319
- for (const row of table.rows) parts.push(serializeTableRow(row));
323
+ for (const row of table.rows) parts.push(serializeTableRow(row, serializeParagraph));
320
324
  return `<w:tbl>${parts.join("")}</w:tbl>`;
321
325
  }
322
326
  /**
@@ -325,8 +329,8 @@ function serializeTable(table) {
325
329
  * @param tables - The tables to serialize
326
330
  * @returns XML string for all tables
327
331
  */
328
- function serializeTables(tables) {
329
- return tables.map(serializeTable).join("");
332
+ function serializeTables(tables, serializeParagraph) {
333
+ return tables.map((table) => serializeTable(table, serializeParagraph)).join("");
330
334
  }
331
335
  /**
332
336
  * Check if a table has any rows
@@ -0,0 +1,87 @@
1
+ import { DocxArchiveOptions } from "./boundedArchive.js";
2
+ import { FOLIO_DOCX_XML_PATCH_PROPOSAL_PROFILE, FolioDocxPreparedXmlReplacement, FolioDocxXmlPatchProposalEvaluation, FolioDocxXmlPatchProposalLimits } from "./evaluateDocxXmlPatchProposal.js";
3
+ import { FOLIO_DOCX_CONFORMANCE_PROFILE, FolioDocxConformanceReport } from "./validateDocxConformance.js";
4
+
5
+ //#region src/docx/server/applyDocxXmlPatchProposal.d.ts
6
+ declare const FOLIO_DOCX_XML_PATCH_APPLICATION_VERSION: 1;
7
+ declare const FOLIO_DOCX_XML_PATCH_APPLICATION_PROFILE: "folio-xml-patch-application-v1";
8
+ type ApplyDocxXmlPatchProposalArgs = {
9
+ readonly bytes: ArrayBuffer | Uint8Array;
10
+ readonly proposal: unknown; /** Exact package paths authorized by the server-side caller. */
11
+ readonly allowedParts: readonly string[];
12
+ readonly validationProfile: typeof FOLIO_DOCX_CONFORMANCE_PROFILE;
13
+ readonly archive?: DocxArchiveOptions;
14
+ readonly limits?: FolioDocxXmlPatchProposalLimits;
15
+ };
16
+ type FolioDocxXmlPatchApplicationReceipt = {
17
+ readonly version: typeof FOLIO_DOCX_XML_PATCH_APPLICATION_VERSION;
18
+ readonly profile: typeof FOLIO_DOCX_XML_PATCH_APPLICATION_PROFILE;
19
+ readonly proposalProfile: typeof FOLIO_DOCX_XML_PATCH_PROPOSAL_PROFILE;
20
+ readonly validationProfile: typeof FOLIO_DOCX_CONFORMANCE_PROFILE;
21
+ readonly input: {
22
+ readonly sha256: string;
23
+ readonly byteLength: number;
24
+ };
25
+ readonly output: {
26
+ readonly sha256: string;
27
+ readonly byteLength: number;
28
+ };
29
+ readonly replacements: readonly [FolioDocxPreparedXmlReplacement, ...FolioDocxPreparedXmlReplacement[]];
30
+ };
31
+ type FolioDocxXmlPatchApplication = {
32
+ readonly version: typeof FOLIO_DOCX_XML_PATCH_APPLICATION_VERSION;
33
+ readonly profile: typeof FOLIO_DOCX_XML_PATCH_APPLICATION_PROFILE;
34
+ readonly status: "proposal-rejected";
35
+ readonly producesOutput: false;
36
+ readonly evaluation: Extract<FolioDocxXmlPatchProposalEvaluation, {
37
+ status: "rejected";
38
+ }>;
39
+ readonly conformance: null;
40
+ readonly receipt: null;
41
+ } | {
42
+ readonly version: typeof FOLIO_DOCX_XML_PATCH_APPLICATION_VERSION;
43
+ readonly profile: typeof FOLIO_DOCX_XML_PATCH_APPLICATION_PROFILE;
44
+ readonly status: "output-rejected";
45
+ readonly producesOutput: false;
46
+ readonly evaluation: Extract<FolioDocxXmlPatchProposalEvaluation, {
47
+ status: "accepted";
48
+ }>;
49
+ readonly conformance: FolioDocxConformanceReport;
50
+ readonly receipt: null;
51
+ } | {
52
+ readonly version: typeof FOLIO_DOCX_XML_PATCH_APPLICATION_VERSION;
53
+ readonly profile: typeof FOLIO_DOCX_XML_PATCH_APPLICATION_PROFILE;
54
+ readonly status: "applied";
55
+ readonly producesOutput: true;
56
+ readonly evaluation: Extract<FolioDocxXmlPatchProposalEvaluation, {
57
+ status: "accepted";
58
+ }>;
59
+ readonly conformance: FolioDocxConformanceReport & {
60
+ readonly status: "conformant";
61
+ };
62
+ readonly receipt: FolioDocxXmlPatchApplicationReceipt;
63
+ readonly bytes: Uint8Array;
64
+ };
65
+ declare const UnsupportedFolioDocxXmlPatchApplicationProfileError_base: import("better-result").TaggedErrorClass<"UnsupportedFolioDocxXmlPatchApplicationProfileError", {
66
+ message: string;
67
+ profile: unknown;
68
+ }>;
69
+ declare class UnsupportedFolioDocxXmlPatchApplicationProfileError extends UnsupportedFolioDocxXmlPatchApplicationProfileError_base {}
70
+ declare const FolioDocxXmlPatchApplicationError_base: import("better-result").TaggedErrorClass<"FolioDocxXmlPatchApplicationError", {
71
+ message: string;
72
+ stage: "verify" | "load" | "replace" | "generate";
73
+ part?: string;
74
+ cause?: unknown;
75
+ }>;
76
+ declare class FolioDocxXmlPatchApplicationError extends FolioDocxXmlPatchApplicationError_base {}
77
+ /** Apply a guarded XML proposal and return output only after full profile validation. */
78
+ declare const applyDocxXmlPatchProposal: ({
79
+ bytes,
80
+ proposal: rawProposal,
81
+ allowedParts,
82
+ validationProfile,
83
+ archive,
84
+ limits
85
+ }: ApplyDocxXmlPatchProposalArgs) => Promise<FolioDocxXmlPatchApplication>;
86
+ //#endregion
87
+ export { ApplyDocxXmlPatchProposalArgs, FOLIO_DOCX_XML_PATCH_APPLICATION_PROFILE, FOLIO_DOCX_XML_PATCH_APPLICATION_VERSION, FolioDocxXmlPatchApplication, FolioDocxXmlPatchApplicationError, FolioDocxXmlPatchApplicationReceipt, UnsupportedFolioDocxXmlPatchApplicationProfileError, applyDocxXmlPatchProposal };
@@ -0,0 +1,204 @@
1
+ import { loadDocxArchive } from "./boundedArchive.js";
2
+ import { FOLIO_DOCX_XML_PATCH_PROPOSAL_PROFILE, InvalidFolioDocxXmlPatchProposalError, evaluateDocxXmlPatchProposal, parseFolioDocxXmlPatchProposal } from "./evaluateDocxXmlPatchProposal.js";
3
+ import { FOLIO_DOCX_CONFORMANCE_PROFILE, validateDocxConformance } from "./validateDocxConformance.js";
4
+ import { TaggedError, panic } from "better-result";
5
+ import JSZip from "jszip";
6
+ import { createHash } from "node:crypto";
7
+ //#region src/docx/server/applyDocxXmlPatchProposal.ts
8
+ const FOLIO_DOCX_XML_PATCH_APPLICATION_VERSION = 1;
9
+ const FOLIO_DOCX_XML_PATCH_APPLICATION_PROFILE = "folio-xml-patch-application-v1";
10
+ const isConformantReport = (report) => report.status === "conformant";
11
+ var UnsupportedFolioDocxXmlPatchApplicationProfileError = class extends TaggedError("UnsupportedFolioDocxXmlPatchApplicationProfileError")() {};
12
+ var FolioDocxXmlPatchApplicationError = class extends TaggedError("FolioDocxXmlPatchApplicationError")() {};
13
+ const sha256 = (bytes) => createHash("sha256").update(bytes).digest("hex");
14
+ const snapshotInput = (bytes) => Uint8Array.from(bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes));
15
+ const snapshotArchiveOptions = (archive) => {
16
+ if (archive === void 0) return;
17
+ return {
18
+ ...archive.maxInputBytes === void 0 ? {} : { maxInputBytes: archive.maxInputBytes },
19
+ ...archive.maxEntryBytes === void 0 ? {} : { maxEntryBytes: archive.maxEntryBytes },
20
+ ...archive.maxTotalBytes === void 0 ? {} : { maxTotalBytes: archive.maxTotalBytes },
21
+ ...archive.maxEntries === void 0 ? {} : { maxEntries: archive.maxEntries }
22
+ };
23
+ };
24
+ const snapshotProposalLimits = (limits) => {
25
+ if (limits === void 0) return;
26
+ return {
27
+ ...limits.maxReplacements === void 0 ? {} : { maxReplacements: limits.maxReplacements },
28
+ ...limits.maxPartBytes === void 0 ? {} : { maxPartBytes: limits.maxPartBytes },
29
+ ...limits.maxTotalBytes === void 0 ? {} : { maxTotalBytes: limits.maxTotalBytes }
30
+ };
31
+ };
32
+ const evaluateProposal = async ({ bytes, proposal, allowedParts, archive, limits }) => await evaluateDocxXmlPatchProposal({
33
+ bytes,
34
+ proposal,
35
+ allowedParts,
36
+ ...archive === void 0 ? {} : { archive },
37
+ ...limits === void 0 ? {} : { limits }
38
+ });
39
+ const proposalRejected = ({ evaluation }) => ({
40
+ version: 1,
41
+ profile: FOLIO_DOCX_XML_PATCH_APPLICATION_PROFILE,
42
+ status: "proposal-rejected",
43
+ producesOutput: false,
44
+ evaluation,
45
+ conformance: null,
46
+ receipt: null
47
+ });
48
+ const verifyArchiveContents = async (bytes, options) => {
49
+ let archive;
50
+ try {
51
+ archive = await loadDocxArchive(bytes, options);
52
+ } catch (cause) {
53
+ throw new FolioDocxXmlPatchApplicationError({
54
+ message: "The evaluated package could not be verified within the archive limits.",
55
+ stage: "verify",
56
+ cause
57
+ });
58
+ }
59
+ for (const entry of archive.entryMetadata.toSorted(({ path: left }, { path: right }) => left < right ? -1 : Number(left > right))) {
60
+ if (entry.directory) continue;
61
+ try {
62
+ if (await archive.readEntryUint8(entry.path) === null) throw new FolioDocxXmlPatchApplicationError({
63
+ message: "An archive entry disappeared during verification.",
64
+ stage: "verify",
65
+ part: entry.path
66
+ });
67
+ } catch (cause) {
68
+ if (cause instanceof FolioDocxXmlPatchApplicationError) throw cause;
69
+ throw new FolioDocxXmlPatchApplicationError({
70
+ message: "An archive entry could not be verified within the configured limits.",
71
+ stage: "verify",
72
+ part: entry.path,
73
+ cause
74
+ });
75
+ }
76
+ }
77
+ };
78
+ const applyReplacements = async ({ bytes, proposal }) => {
79
+ let zip;
80
+ try {
81
+ zip = await JSZip.loadAsync(bytes);
82
+ } catch (cause) {
83
+ throw new FolioDocxXmlPatchApplicationError({
84
+ message: "The evaluated package could not be loaded for replacement.",
85
+ stage: "load",
86
+ cause
87
+ });
88
+ }
89
+ for (const replacement of proposal.replacements) {
90
+ const current = zip.file(replacement.path);
91
+ if (current === null) throw new FolioDocxXmlPatchApplicationError({
92
+ message: "An evaluated package part was unavailable during replacement.",
93
+ stage: "replace"
94
+ });
95
+ zip.file(replacement.path, new TextEncoder().encode(replacement.replacementXml), {
96
+ binary: true,
97
+ date: current.date,
98
+ comment: current.comment,
99
+ createFolders: false,
100
+ unixPermissions: current.unixPermissions,
101
+ dosPermissions: current.dosPermissions,
102
+ compression: "DEFLATE",
103
+ compressionOptions: { level: 6 }
104
+ });
105
+ }
106
+ try {
107
+ return await zip.generateAsync({
108
+ type: "uint8array",
109
+ compression: "DEFLATE",
110
+ compressionOptions: { level: 6 }
111
+ });
112
+ } catch (cause) {
113
+ throw new FolioDocxXmlPatchApplicationError({
114
+ message: "The replacement package could not be generated.",
115
+ stage: "generate",
116
+ cause
117
+ });
118
+ }
119
+ };
120
+ const outputRejected = ({ evaluation, conformance }) => ({
121
+ version: 1,
122
+ profile: FOLIO_DOCX_XML_PATCH_APPLICATION_PROFILE,
123
+ status: "output-rejected",
124
+ producesOutput: false,
125
+ evaluation,
126
+ conformance,
127
+ receipt: null
128
+ });
129
+ const applied = ({ input, output, evaluation, conformance }) => ({
130
+ version: 1,
131
+ profile: FOLIO_DOCX_XML_PATCH_APPLICATION_PROFILE,
132
+ status: "applied",
133
+ producesOutput: true,
134
+ evaluation,
135
+ conformance,
136
+ receipt: {
137
+ version: 1,
138
+ profile: FOLIO_DOCX_XML_PATCH_APPLICATION_PROFILE,
139
+ proposalProfile: FOLIO_DOCX_XML_PATCH_PROPOSAL_PROFILE,
140
+ validationProfile: FOLIO_DOCX_CONFORMANCE_PROFILE,
141
+ input: {
142
+ sha256: sha256(input),
143
+ byteLength: input.byteLength
144
+ },
145
+ output: {
146
+ sha256: sha256(output),
147
+ byteLength: output.byteLength
148
+ },
149
+ replacements: evaluation.replacements
150
+ },
151
+ bytes: output
152
+ });
153
+ /** Apply a guarded XML proposal and return output only after full profile validation. */
154
+ const applyDocxXmlPatchProposal = async ({ bytes, proposal: rawProposal, allowedParts, validationProfile, archive, limits }) => {
155
+ if (validationProfile !== "folio-supported-v1") throw new UnsupportedFolioDocxXmlPatchApplicationProfileError({
156
+ message: "The requested package validation profile is not supported.",
157
+ profile: validationProfile
158
+ });
159
+ const input = snapshotInput(bytes);
160
+ const policyAllowedParts = [...allowedParts];
161
+ const policyArchive = snapshotArchiveOptions(archive);
162
+ const policyLimits = snapshotProposalLimits(limits);
163
+ let proposal;
164
+ try {
165
+ proposal = parseFolioDocxXmlPatchProposal(rawProposal);
166
+ } catch (error) {
167
+ if (!(error instanceof InvalidFolioDocxXmlPatchProposalError)) throw error;
168
+ const evaluation = await evaluateProposal({
169
+ bytes: input,
170
+ proposal: rawProposal,
171
+ allowedParts: policyAllowedParts,
172
+ archive: policyArchive,
173
+ limits: policyLimits
174
+ });
175
+ if (evaluation.status !== "rejected") return panic("An invalid XML proposal produced an accepted evaluation");
176
+ return proposalRejected({ evaluation });
177
+ }
178
+ const evaluation = await evaluateProposal({
179
+ bytes: input,
180
+ proposal,
181
+ allowedParts: policyAllowedParts,
182
+ archive: policyArchive,
183
+ limits: policyLimits
184
+ });
185
+ if (evaluation.status === "rejected") return proposalRejected({ evaluation });
186
+ await verifyArchiveContents(input, policyArchive);
187
+ const output = await applyReplacements({
188
+ bytes: input,
189
+ proposal
190
+ });
191
+ const conformance = await validateDocxConformance(output, { ...policyArchive === void 0 ? {} : { archive: policyArchive } });
192
+ if (!isConformantReport(conformance)) return outputRejected({
193
+ evaluation,
194
+ conformance
195
+ });
196
+ return applied({
197
+ input,
198
+ output,
199
+ evaluation,
200
+ conformance
201
+ });
202
+ };
203
+ //#endregion
204
+ export { FOLIO_DOCX_XML_PATCH_APPLICATION_PROFILE, FOLIO_DOCX_XML_PATCH_APPLICATION_VERSION, FolioDocxXmlPatchApplicationError, UnsupportedFolioDocxXmlPatchApplicationProfileError, applyDocxXmlPatchProposal };
@@ -2,23 +2,34 @@
2
2
  declare const DOCX_MAX_ENTRY_BYTES: number;
3
3
  declare const DOCX_MAX_TOTAL_BYTES: number;
4
4
  declare const DOCX_MAX_ENTRIES = 4096;
5
+ declare const DOCX_MAX_INPUT_BYTES: number;
5
6
  declare const DocxArchiveError_base: import("better-result").TaggedErrorClass<"DocxArchiveError", {
6
7
  message: string;
7
- reason: "load-failed" | "too-many-entries" | "entry-too-large" | "total-too-large";
8
+ reason: "load-failed" | "input-too-large" | "too-many-entries" | "entry-too-large" | "total-too-large" | "invalid-options";
8
9
  cause?: unknown;
9
10
  }>;
10
11
  /** Error raised when a DOCX archive cannot be loaded within configured limits. */
11
12
  declare class DocxArchiveError extends DocxArchiveError_base {}
12
13
  type DocxArchiveOptions = {
14
+ maxInputBytes?: number;
13
15
  maxEntryBytes?: number;
14
16
  maxTotalBytes?: number;
15
17
  maxEntries?: number;
16
18
  };
19
+ type DocxArchiveEntry = {
20
+ readonly path: string;
21
+ readonly directory: boolean;
22
+ readonly declaredUncompressedBytes: number | null;
23
+ };
24
+ type DocxArchiveReadOptions = {
25
+ maxBytes?: number;
26
+ };
17
27
  type DocxArchive = {
18
28
  entries: readonly string[];
29
+ entryMetadata: readonly DocxArchiveEntry[];
19
30
  readEntryString: (path: string) => Promise<string | null>;
20
- readEntryUint8: (path: string) => Promise<Uint8Array | null>;
31
+ readEntryUint8: (path: string, options?: DocxArchiveReadOptions) => Promise<Uint8Array | null>;
21
32
  };
22
33
  declare const loadDocxArchive: (bytes: ArrayBuffer | Uint8Array, options?: DocxArchiveOptions) => Promise<DocxArchive>;
23
34
  //#endregion
24
- export { DOCX_MAX_ENTRIES, DOCX_MAX_ENTRY_BYTES, DOCX_MAX_TOTAL_BYTES, DocxArchive, DocxArchiveError, DocxArchiveOptions, loadDocxArchive };
35
+ export { DOCX_MAX_ENTRIES, DOCX_MAX_ENTRY_BYTES, DOCX_MAX_INPUT_BYTES, DOCX_MAX_TOTAL_BYTES, DocxArchive, DocxArchiveEntry, DocxArchiveError, DocxArchiveOptions, DocxArchiveReadOptions, loadDocxArchive };
@@ -4,6 +4,7 @@ import JSZip from "jszip";
4
4
  const DOCX_MAX_ENTRY_BYTES = 128 * 1024 * 1024;
5
5
  const DOCX_MAX_TOTAL_BYTES = 256 * 1024 * 1024;
6
6
  const DOCX_MAX_ENTRIES = 4096;
7
+ const DOCX_MAX_INPUT_BYTES = 50 * 1024 * 1024;
7
8
  /** Error raised when a DOCX archive cannot be loaded within configured limits. */
8
9
  var DocxArchiveError = class extends TaggedError("DocxArchiveError")() {};
9
10
  const collectStream = async ({ stream, maxEntryBytes, remainingBytes, maxTotalBytes, path }) => await new Promise((resolve, reject) => {
@@ -33,10 +34,44 @@ const collectStream = async ({ stream, maxEntryBytes, remainingBytes, maxTotalBy
33
34
  stream.on("end", () => resolve(Buffer.concat(chunks)));
34
35
  stream.on("error", reject);
35
36
  });
37
+ const getDeclaredUncompressedBytes = (entry) => {
38
+ const data = "_data" in entry ? entry._data : void 0;
39
+ const declaredBytes = typeof data === "object" && data !== null && "uncompressedSize" in data ? data.uncompressedSize : void 0;
40
+ return typeof declaredBytes === "number" && Number.isFinite(declaredBytes) ? declaredBytes : null;
41
+ };
42
+ const resolveByteLimit = ({ value, fallback, name }) => {
43
+ const limit = value ?? fallback;
44
+ if (!Number.isSafeInteger(limit) || limit < 0) throw new DocxArchiveError({
45
+ message: `${name} must be a non-negative safe integer`,
46
+ reason: "invalid-options"
47
+ });
48
+ return limit;
49
+ };
36
50
  const loadDocxArchive = async (bytes, options = {}) => {
37
- const maxEntryBytes = options.maxEntryBytes ?? 134217728;
38
- const maxTotalBytes = options.maxTotalBytes ?? 268435456;
39
- const maxEntries = options.maxEntries ?? 4096;
51
+ const maxInputBytes = resolveByteLimit({
52
+ value: options.maxInputBytes,
53
+ fallback: DOCX_MAX_INPUT_BYTES,
54
+ name: "DOCX input byte limit"
55
+ });
56
+ const maxEntryBytes = resolveByteLimit({
57
+ value: options.maxEntryBytes,
58
+ fallback: DOCX_MAX_ENTRY_BYTES,
59
+ name: "DOCX entry byte limit"
60
+ });
61
+ const maxTotalBytes = resolveByteLimit({
62
+ value: options.maxTotalBytes,
63
+ fallback: DOCX_MAX_TOTAL_BYTES,
64
+ name: "DOCX cumulative byte limit"
65
+ });
66
+ const maxEntries = resolveByteLimit({
67
+ value: options.maxEntries,
68
+ fallback: DOCX_MAX_ENTRIES,
69
+ name: "DOCX entry limit"
70
+ });
71
+ if (bytes.byteLength > maxInputBytes) throw new DocxArchiveError({
72
+ message: `DOCX input contains ${bytes.byteLength} bytes (max ${maxInputBytes})`,
73
+ reason: "input-too-large"
74
+ });
40
75
  let zip;
41
76
  try {
42
77
  zip = await JSZip.loadAsync(bytes);
@@ -54,9 +89,9 @@ const loadDocxArchive = async (bytes, options = {}) => {
54
89
  });
55
90
  let declaredTotalBytes = 0;
56
91
  for (const entry of archiveEntries) {
57
- const data = "_data" in entry ? entry._data : void 0;
58
- const declaredBytes = typeof data === "object" && data !== null && "uncompressedSize" in data ? data.uncompressedSize : void 0;
59
- if (typeof declaredBytes !== "number" || !Number.isFinite(declaredBytes)) {
92
+ if (entry.dir) continue;
93
+ const declaredBytes = getDeclaredUncompressedBytes(entry);
94
+ if (declaredBytes === null) {
60
95
  declaredTotalBytes = NaN;
61
96
  break;
62
97
  }
@@ -72,13 +107,18 @@ const loadDocxArchive = async (bytes, options = {}) => {
72
107
  });
73
108
  let totalBytesRead = 0;
74
109
  let readChain = Promise.resolve();
75
- const readEntry = async (path) => {
110
+ const readEntry = async (path, readOptions = {}) => {
111
+ const requestedMaxBytes = resolveByteLimit({
112
+ value: readOptions.maxBytes,
113
+ fallback: maxEntryBytes,
114
+ name: "DOCX entry read byte limit"
115
+ });
76
116
  const work = async () => {
77
117
  const entry = zip.file(path);
78
118
  if (!entry) return null;
79
119
  const buffer = await collectStream({
80
120
  stream: entry.nodeStream("nodebuffer"),
81
- maxEntryBytes,
121
+ maxEntryBytes: Math.min(requestedMaxBytes, maxEntryBytes),
82
122
  remainingBytes: maxTotalBytes - totalBytesRead,
83
123
  maxTotalBytes,
84
124
  path
@@ -92,15 +132,20 @@ const loadDocxArchive = async (bytes, options = {}) => {
92
132
  };
93
133
  return {
94
134
  entries: Object.freeze(archiveEntries.map(({ name }) => name)),
135
+ entryMetadata: Object.freeze(archiveEntries.map((entry) => ({
136
+ path: entry.name,
137
+ directory: entry.dir,
138
+ declaredUncompressedBytes: getDeclaredUncompressedBytes(entry)
139
+ }))),
95
140
  async readEntryString(path) {
96
141
  const buffer = await readEntry(path);
97
142
  return buffer === null ? null : buffer.toString("utf-8");
98
143
  },
99
- async readEntryUint8(path) {
100
- const buffer = await readEntry(path);
144
+ async readEntryUint8(path, readOptions) {
145
+ const buffer = await readEntry(path, readOptions);
101
146
  return buffer === null ? null : new Uint8Array(buffer);
102
147
  }
103
148
  };
104
149
  };
105
150
  //#endregion
106
- export { DOCX_MAX_ENTRIES, DOCX_MAX_ENTRY_BYTES, DOCX_MAX_TOTAL_BYTES, DocxArchiveError, loadDocxArchive };
151
+ export { DOCX_MAX_ENTRIES, DOCX_MAX_ENTRY_BYTES, DOCX_MAX_INPUT_BYTES, DOCX_MAX_TOTAL_BYTES, DocxArchiveError, loadDocxArchive };
@@ -0,0 +1,85 @@
1
+ import { DocxArchiveOptions } from "./boundedArchive.js";
2
+
3
+ //#region src/docx/server/evaluateDocxXmlPatchProposal.d.ts
4
+ declare const FOLIO_DOCX_XML_PATCH_PROPOSAL_VERSION: 1;
5
+ declare const FOLIO_DOCX_XML_PATCH_PROPOSAL_PROFILE: "folio-xml-patch-proposal-v1";
6
+ declare const FOLIO_DOCX_XML_PATCH_PROPOSAL_DEFAULTS: Readonly<{
7
+ readonly maxReplacements: 16;
8
+ readonly maxPartBytes: number;
9
+ readonly maxTotalBytes: number;
10
+ }>;
11
+ declare const FOLIO_DOCX_XML_PATCH_PROPOSAL_ISSUE_CODES: readonly ["invalid-proposal", "unsupported-version", "too-many-replacements", "duplicate-part", "invalid-part-path", "invalid-base-sha256", "part-not-allowed", "part-not-found", "part-not-xml", "replacement-too-large", "replacements-too-large", "xml-doctype-forbidden", "xml-not-well-formed", "xml-encoding-mismatch", "base-hash-mismatch", "package-inspection-failed"];
12
+ type FolioDocxXmlPatchProposalIssueCode = (typeof FOLIO_DOCX_XML_PATCH_PROPOSAL_ISSUE_CODES)[number];
13
+ type FolioDocxXmlReplacement = {
14
+ readonly path: string;
15
+ readonly baseSha256: string;
16
+ readonly replacementXml: string;
17
+ };
18
+ type FolioDocxXmlPatchProposal = {
19
+ readonly version: typeof FOLIO_DOCX_XML_PATCH_PROPOSAL_VERSION;
20
+ readonly replacements: readonly [FolioDocxXmlReplacement, ...FolioDocxXmlReplacement[]];
21
+ };
22
+ type FolioDocxXmlPatchProposalLimits = {
23
+ readonly maxReplacements?: number;
24
+ readonly maxPartBytes?: number;
25
+ readonly maxTotalBytes?: number;
26
+ };
27
+ type EvaluateDocxXmlPatchProposalArgs = {
28
+ readonly bytes: ArrayBuffer | Uint8Array;
29
+ readonly proposal: unknown; /** Exact package paths authorized by the server-side caller. */
30
+ readonly allowedParts: readonly string[];
31
+ readonly archive?: DocxArchiveOptions;
32
+ readonly limits?: FolioDocxXmlPatchProposalLimits;
33
+ };
34
+ type FolioDocxXmlPatchProposalIssue = {
35
+ readonly code: FolioDocxXmlPatchProposalIssueCode;
36
+ readonly message: string;
37
+ readonly proposalPath?: string;
38
+ readonly part?: string;
39
+ };
40
+ type FolioDocxPreparedXmlReplacement = {
41
+ readonly path: string;
42
+ readonly baseSha256: string;
43
+ readonly currentSha256: string;
44
+ readonly replacementSha256: string;
45
+ readonly replacementByteLength: number;
46
+ readonly encoding: "utf-8";
47
+ };
48
+ type FolioDocxXmlPatchProposalEvaluation = {
49
+ readonly version: typeof FOLIO_DOCX_XML_PATCH_PROPOSAL_VERSION;
50
+ readonly profile: typeof FOLIO_DOCX_XML_PATCH_PROPOSAL_PROFILE;
51
+ readonly status: "accepted";
52
+ readonly producesOutput: false;
53
+ readonly issues: readonly [];
54
+ readonly replacements: readonly [FolioDocxPreparedXmlReplacement, ...FolioDocxPreparedXmlReplacement[]];
55
+ readonly limits: Required<FolioDocxXmlPatchProposalLimits>;
56
+ } | {
57
+ readonly version: typeof FOLIO_DOCX_XML_PATCH_PROPOSAL_VERSION;
58
+ readonly profile: typeof FOLIO_DOCX_XML_PATCH_PROPOSAL_PROFILE;
59
+ readonly status: "rejected";
60
+ readonly producesOutput: false;
61
+ readonly issues: readonly [FolioDocxXmlPatchProposalIssue, ...FolioDocxXmlPatchProposalIssue[]];
62
+ readonly replacements: readonly [];
63
+ readonly limits: Required<FolioDocxXmlPatchProposalLimits>;
64
+ };
65
+ declare const InvalidFolioDocxXmlPatchProposalError_base: import("better-result").TaggedErrorClass<"InvalidFolioDocxXmlPatchProposalError", {
66
+ message: string;
67
+ path: string;
68
+ reason: string;
69
+ }>;
70
+ declare class InvalidFolioDocxXmlPatchProposalError extends InvalidFolioDocxXmlPatchProposalError_base {}
71
+ declare const InvalidFolioDocxXmlPatchProposalOptionsError_base: import("better-result").TaggedErrorClass<"InvalidFolioDocxXmlPatchProposalOptionsError", {
72
+ message: string;
73
+ path: string;
74
+ }>;
75
+ declare class InvalidFolioDocxXmlPatchProposalOptionsError extends InvalidFolioDocxXmlPatchProposalOptionsError_base {}
76
+ declare const parseFolioDocxXmlPatchProposal: (value: unknown) => FolioDocxXmlPatchProposal;
77
+ declare const evaluateDocxXmlPatchProposal: ({
78
+ bytes,
79
+ proposal: rawProposal,
80
+ allowedParts,
81
+ archive,
82
+ limits: rawLimits
83
+ }: EvaluateDocxXmlPatchProposalArgs) => Promise<FolioDocxXmlPatchProposalEvaluation>;
84
+ //#endregion
85
+ export { EvaluateDocxXmlPatchProposalArgs, FOLIO_DOCX_XML_PATCH_PROPOSAL_DEFAULTS, FOLIO_DOCX_XML_PATCH_PROPOSAL_ISSUE_CODES, FOLIO_DOCX_XML_PATCH_PROPOSAL_PROFILE, FOLIO_DOCX_XML_PATCH_PROPOSAL_VERSION, FolioDocxPreparedXmlReplacement, FolioDocxXmlPatchProposal, FolioDocxXmlPatchProposalEvaluation, FolioDocxXmlPatchProposalIssue, FolioDocxXmlPatchProposalIssueCode, FolioDocxXmlPatchProposalLimits, FolioDocxXmlReplacement, InvalidFolioDocxXmlPatchProposalError, InvalidFolioDocxXmlPatchProposalOptionsError, evaluateDocxXmlPatchProposal, parseFolioDocxXmlPatchProposal };