@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
package/dist/server.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "./types/block-id.js";
2
- import { createFolioAITextRangeHandle } from "./ai-edits/snapshot.js";
2
+ import { createFolioAITextRangeHandle, hashFolioAIBlockText, normalizeFolioAIBlockText } from "./ai-edits/snapshot.js";
3
3
  import { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch } from "./document-operations.js";
4
4
  import { DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION } from "./style-sets/types.js";
5
5
  import { createEmptyDocument } from "./utils/createDocument.js";
@@ -12,7 +12,11 @@ import { FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, FolioDocumentStory
12
12
  import { FOLIO_DOCUMENT_METADATA_PROPERTIES, FOLIO_DOCUMENT_PRIVACY_TRANSFORMS, FolioDocumentPrivacyArchiveError, InvalidFolioDocumentPrivacyOptionsError, isFolioDocumentPrivacyTransform, rewriteDocxMetadataPrivacy } from "./docx/metadataPrivacy.js";
13
13
  import { FOLIO_VERSION_COMPARISON_PRIVACY_TRANSFORMS, FOLIO_VERSION_COMPARISON_SCOPES, InvalidFolioVersionComparisonOptionsError, applyFolioVersionDiffPrivacy, compareDocxVersions, isFolioVersionComparisonPrivacyTransform, isFolioVersionComparisonScope } from "./version-comparison.js";
14
14
  import { InvalidGenerateRedlineDocxOptionsError, generateRedlineDocx } from "./redline.js";
15
- import { EnsureParaIdsError, ensureParaIds } from "./docx/ensureParaIds.js";
16
15
  import { DocxArchiveError } from "./docx/server/boundedArchive.js";
16
+ import { EnsureParaIdsError, ensureParaIds } from "./docx/ensureParaIds.js";
17
17
  import { extractDocxText } from "./docx/server/extractDocxText.js";
18
- export { DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DocxArchiveError, EnsureParaIdsError, FOLIO_DOCUMENT_METADATA_PROPERTIES, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_DOCUMENT_PRIVACY_TRANSFORMS, FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, FOLIO_VERSION_COMPARISON_PRIVACY_TRANSFORMS, FOLIO_VERSION_COMPARISON_SCOPES, FolioDocumentPrivacyArchiveError, FolioDocumentStoryNotFoundError, FolioDocxReviewer, InvalidFolioDocumentOperationBatchError, InvalidFolioDocumentPrivacyOptionsError, InvalidFolioVersionComparisonOptionsError, InvalidGenerateRedlineDocxOptionsError, STELLA_STYLE_SET_NAME, UnsupportedFolioDocumentOperationVersionError, UnsupportedFolioReviewedViewError, applyFolioAIEditsToBuffer, applyFolioVersionDiffPrivacy, assertSupportedFolioDocumentOperationVersion, compareDocxVersions, createDocx, createEmptyDocument, createFolioAITextRangeHandle, createStellaStyleDocumentPreset, createStellaStyleSet, deriveBlockId, ensureParaIds, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, extractDocxText, generateRedlineDocx, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioDocumentOutline, getFolioParaIdFromBlockId, inspectDocumentStyles, inspectDocumentStylesFromDocx, isFolioBlockId, isFolioDocumentOperationModeSupported, isFolioDocumentPrivacyTransform, isFolioResolvedReviewedView, isFolioReviewedView, isFolioVersionComparisonPrivacyTransform, isFolioVersionComparisonScope, isSequentialFolioBlockId, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch, readFolioDocumentSection, replyToComment, rewriteDocxMetadataPrivacy };
18
+ import { FOLIO_DOCX_PACKAGE_INSPECTION_DEFAULTS, FOLIO_DOCX_PACKAGE_INSPECTION_ERROR_CODES, FOLIO_DOCX_PACKAGE_INSPECTION_VERSION, FolioDocxPackageInspectionError, inspectDocxPackage } from "./docx/server/inspectDocxPackage.js";
19
+ import { 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, InvalidFolioDocxXmlPatchProposalError, InvalidFolioDocxXmlPatchProposalOptionsError, evaluateDocxXmlPatchProposal, parseFolioDocxXmlPatchProposal } from "./docx/server/evaluateDocxXmlPatchProposal.js";
20
+ import { FOLIO_DOCX_CONFORMANCE_CHECKS, FOLIO_DOCX_CONFORMANCE_ISSUE_CODES, FOLIO_DOCX_CONFORMANCE_PROFILE, FOLIO_DOCX_CONFORMANCE_REPORT_VERSION, validateDocxConformance } from "./docx/server/validateDocxConformance.js";
21
+ import { FOLIO_DOCX_XML_PATCH_APPLICATION_PROFILE, FOLIO_DOCX_XML_PATCH_APPLICATION_VERSION, FolioDocxXmlPatchApplicationError, UnsupportedFolioDocxXmlPatchApplicationProfileError, applyDocxXmlPatchProposal } from "./docx/server/applyDocxXmlPatchProposal.js";
22
+ export { DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DocxArchiveError, EnsureParaIdsError, FOLIO_DOCUMENT_METADATA_PROPERTIES, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_DOCUMENT_PRIVACY_TRANSFORMS, FOLIO_DOCX_CONFORMANCE_CHECKS, FOLIO_DOCX_CONFORMANCE_ISSUE_CODES, FOLIO_DOCX_CONFORMANCE_PROFILE, FOLIO_DOCX_CONFORMANCE_REPORT_VERSION, FOLIO_DOCX_PACKAGE_INSPECTION_DEFAULTS, FOLIO_DOCX_PACKAGE_INSPECTION_ERROR_CODES, FOLIO_DOCX_PACKAGE_INSPECTION_VERSION, FOLIO_DOCX_XML_PATCH_APPLICATION_PROFILE, FOLIO_DOCX_XML_PATCH_APPLICATION_VERSION, 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, FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, FOLIO_VERSION_COMPARISON_PRIVACY_TRANSFORMS, FOLIO_VERSION_COMPARISON_SCOPES, FolioDocumentPrivacyArchiveError, FolioDocumentStoryNotFoundError, FolioDocxPackageInspectionError, FolioDocxReviewer, FolioDocxXmlPatchApplicationError, InvalidFolioDocumentOperationBatchError, InvalidFolioDocumentPrivacyOptionsError, InvalidFolioDocxXmlPatchProposalError, InvalidFolioDocxXmlPatchProposalOptionsError, InvalidFolioVersionComparisonOptionsError, InvalidGenerateRedlineDocxOptionsError, STELLA_STYLE_SET_NAME, UnsupportedFolioDocumentOperationVersionError, UnsupportedFolioDocxXmlPatchApplicationProfileError, UnsupportedFolioReviewedViewError, applyDocxXmlPatchProposal, applyFolioAIEditsToBuffer, applyFolioVersionDiffPrivacy, assertSupportedFolioDocumentOperationVersion, compareDocxVersions, createDocx, createEmptyDocument, createFolioAITextRangeHandle, createStellaStyleDocumentPreset, createStellaStyleSet, deriveBlockId, ensureParaIds, evaluateDocxXmlPatchProposal, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, extractDocxText, generateRedlineDocx, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioDocumentOutline, getFolioParaIdFromBlockId, hashFolioAIBlockText, inspectDocumentStyles, inspectDocumentStylesFromDocx, inspectDocxPackage, isFolioBlockId, isFolioDocumentOperationModeSupported, isFolioDocumentPrivacyTransform, isFolioResolvedReviewedView, isFolioReviewedView, isFolioVersionComparisonPrivacyTransform, isFolioVersionComparisonScope, isSequentialFolioBlockId, isSupportedFolioDocumentOperationVersion, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, parseFolioDocxXmlPatchProposal, readFolioDocumentSection, replyToComment, rewriteDocxMetadataPrivacy, validateDocxConformance };
@@ -85,6 +85,15 @@ declare function isWordHtml(html: string): boolean;
85
85
  * Check if HTML is from our editor
86
86
  */
87
87
  declare function isEditorHtml(html: string): boolean;
88
+ /**
89
+ * Sanitize inbound clipboard HTML at the paste trust boundary.
90
+ *
91
+ * Comments and XML declarations are stripped with linear scanners. When a
92
+ * browser `window` is available, DOMPurify removes scripts, event handlers,
93
+ * and dangerous URLs before any DOM walk. Without a window (unit stubs / SSR)
94
+ * the linear cleaners still run; the live editor path always has `window`.
95
+ */
96
+ declare function sanitizeInboundClipboardHtml(html: string): string;
88
97
  /**
89
98
  * Clean Microsoft Word HTML
90
99
  */
@@ -123,4 +132,4 @@ declare const _default: {
123
132
  createClipboardHandlers: typeof createClipboardHandlers;
124
133
  };
125
134
  //#endregion
126
- export { CLIPBOARD_TYPES, ClipboardContent, ClipboardOptions, INTERNAL_CLIPBOARD_TYPE, ParsedClipboardContent, cleanWordHtml, copyParagraphs, copyRuns, createClipboardHandlers, _default as default, getClipboardImageFiles, handlePasteEvent, htmlToRuns, isEditorHtml, isWordHtml, paragraphsToClipboardContent, parseClipboardHtml, readFromClipboard, runsToClipboardContent, writeToClipboard };
135
+ export { CLIPBOARD_TYPES, ClipboardContent, ClipboardOptions, INTERNAL_CLIPBOARD_TYPE, ParsedClipboardContent, cleanWordHtml, copyParagraphs, copyRuns, createClipboardHandlers, _default as default, getClipboardImageFiles, handlePasteEvent, htmlToRuns, isEditorHtml, isWordHtml, paragraphsToClipboardContent, parseClipboardHtml, readFromClipboard, runsToClipboardContent, sanitizeInboundClipboardHtml, writeToClipboard };
@@ -1,5 +1,18 @@
1
+ import { stripXmlDeclarations } from "./stripXmlDeclarations.js";
2
+ import createDOMPurify from "dompurify";
1
3
  //#region src/utils/clipboard.ts
2
4
  /**
5
+ * Clipboard utilities for copy/paste with formatting
6
+ *
7
+ * Handles:
8
+ * - Copy: puts formatted HTML and plain text on clipboard
9
+ * - Paste: reads HTML clipboard, converts to runs with formatting
10
+ * - Handles paste from Word (cleans up Word HTML)
11
+ * - Ctrl+C, Ctrl+V, Ctrl+X keyboard shortcuts
12
+ */
13
+ let domPurify;
14
+ const getDomPurify = () => domPurify ??= createDOMPurify(window);
15
+ /**
3
16
  * Custom MIME type for internal clipboard format
4
17
  */
5
18
  const INTERNAL_CLIPBOARD_TYPE = "application/x-stella-folio";
@@ -308,12 +321,24 @@ function stripPairedNamespaceTags(html, prefix) {
308
321
  return result;
309
322
  }
310
323
  /**
324
+ * Sanitize inbound clipboard HTML at the paste trust boundary.
325
+ *
326
+ * Comments and XML declarations are stripped with linear scanners. When a
327
+ * browser `window` is available, DOMPurify removes scripts, event handlers,
328
+ * and dangerous URLs before any DOM walk. Without a window (unit stubs / SSR)
329
+ * the linear cleaners still run; the live editor path always has `window`.
330
+ */
331
+ function sanitizeInboundClipboardHtml(html) {
332
+ let cleaned = stripHtmlComments(html);
333
+ cleaned = stripXmlDeclarations(cleaned);
334
+ if (typeof globalThis.window === "undefined") return cleaned;
335
+ return getDomPurify().sanitize(cleaned);
336
+ }
337
+ /**
311
338
  * Clean Microsoft Word HTML
312
339
  */
313
340
  function cleanWordHtml(html) {
314
- let cleaned = html;
315
- cleaned = stripHtmlComments(cleaned);
316
- cleaned = cleaned.replace(/<\?xml[^>]*>/gi, "");
341
+ let cleaned = sanitizeInboundClipboardHtml(html);
317
342
  cleaned = stripPairedNamespaceTags(cleaned, "o:");
318
343
  cleaned = cleaned.replace(/<o:[^>]*\/>/gi, "");
319
344
  cleaned = stripPairedNamespaceTags(cleaned, "w:");
@@ -325,7 +350,8 @@ function cleanWordHtml(html) {
325
350
  return cleaned;
326
351
  }
327
352
  function cleanWordAttributes(html) {
328
- const container = new DOMParser().parseFromString(html, "text/html").body;
353
+ const sanitized = sanitizeInboundClipboardHtml(html);
354
+ const container = new DOMParser().parseFromString(sanitized, "text/html").body;
329
355
  for (const element of Array.from(container.querySelectorAll("*"))) {
330
356
  const filteredClasses = Array.from(element.classList).filter((className) => !className.includes("Mso"));
331
357
  if (filteredClasses.length === 0) element.removeAttribute("class");
@@ -346,7 +372,8 @@ function cleanWordAttributes(html) {
346
372
  */
347
373
  function htmlToRuns(html, plainTextFallback) {
348
374
  if (!html || html.trim() === "") return plainTextFallback ? [createTextRun(plainTextFallback)] : [];
349
- const container = new DOMParser().parseFromString(html, "text/html").body;
375
+ const sanitized = sanitizeInboundClipboardHtml(html);
376
+ const container = new DOMParser().parseFromString(sanitized, "text/html").body;
350
377
  const runs = [];
351
378
  processNode(container, runs, {});
352
379
  if (runs.length === 0 && plainTextFallback) return [createTextRun(plainTextFallback)];
@@ -619,4 +646,4 @@ var clipboard_default = {
619
646
  createClipboardHandlers
620
647
  };
621
648
  //#endregion
622
- export { CLIPBOARD_TYPES, INTERNAL_CLIPBOARD_TYPE, cleanWordHtml, copyParagraphs, copyRuns, createClipboardHandlers, clipboard_default as default, getClipboardImageFiles, handlePasteEvent, htmlToRuns, isEditorHtml, isWordHtml, paragraphsToClipboardContent, parseClipboardHtml, readFromClipboard, runsToClipboardContent, writeToClipboard };
649
+ export { CLIPBOARD_TYPES, INTERNAL_CLIPBOARD_TYPE, cleanWordHtml, copyParagraphs, copyRuns, createClipboardHandlers, clipboard_default as default, getClipboardImageFiles, handlePasteEvent, htmlToRuns, isEditorHtml, isWordHtml, paragraphsToClipboardContent, parseClipboardHtml, readFromClipboard, runsToClipboardContent, sanitizeInboundClipboardHtml, writeToClipboard };
@@ -1,6 +1,13 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
2
 
3
3
  //#region src/utils/colorResolver.d.ts
4
+ /**
5
+ * Public form of the same hex-color check, for callers that read a color
6
+ * value from an untrusted surface (e.g. a pasted DOM node's `dataset`,
7
+ * which bypasses the CSSOM's own value validation) and must reject it
8
+ * before storing it as editor state.
9
+ */
10
+ declare function isValidHexColor(value: string | undefined | null): boolean;
4
11
  /**
5
12
  * Resolve a ColorValue to a CSS color string
6
13
  *
@@ -162,4 +169,4 @@ declare function generateThemeTintShadeMatrix(colorScheme?: document_d_exports.T
162
169
  */
163
170
  declare function colorsEqual(color1: document_d_exports.ColorValue | undefined | null, color2: document_d_exports.ColorValue | undefined | null, theme: document_d_exports.Theme | null | undefined): boolean;
164
171
  //#endregion
165
- export { STANDARD_TEXT_COLORS, ThemeMatrixCell, blendColors, colorsEqual, createRgbColor, createThemeColor, darkenColor, ensureHexPrefix, generateThemeTintShadeMatrix, getContrastingColor, getThemeTintShadeHex, isBlack, isWhite, lightenColor, parseColorString, resolveColor, resolveColorToHex, resolveHighlightColor, resolveHighlightToCss, resolveShadingColor };
172
+ export { STANDARD_TEXT_COLORS, ThemeMatrixCell, blendColors, colorsEqual, createRgbColor, createThemeColor, darkenColor, ensureHexPrefix, generateThemeTintShadeMatrix, getContrastingColor, getThemeTintShadeHex, isBlack, isValidHexColor, isWhite, lightenColor, parseColorString, resolveColor, resolveColorToHex, resolveHighlightColor, resolveHighlightToCss, resolveShadingColor };
@@ -1,5 +1,34 @@
1
1
  //#region src/utils/colorResolver.ts
2
2
  /**
3
+ * Strict hex-color validator shared by every OOXML → CSS color path in this
4
+ * module. OOXML readers are lenient about `w:val`/`w:fill` attribute content
5
+ * and theme swatch text, so a crafted `<w:color>`, table shading, or
6
+ * `themeN.xml` color-scheme entry can carry arbitrary text — including a CSS
7
+ * `url(...)` payload — instead of a real color. Accepts a 3, 6, or 8 digit
8
+ * hex string with an optional leading `#`; anything else (including the
9
+ * literal `"auto"`, which callers handle separately) is rejected.
10
+ */
11
+ const HEX_COLOR_PATTERN = /^#?[0-9A-Fa-f]{3}(?:[0-9A-Fa-f]{3})?(?:[0-9A-Fa-f]{2})?$/u;
12
+ /**
13
+ * Normalize a raw color string to a bare uppercase hex value (no `#`), or
14
+ * `undefined` when it is not a valid 3/6/8-digit hex color. This is the
15
+ * single choke point every resolved color passes through before becoming a
16
+ * CSS string — see {@link resolveColor} and {@link resolveColorToHex}.
17
+ */
18
+ function normalizeHexColor(value) {
19
+ if (!value) return;
20
+ return HEX_COLOR_PATTERN.test(value) ? value.replace(/^#/u, "").toUpperCase() : void 0;
21
+ }
22
+ /**
23
+ * Public form of the same hex-color check, for callers that read a color
24
+ * value from an untrusted surface (e.g. a pasted DOM node's `dataset`,
25
+ * which bypasses the CSSOM's own value validation) and must reject it
26
+ * before storing it as editor state.
27
+ */
28
+ function isValidHexColor(value) {
29
+ return typeof value === "string" && normalizeHexColor(value) !== void 0;
30
+ }
31
+ /**
3
32
  * Default theme colors (Office 2016 default theme)
4
33
  */
5
34
  const DEFAULT_THEME_COLORS = {
@@ -194,8 +223,9 @@ function resolveThemeColorSlot(colorName) {
194
223
  * @returns CSS color string (e.g., "#FF0000" or "inherit")
195
224
  */
196
225
  function resolveColor(color, theme, defaultColor = "000000") {
197
- if (!color) return `#${defaultColor}`;
198
- if (color.auto) return `#${defaultColor}`;
226
+ const safeDefault = normalizeHexColor(defaultColor) ?? "000000";
227
+ if (!color) return `#${safeDefault}`;
228
+ if (color.auto) return `#${safeDefault}`;
199
229
  let hexColor;
200
230
  if (color.themeColor) {
201
231
  const slot = resolveThemeColorSlot(color.themeColor);
@@ -210,7 +240,7 @@ function resolveColor(color, theme, defaultColor = "000000") {
210
240
  }
211
241
  } else if (color.rgb) hexColor = color.rgb === "auto" ? defaultColor : color.rgb;
212
242
  else hexColor = defaultColor;
213
- return `#${hexColor.toUpperCase().replace(/^#/u, "")}`;
243
+ return `#${normalizeHexColor(hexColor) ?? safeDefault}`;
214
244
  }
215
245
  /**
216
246
  * Resolve a highlight color name to CSS
@@ -227,7 +257,7 @@ function resolveColor(color, theme, defaultColor = "000000") {
227
257
  function resolveColorToHex(color, theme) {
228
258
  if (!color || color.auto) return void 0;
229
259
  if (color.themeColor && theme) return resolveColor(color, theme).slice(1);
230
- if (color.rgb && color.rgb !== "auto") return color.rgb.toUpperCase().replace(/^#/, "");
260
+ if (color.rgb && color.rgb !== "auto") return normalizeHexColor(color.rgb);
231
261
  }
232
262
  function resolveHighlightColor(highlight) {
233
263
  if (!highlight || highlight === "none") return "";
@@ -565,4 +595,4 @@ function colorsEqual(color1, color2, theme) {
565
595
  return resolveColor(color1, theme).toUpperCase() === resolveColor(color2, theme).toUpperCase();
566
596
  }
567
597
  //#endregion
568
- export { STANDARD_TEXT_COLORS, blendColors, colorsEqual, createRgbColor, createThemeColor, darkenColor, ensureHexPrefix, generateThemeTintShadeMatrix, getContrastingColor, getThemeTintShadeHex, isBlack, isWhite, lightenColor, parseColorString, resolveColor, resolveColorToHex, resolveHighlightColor, resolveHighlightToCss, resolveShadingColor };
598
+ export { STANDARD_TEXT_COLORS, blendColors, colorsEqual, createRgbColor, createThemeColor, darkenColor, ensureHexPrefix, generateThemeTintShadeMatrix, getContrastingColor, getThemeTintShadeHex, isBlack, isValidHexColor, isWhite, lightenColor, parseColorString, resolveColor, resolveColorToHex, resolveHighlightColor, resolveHighlightToCss, resolveShadingColor };
@@ -1,4 +1,11 @@
1
1
  //#region src/utils/fontFamilyMerge.ts
2
+ const FONT_FAMILY_PAIRS = [
3
+ ["ascii", "asciiTheme"],
4
+ ["hAnsi", "hAnsiTheme"],
5
+ ["eastAsia", "eastAsiaTheme"],
6
+ ["cs", "csTheme"]
7
+ ];
8
+ const isFontFamilyPairKey = (key) => key === "ascii" || key === "asciiTheme" || key === "hAnsi" || key === "hAnsiTheme" || key === "eastAsia" || key === "eastAsiaTheme" || key === "cs" || key === "csTheme";
2
9
  function mergeFontFamily(target, source) {
3
10
  const result = {};
4
11
  const src = source;
@@ -10,21 +17,12 @@ function mergeFontFamily(target, source) {
10
17
  if (replacesAscii && (key === "ascii" || key === "asciiTheme") || replacesHAnsi && (key === "hAnsi" || key === "hAnsiTheme") || replacesEastAsia && (key === "eastAsia" || key === "eastAsiaTheme") || replacesCs && (key === "cs" || key === "csTheme")) continue;
11
18
  result[key] = target[key];
12
19
  }
13
- const pairs = [
14
- ["ascii", "asciiTheme"],
15
- ["hAnsi", "hAnsiTheme"],
16
- ["eastAsia", "eastAsiaTheme"],
17
- ["cs", "csTheme"]
18
- ];
19
- const pairKeys = /* @__PURE__ */ new Set();
20
- for (const [explicit, theme] of pairs) {
21
- pairKeys.add(explicit);
22
- pairKeys.add(theme);
20
+ for (const [explicit, theme] of FONT_FAMILY_PAIRS) {
23
21
  if (src[explicit] === void 0 && src[theme] === void 0) continue;
24
22
  if (src[explicit] !== void 0) result[explicit] = src[explicit];
25
23
  if (src[theme] !== void 0) result[theme] = src[theme];
26
24
  }
27
- for (const key of Object.keys(src)) if (!pairKeys.has(key) && src[key] !== void 0) result[key] = src[key];
25
+ for (const key of Object.keys(src)) if (!isFontFamilyPairKey(key) && src[key] !== void 0) result[key] = src[key];
28
26
  return result;
29
27
  }
30
28
  //#endregion
@@ -17,8 +17,8 @@ let isLoadingAny = false;
17
17
  * this map is used for font availability checks and preloading.
18
18
  */
19
19
  const FONT_MAPPING = {
20
- Aptos: "Source Sans 3",
21
- "Aptos Display": "Source Sans 3",
20
+ Aptos: "Lato",
21
+ "Aptos Display": "Lato",
22
22
  Calibri: "Carlito",
23
23
  Cambria: "Caladea",
24
24
  Arial: "Arimo",
@@ -40,6 +40,7 @@ const BUNDLED_FONTS = /* @__PURE__ */ new Set([
40
40
  "Arimo",
41
41
  "Tinos",
42
42
  "Cousine",
43
+ "Lato",
43
44
  "Source Sans 3",
44
45
  "Calibri",
45
46
  "Cambria",
@@ -40,6 +40,7 @@ declare function isCjkFont(family: string): boolean;
40
40
  declare const CJK_FALLBACK_FONT_FAMILY = "MS Mincho";
41
41
  declare const setGoogleFontsEnabled: (enabled: boolean) => void;
42
42
  declare const getGoogleFontsEnabled: () => boolean;
43
+ declare const setEmbeddedFontFamilyMap: (map: ReadonlyMap<string, string> | null) => void;
43
44
  declare function resolveFontFamily(docxFontName: string): ResolvedFont;
44
45
  /**
45
46
  * Resolve a theme font reference to actual font names
@@ -79,4 +80,4 @@ declare function getGoogleFontEquivalent(docxFontName: string): string | null;
79
80
  */
80
81
  declare function hasGoogleFontEquivalent(docxFontName: string): boolean;
81
82
  //#endregion
82
- export { CJK_FALLBACK_FONT_FAMILY, DEFAULT_SINGLE_LINE_RATIO, ResolvedFont, buildFontFamilyString, getGoogleFontEquivalent, getGoogleFontsEnabled, getGoogleFontsToLoad, hasGoogleFontEquivalent, isCjkFont, resolveFontFamily, resolveThemeFont, setGoogleFontsEnabled };
83
+ export { CJK_FALLBACK_FONT_FAMILY, DEFAULT_SINGLE_LINE_RATIO, ResolvedFont, buildFontFamilyString, getGoogleFontEquivalent, getGoogleFontsEnabled, getGoogleFontsToLoad, hasGoogleFontEquivalent, isCjkFont, resolveFontFamily, resolveThemeFont, setEmbeddedFontFamilyMap, setGoogleFontsEnabled };
@@ -65,11 +65,11 @@ const APTOS_MEASURED_LINE_HEIGHT = {
65
65
  */
66
66
  const FONT_MAPPINGS = {
67
67
  aptos: {
68
- googleFont: "Source Sans 3",
68
+ googleFont: "Lato",
69
69
  category: "sans-serif",
70
70
  fallbackStack: [
71
71
  "Aptos",
72
- "Source Sans 3",
72
+ "Lato",
73
73
  "Arial",
74
74
  "Helvetica",
75
75
  "sans-serif"
@@ -77,11 +77,11 @@ const FONT_MAPPINGS = {
77
77
  singleLineRatio: singleLineRatioOf(APTOS_MEASURED_LINE_HEIGHT)
78
78
  },
79
79
  "aptos display": {
80
- googleFont: "Source Sans 3",
80
+ googleFont: "Lato",
81
81
  category: "sans-serif",
82
82
  fallbackStack: [
83
83
  "Aptos Display",
84
- "Source Sans 3",
84
+ "Lato",
85
85
  "Arial",
86
86
  "Helvetica",
87
87
  "sans-serif"
@@ -242,6 +242,24 @@ const FONT_MAPPINGS = {
242
242
  unitsPerEm: 2048
243
243
  })
244
244
  },
245
+ "segoe ui": {
246
+ googleFont: "Source Sans 3",
247
+ category: "sans-serif",
248
+ fallbackStack: [
249
+ "Segoe UI",
250
+ "Source Sans 3",
251
+ "Arial",
252
+ "Helvetica",
253
+ "sans-serif"
254
+ ],
255
+ singleLineRatio: singleLineRatioOf({
256
+ source: "hhea",
257
+ hheaAscent: 2210,
258
+ hheaDescent: -514,
259
+ hheaLineGap: 0,
260
+ unitsPerEm: 2048
261
+ })
262
+ },
245
263
  montserrat: {
246
264
  googleFont: "Montserrat",
247
265
  category: "sans-serif",
@@ -791,15 +809,21 @@ const setGoogleFontsEnabled = (enabled) => {
791
809
  googleFontsEnabled = enabled;
792
810
  };
793
811
  const getGoogleFontsEnabled = () => googleFontsEnabled;
812
+ let embeddedFontFamilyMap = null;
813
+ const setEmbeddedFontFamilyMap = (map) => {
814
+ embeddedFontFamilyMap = map;
815
+ };
794
816
  function resolveFontFamily(docxFontName) {
795
817
  const normalizedName = docxFontName.trim().toLowerCase();
818
+ const scopedFamily = embeddedFontFamilyMap?.get(docxFontName) ?? null;
796
819
  const aliasTarget = CJK_FONT_ALIASES[normalizedName];
797
820
  const mapping = FONT_MAPPINGS[aliasTarget ?? normalizedName];
798
821
  if (mapping) {
799
822
  const fallbackStack = aliasTarget && !mapping.fallbackStack.some((f) => f.toLowerCase() === normalizedName) ? [docxFontName, ...mapping.fallbackStack] : mapping.fallbackStack;
823
+ const primaryStack = scopedFamily ? [scopedFamily, ...fallbackStack.filter((f) => f.toLowerCase() !== normalizedName)] : fallbackStack;
800
824
  return {
801
825
  googleFont: googleFontsEnabled ? mapping.googleFont : null,
802
- cssFallback: withArabicFallback(fallbackStack.map(quoteFontName).join(", ")),
826
+ cssFallback: withArabicFallback(primaryStack.map(quoteFontName).join(", ")),
803
827
  originalFont: docxFontName,
804
828
  hasGoogleEquivalent: googleFontsEnabled,
805
829
  singleLineRatio: mapping.singleLineRatio
@@ -809,7 +833,7 @@ function resolveFontFamily(docxFontName) {
809
833
  const defaultFallback = DEFAULT_FALLBACKS[category];
810
834
  return {
811
835
  googleFont: null,
812
- cssFallback: withArabicFallback(`${quoteFontName(docxFontName)}, ${defaultFallback}`),
836
+ cssFallback: withArabicFallback(`${quoteFontName(scopedFamily ?? docxFontName)}, ${defaultFallback}`),
813
837
  originalFont: docxFontName,
814
838
  hasGoogleEquivalent: false,
815
839
  singleLineRatio: DEFAULT_SINGLE_LINE_RATIO
@@ -904,4 +928,4 @@ function hasGoogleFontEquivalent(docxFontName) {
904
928
  return (CJK_FONT_ALIASES[normalizedName] ?? normalizedName) in FONT_MAPPINGS;
905
929
  }
906
930
  //#endregion
907
- export { CJK_FALLBACK_FONT_FAMILY, DEFAULT_SINGLE_LINE_RATIO, buildFontFamilyString, getGoogleFontEquivalent, getGoogleFontsEnabled, getGoogleFontsToLoad, hasGoogleFontEquivalent, isCjkFont, resolveFontFamily, resolveThemeFont, setGoogleFontsEnabled };
931
+ export { CJK_FALLBACK_FONT_FAMILY, DEFAULT_SINGLE_LINE_RATIO, buildFontFamilyString, getGoogleFontEquivalent, getGoogleFontsEnabled, getGoogleFontsToLoad, hasGoogleFontEquivalent, isCjkFont, resolveFontFamily, resolveThemeFont, setEmbeddedFontFamilyMap, setGoogleFontsEnabled };
@@ -1,4 +1,4 @@
1
1
  //#region src/utils/fontWeights.d.ts
2
- declare const DOCX_BOLD_FONT_WEIGHT = "800";
2
+ declare const DOCX_BOLD_FONT_WEIGHT = "700";
3
3
  //#endregion
4
4
  export { DOCX_BOLD_FONT_WEIGHT };
@@ -1,4 +1,4 @@
1
1
  //#region src/utils/fontWeights.ts
2
- const DOCX_BOLD_FONT_WEIGHT = "800";
2
+ const DOCX_BOLD_FONT_WEIGHT = "700";
3
3
  //#endregion
4
4
  export { DOCX_BOLD_FONT_WEIGHT };
@@ -15,6 +15,16 @@
15
15
  * strict OOXML validators.
16
16
  */
17
17
  declare const MAX_HEX_ID_EXCLUSIVE = 2147483647;
18
+ /**
19
+ * OOXML `ST_LongHexNumber` shape: exactly 8 hex digits (`xsd:hexBinary`,
20
+ * length 4 bytes). `w14:paraId` / `w14:textId` / comment `paraId` /
21
+ * `w15:paraIdParent` are all typed this way. A value that doesn't match this
22
+ * is not a real Word id — it must not be trusted as one (e.g. echoed
23
+ * unescaped into serialized XML attributes).
24
+ */
25
+ declare const HEX_ID_PATTERN: RegExp;
26
+ /** Whether `value` is a well-formed 8-hex-digit OOXML long-hex id. */
27
+ declare const isValidHexId: (value: string | undefined | null) => boolean;
18
28
  /**
19
29
  * Random 8-char uppercase hex id, matching Microsoft's `w14:paraId`
20
30
  * extension format (also reused for comment `paraId` / `durableId`).
@@ -37,4 +47,4 @@ declare const generateHexId: () => string;
37
47
  */
38
48
  declare const deterministicHexId: (seed: string) => string;
39
49
  //#endregion
40
- export { MAX_HEX_ID_EXCLUSIVE, deterministicHexId, generateHexId };
50
+ export { HEX_ID_PATTERN, MAX_HEX_ID_EXCLUSIVE, deterministicHexId, generateHexId, isValidHexId };
@@ -16,6 +16,16 @@
16
16
  */
17
17
  const MAX_HEX_ID_EXCLUSIVE = 2147483647;
18
18
  /**
19
+ * OOXML `ST_LongHexNumber` shape: exactly 8 hex digits (`xsd:hexBinary`,
20
+ * length 4 bytes). `w14:paraId` / `w14:textId` / comment `paraId` /
21
+ * `w15:paraIdParent` are all typed this way. A value that doesn't match this
22
+ * is not a real Word id — it must not be trusted as one (e.g. echoed
23
+ * unescaped into serialized XML attributes).
24
+ */
25
+ const HEX_ID_PATTERN = /^[0-9A-Fa-f]{8}$/u;
26
+ /** Whether `value` is a well-formed 8-hex-digit OOXML long-hex id. */
27
+ const isValidHexId = (value) => typeof value === "string" && HEX_ID_PATTERN.test(value);
28
+ /**
19
29
  * Random 8-char uppercase hex id, matching Microsoft's `w14:paraId`
20
30
  * extension format (also reused for comment `paraId` / `durableId`).
21
31
  *
@@ -42,4 +52,4 @@ const deterministicHexId = (seed) => {
42
52
  return (value === 0 ? 1 : value).toString(16).toUpperCase().padStart(8, "0");
43
53
  };
44
54
  //#endregion
45
- export { MAX_HEX_ID_EXCLUSIVE, deterministicHexId, generateHexId };
55
+ export { HEX_ID_PATTERN, MAX_HEX_ID_EXCLUSIVE, deterministicHexId, generateHexId, isValidHexId };
@@ -9,6 +9,7 @@ const PARAGRAPH_REPLACE_KEYS = [
9
9
  "spaceAfter",
10
10
  "lineSpacing",
11
11
  "lineSpacingRule",
12
+ "snapToGrid",
12
13
  "beforeAutospacing",
13
14
  "afterAutospacing",
14
15
  "spacingExplicit",
@@ -0,0 +1,21 @@
1
+ //#region src/utils/sanitizeImageSrc.d.ts
2
+ /**
3
+ * Keep painted image sources local to bytes the host already owns.
4
+ *
5
+ * Document media and pasted files enter the editor as `data:image/*` or
6
+ * `blob:` URLs. Network and executable schemes are rejected so opening or
7
+ * pasting an untrusted document cannot trigger an external request or run a
8
+ * script scheme through `<img src>`.
9
+ */
10
+ declare function sanitizeImageSrc(src: string | null | undefined): string | undefined;
11
+ /**
12
+ * Assign a sanitized source to an `<img>` element. When the source is rejected
13
+ * the `src` attribute is left unset: assigning `""` makes some browsers resolve
14
+ * it against the page URL and fire a spurious request for the current page.
15
+ *
16
+ * Structural parameter type so painter unit tests (which fake the DOM) can
17
+ * exercise it without an `HTMLImageElement`.
18
+ */
19
+ declare function applySanitizedImageSrc(imgEl: Pick<HTMLImageElement, "src">, src: string | null | undefined): void;
20
+ //#endregion
21
+ export { applySanitizedImageSrc, sanitizeImageSrc };
@@ -0,0 +1,30 @@
1
+ //#region src/utils/sanitizeImageSrc.ts
2
+ /**
3
+ * Keep painted image sources local to bytes the host already owns.
4
+ *
5
+ * Document media and pasted files enter the editor as `data:image/*` or
6
+ * `blob:` URLs. Network and executable schemes are rejected so opening or
7
+ * pasting an untrusted document cannot trigger an external request or run a
8
+ * script scheme through `<img src>`.
9
+ */
10
+ function sanitizeImageSrc(src) {
11
+ if (typeof src !== "string") return;
12
+ const value = src.trim();
13
+ if (!value) return;
14
+ if (/^blob:/iu.test(value)) return value;
15
+ if (/^data:image\/[a-z0-9.+-]+(?:;[^,]*)?,/iu.test(value)) return value;
16
+ }
17
+ /**
18
+ * Assign a sanitized source to an `<img>` element. When the source is rejected
19
+ * the `src` attribute is left unset: assigning `""` makes some browsers resolve
20
+ * it against the page URL and fire a spurious request for the current page.
21
+ *
22
+ * Structural parameter type so painter unit tests (which fake the DOM) can
23
+ * exercise it without an `HTMLImageElement`.
24
+ */
25
+ function applySanitizedImageSrc(imgEl, src) {
26
+ const safeSrc = sanitizeImageSrc(src);
27
+ if (safeSrc !== void 0) imgEl.src = safeSrc;
28
+ }
29
+ //#endregion
30
+ export { applySanitizedImageSrc, sanitizeImageSrc };
@@ -0,0 +1,11 @@
1
+ //#region src/utils/stripXmlDeclarations.d.ts
2
+ /**
3
+ * Remove complete `<?xml ...?>` declarations from attacker-controlled clipboard HTML.
4
+ *
5
+ * Linear scan instead of `/<\?xml[^>]*>/gi`: that pattern backtracks polynomially
6
+ * when many `<?xml` openers appear with no closing `>`. An unterminated opener
7
+ * is preserved verbatim (same as the regex, which never matched it).
8
+ */
9
+ declare function stripXmlDeclarations(html: string): string;
10
+ //#endregion
11
+ export { stripXmlDeclarations };
@@ -0,0 +1,35 @@
1
+ //#region src/utils/stripXmlDeclarations.ts
2
+ /**
3
+ * Remove complete `<?xml ...?>` declarations from attacker-controlled clipboard HTML.
4
+ *
5
+ * Linear scan instead of `/<\?xml[^>]*>/gi`: that pattern backtracks polynomially
6
+ * when many `<?xml` openers appear with no closing `>`. An unterminated opener
7
+ * is preserved verbatim (same as the regex, which never matched it).
8
+ */
9
+ function stripXmlDeclarations(html) {
10
+ const chunks = [];
11
+ let cursor = 0;
12
+ let searchFrom = 0;
13
+ while (true) {
14
+ const start = html.indexOf("<", searchFrom);
15
+ if (start === -1) {
16
+ chunks.push(html.slice(cursor));
17
+ break;
18
+ }
19
+ if (!(html.charCodeAt(start + 1) === 63 && (html.charCodeAt(start + 2) === 88 || html.charCodeAt(start + 2) === 120) && (html.charCodeAt(start + 3) === 77 || html.charCodeAt(start + 3) === 109) && (html.charCodeAt(start + 4) === 76 || html.charCodeAt(start + 4) === 108))) {
20
+ searchFrom = start + 1;
21
+ continue;
22
+ }
23
+ const end = html.indexOf(">", start + 5);
24
+ if (end === -1) {
25
+ chunks.push(html.slice(cursor));
26
+ break;
27
+ }
28
+ chunks.push(html.slice(cursor, start));
29
+ cursor = end + 1;
30
+ searchFrom = cursor;
31
+ }
32
+ return chunks.join("");
33
+ }
34
+ //#endregion
35
+ export { stripXmlDeclarations };
@@ -109,6 +109,20 @@ type FolioVersionDiff = {
109
109
  };
110
110
  /** True when an `unpairedBaseCount * unpairedRevisedCount` LCS table would exceed {@link MAX_LCS_CELLS}. */
111
111
  declare const exceedsLcsBudget: (unpairedBaseCount: number, unpairedRevisedCount: number) => boolean;
112
+ /**
113
+ * Mutable cell budget SHARED across every story pair one {@link compareDocxVersions}
114
+ * call compares. {@link exceedsLcsBudget} alone only bounds a single pass 2
115
+ * call's own table; without an aggregate budget, a document with many
116
+ * attacker-controlled stories (footnotes/endnotes) could still force a fresh
117
+ * near-{@link MAX_LCS_CELLS}-sized allocation for EVERY story pair. Each
118
+ * `pairByExactText` call that actually runs pass 2 decrements
119
+ * `remainingCells` by its own `m * n`; once exhausted, every subsequent
120
+ * story's pass 2 is refused regardless of that story's own size, falling
121
+ * through to pass 3's linear positional zip.
122
+ */
123
+ type FolioVersionComparisonLcsBudget = {
124
+ remainingCells: number;
125
+ };
112
126
  /**
113
127
  * One step of a completed alignment, in revised-side document order with
114
128
  * base-only blocks slotted where they sat. `pair` events cover pass 1/2
@@ -131,8 +145,14 @@ type FolioAlignedBlockEvent = {
131
145
  * snapshots and flatten it into an ordered event stream. Shared by
132
146
  * {@link compareDocxVersions} and the redline generator so both interpret
133
147
  * one document walk instead of re-deriving it.
148
+ *
149
+ * `lcsBudget` defaults to a fresh, single-call budget so a caller comparing
150
+ * one block pair in isolation (the redline generator) behaves exactly as
151
+ * before. {@link compareDocxVersions} passes one budget object shared across
152
+ * every story pair instead, so pass 2's cell allowance is aggregate across
153
+ * the whole comparison rather than reset per story.
134
154
  */
135
- declare const alignFolioBlocks: (baseBlocks: readonly FolioAIBlock[], revisedBlocks: readonly FolioAIBlock[]) => FolioAlignedBlockEvent[];
155
+ declare const alignFolioBlocks: (baseBlocks: readonly FolioAIBlock[], revisedBlocks: readonly FolioAIBlock[], lcsBudget?: FolioVersionComparisonLcsBudget) => FolioAlignedBlockEvent[];
136
156
  /** Apply auditable, output-only privacy transforms to a structured version diff. */
137
157
  declare const applyFolioVersionDiffPrivacy: (diff: FolioVersionDiff, options: FolioVersionDiffPrivacyOptions) => FolioVersionDiff;
138
158
  /**
@@ -143,4 +163,4 @@ declare const applyFolioVersionDiffPrivacy: (diff: FolioVersionDiff, options: Fo
143
163
  */
144
164
  declare const compareDocxVersions: (base: ArrayBuffer, revised: ArrayBuffer, options?: FolioCompareDocxVersionsOptions) => Promise<FolioVersionDiff>;
145
165
  //#endregion
146
- export { FOLIO_DOCUMENT_METADATA_PROPERTIES, FOLIO_VERSION_COMPARISON_PRIVACY_TRANSFORMS, FOLIO_VERSION_COMPARISON_SCOPES, FolioAlignedBlockEvent, FolioBlockDiff, FolioCompareDocxVersionsOptions, type FolioDocumentMetadataProperty, FolioDocumentMetadataValue, FolioFormatProperty, FolioMetadataDiff, FolioStoryDiff, FolioVersionBlockHandle, FolioVersionComparisonPrivacyTransform, FolioVersionComparisonScope, FolioVersionDiff, FolioVersionDiffPrivacyOptions, FolioVersionDiffPrivacyReport, FolioVersionDiffSegment, FolioVersionDiffSummaryCounts, InvalidFolioVersionComparisonOptionsError, alignFolioBlocks, applyFolioVersionDiffPrivacy, compareDocxVersions, exceedsLcsBudget, isFolioVersionComparisonPrivacyTransform, isFolioVersionComparisonScope };
166
+ export { FOLIO_DOCUMENT_METADATA_PROPERTIES, FOLIO_VERSION_COMPARISON_PRIVACY_TRANSFORMS, FOLIO_VERSION_COMPARISON_SCOPES, FolioAlignedBlockEvent, FolioBlockDiff, FolioCompareDocxVersionsOptions, type FolioDocumentMetadataProperty, FolioDocumentMetadataValue, FolioFormatProperty, FolioMetadataDiff, FolioStoryDiff, FolioVersionBlockHandle, FolioVersionComparisonLcsBudget, FolioVersionComparisonPrivacyTransform, FolioVersionComparisonScope, FolioVersionDiff, FolioVersionDiffPrivacyOptions, FolioVersionDiffPrivacyReport, FolioVersionDiffSegment, FolioVersionDiffSummaryCounts, InvalidFolioVersionComparisonOptionsError, alignFolioBlocks, applyFolioVersionDiffPrivacy, compareDocxVersions, exceedsLcsBudget, isFolioVersionComparisonPrivacyTransform, isFolioVersionComparisonScope };