@stll/folio-core 0.54.2 → 0.56.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 (267) hide show
  1. package/dist/ai-edits/apply.js +185 -33
  2. package/dist/ai-edits/headless.js +3 -2
  3. package/dist/ai-edits/types.d.ts +7 -1
  4. package/dist/compare/compare.js +1 -0
  5. package/dist/compare/content-types.d.ts +3 -15
  6. package/dist/compare/reproducible-package.d.ts +0 -17
  7. package/dist/compare/reproducible-package.js +12 -18
  8. package/dist/controller/canonicalClipboard.d.ts +23 -0
  9. package/dist/controller/canonicalClipboard.js +476 -0
  10. package/dist/controller/canonicalClipboardResources.d.ts +21 -0
  11. package/dist/controller/canonicalClipboardResources.js +382 -0
  12. package/dist/controller/canonicalComposition.d.ts +53 -0
  13. package/dist/controller/canonicalComposition.js +296 -0
  14. package/dist/controller/canonicalInlineProjection.d.ts +113 -0
  15. package/dist/controller/canonicalInlineProjection.js +393 -0
  16. package/dist/controller/canonicalInput.d.ts +54 -0
  17. package/dist/controller/canonicalInput.js +377 -0
  18. package/dist/controller/canonicalInputTimer.d.ts +7 -0
  19. package/dist/controller/canonicalInputTimer.js +11 -0
  20. package/dist/controller/canonicalOperations.d.ts +22 -0
  21. package/dist/controller/canonicalOperations.js +85 -0
  22. package/dist/controller/canonicalPublicOperations.d.ts +48 -0
  23. package/dist/controller/canonicalPublicOperations.js +556 -0
  24. package/dist/controller/canonicalReview.d.ts +12 -0
  25. package/dist/controller/canonicalReview.js +19 -0
  26. package/dist/controller/canonicalSession.d.ts +167 -0
  27. package/dist/controller/canonicalSession.js +1186 -0
  28. package/dist/controller/canonicalStoryEditor.d.ts +36 -0
  29. package/dist/controller/canonicalStoryEditor.js +87 -0
  30. package/dist/controller/canonicalStructure.d.ts +16 -0
  31. package/dist/controller/canonicalStructure.js +322 -0
  32. package/dist/controller/canonicalTocSelection.d.ts +11 -0
  33. package/dist/controller/canonicalTocSelection.js +43 -0
  34. package/dist/controller/folioEditor.d.ts +3 -10
  35. package/dist/controller/folioEditor.js +14 -4
  36. package/dist/controller/headerFooterEditorManager.d.ts +5 -0
  37. package/dist/controller/headerFooterEditorManager.js +72 -3
  38. package/dist/controller/hiddenEditorApi.d.ts +45 -0
  39. package/dist/controller/hiddenEditorApi.js +29 -8
  40. package/dist/controller/hiddenEditorManager.d.ts +13 -2
  41. package/dist/controller/hiddenEditorManager.js +639 -31
  42. package/dist/controller/layoutPipeline.d.ts +1 -1
  43. package/dist/controller/layoutPipeline.js +2 -0
  44. package/dist/controller/noteEditorManager.d.ts +5 -0
  45. package/dist/controller/noteEditorManager.js +114 -15
  46. package/dist/document-operations.d.ts +8 -1
  47. package/dist/document-operations.js +6 -4
  48. package/dist/docx/attributeRemainder.js +1 -0
  49. package/dist/docx/blockPlainText.d.ts +1 -1
  50. package/dist/docx/blockPlainText.js +11 -3
  51. package/dist/docx/canonicalResourceSave.d.ts +16 -0
  52. package/dist/docx/canonicalResourceSave.js +27 -0
  53. package/dist/docx/canonicalSave.d.ts +29 -0
  54. package/dist/docx/canonicalSave.js +101 -0
  55. package/dist/docx/canonicalSessionInput.d.ts +11 -0
  56. package/dist/docx/canonicalSessionInput.js +27 -0
  57. package/dist/docx/canonicalStoryRepack.d.ts +10 -0
  58. package/dist/docx/canonicalStoryRepack.js +74 -0
  59. package/dist/docx/contentTypeRegistry.d.ts +8 -0
  60. package/dist/docx/contentTypeRegistry.js +64 -0
  61. package/dist/docx/documentParser.d.ts +1 -13
  62. package/dist/docx/documentParser.js +1 -47
  63. package/dist/docx/ensureParaIds.d.ts +7 -1
  64. package/dist/docx/ensureParaIds.js +173 -215
  65. package/dist/docx/foldedListNumberFields.d.ts +85 -0
  66. package/dist/docx/foldedListNumberFields.js +267 -0
  67. package/dist/docx/footnoteParser.d.ts +1 -11
  68. package/dist/docx/footnoteParser.js +1 -16
  69. package/dist/docx/headerFooterParser.d.ts +1 -9
  70. package/dist/docx/headerFooterParser.js +1 -12
  71. package/dist/docx/headerFooterVerbatim.d.ts +39 -1
  72. package/dist/docx/headerFooterVerbatim.js +173 -2
  73. package/dist/docx/imageParser.d.ts +13 -1
  74. package/dist/docx/imageParser.js +20 -11
  75. package/dist/docx/metadataPrivacy.js +6 -1
  76. package/dist/docx/noteIds.d.ts +5 -0
  77. package/dist/docx/noteIds.js +6 -2
  78. package/dist/docx/noteReferenceMark.d.ts +3 -1
  79. package/dist/docx/noteReferenceMark.js +15 -14
  80. package/dist/docx/numberingParser.d.ts +3 -1
  81. package/dist/docx/numberingParser.js +17 -3
  82. package/dist/docx/packageParts.d.ts +3 -1
  83. package/dist/docx/packageParts.js +74 -19
  84. package/dist/docx/paragraphMarkPropertyPresence.d.ts +9 -0
  85. package/dist/docx/paragraphMarkPropertyPresence.js +21 -0
  86. package/dist/docx/paragraphParser.js +101 -53
  87. package/dist/docx/paragraphPropertySource.d.ts +15 -1
  88. package/dist/docx/paragraphPropertySource.js +77 -22
  89. package/dist/docx/parser.js +3 -1
  90. package/dist/docx/removeHeaderFooterParts.js +17 -6
  91. package/dist/docx/reviewHistoryNamespace.d.ts +4 -0
  92. package/dist/docx/reviewHistoryNamespace.js +4 -0
  93. package/dist/docx/reviewResolutionProvenance.d.ts +25 -0
  94. package/dist/docx/reviewResolutionProvenance.js +153 -0
  95. package/dist/docx/rezip.d.ts +54 -6
  96. package/dist/docx/rezip.js +835 -257
  97. package/dist/docx/runConsolidator.d.ts +2 -58
  98. package/dist/docx/runConsolidator.js +3 -175
  99. package/dist/docx/runParser.d.ts +2 -1
  100. package/dist/docx/runParser.js +156 -116
  101. package/dist/docx/saveDiagnostics.d.ts +22 -0
  102. package/dist/docx/saveDiagnostics.js +0 -0
  103. package/dist/docx/selectiveSave.d.ts +3 -1
  104. package/dist/docx/selectiveSave.js +36 -4
  105. package/dist/docx/selectiveXmlPatch.d.ts +16 -8
  106. package/dist/docx/selectiveXmlPatch.js +81 -7
  107. package/dist/docx/serializer/documentSerializer.d.ts +9 -2
  108. package/dist/docx/serializer/documentSerializer.js +29 -10
  109. package/dist/docx/serializer/headerFooterSerializer.d.ts +5 -1
  110. package/dist/docx/serializer/headerFooterSerializer.js +19 -11
  111. package/dist/docx/serializer/noteSerializer.d.ts +2 -2
  112. package/dist/docx/serializer/noteSerializer.js +24 -8
  113. package/dist/docx/serializer/paragraphSerializer.js +41 -4
  114. package/dist/docx/serializer/partNamespaces.js +2 -1
  115. package/dist/docx/serializer/runSerializer.js +3 -1
  116. package/dist/docx/server/applyDocxXmlPatchProposal.js +14 -9
  117. package/dist/docx/settingsHeaderFooterUpdate.d.ts +5 -0
  118. package/dist/docx/settingsHeaderFooterUpdate.js +90 -0
  119. package/dist/docx/settingsParser.d.ts +1 -2
  120. package/dist/docx/settingsParser.js +5 -6
  121. package/dist/docx/storyBlockReplay.d.ts +31 -0
  122. package/dist/docx/storyBlockReplay.js +471 -0
  123. package/dist/docx/storyPlainText.d.ts +20 -0
  124. package/dist/docx/storyPlainText.js +23 -0
  125. package/dist/docx/streamingXmlParser.d.ts +22 -1
  126. package/dist/docx/streamingXmlParser.js +49 -3
  127. package/dist/docx/structuralXmlPatch.js +18 -23
  128. package/dist/docx/styleParser.d.ts +5 -1
  129. package/dist/docx/styleParser.js +1 -1
  130. package/dist/docx/tableParser.d.ts +1 -8
  131. package/dist/docx/tableParser.js +1 -28
  132. package/dist/docx/textBoxParser.d.ts +1 -5
  133. package/dist/docx/textBoxParser.js +1 -20
  134. package/dist/docx/unzip.js +6 -1
  135. package/dist/docx/verbatimCapture.d.ts +3 -1
  136. package/dist/docx/verbatimCapture.js +49 -6
  137. package/dist/i18n/messages/ar.gen.d.ts +5 -0
  138. package/dist/i18n/messages/ar.gen.js +656 -0
  139. package/dist/i18n/messages/cs.gen.d.ts +5 -0
  140. package/dist/i18n/messages/cs.gen.js +656 -0
  141. package/dist/i18n/messages/de.gen.d.ts +5 -0
  142. package/dist/i18n/messages/de.gen.js +656 -0
  143. package/dist/i18n/messages/en.gen.d.ts +5 -0
  144. package/dist/i18n/messages/en.gen.js +656 -0
  145. package/dist/i18n/messages/es.gen.d.ts +5 -0
  146. package/dist/i18n/messages/es.gen.js +656 -0
  147. package/dist/i18n/messages/et.gen.d.ts +5 -0
  148. package/dist/i18n/messages/et.gen.js +656 -0
  149. package/dist/i18n/messages/fr.gen.d.ts +5 -0
  150. package/dist/i18n/messages/fr.gen.js +656 -0
  151. package/dist/i18n/messages/he.gen.d.ts +5 -0
  152. package/dist/i18n/messages/he.gen.js +656 -0
  153. package/dist/i18n/messages/hi.gen.d.ts +5 -0
  154. package/dist/i18n/messages/hi.gen.js +656 -0
  155. package/dist/i18n/messages/hu.gen.d.ts +5 -0
  156. package/dist/i18n/messages/hu.gen.js +656 -0
  157. package/dist/i18n/messages/locales.d.ts +5 -0
  158. package/dist/i18n/messages/locales.js +22 -0
  159. package/dist/i18n/messages/lt.gen.d.ts +5 -0
  160. package/dist/i18n/messages/lt.gen.js +656 -0
  161. package/dist/i18n/messages/lv.gen.d.ts +5 -0
  162. package/dist/i18n/messages/lv.gen.js +656 -0
  163. package/dist/i18n/messages/pl.gen.d.ts +5 -0
  164. package/dist/i18n/messages/pl.gen.js +656 -0
  165. package/dist/i18n/messages/pt-BR.gen.d.ts +5 -0
  166. package/dist/i18n/messages/pt-BR.gen.js +656 -0
  167. package/dist/i18n/messages/sk.gen.d.ts +5 -0
  168. package/dist/i18n/messages/sk.gen.js +656 -0
  169. package/dist/i18n/messages/tr.gen.d.ts +5 -0
  170. package/dist/i18n/messages/tr.gen.js +656 -0
  171. package/dist/i18n/messages/zh-CN.gen.d.ts +5 -0
  172. package/dist/i18n/messages/zh-CN.gen.js +656 -0
  173. package/dist/i18n/messages.d.ts +2 -3
  174. package/dist/i18n/messages.js +1 -19
  175. package/dist/internal/acceptedBlockProjection.d.ts +12 -0
  176. package/dist/internal/acceptedBlockProjection.js +45 -0
  177. package/dist/internal/noteMarkerAttrs.d.ts +8 -0
  178. package/dist/internal/noteMarkerAttrs.js +16 -0
  179. package/dist/internal/pageBreakRunSourceDescendantIndex.js +1 -0
  180. package/dist/internal/prosemirrorAttrBoundary.d.ts +21 -0
  181. package/dist/internal/prosemirrorAttrBoundary.js +50 -0
  182. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  183. package/dist/layout-bridge/convert/footnoteLayout.js +3 -3
  184. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  185. package/dist/layout-bridge/convert/headerFooterLayout.js +1 -0
  186. package/dist/layout-bridge/convert/noteReferences.d.ts +1 -3
  187. package/dist/layout-bridge/convert/noteReferences.js +1 -6
  188. package/dist/layout-bridge/convert/paragraphRuns.js +2 -4
  189. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +2 -2
  190. package/dist/layout-bridge/convert/toFlowBlocks.js +2 -2
  191. package/dist/managers/DocumentLoaderManager.d.ts +1 -0
  192. package/dist/managers/DocumentLoaderManager.js +9 -1
  193. package/dist/markdown/escape.d.ts +3 -1
  194. package/dist/markdown/escape.js +9 -2
  195. package/dist/markdown/renderBlock.js +20 -121
  196. package/dist/markdown/renderParagraph.js +13 -15
  197. package/dist/markdown/renderRuns.d.ts +7 -1
  198. package/dist/markdown/renderRuns.js +35 -15
  199. package/dist/markdown/renderTable.js +2 -0
  200. package/dist/markdown/types.d.ts +3 -9
  201. package/dist/prosemirror/attrs/index.d.ts +2 -12
  202. package/dist/prosemirror/attrs/index.js +22 -48
  203. package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +2 -1
  204. package/dist/prosemirror/canonicalCommands.d.ts +121 -0
  205. package/dist/prosemirror/canonicalCommands.js +35 -0
  206. package/dist/prosemirror/canonicalSelectionRange.d.ts +9 -0
  207. package/dist/prosemirror/canonicalSelectionRange.js +15 -0
  208. package/dist/prosemirror/clipboardIntent.d.ts +7 -0
  209. package/dist/prosemirror/clipboardIntent.js +9 -0
  210. package/dist/prosemirror/commands/pageBreak.js +15 -1
  211. package/dist/prosemirror/commands/pastePlainText.js +2 -1
  212. package/dist/prosemirror/commentReferenceAttrs.d.ts +2 -1
  213. package/dist/prosemirror/conversion/fromProseDoc.js +91 -19
  214. package/dist/prosemirror/conversion/hyphenTextCarriers.d.ts +8 -0
  215. package/dist/prosemirror/conversion/hyphenTextCarriers.js +8 -0
  216. package/dist/prosemirror/conversion/listRenderingDefinition.d.ts +6 -0
  217. package/dist/prosemirror/conversion/listRenderingDefinition.js +97 -0
  218. package/dist/prosemirror/conversion/toProseDoc.d.ts +11 -4
  219. package/dist/prosemirror/conversion/toProseDoc.js +55 -14
  220. package/dist/prosemirror/executeEditorCommand.d.ts +11 -0
  221. package/dist/prosemirror/executeEditorCommand.js +26 -0
  222. package/dist/prosemirror/extensions/StarterKit.js +2 -0
  223. package/dist/prosemirror/extensions/core/ParagraphExtension.js +88 -48
  224. package/dist/prosemirror/extensions/features/ListExtension.js +18 -5
  225. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +5 -2
  226. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +13 -1
  227. package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +56 -28
  228. package/dist/prosemirror/extensions/marks/TextColorExtension.js +3 -2
  229. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +2 -0
  230. package/dist/prosemirror/extensions/marks/markUtils.js +72 -8
  231. package/dist/prosemirror/extensions/nodes/NoteMarkerExtension.d.ts +6 -0
  232. package/dist/prosemirror/extensions/nodes/NoteMarkerExtension.js +36 -0
  233. package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.js +4 -2
  234. package/dist/prosemirror/insertOperations.js +2 -1
  235. package/dist/prosemirror/listMarker.d.ts +1 -0
  236. package/dist/prosemirror/listMarker.js +16 -7
  237. package/dist/prosemirror/listNumbering.js +26 -5
  238. package/dist/prosemirror/listRenderingAttrs.d.ts +1 -0
  239. package/dist/prosemirror/listRenderingAttrs.js +3 -0
  240. package/dist/prosemirror/markupViewNotes.js +3 -2
  241. package/dist/prosemirror/moveRangeBoundaryAttrs.d.ts +2 -1
  242. package/dist/prosemirror/noteReferenceReview.js +5 -3
  243. package/dist/prosemirror/paragraphPropertyCarry.d.ts +7 -1
  244. package/dist/prosemirror/paragraphPropertyCarry.js +8 -3
  245. package/dist/prosemirror/plugins/suggestionMode.js +57 -7
  246. package/dist/prosemirror/rangeAnchorAttrs.d.ts +2 -1
  247. package/dist/prosemirror/runFormattingFromMarks.d.ts +4 -1
  248. package/dist/prosemirror/runFormattingFromMarks.js +15 -1
  249. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +2 -1
  250. package/dist/prosemirror/runFormattingInlineCarriers.js +4 -1
  251. package/dist/prosemirror/schema/marks.d.ts +2 -0
  252. package/dist/prosemirror/schema/nodes.d.ts +10 -2
  253. package/dist/prosemirror/textBoxAnchorAttrs.d.ts +2 -1
  254. package/dist/prosemirror/textInput.js +5 -1
  255. package/dist/prosemirror/trackedRevisionPath.js +2 -1
  256. package/dist/prosemirror/trackedRunInlineAtoms.d.ts +1 -0
  257. package/dist/prosemirror/trackedRunInlineAtoms.js +1 -0
  258. package/dist/prosemirror/validation.js +4 -0
  259. package/dist/types/canonicalCapabilities.d.ts +215 -0
  260. package/dist/types/canonicalCapabilities.js +212 -0
  261. package/dist/types/canonicalSave.d.ts +11 -0
  262. package/dist/types/canonicalSave.js +0 -0
  263. package/dist/types/content.d.ts +2 -2
  264. package/dist/types/docxSerialization.d.ts +14 -0
  265. package/dist/types/docxSerialization.js +7 -0
  266. package/dist/utils/createDocument.js +2 -2
  267. package/package.json +16 -4
@@ -1,9 +1,9 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
2
  import { TemplatePreviewEntry, TemplatePreviewHiddenRange } from "../prosemirror/plugins/templatePreviewValues.js";
3
3
  import { ColumnLayout, FlowBlock, FootnoteContent, HeaderFooterContent, Layout, Measure, PageHeaderFooterRefs, PageMargins } from "../layout-engine/types.js";
4
+ import { LayoutRunOptions } from "./layoutRunOptions.js";
4
5
  import { DisplayMode } from "../managers/EditorModeManager.js";
5
6
  import { LayoutSession } from "./layoutSession.js";
6
- import { LayoutRunOptions } from "./layoutRunOptions.js";
7
7
  import { HyphenationReadiness } from "./hyphenationReadiness.js";
8
8
  import { ConvertHeaderFooterOptions, HeaderFooterMetrics } from "../layout-bridge/convert/headerFooterLayout.js";
9
9
  import "../layout-engine/index.js";
@@ -244,6 +244,7 @@ function runLayoutPipelineMeasured(deps, state, options) {
244
244
  const hfMeasureBlocks = (hfBlocks, hfWidth) => measureBlocks(hfBlocks, hfWidth, void 0, void 0, buildHeaderFooterFieldValues(hfBlocks, pageCount, hfClock, fieldInputs), { allowEndTabOverflow: true });
245
245
  return {
246
246
  ...flowOpts.styles ? { styles: flowOpts.styles } : {},
247
+ ...document?.package.numbering === void 0 ? {} : { numbering: document.package.numbering },
247
248
  ...flowOpts.defaultSize === void 0 ? {} : { defaultSize: flowOpts.defaultSize },
248
249
  ..._theme !== void 0 ? { theme: _theme } : {},
249
250
  fontAlternates,
@@ -377,6 +378,7 @@ function runLayoutPipelineMeasured(deps, state, options) {
377
378
  if (flowOpts.styles) noteOptions.styles = flowOpts.styles;
378
379
  if (flowOpts.defaultSize !== void 0) noteOptions.defaultSize = flowOpts.defaultSize;
379
380
  if (_theme !== void 0) noteOptions.theme = _theme;
381
+ if (document?.package.numbering !== void 0) noteOptions.numbering = document.package.numbering;
380
382
  noteOptions.fontAlternates = fontAlternates;
381
383
  if (defaultTabStop !== void 0) noteOptions.defaultTabStopTwips = defaultTabStop;
382
384
  if (flowOpts.lineBreakRules) noteOptions.lineBreakRules = flowOpts.lineBreakRules;
@@ -1,4 +1,6 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
+ import { CanonicalGap } from "../types/canonicalCapabilities.js";
3
+ import { HiddenEditorApi } from "./hiddenEditorApi.js";
2
4
  import { NoteStoryKey } from "../types/editor-story.js";
3
5
  import { Plugin } from "prosemirror-state";
4
6
  import { DirectEditorProps, EditorView } from "prosemirror-view";
@@ -12,6 +14,9 @@ type NoteEditorTransaction = NoteStoryKey & {
12
14
  type NoteEditorManagerDeps = {
13
15
  createView?: ((mountNode: HTMLElement, props: DirectEditorProps) => EditorView) | undefined;
14
16
  getDocument: () => document_d_exports.Document | null;
17
+ getCanonicalApi?: (() => HiddenEditorApi | null) | undefined;
18
+ getExperimentalSession?: (() => "canonical" | undefined) | undefined;
19
+ onSessionRefusal?: ((reason: string, gap: CanonicalGap) => void) | undefined;
15
20
  getHost: () => HTMLElement | null;
16
21
  getPlugins?: (() => Plugin[]) | undefined;
17
22
  getStyles: () => document_d_exports.StyleDefinitions | null | undefined;
@@ -1,4 +1,6 @@
1
1
  import { isSeparatorEndnote, isSeparatorFootnote } from "../docx/footnoteParser.js";
2
+ import { cloneDocumentWithParagraphPropertySources } from "../docx/paragraphPropertySource.js";
3
+ import { visitDocxParagraphs, visitParagraphRuns } from "../docx/paragraphTraversal.js";
2
4
  import { proseDocToBlocks } from "../prosemirror/conversion/fromProseDoc.js";
3
5
  import { footnoteToProseDoc } from "../prosemirror/conversion/toProseDoc.js";
4
6
  import { ExtensionManager } from "../prosemirror/extensions/ExtensionManager.js";
@@ -9,7 +11,10 @@ import { createDocumentNumberingPlugin } from "../prosemirror/plugins/documentNu
9
11
  import { createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
10
12
  import { schema } from "../prosemirror/schema/index.js";
11
13
  import { storyListNumbering } from "../prosemirror/storyListNumbering.js";
12
- import { EditorState } from "prosemirror-state";
14
+ import { CANONICAL_GAP, usesCanonicalSession } from "../types/canonicalCapabilities.js";
15
+ import { createCanonicalStoryEditor } from "./canonicalStoryEditor.js";
16
+ import { OP_STORIES } from "@stll/docx-core/ops";
17
+ import { EditorState, TextSelection } from "prosemirror-state";
13
18
  import { EditorView } from "prosemirror-view";
14
19
  //#region src/controller/noteEditorManager.ts
15
20
  /** Framework-neutral lifecycle owner for editable footnote and endnote stories. */
@@ -28,12 +33,7 @@ const enumerateDocumentNoteStories = (document) => [...(document?.package.footno
28
33
  const resolveNote = (document, story) => {
29
34
  return (story.kind === "footnote" ? document?.package.footnotes : document?.package.endnotes)?.find(({ id }) => id === story.noteId) ?? null;
30
35
  };
31
- const noteToProseDocument = (note, styles, theme) => {
32
- const options = {};
33
- if (styles) options.styles = styles;
34
- if (theme !== void 0) options.theme = theme;
35
- return footnoteToProseDoc(note.content, options);
36
- };
36
+ const noteToProseDocument = (note, options) => footnoteToProseDoc(note.content, options);
37
37
  const buildInitialState = (document, styles, numbering, manager, externalPlugins) => {
38
38
  return ensureBaseDirectionInState(ensureParaIdsInState(EditorState.create({
39
39
  doc: document,
@@ -46,6 +46,31 @@ const buildInitialState = (document, styles, numbering, manager, externalPlugins
46
46
  ]
47
47
  })));
48
48
  };
49
+ /** Automatic note marks have no PM width; retain their authored runs on default writeback. */
50
+ const preserveNoteMarkers = ({ source, projected }) => {
51
+ const marks = [];
52
+ visitDocxParagraphs({ documentBody: { content: source } }, (paragraph) => visitParagraphRuns(paragraph, (run) => {
53
+ const content = run.content.filter((child) => child.type === "noteMarker");
54
+ if (content.length > 0) marks.push({
55
+ ...run,
56
+ content
57
+ });
58
+ }));
59
+ if (marks.length === 0) return projected;
60
+ let hasMarker = false;
61
+ visitDocxParagraphs({ documentBody: { content: projected } }, (paragraph) => visitParagraphRuns(paragraph, (run) => {
62
+ if (run.content.some((child) => child.type === "noteMarker")) hasMarker = true;
63
+ }));
64
+ if (hasMarker) return projected;
65
+ const owned = cloneDocumentWithParagraphPropertySources({ package: { document: { content: projected } } }).package.document.content;
66
+ const paragraphs = [];
67
+ visitDocxParagraphs({ documentBody: { content: owned } }, (paragraph) => {
68
+ paragraphs.push(paragraph);
69
+ });
70
+ const first = paragraphs.at(0);
71
+ if (first) first.content.unshift(...marks);
72
+ return owned;
73
+ };
49
74
  const createNoteEditorManager = (deps) => {
50
75
  const mounted = /* @__PURE__ */ new Map();
51
76
  let active = null;
@@ -66,10 +91,16 @@ const createNoteEditorManager = (deps) => {
66
91
  const sync = () => {
67
92
  const host = deps.getHost();
68
93
  if (!host) return;
69
- const document = deps.getDocument();
94
+ if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories) && !deps.getCanonicalApi?.()?.getCanonicalStoryProjection(OP_STORIES.MAIN)) return;
95
+ const document = usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories) ? deps.getCanonicalApi?.()?.getCanonicalDocument() ?? deps.getDocument() : deps.getDocument();
70
96
  const styles = deps.getStyles();
71
97
  const theme = deps.getTheme();
72
98
  const numbering = document?.package.numbering;
99
+ const proseOptions = {
100
+ ...styles ? { styles } : {},
101
+ ...theme !== void 0 ? { theme } : {},
102
+ ...numbering !== void 0 ? { numbering } : {}
103
+ };
73
104
  const externalPlugins = deps.getPlugins?.() ?? EMPTY_PLUGINS;
74
105
  const wanted = new Map(enumerateDocumentNoteStories(document).map((story) => [storyMapKey(story), story]));
75
106
  const activeKey = active ? storyMapKey(active) : null;
@@ -85,7 +116,33 @@ const createNoteEditorManager = (deps) => {
85
116
  const existing = mounted.get(key);
86
117
  if (existing) {
87
118
  if (existing.mountNode.parentElement !== host) host.append(existing.mountNode);
88
- const nextProseDocument = noteToProseDocument(note, styles, theme);
119
+ if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories)) {
120
+ const projected = deps.getCanonicalApi?.()?.getCanonicalStoryProjection({
121
+ kind: storyKey.kind,
122
+ id: storyKey.noteId
123
+ });
124
+ if (projected && !existing.view.state.doc.eq(projected)) {
125
+ const transaction = existing.view.state.tr.replaceWith(0, existing.view.state.doc.content.size, projected.content);
126
+ const restored = deps.getCanonicalApi?.()?.getCanonicalStorySelection({
127
+ kind: storyKey.kind,
128
+ id: storyKey.noteId
129
+ });
130
+ const anchor = Math.min(existing.view.state.selection.anchor, projected.content.size);
131
+ transaction.setSelection(restored ? TextSelection.create(transaction.doc, restored.anchor, restored.head) : TextSelection.near(transaction.doc.resolve(anchor)));
132
+ transaction.setMeta("addToHistory", false);
133
+ existing.view.updateState(existing.view.state.apply(transaction));
134
+ }
135
+ existing.appliedNote = note;
136
+ existing.appliedContent = note.content;
137
+ existing.appliedProseDocument = existing.view.state.doc;
138
+ existing.appliedStyles = styles;
139
+ existing.appliedTheme = theme;
140
+ existing.appliedNumbering = numbering;
141
+ existing.appliedPlugins = externalPlugins;
142
+ existing.dirty = false;
143
+ continue;
144
+ }
145
+ const nextProseDocument = noteToProseDocument(note, proseOptions);
89
146
  const contextIsCurrent = existing.appliedStyles === styles && existing.appliedTheme === theme && existing.appliedNumbering === numbering && existing.appliedPlugins === externalPlugins;
90
147
  if ((existing.appliedNote === note && existing.appliedContent === note.content || existing.appliedProseDocument.eq(nextProseDocument)) && contextIsCurrent) {
91
148
  existing.appliedNote = note;
@@ -111,10 +168,40 @@ const createNoteEditorManager = (deps) => {
111
168
  mountNode.dataset["noteKind"] = storyKey.kind;
112
169
  mountNode.dataset["noteId"] = String(storyKey.noteId);
113
170
  host.append(mountNode);
114
- const proseDocument = noteToProseDocument(note, styles, theme);
171
+ const proseDocument = noteToProseDocument(note, proseOptions);
172
+ const canonical = createCanonicalStoryEditor({
173
+ story: {
174
+ kind: storyKey.kind,
175
+ id: storyKey.noteId
176
+ },
177
+ getView: () => view,
178
+ getApi: () => deps.getCanonicalApi?.() ?? null,
179
+ enabled: () => usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories),
180
+ onRefusal: deps.onSessionRefusal,
181
+ onSelectionChange: () => deps.onTransaction?.({
182
+ ...storyKey,
183
+ view,
184
+ docChanged: false,
185
+ selectionChanged: true
186
+ })
187
+ });
188
+ const canonicalProjection = usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories) ? deps.getCanonicalApi?.()?.getCanonicalStoryProjection({
189
+ kind: storyKey.kind,
190
+ id: storyKey.noteId
191
+ }) : null;
192
+ if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories) && !canonicalProjection) {
193
+ manager.destroy();
194
+ mountNode.remove();
195
+ continue;
196
+ }
115
197
  const view = (deps.createView ?? createEditorView)(mountNode, {
116
- state: buildInitialState(proseDocument, styles, numbering, manager, externalPlugins),
198
+ ...canonical.props,
199
+ state: canonicalProjection ? EditorState.create({
200
+ doc: canonicalProjection,
201
+ plugins: [createDocumentStylesPlugin(styles), createDocumentNumberingPlugin(numbering)]
202
+ }) : buildInitialState(proseDocument, styles, numbering, manager, externalPlugins),
117
203
  dispatchTransaction(transaction) {
204
+ if (canonical.dispatch(transaction)) return;
118
205
  view.updateState(view.state.apply(transaction));
119
206
  const mountedStory = mounted.get(key);
120
207
  if (mountedStory && transaction.docChanged) mountedStory.dirty = true;
@@ -160,6 +247,7 @@ const createNoteEditorManager = (deps) => {
160
247
  getView: (story) => mounted.get(storyMapKey(story))?.view ?? null,
161
248
  listStories: () => enumerateDocumentNoteStories(deps.getDocument()),
162
249
  snapshotDocument: (document) => {
250
+ if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories)) return deps.getCanonicalApi?.()?.getCanonicalDocument() ?? document;
163
251
  let footnotes = document.package.footnotes;
164
252
  let endnotes = document.package.endnotes;
165
253
  let footnotesChanged = false;
@@ -169,6 +257,11 @@ const createNoteEditorManager = (deps) => {
169
257
  if (!story.dirty) continue;
170
258
  const lists = storyListNumbering(story.view.state, numbering);
171
259
  numbering = lists.numbering;
260
+ const proseOptions = {
261
+ ...story.appliedStyles ? { styles: story.appliedStyles } : {},
262
+ ...story.appliedTheme !== void 0 ? { theme: story.appliedTheme } : {},
263
+ ...numbering !== void 0 ? { numbering } : {}
264
+ };
172
265
  if (story.note.kind === "footnote") {
173
266
  const index = footnotes?.findIndex(({ id }) => id === story.note.noteId) ?? -1;
174
267
  const current = index === -1 ? null : footnotes?.at(index);
@@ -179,12 +272,15 @@ const createNoteEditorManager = (deps) => {
179
272
  }
180
273
  const updated = {
181
274
  ...current,
182
- content: proseDocToBlocks(lists.doc, current.content, document.package.styles)
275
+ content: preserveNoteMarkers({
276
+ source: current.content,
277
+ projected: proseDocToBlocks(lists.doc, current.content, document.package.styles)
278
+ })
183
279
  };
184
280
  footnotes[index] = updated;
185
281
  story.appliedNote = updated;
186
282
  story.appliedContent = updated.content;
187
- story.appliedProseDocument = noteToProseDocument(updated, story.appliedStyles, story.appliedTheme);
283
+ story.appliedProseDocument = noteToProseDocument(updated, proseOptions);
188
284
  continue;
189
285
  }
190
286
  const index = endnotes?.findIndex(({ id }) => id === story.note.noteId) ?? -1;
@@ -196,12 +292,15 @@ const createNoteEditorManager = (deps) => {
196
292
  }
197
293
  const updated = {
198
294
  ...current,
199
- content: proseDocToBlocks(lists.doc, current.content, document.package.styles)
295
+ content: preserveNoteMarkers({
296
+ source: current.content,
297
+ projected: proseDocToBlocks(lists.doc, current.content, document.package.styles)
298
+ })
200
299
  };
201
300
  endnotes[index] = updated;
202
301
  story.appliedNote = updated;
203
302
  story.appliedContent = updated.content;
204
- story.appliedProseDocument = noteToProseDocument(updated, story.appliedStyles, story.appliedTheme);
303
+ story.appliedProseDocument = noteToProseDocument(updated, proseOptions);
205
304
  }
206
305
  if (!footnotesChanged && !endnotesChanged) return document;
207
306
  return {
@@ -132,6 +132,7 @@ type FolioDocumentOperationIssue = {
132
132
  code: FolioAIEditSkippedOperation["reason"];
133
133
  retryable: boolean;
134
134
  recovery: FolioDocumentOperationRecovery;
135
+ canonicalRefusal?: FolioAIEditSkippedOperation["canonicalRefusal"];
135
136
  /** The skip's detail, when it has one; see {@link FolioAIEditSkippedOperation.message}. */
136
137
  message?: string;
137
138
  };
@@ -264,6 +265,12 @@ type FolioDocumentOperationResult = (FolioDocumentOperationResultBase & {
264
265
  declare const getFolioDocumentOperationIssues: (operations: readonly FolioDocumentOperation[], skipped: readonly FolioAIEditSkippedOperation[]) => FolioDocumentOperationIssue[];
265
266
  /** Build deterministic affected-target receipts from operations and their applied entries. */
266
267
  declare const getFolioDocumentOperationReceipts: (operations: readonly FolioDocumentOperation[], applied: readonly FolioAIEditAppliedOperation[]) => FolioDocumentOperationReceipt[];
268
+ type GetFolioDocumentOperationReceiptsForStoryOptions = {
269
+ operations: readonly FolioDocumentOperation[];
270
+ applied: readonly FolioAIEditAppliedOperation[];
271
+ story: FolioDocumentOperationStory;
272
+ };
273
+ declare const getFolioDocumentOperationReceiptsForStory: ({ operations, applied, story }: GetFolioDocumentOperationReceiptsForStoryOptions) => FolioDocumentOperationReceipt[];
267
274
  type ApplyFolioDocumentOperationsOptions = {
268
275
  view: FolioAIEditView;
269
276
  snapshot: FolioAIEditSnapshot;
@@ -301,4 +308,4 @@ type ApplyFolioDocumentOperationsOptions = {
301
308
  };
302
309
  declare const applyFolioDocumentOperations: ({ view, snapshot, batch, story, author, createCommentId, createUndoHandle, revisionStamp, wordDiff, tableTemplates, replacementBackground, undefinedStyles }: ApplyFolioDocumentOperationsOptions) => FolioDocumentOperationResult;
303
310
  //#endregion
304
- export { ApplyFolioDocumentOperationsOptions, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_BATCH_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_LINE_SPACING_RULE_VALUES, FOLIO_PAGE_BREAK_CLEAR_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, FolioDocumentOperation, FolioDocumentOperationAffectedTarget, FolioDocumentOperationBatch, FolioDocumentOperationBatchPrecondition, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationQueuedOperation, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationResultBase, FolioDocumentOperationStatus, FolioDocumentOperationStory, FolioDocumentOperationType, FolioDocumentOperationUndoFailureReason, FolioDocumentOperationUndoHandle, FolioDocumentOperationUndoResult, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch };
311
+ export { ApplyFolioDocumentOperationsOptions, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_BATCH_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_LINE_SPACING_RULE_VALUES, FOLIO_PAGE_BREAK_CLEAR_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, FolioDocumentOperation, FolioDocumentOperationAffectedTarget, FolioDocumentOperationBatch, FolioDocumentOperationBatchPrecondition, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationQueuedOperation, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationResultBase, FolioDocumentOperationStatus, FolioDocumentOperationStory, FolioDocumentOperationType, FolioDocumentOperationUndoFailureReason, FolioDocumentOperationUndoHandle, FolioDocumentOperationUndoResult, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioDocumentOperationReceiptsForStory, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch };
@@ -1072,22 +1072,24 @@ const recoveryByReason = {
1072
1072
  missingStyle: "refreshDocument",
1073
1073
  missingNumbering: "refreshDocument",
1074
1074
  invalidResult: "refreshDocument",
1075
- pendingDeletion: "resolveTrackedChange"
1075
+ pendingDeletion: "resolveTrackedChange",
1076
+ pendingParagraphMarkDeletion: "resolveTrackedChange"
1076
1077
  };
1077
1078
  const getFolioDocumentOperationIssues = (operations, skipped) => {
1078
1079
  const indexById = /* @__PURE__ */ new Map();
1079
1080
  operations.forEach(({ id }, index) => {
1080
1081
  indexById.set(id, index);
1081
1082
  });
1082
- return skipped.map(({ id, reason, message }) => {
1083
+ return skipped.map(({ id, reason, message, canonicalRefusal }) => {
1083
1084
  const operationIndex = indexById.get(id) ?? -1;
1084
1085
  return {
1085
1086
  operationId: id,
1086
1087
  operationIndex,
1087
1088
  path: `$.operations[${operationIndex}]`,
1088
1089
  code: reason,
1089
- retryable: reason !== "emptyOperation" && reason !== "noopOperation" && reason !== "pendingParagraphPropertyChange" && reason !== "pendingRunPropertyChange" && reason !== "pendingDeletion" && reason !== "payloadDoesNotFit" && reason !== "protectedReference" && reason !== "invalidResult",
1090
+ retryable: reason !== "emptyOperation" && reason !== "noopOperation" && reason !== "pendingParagraphPropertyChange" && reason !== "pendingRunPropertyChange" && reason !== "pendingDeletion" && reason !== "pendingParagraphMarkDeletion" && reason !== "payloadDoesNotFit" && reason !== "protectedReference" && reason !== "invalidResult",
1090
1091
  recovery: recoveryByReason[reason],
1092
+ ...canonicalRefusal === void 0 ? {} : { canonicalRefusal },
1091
1093
  ...message !== void 0 && { message }
1092
1094
  };
1093
1095
  });
@@ -1468,4 +1470,4 @@ const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", a
1468
1470
  };
1469
1471
  };
1470
1472
  //#endregion
1471
- export { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_BATCH_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_LINE_SPACING_RULE_VALUES, FOLIO_PAGE_BREAK_CLEAR_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch };
1473
+ export { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_BATCH_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_LINE_SPACING_RULE_VALUES, FOLIO_PAGE_BREAK_CLEAR_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioDocumentOperationReceiptsForStory, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch };
@@ -55,6 +55,7 @@ const attributeRemainder = ({ element, modelled }) => {
55
55
  const name = getLocalName(spelling);
56
56
  if (modelled.has(name)) continue;
57
57
  const namespace = resolveAttributeNamespaceUri(element, spelling);
58
+ if (namespace === OOXML_NAMESPACES.mc.uri && name === "Ignorable") continue;
58
59
  if (namespace !== void 0 && !CANONICAL_PREFIX.has(namespace)) continue;
59
60
  remainder.push({
60
61
  ...namespace === void 0 ? {} : { namespace },
@@ -1,6 +1,6 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
2
  //#region src/docx/blockPlainText.d.ts
3
- /** One entry per block, so callers can join or count lines as they need. */
3
+ /** One entry per accepted block; deleted breaks and table structure resolve together. */
4
4
  declare const collectBlockTexts: (blocks: readonly document_d_exports.BlockContent[]) => string[];
5
5
  declare const blockPlainText: (blocks: readonly document_d_exports.BlockContent[]) => string;
6
6
  //#endregion
@@ -1,3 +1,4 @@
1
+ import { projectAcceptedBlocks } from "../internal/acceptedBlockProjection.js";
1
2
  import { ALT_CHUNK_READER_DIAGNOSTIC, isAltChunkMarkup } from "./altChunk.js";
2
3
  import { OPAQUE_REVISION_CARRIER_READER_DIAGNOSTIC, isOpaqueNestedRowMarkup, opaqueRevisionCarrierName } from "./opaqueCarrier.js";
3
4
  import { getParagraphText } from "./paragraphParser.js";
@@ -18,7 +19,7 @@ import { panic } from "better-result";
18
19
  * everything below block level and reads the accepted tracked-change view.
19
20
  */
20
21
  /** One entry per block, so callers can join or count lines as they need. */
21
- const collectBlockTexts = (blocks) => {
22
+ const collectResolvedBlockTexts = (blocks) => {
22
23
  const texts = [];
23
24
  for (const block of blocks) switch (block.type) {
24
25
  case "paragraph":
@@ -27,12 +28,12 @@ const collectBlockTexts = (blocks) => {
27
28
  case "table":
28
29
  for (const row of block.rows) {
29
30
  if (row.formatting?.hidden === true) continue;
30
- texts.push(row.cells.map((cell) => collectBlockTexts(cell.content).join("\n")).join(" "));
31
+ texts.push(row.cells.map((cell) => collectResolvedBlockTexts(cell.content).join("\n")).join(" "));
31
32
  }
32
33
  break;
33
34
  case "blockSdt":
34
35
  case "blockCustomXml":
35
- texts.push(...collectBlockTexts(block.content));
36
+ texts.push(...collectResolvedBlockTexts(block.content));
36
37
  break;
37
38
  case "preservedBlock":
38
39
  if (isAltChunkMarkup(block.xml)) texts.push(block.readerText === void 0 ? ALT_CHUNK_READER_DIAGNOSTIC : `${ALT_CHUNK_READER_DIAGNOSTIC}\n${block.readerText}`);
@@ -45,6 +46,13 @@ const collectBlockTexts = (blocks) => {
45
46
  }
46
47
  return texts;
47
48
  };
49
+ /** One entry per accepted block; deleted breaks and table structure resolve together. */
50
+ const collectBlockTexts = (blocks) => {
51
+ const projection = projectAcceptedBlocks(blocks, void 0);
52
+ const texts = collectResolvedBlockTexts(projection?.blocks ?? blocks);
53
+ if (projection?.completeness === "partial") texts.push("[Unresolved tracked structural changes]");
54
+ return texts;
55
+ };
48
56
  const blockPlainText = (blocks) => collectBlockTexts(blocks).join("\n");
49
57
  //#endregion
50
58
  export { blockPlainText, collectBlockTexts };
@@ -0,0 +1,16 @@
1
+ import { document_d_exports } from "../types/document.js";
2
+ import { CANONICAL_GAP } from "../types/canonicalCapabilities.js";
3
+ import { SaveDiagnostic } from "./saveDiagnostics.js";
4
+ //#region src/docx/canonicalResourceSave.d.ts
5
+ declare const CanonicalResourceSaveRefusalError_base: import("better-result").TaggedErrorClass<"CanonicalResourceSaveRefusalError">;
6
+ declare class CanonicalResourceSaveRefusalError extends CanonicalResourceSaveRefusalError_base<{
7
+ message: string;
8
+ gap: typeof CANONICAL_GAP.resourceReplacement;
9
+ diagnostic: Extract<SaveDiagnostic, {
10
+ type: "canonicalResourceReplacement";
11
+ }>;
12
+ }> {}
13
+ /** Full and selective package writers preserve existing style/media source entries. */
14
+ declare const canonicalResourceReplacementOf: (document: document_d_exports.Document) => string | undefined;
15
+ //#endregion
16
+ export { CanonicalResourceSaveRefusalError, canonicalResourceReplacementOf };
@@ -0,0 +1,27 @@
1
+ import { canonicalJson } from "../utils/canonicalJson.js";
2
+ import { getDocumentSourceBaseline } from "./headerFooterVerbatim.js";
3
+ import { TaggedError } from "better-result";
4
+ //#region src/docx/canonicalResourceSave.ts
5
+ var CanonicalResourceSaveRefusalError = class extends TaggedError("CanonicalResourceSaveRefusalError") {};
6
+ /** Full and selective package writers preserve existing style/media source entries. */
7
+ const canonicalResourceReplacementOf = (document) => {
8
+ const source = getDocumentSourceBaseline(document);
9
+ if (source.type !== "captured" || !document.originalBuffer) return void 0;
10
+ const baseline = source.resourceStyles;
11
+ const current = document.package.styles;
12
+ if (baseline) {
13
+ const { styles: sourceStyles, ...sourceDefaults } = baseline;
14
+ const { styles: currentStyles, ...currentDefaults } = current ?? { styles: [] };
15
+ const currentById = new Map(currentStyles.map((style) => [style.styleId, style]));
16
+ if (canonicalJson(sourceDefaults) !== canonicalJson(currentDefaults) || sourceStyles.some((style) => canonicalJson(style) !== canonicalJson(currentById.get(style.styleId)))) return "word/styles.xml";
17
+ }
18
+ for (const [path, media] of source.resourceMedia) {
19
+ const currentMedia = document.package.media?.get(path);
20
+ if (!currentMedia || media.mimeType !== currentMedia.mimeType) return path;
21
+ const sourceBytes = new Uint8Array(media.data);
22
+ const currentBytes = new Uint8Array(currentMedia.data);
23
+ if (sourceBytes.length !== currentBytes.length || sourceBytes.some((byte, index) => byte !== currentBytes[index])) return path;
24
+ }
25
+ };
26
+ //#endregion
27
+ export { CanonicalResourceSaveRefusalError, canonicalResourceReplacementOf };
@@ -0,0 +1,29 @@
1
+ import { CANONICAL_GAP } from "../types/canonicalCapabilities.js";
2
+ import { SaveDiagnostic } from "./saveDiagnostics.js";
3
+ import { CanonicalSaveSnapshot } from "../types/canonicalSave.js";
4
+ import { FolioGetDocxOptions } from "../types/docxSerialization.js";
5
+ import { TripwireResult } from "./selectiveSaveTripwire.js";
6
+ import { FolioSelectiveSaveFlags } from "./selectiveSaveFlags.js";
7
+ //#region src/docx/canonicalSave.d.ts
8
+ declare const CanonicalSaveDiagnosticError_base: import("better-result").TaggedErrorClass<"CanonicalSaveDiagnosticError">;
9
+ /** Forward a fidelity fallback through the adapters' existing error channel. */
10
+ declare class CanonicalSaveDiagnosticError extends CanonicalSaveDiagnosticError_base<{
11
+ message: string;
12
+ gap: typeof CANONICAL_GAP.save;
13
+ diagnostic: SaveDiagnostic;
14
+ }> {}
15
+ type SerializeCanonicalSaveOptions = {
16
+ snapshot: CanonicalSaveSnapshot;
17
+ options?: FolioGetDocxOptions | undefined;
18
+ featureFlags?: FolioSelectiveSaveFlags | undefined;
19
+ };
20
+ /** Model and change signals come from one committed snapshot, never from PM. */
21
+ declare const serializeCanonicalSave: ({ snapshot, options, featureFlags }: SerializeCanonicalSaveOptions) => Promise<{
22
+ buffer: ArrayBuffer;
23
+ document: import("@stll/docx-core").Document;
24
+ version: number;
25
+ diagnostics: SaveDiagnostic[];
26
+ tripwireResult: TripwireResult | null;
27
+ }>;
28
+ //#endregion
29
+ export { CanonicalSaveDiagnosticError, serializeCanonicalSave };
@@ -0,0 +1,101 @@
1
+ import { withoutUnreferencedNotes } from "../prosemirror/noteReferenceReview.js";
2
+ import { CANONICAL_GAP } from "../types/canonicalCapabilities.js";
3
+ import { FOLIO_DOCX_SERIALIZATION_MODE } from "../types/docxSerialization.js";
4
+ import { CanonicalResourceSaveRefusalError, canonicalResourceReplacementOf } from "./canonicalResourceSave.js";
5
+ import { repackWithCanonicalStoryRemovals } from "./canonicalStoryRepack.js";
6
+ import { getDocumentSourceBaseline } from "./headerFooterVerbatim.js";
7
+ import { resolveSelectiveSaveFlags } from "./selectiveSaveFlags.js";
8
+ import { Result, TaggedError } from "better-result";
9
+ //#region src/docx/canonicalSave.ts
10
+ /** Forward a fidelity fallback through the adapters' existing error channel. */
11
+ var CanonicalSaveDiagnosticError = class extends TaggedError("CanonicalSaveDiagnosticError") {};
12
+ /** Model and change signals come from one committed snapshot, never from PM. */
13
+ const serializeCanonicalSave = async ({ snapshot, options, featureFlags }) => {
14
+ const document = withoutUnreferencedNotes(snapshot.document);
15
+ const replacementPart = snapshot.structure === "changed" ? canonicalResourceReplacementOf(document) : void 0;
16
+ if (replacementPart) {
17
+ const diagnostic = {
18
+ type: "canonicalResourceReplacement",
19
+ gap: CANONICAL_GAP.resourceReplacement,
20
+ part: replacementPart
21
+ };
22
+ options?.onDiagnostic?.(diagnostic);
23
+ throw new CanonicalResourceSaveRefusalError({
24
+ message: "Canonical save cannot preserve this package resource replacement.",
25
+ gap: CANONICAL_GAP.resourceReplacement,
26
+ diagnostic
27
+ });
28
+ }
29
+ const baseline = document.originalBuffer;
30
+ const flags = resolveSelectiveSaveFlags(featureFlags);
31
+ const diagnostics = [];
32
+ const onDiagnostic = (diagnostic) => {
33
+ if (!diagnostics.some((existing) => existing.type === diagnostic.type && existing.part === diagnostic.part)) diagnostics.push(diagnostic);
34
+ };
35
+ const { repackDocx, createDocx } = await import("./rezip.js");
36
+ const useSelective = flags.selectiveSave && options?.mode !== FOLIO_DOCX_SERIALIZATION_MODE.full;
37
+ let selectiveBuffer = null;
38
+ if (baseline && (useSelective || flags.selectiveSaveTripwire)) {
39
+ const { attemptSelectiveSave } = await import("./selectiveSave.js");
40
+ selectiveBuffer = await attemptSelectiveSave(document, baseline, {
41
+ bodyAuthority: "canonical",
42
+ changedParaIds: new Set(snapshot.changedBlockIds),
43
+ structuralChange: snapshot.structure === "changed",
44
+ hasUntrackedChanges: false,
45
+ maxBytes: flags.selectiveSaveMaxBytes,
46
+ onDiagnostic
47
+ });
48
+ if (useSelective && !selectiveBuffer) onDiagnostic({
49
+ type: "selectiveSaveRefused",
50
+ part: "word/document.xml"
51
+ });
52
+ }
53
+ const repack = () => {
54
+ if (baseline && getDocumentSourceBaseline(document).type === "missing") onDiagnostic({
55
+ type: "sourceReplayUnavailable",
56
+ part: "word/document.xml"
57
+ });
58
+ return baseline ? repackWithCanonicalStoryRemovals({
59
+ document,
60
+ repack: () => repackDocx(document, {
61
+ onDiagnostic,
62
+ bodyAuthority: "canonical"
63
+ })
64
+ }) : createDocx(document, {
65
+ onDiagnostic,
66
+ bodyAuthority: "canonical"
67
+ });
68
+ };
69
+ let buffer = useSelective ? selectiveBuffer : null;
70
+ let fullBuffer = null;
71
+ if (!buffer) {
72
+ fullBuffer = await repack();
73
+ buffer = fullBuffer;
74
+ } else if (flags.selectiveSaveTripwire) {
75
+ const full = await Result.tryPromise({
76
+ try: repack,
77
+ catch: (error) => error
78
+ });
79
+ if (full.isOk()) fullBuffer = full.value;
80
+ }
81
+ let tripwireResult = null;
82
+ if (flags.selectiveSaveTripwire && fullBuffer) {
83
+ const { compareSelectiveVsFull } = await import("./selectiveSaveTripwire.js");
84
+ const capturedFullBuffer = fullBuffer;
85
+ const compared = await Result.tryPromise({
86
+ try: () => compareSelectiveVsFull(selectiveBuffer, capturedFullBuffer),
87
+ catch: (error) => error
88
+ });
89
+ if (compared.isOk()) tripwireResult = compared.value;
90
+ }
91
+ for (const diagnostic of diagnostics) options?.onDiagnostic?.(diagnostic);
92
+ return {
93
+ buffer,
94
+ document,
95
+ version: snapshot.version,
96
+ diagnostics,
97
+ tripwireResult
98
+ };
99
+ };
100
+ //#endregion
101
+ export { CanonicalSaveDiagnosticError, serializeCanonicalSave };
@@ -0,0 +1,11 @@
1
+ import { DocxInput } from "../utils/docxInput.js";
2
+ //#region src/docx/canonicalSessionInput.d.ts
3
+ declare const CanonicalDocxInputError_base: import("better-result").TaggedErrorClass<"CanonicalDocxInputError">;
4
+ declare class CanonicalDocxInputError extends CanonicalDocxInputError_base<{
5
+ message: string;
6
+ cause?: unknown;
7
+ }> {}
8
+ /** Canonical seeding supports plaintext packages; refuse encryption before ZIP normalization. */
9
+ declare const prepareCanonicalDocxInput: (input: DocxInput) => Promise<import("better-result").Err<ArrayBuffer, CanonicalDocxInputError> | import("better-result").Ok<Uint8Array<ArrayBufferLike>, CanonicalDocxInputError>>;
10
+ //#endregion
11
+ export { CanonicalDocxInputError, prepareCanonicalDocxInput };
@@ -0,0 +1,27 @@
1
+ import { toArrayBuffer } from "../utils/docxInput.js";
2
+ import { DOCX_CONTAINER_TYPES, detectDocxContainerType } from "./encryption/containerFormat.js";
3
+ import { ensureParaIds } from "./ensureParaIds.js";
4
+ import { Result, TaggedError } from "better-result";
5
+ //#region src/docx/canonicalSessionInput.ts
6
+ var CanonicalDocxInputError = class extends TaggedError("CanonicalDocxInputError") {};
7
+ /** Canonical seeding supports plaintext packages; refuse encryption before ZIP normalization. */
8
+ const prepareCanonicalDocxInput = async (input) => {
9
+ const bytes = await Result.tryPromise({
10
+ try: () => toArrayBuffer(input),
11
+ catch: (cause) => new CanonicalDocxInputError({
12
+ message: "Cannot read canonical document bytes.",
13
+ cause
14
+ })
15
+ });
16
+ if (bytes.isErr()) return bytes;
17
+ if (detectDocxContainerType(bytes.value) === DOCX_CONTAINER_TYPES.CFB) return Result.err(new CanonicalDocxInputError({ message: "Password-protected documents are unavailable in the experimental canonical session." }));
18
+ return Result.tryPromise({
19
+ try: async () => (await ensureParaIds(bytes.value)).docx,
20
+ catch: (cause) => new CanonicalDocxInputError({
21
+ message: cause instanceof Error ? cause.message : "Canonical document normalization failed.",
22
+ cause
23
+ })
24
+ });
25
+ };
26
+ //#endregion
27
+ export { CanonicalDocxInputError, prepareCanonicalDocxInput };
@@ -0,0 +1,10 @@
1
+ import { document_d_exports } from "../types/document.js";
2
+ //#region src/docx/canonicalStoryRepack.d.ts
3
+ type CanonicalStoryRepackOptions<T> = {
4
+ document: document_d_exports.Document;
5
+ repack: () => Promise<T>;
6
+ };
7
+ /** Authorize exact canonical section removals and references missing from the committed snapshot. */
8
+ declare const repackWithCanonicalStoryRemovals: <T>({ document, repack }: CanonicalStoryRepackOptions<T>) => Promise<T>;
9
+ //#endregion
10
+ export { repackWithCanonicalStoryRemovals };