@stll/folio-core 0.11.0 → 0.13.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 (263) hide show
  1. package/dist/ai-edits/apply.d.ts +2 -1
  2. package/dist/ai-edits/apply.js +693 -63
  3. package/dist/ai-edits/block-identity.d.ts +4 -0
  4. package/dist/ai-edits/block-identity.js +9 -0
  5. package/dist/ai-edits/blockRange.d.ts +28 -1
  6. package/dist/ai-edits/blockRange.js +68 -2
  7. package/dist/ai-edits/clean-text.js +2 -1
  8. package/dist/ai-edits/headless.d.ts +4 -4
  9. package/dist/ai-edits/headless.js +9 -9
  10. package/dist/ai-edits/index.d.ts +2 -2
  11. package/dist/ai-edits/index.js +2 -2
  12. package/dist/ai-edits/read.d.ts +7 -7
  13. package/dist/ai-edits/read.js +110 -3
  14. package/dist/ai-edits/snapshot.js +21 -3
  15. package/dist/ai-edits/table-cell-mutations.d.ts +48 -0
  16. package/dist/ai-edits/table-cell-mutations.js +238 -0
  17. package/dist/ai-edits/table-mutation-plan.d.ts +38 -0
  18. package/dist/ai-edits/table-mutation-plan.js +90 -0
  19. package/dist/ai-edits/table-row-column-mutations.d.ts +108 -0
  20. package/dist/ai-edits/table-row-column-mutations.js +300 -0
  21. package/dist/ai-edits/table-targets.d.ts +32 -0
  22. package/dist/ai-edits/table-targets.js +70 -0
  23. package/dist/ai-edits/types.d.ts +62 -1
  24. package/dist/ai-edits/word-diff.js +21 -0
  25. package/dist/compat/eigenpal.d.ts +3 -3
  26. package/dist/compat/eigenpal.js +3 -3
  27. package/dist/content-controls/mutateContentControls.js +1 -1
  28. package/dist/controller/activeEditorStory.d.ts +36 -0
  29. package/dist/controller/activeEditorStory.js +30 -0
  30. package/dist/controller/contentControlWidgetController.d.ts +55 -0
  31. package/dist/controller/contentControlWidgetController.js +141 -0
  32. package/dist/controller/fontReadiness.js +2 -0
  33. package/dist/controller/headerFooterEditorManager.js +2 -2
  34. package/dist/controller/hiddenEditorApi.js +2 -2
  35. package/dist/controller/hiddenEditorManager.d.ts +12 -1
  36. package/dist/controller/hiddenEditorManager.js +44 -12
  37. package/dist/controller/layoutPipeline.d.ts +2 -0
  38. package/dist/controller/layoutPipeline.js +17 -2
  39. package/dist/controller/noteEditorManager.d.ts +36 -0
  40. package/dist/controller/noteEditorManager.js +210 -0
  41. package/dist/document-operations.d.ts +43 -11
  42. package/dist/document-operations.js +186 -18
  43. package/dist/docx/blockContentParser.js +21 -7
  44. package/dist/docx/commentParser.js +6 -1
  45. package/dist/docx/commentRangeIntegrity.d.ts +6 -0
  46. package/dist/docx/commentRangeIntegrity.js +186 -0
  47. package/dist/docx/conformance.js +62 -1
  48. package/dist/docx/documentGrid.d.ts +8 -0
  49. package/dist/docx/documentGrid.js +8 -0
  50. package/dist/docx/drawingUtils.js +1 -1
  51. package/dist/docx/encryption/agileDecryption.js +12 -2
  52. package/dist/docx/encryption/compoundFile.js +6 -1
  53. package/dist/docx/encryption/encryptionInfo.d.ts +9 -1
  54. package/dist/docx/encryption/encryptionInfo.js +18 -2
  55. package/dist/docx/encryption/openEncryptedDocx.js +1 -1
  56. package/dist/docx/ensureParaIds.js +8 -7
  57. package/dist/docx/fieldParser.js +1 -1
  58. package/dist/docx/groupDrawingParser.js +10 -5
  59. package/dist/docx/hyperlinkParser.js +1 -1
  60. package/dist/docx/imageParser.js +10 -6
  61. package/dist/docx/metadataPrivacy.js +17 -3
  62. package/dist/docx/notePropertiesParser.js +1 -1
  63. package/dist/docx/numberingParser.js +1 -1
  64. package/dist/docx/paragraphParser.js +70 -61
  65. package/dist/docx/paragraphTextBoxEnrichment.d.ts +2 -1
  66. package/dist/docx/paragraphTextBoxEnrichment.js +67 -13
  67. package/dist/docx/paragraphTraversal.js +1 -1
  68. package/dist/docx/parser.js +3 -3
  69. package/dist/docx/rezip.js +20 -9
  70. package/dist/docx/runParser.js +17 -6
  71. package/dist/docx/sdtProperties.js +1 -1
  72. package/dist/docx/sectionParser.js +18 -5
  73. package/dist/docx/selectiveSave.js +5 -1
  74. package/dist/docx/selectiveXmlPatch.d.ts +22 -1
  75. package/dist/docx/selectiveXmlPatch.js +61 -1
  76. package/dist/docx/serializer/blockSdtSerializer.js +3 -2
  77. package/dist/docx/serializer/commentSerializer.js +5 -6
  78. package/dist/docx/serializer/documentSerializer.js +2 -2
  79. package/dist/docx/serializer/headerFooterSerializer.js +2 -2
  80. package/dist/docx/serializer/noteSerializer.js +2 -2
  81. package/dist/docx/serializer/paragraphSerializer.js +23 -15
  82. package/dist/docx/serializer/runSerializer.js +25 -21
  83. package/dist/docx/serializer/sectionPropertiesSerializer.js +2 -1
  84. package/dist/docx/serializer/stylesSerializer.js +1 -1
  85. package/dist/docx/serializer/tableSerializer.d.ts +5 -4
  86. package/dist/docx/serializer/tableSerializer.js +26 -20
  87. package/dist/docx/serializer/xmlUtils.d.ts +13 -1
  88. package/dist/docx/serializer/xmlUtils.js +27 -1
  89. package/dist/docx/server/applyDocxXmlPatchProposal.d.ts +87 -0
  90. package/dist/docx/server/applyDocxXmlPatchProposal.js +204 -0
  91. package/dist/docx/server/boundedArchive.d.ts +14 -3
  92. package/dist/docx/server/boundedArchive.js +56 -11
  93. package/dist/docx/server/evaluateDocxXmlPatchProposal.d.ts +85 -0
  94. package/dist/docx/server/evaluateDocxXmlPatchProposal.js +361 -0
  95. package/dist/docx/server/extractDocxText.js +55 -8
  96. package/dist/docx/server/inspectDocxPackage.d.ts +70 -0
  97. package/dist/docx/server/inspectDocxPackage.js +217 -0
  98. package/dist/docx/server/validateDocxConformance.d.ts +41 -0
  99. package/dist/docx/server/validateDocxConformance.js +336 -0
  100. package/dist/docx/settingsParser.js +26 -3
  101. package/dist/docx/shapeParser.js +1 -1
  102. package/dist/docx/styleParser.js +4 -2
  103. package/dist/docx/tableParser.d.ts +8 -1
  104. package/dist/docx/tableParser.js +31 -10
  105. package/dist/docx/textBoxParser.d.ts +3 -3
  106. package/dist/docx/textBoxParser.js +16 -12
  107. package/dist/docx/unzip.js +1 -0
  108. package/dist/docx/vmlImageParser.js +11 -3
  109. package/dist/docx/xmlParser.js +11 -1
  110. package/dist/docx/xmlSafety.d.ts +5 -0
  111. package/dist/docx/xmlSafety.js +9 -0
  112. package/dist/fields/resolveFieldValues.js +1 -3
  113. package/dist/fonts/embeddedFonts.d.ts +33 -5
  114. package/dist/fonts/embeddedFonts.js +37 -8
  115. package/dist/i18n/messages/catalogs.gen.d.ts +17 -0
  116. package/dist/i18n/messages/catalogs.gen.js +17 -0
  117. package/dist/i18n/messages/messages.gen.d.ts +1 -0
  118. package/dist/index.d.ts +3 -3
  119. package/dist/index.js +3 -3
  120. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  121. package/dist/layout-bridge/convert/footnoteLayout.js +47 -40
  122. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  123. package/dist/layout-bridge/convert/headerFooterLayout.js +3 -0
  124. package/dist/layout-bridge/convert/templatePreviewFlow.js +3 -3
  125. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -2
  126. package/dist/layout-bridge/convert/toFlowBlocks.js +151 -20
  127. package/dist/layout-bridge/dom/noteStoryDom.d.ts +6 -0
  128. package/dist/layout-bridge/dom/noteStoryDom.js +17 -0
  129. package/dist/layout-bridge/engine/clickToPosition.js +2 -2
  130. package/dist/layout-engine/index.d.ts +2 -2
  131. package/dist/layout-engine/index.js +58 -30
  132. package/dist/layout-engine/justificationCompatibility.d.ts +6 -0
  133. package/dist/layout-engine/justificationCompatibility.js +8 -0
  134. package/dist/layout-engine/keep-together.js +11 -1
  135. package/dist/layout-engine/measure/cache.js +23 -5
  136. package/dist/layout-engine/measure/effectiveLineBreakPolicy.js +8 -2
  137. package/dist/layout-engine/measure/lineBreakProvider.d.ts +2 -2
  138. package/dist/layout-engine/measure/lineBreakProvider.js +56 -37
  139. package/dist/layout-engine/measure/measureBlocks.js +15 -4
  140. package/dist/layout-engine/measure/measureContainer.js +1 -1
  141. package/dist/layout-engine/measure/measureHelpers.d.ts +11 -2
  142. package/dist/layout-engine/measure/measureHelpers.js +15 -4
  143. package/dist/layout-engine/measure/measureParagraph.js +85 -25
  144. package/dist/layout-engine/measure/measureProvider.js +4 -3
  145. package/dist/layout-engine/measure/tableCellFlow.js +5 -2
  146. package/dist/layout-engine/measure/textBoxParagraphLayout.d.ts +9 -7
  147. package/dist/layout-engine/measure/textBoxParagraphLayout.js +22 -6
  148. package/dist/layout-engine/measure/textMeasurementPolicy.d.ts +3 -1
  149. package/dist/layout-engine/measure/textMeasurementPolicy.js +7 -1
  150. package/dist/layout-engine/paginator.js +5 -1
  151. package/dist/layout-engine/paragraphSpacing.d.ts +28 -4
  152. package/dist/layout-engine/paragraphSpacing.js +107 -13
  153. package/dist/layout-engine/renderedBreakReconciliation.js +1 -1
  154. package/dist/layout-engine/types.d.ts +48 -15
  155. package/dist/layout-painter/registry/modules/textBox.js +5 -1
  156. package/dist/layout-painter/renderImage.d.ts +12 -1
  157. package/dist/layout-painter/renderImage.js +21 -4
  158. package/dist/layout-painter/renderPage.d.ts +5 -2
  159. package/dist/layout-painter/renderPage.js +59 -14
  160. package/dist/layout-painter/renderParagraph.js +55 -15
  161. package/dist/layout-painter/renderTable.d.ts +5 -1
  162. package/dist/layout-painter/renderTable.js +7 -3
  163. package/dist/layout-painter/renderTextBox.d.ts +2 -1
  164. package/dist/layout-painter/renderTextBox.js +25 -14
  165. package/dist/layout-painter/renderWatermark.d.ts +1 -1
  166. package/dist/layout-painter/renderWatermark.js +2 -1
  167. package/dist/managers/DocumentLoaderManager.js +1 -1
  168. package/dist/markdown/fromMarkdown.js +1 -1
  169. package/dist/model.js +1 -1
  170. package/dist/prosemirror/attrs/index.d.ts +4 -2
  171. package/dist/prosemirror/attrs/index.js +175 -18
  172. package/dist/prosemirror/commands/comments.d.ts +79 -4
  173. package/dist/prosemirror/commands/comments.js +622 -13
  174. package/dist/prosemirror/commands/contentControls.js +1 -1
  175. package/dist/prosemirror/commands/hyperlink.js +15 -1
  176. package/dist/prosemirror/commands/image.js +7 -1
  177. package/dist/prosemirror/commands/index.d.ts +2 -2
  178. package/dist/prosemirror/commands/index.js +2 -2
  179. package/dist/prosemirror/commands/pageBreak.js +1 -1
  180. package/dist/prosemirror/commands/propertyChangeScope.d.ts +2 -2
  181. package/dist/prosemirror/commands/propertyChangeScope.js +3 -2
  182. package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +9 -0
  183. package/dist/prosemirror/commands/tableCellMergeResolution.js +181 -0
  184. package/dist/prosemirror/commentIdAllocator.js +13 -3
  185. package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -1
  186. package/dist/prosemirror/conversion/fromProseDoc.js +404 -62
  187. package/dist/prosemirror/conversion/index.js +1 -1
  188. package/dist/prosemirror/conversion/sdtAttrs.d.ts +9 -0
  189. package/dist/prosemirror/conversion/sdtAttrs.js +49 -0
  190. package/dist/prosemirror/conversion/toProseDoc.d.ts +2 -1
  191. package/dist/prosemirror/conversion/toProseDoc.js +364 -103
  192. package/dist/prosemirror/extensions/ExtensionManager.js +1 -1
  193. package/dist/prosemirror/extensions/StarterKit.js +6 -1
  194. package/dist/prosemirror/extensions/core/ParagraphExtension.js +6 -2
  195. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +1 -0
  196. package/dist/prosemirror/extensions/features/ImagePasteExtension.js +10 -2
  197. package/dist/prosemirror/extensions/features/ListExtension.js +1 -1
  198. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +10 -1
  199. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +93 -2
  200. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +2 -1
  201. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +6 -2
  202. package/dist/prosemirror/extensions/features/pasteCleanup.js +15 -2
  203. package/dist/prosemirror/extensions/marks/CharacterSpacingExtension.js +1 -1
  204. package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +30 -4
  205. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.d.ts +9 -1
  206. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +70 -11
  207. package/dist/prosemirror/extensions/nodes/FieldExtension.js +1 -1
  208. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.d.ts +7 -0
  209. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.js +22 -0
  210. package/dist/prosemirror/extensions/nodes/TableExtension.d.ts +1 -1
  211. package/dist/prosemirror/extensions/nodes/TableExtension.js +14 -6
  212. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +13 -0
  213. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +41 -0
  214. package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +5 -2
  215. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +4 -1
  216. package/dist/prosemirror/index.d.ts +1 -1
  217. package/dist/prosemirror/index.js +1 -1
  218. package/dist/prosemirror/plugins/contentControlWidgets.d.ts +36 -10
  219. package/dist/prosemirror/plugins/contentControlWidgets.js +128 -94
  220. package/dist/prosemirror/plugins/revisionIds.d.ts +23 -0
  221. package/dist/prosemirror/plugins/revisionIds.js +57 -0
  222. package/dist/prosemirror/plugins/selectionTracker.js +1 -0
  223. package/dist/prosemirror/plugins/suggestionMode.js +5 -4
  224. package/dist/prosemirror/runFormattingMarkNames.d.ts +14 -0
  225. package/dist/prosemirror/runFormattingMarkNames.js +40 -0
  226. package/dist/prosemirror/schema/index.d.ts +2 -2
  227. package/dist/prosemirror/schema/marks.d.ts +30 -3
  228. package/dist/prosemirror/schema/marks.js +15 -0
  229. package/dist/prosemirror/schema/nodes.d.ts +111 -6
  230. package/dist/prosemirror/selectionState.js +1 -0
  231. package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
  232. package/dist/prosemirror/tableCellMergeRevision.d.ts +9 -0
  233. package/dist/prosemirror/tableCellMergeRevision.js +22 -0
  234. package/dist/prosemirror/textBoxAnchorAttrs.d.ts +9 -0
  235. package/dist/prosemirror/textBoxAnchorAttrs.js +33 -0
  236. package/dist/prosemirror/utils/extractTrackedChanges.d.ts +1 -1
  237. package/dist/prosemirror/utils/extractTrackedChanges.js +62 -14
  238. package/dist/prosemirror/validation.js +9 -1
  239. package/dist/render-dom/RemoteSelectionOverlay.js +2 -2
  240. package/dist/server.d.ts +7 -3
  241. package/dist/server.js +7 -3
  242. package/dist/utils/clipboard.d.ts +10 -1
  243. package/dist/utils/clipboard.js +33 -6
  244. package/dist/utils/colorResolver.d.ts +8 -1
  245. package/dist/utils/colorResolver.js +35 -5
  246. package/dist/utils/fontFamilyMerge.js +9 -11
  247. package/dist/utils/fontLoader.js +3 -2
  248. package/dist/utils/fontResolver.d.ts +2 -1
  249. package/dist/utils/fontResolver.js +31 -7
  250. package/dist/utils/fontWeights.d.ts +1 -1
  251. package/dist/utils/fontWeights.js +1 -1
  252. package/dist/utils/hexId.d.ts +11 -1
  253. package/dist/utils/hexId.js +11 -1
  254. package/dist/utils/paragraphFormattingMerge.js +1 -0
  255. package/dist/utils/sanitizeImageSrc.d.ts +21 -0
  256. package/dist/utils/sanitizeImageSrc.js +30 -0
  257. package/dist/utils/stripXmlDeclarations.d.ts +11 -0
  258. package/dist/utils/stripXmlDeclarations.js +35 -0
  259. package/dist/version-comparison.d.ts +22 -2
  260. package/dist/version-comparison.js +41 -12
  261. package/dist/watermark/index.d.ts +11 -1
  262. package/dist/watermark/index.js +22 -1
  263. package/package.json +3 -2
@@ -1,3 +1,4 @@
1
+ import { getLocalName, parseXml } from "../xmlParser.js";
1
2
  //#region src/docx/serializer/xmlUtils.ts
2
3
  /**
3
4
  * Shared XML utility functions for serializers.
@@ -21,5 +22,30 @@ function intAttr(value) {
21
22
  if (value == null || !Number.isFinite(value)) return "0";
22
23
  return String(Math.round(value));
23
24
  }
25
+ /**
26
+ * Verify that `xml` parses to exactly one root element named `expectedLocalName`
27
+ * (namespace prefix ignored). Used to gate raw XML snapshots — e.g. an SDT's
28
+ * `rawPropertiesXml`/`rawEndPropertiesXml` — before splicing them verbatim
29
+ * into a serialized document. Those snapshots are normally produced by our
30
+ * own parser, but they can also arrive from an untrusted surface (a
31
+ * programmatically constructed node, a collaboration payload); a value that
32
+ * is not a single well-formed `<w:sdtPr>`/`<w:sdtEndPr>` element could inject
33
+ * sibling markup or close the enclosing `<w:sdt>` early. Callers should fall
34
+ * back to a synthesized properties block when this returns `false`.
35
+ */
36
+ function isSingleWellFormedElement(xml, expectedLocalName) {
37
+ const trimmed = xml.trim();
38
+ if (!trimmed) return false;
39
+ let parsed;
40
+ try {
41
+ parsed = parseXml(trimmed);
42
+ } catch {
43
+ return false;
44
+ }
45
+ const roots = (parsed.elements ?? []).filter((element) => element.type === "element");
46
+ if (roots.length !== 1) return false;
47
+ const root = roots[0];
48
+ return root?.name !== void 0 && getLocalName(root.name) === expectedLocalName;
49
+ }
24
50
  //#endregion
25
- export { escapeXml, intAttr };
51
+ export { escapeXml, intAttr, isSingleWellFormedElement };
@@ -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 };