@stll/folio-core 0.55.0 → 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 (119) hide show
  1. package/dist/ai-edits/apply.js +169 -38
  2. package/dist/ai-edits/headless.js +2 -2
  3. package/dist/ai-edits/types.d.ts +7 -1
  4. package/dist/compare/compare.js +1 -0
  5. package/dist/compare/reproducible-package.d.ts +0 -17
  6. package/dist/compare/reproducible-package.js +12 -18
  7. package/dist/controller/canonicalClipboard.d.ts +23 -0
  8. package/dist/controller/canonicalClipboard.js +476 -0
  9. package/dist/controller/canonicalClipboardResources.d.ts +21 -0
  10. package/dist/controller/canonicalClipboardResources.js +382 -0
  11. package/dist/controller/canonicalComposition.d.ts +20 -3
  12. package/dist/controller/canonicalComposition.js +166 -38
  13. package/dist/controller/canonicalInlineProjection.d.ts +113 -0
  14. package/dist/controller/canonicalInlineProjection.js +393 -0
  15. package/dist/controller/canonicalInput.d.ts +13 -4
  16. package/dist/controller/canonicalInput.js +52 -13
  17. package/dist/controller/canonicalInputTimer.d.ts +7 -0
  18. package/dist/controller/canonicalInputTimer.js +11 -0
  19. package/dist/controller/canonicalPublicOperations.d.ts +48 -0
  20. package/dist/controller/canonicalPublicOperations.js +556 -0
  21. package/dist/controller/canonicalSession.d.ts +24 -6
  22. package/dist/controller/canonicalSession.js +259 -111
  23. package/dist/controller/canonicalStoryEditor.d.ts +5 -3
  24. package/dist/controller/canonicalStoryEditor.js +7 -2
  25. package/dist/controller/canonicalStructure.js +57 -4
  26. package/dist/controller/canonicalTocSelection.d.ts +11 -0
  27. package/dist/controller/canonicalTocSelection.js +43 -0
  28. package/dist/controller/folioEditor.d.ts +2 -9
  29. package/dist/controller/folioEditor.js +5 -4
  30. package/dist/controller/headerFooterEditorManager.d.ts +2 -1
  31. package/dist/controller/headerFooterEditorManager.js +8 -7
  32. package/dist/controller/hiddenEditorApi.d.ts +12 -2
  33. package/dist/controller/hiddenEditorApi.js +4 -0
  34. package/dist/controller/hiddenEditorManager.d.ts +3 -1
  35. package/dist/controller/hiddenEditorManager.js +216 -34
  36. package/dist/controller/noteEditorManager.d.ts +2 -1
  37. package/dist/controller/noteEditorManager.js +8 -7
  38. package/dist/document-operations.d.ts +8 -1
  39. package/dist/document-operations.js +6 -4
  40. package/dist/docx/blockPlainText.d.ts +1 -1
  41. package/dist/docx/blockPlainText.js +11 -3
  42. package/dist/docx/canonicalResourceSave.d.ts +16 -0
  43. package/dist/docx/canonicalResourceSave.js +27 -0
  44. package/dist/docx/canonicalSave.d.ts +29 -0
  45. package/dist/docx/canonicalSave.js +101 -0
  46. package/dist/docx/canonicalStoryRepack.d.ts +1 -1
  47. package/dist/docx/canonicalStoryRepack.js +38 -5
  48. package/dist/docx/documentParser.d.ts +1 -13
  49. package/dist/docx/documentParser.js +1 -47
  50. package/dist/docx/ensureParaIds.js +10 -4
  51. package/dist/docx/footnoteParser.d.ts +1 -11
  52. package/dist/docx/footnoteParser.js +1 -16
  53. package/dist/docx/headerFooterParser.d.ts +1 -9
  54. package/dist/docx/headerFooterParser.js +1 -12
  55. package/dist/docx/headerFooterVerbatim.d.ts +26 -1
  56. package/dist/docx/headerFooterVerbatim.js +81 -3
  57. package/dist/docx/imageParser.d.ts +13 -1
  58. package/dist/docx/imageParser.js +20 -11
  59. package/dist/docx/metadataPrivacy.js +6 -1
  60. package/dist/docx/packageParts.js +9 -3
  61. package/dist/docx/paragraphPropertySource.js +2 -1
  62. package/dist/docx/parser.js +2 -1
  63. package/dist/docx/removeHeaderFooterParts.js +17 -6
  64. package/dist/docx/rezip.d.ts +49 -5
  65. package/dist/docx/rezip.js +745 -229
  66. package/dist/docx/saveDiagnostics.d.ts +11 -0
  67. package/dist/docx/selectiveSave.d.ts +2 -1
  68. package/dist/docx/selectiveSave.js +32 -3
  69. package/dist/docx/selectiveXmlPatch.js +7 -5
  70. package/dist/docx/serializer/documentSerializer.d.ts +9 -2
  71. package/dist/docx/serializer/documentSerializer.js +29 -10
  72. package/dist/docx/server/applyDocxXmlPatchProposal.js +14 -9
  73. package/dist/docx/storyBlockReplay.d.ts +21 -1
  74. package/dist/docx/storyBlockReplay.js +113 -9
  75. package/dist/docx/storyPlainText.d.ts +20 -0
  76. package/dist/docx/storyPlainText.js +23 -0
  77. package/dist/docx/structuralXmlPatch.js +10 -22
  78. package/dist/docx/styleParser.d.ts +5 -1
  79. package/dist/docx/styleParser.js +1 -1
  80. package/dist/docx/tableParser.d.ts +1 -8
  81. package/dist/docx/tableParser.js +1 -28
  82. package/dist/docx/textBoxParser.d.ts +1 -5
  83. package/dist/docx/textBoxParser.js +1 -20
  84. package/dist/docx/unzip.js +6 -1
  85. package/dist/internal/acceptedBlockProjection.d.ts +12 -0
  86. package/dist/internal/acceptedBlockProjection.js +45 -0
  87. package/dist/managers/DocumentLoaderManager.js +2 -1
  88. package/dist/markdown/escape.d.ts +3 -1
  89. package/dist/markdown/escape.js +9 -2
  90. package/dist/markdown/renderBlock.js +5 -120
  91. package/dist/markdown/renderParagraph.js +4 -2
  92. package/dist/markdown/renderRuns.d.ts +7 -1
  93. package/dist/markdown/renderRuns.js +32 -13
  94. package/dist/prosemirror/canonicalCommands.d.ts +28 -4
  95. package/dist/prosemirror/canonicalCommands.js +11 -4
  96. package/dist/prosemirror/canonicalSelectionRange.d.ts +9 -0
  97. package/dist/prosemirror/canonicalSelectionRange.js +15 -0
  98. package/dist/prosemirror/clipboardIntent.d.ts +7 -0
  99. package/dist/prosemirror/clipboardIntent.js +9 -0
  100. package/dist/prosemirror/commands/pageBreak.js +2 -2
  101. package/dist/prosemirror/commands/pastePlainText.js +2 -1
  102. package/dist/prosemirror/conversion/hyphenTextCarriers.d.ts +8 -0
  103. package/dist/prosemirror/conversion/hyphenTextCarriers.js +8 -0
  104. package/dist/prosemirror/conversion/toProseDoc.d.ts +7 -1
  105. package/dist/prosemirror/conversion/toProseDoc.js +5 -4
  106. package/dist/prosemirror/extensions/core/ParagraphExtension.js +39 -30
  107. package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +56 -28
  108. package/dist/prosemirror/extensions/marks/markUtils.js +3 -1
  109. package/dist/prosemirror/insertOperations.js +2 -1
  110. package/dist/prosemirror/paragraphPropertyCarry.d.ts +7 -1
  111. package/dist/prosemirror/paragraphPropertyCarry.js +8 -3
  112. package/dist/prosemirror/plugins/suggestionMode.js +7 -5
  113. package/dist/types/canonicalCapabilities.d.ts +215 -0
  114. package/dist/types/canonicalCapabilities.js +212 -0
  115. package/dist/types/canonicalSave.d.ts +11 -0
  116. package/dist/types/canonicalSave.js +0 -0
  117. package/dist/types/docxSerialization.d.ts +14 -0
  118. package/dist/types/docxSerialization.js +7 -0
  119. package/package.json +4 -4
@@ -2,6 +2,8 @@ import { recordHiddenEditorPhase, recordHiddenEditorStateCreate } from "../layou
2
2
  import { suppressHiddenEditorScrollToSelection } from "../paged-layout/hiddenEditorScroll.js";
3
3
  import { isReadOnlyEditKey } from "../paged-layout/readOnlyEditAttempt.js";
4
4
  import { getCanonicalCommandIntents } from "../prosemirror/canonicalCommands.js";
5
+ import { registerClipboardIntentHandler } from "../prosemirror/clipboardIntent.js";
6
+ import { pasteWithoutFormatting } from "../prosemirror/commands/pastePlainText.js";
5
7
  import { createEmptyDoc, toProseDoc } from "../prosemirror/conversion/toProseDoc.js";
6
8
  import { registerEditorCommandOwner } from "../prosemirror/executeEditorCommand.js";
7
9
  import { ensureBaseDirectionInState } from "../prosemirror/extensions/features/AutoBidiDetectionExtension.js";
@@ -13,13 +15,16 @@ import { createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyle
13
15
  import { schema } from "../prosemirror/schema/index.js";
14
16
  import { createTextInputPlugin } from "../prosemirror/textInput.js";
15
17
  import { applyAttrSchemaMigrations, proseDocumentParagraphSourceContract, readYjsAttrSchemaVersion, readYjsParagraphSourceContract, withParagraphSourceContract, writeYjsDocumentMetadata } from "../prosemirror/yjsDocumentMetadata.js";
18
+ import { CANONICAL_GAP, usesCanonicalSession } from "../types/canonicalCapabilities.js";
19
+ import { prepareCanonicalPaste } from "./canonicalClipboard.js";
16
20
  import { createCanonicalInputBoundary } from "./canonicalInput.js";
21
+ import { CanonicalPublicOperations } from "./canonicalPublicOperations.js";
17
22
  import { createCanonicalSession, publishCanonicalProjection } from "./canonicalSession.js";
18
23
  import { prepareCanonicalAutoformat, prepareCanonicalCommands } from "./canonicalStructure.js";
19
24
  import { createHiddenEditorApi } from "./hiddenEditorApi.js";
20
25
  import { Result, TaggedError, panic } from "better-result";
21
26
  import { OP_STORIES } from "@stll/docx-core/ops";
22
- import { EditorState } from "prosemirror-state";
27
+ import { EditorState, Plugin } from "prosemirror-state";
23
28
  import { EditorView } from "prosemirror-view";
24
29
  //#region src/controller/hiddenEditorManager.ts
25
30
  var CanonicalSessionRefusalError = class extends TaggedError("CanonicalSessionRefusalError") {};
@@ -209,12 +214,16 @@ const createHiddenEditorManager = (deps) => {
209
214
  author: deps.getSuggestionAuthor?.() ?? "User"
210
215
  } : { type: "editing" }));
211
216
  };
212
- const refuse = (reason) => {
213
- if (deps.onSessionRefusal) deps.onSessionRefusal(reason);
214
- else throw new CanonicalSessionRefusalError({ message: reason });
217
+ const refuse = (reason, gap = CANONICAL_GAP.dispatch) => {
218
+ const message = reason;
219
+ if (deps.onSessionRefusal) deps.onSessionRefusal(message, gap);
220
+ else throw new CanonicalSessionRefusalError({
221
+ gap,
222
+ message
223
+ });
215
224
  };
216
225
  const seedSession = (document) => {
217
- if (deps.getExperimentalSession?.() !== "canonical") {
226
+ if (!usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) {
218
227
  editorSession = { type: "prosemirror" };
219
228
  return true;
220
229
  }
@@ -227,7 +236,7 @@ const createHiddenEditorManager = (deps) => {
227
236
  reason,
228
237
  documentIdentity
229
238
  };
230
- refuse(reason);
239
+ refuse(reason, CANONICAL_GAP.collaboration);
231
240
  return false;
232
241
  }
233
242
  const result = createCanonicalSession(document, deps.getStyles());
@@ -237,7 +246,7 @@ const createHiddenEditorManager = (deps) => {
237
246
  reason: result.error.message,
238
247
  documentIdentity
239
248
  };
240
- refuse(result.error.message);
249
+ refuse(result.error.message, result.error.gap);
241
250
  return false;
242
251
  }
243
252
  editorSession = {
@@ -253,7 +262,13 @@ const createHiddenEditorManager = (deps) => {
253
262
  plugins: [
254
263
  createParagraphChangeTrackerPlugin(),
255
264
  createDocumentStylesPlugin(deps.getStyles() ?? session.document.package.styles),
256
- createDocumentNumberingPlugin(session.document.package.numbering)
265
+ createDocumentNumberingPlugin(session.document.package.numbering),
266
+ ...[...deps.getExtensionManager()?.getPlugins() ?? [], ...deps.getExternalPlugins()].flatMap(({ props }) => props.transformPastedHTML === void 0 && props.transformPasted === void 0 && props.transformCopied === void 0 && props.clipboardTextSerializer === void 0 ? [] : [new Plugin({ props: {
267
+ ...props.transformCopied === void 0 ? {} : { transformCopied: props.transformCopied },
268
+ ...props.clipboardTextSerializer === void 0 ? {} : { clipboardTextSerializer: props.clipboardTextSerializer },
269
+ ...props.transformPastedHTML === void 0 ? {} : { transformPastedHTML: props.transformPastedHTML },
270
+ ...props.transformPasted === void 0 ? {} : { transformPasted: props.transformPasted }
271
+ } })])
257
272
  ]
258
273
  });
259
274
  const publishCommit = (commit) => {
@@ -265,7 +280,7 @@ const createHiddenEditorManager = (deps) => {
265
280
  session
266
281
  });
267
282
  if (result.isErr()) {
268
- refuse(result.error.message);
283
+ refuse(result.error.message, result.error.gap);
269
284
  return false;
270
285
  }
271
286
  const staged = result.value;
@@ -284,7 +299,7 @@ const createHiddenEditorManager = (deps) => {
284
299
  if (direction === "undo" ? !session.canUndo : !session.canRedo) return false;
285
300
  const prepared = direction === "undo" ? session.prepareUndo(view.state) : session.prepareRedo(view.state);
286
301
  if (prepared.isErr()) {
287
- if (prepared.error.reason !== "noChange") refuse(prepared.error.message);
302
+ if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
288
303
  return false;
289
304
  }
290
305
  return publishCommit(prepared.value);
@@ -292,6 +307,7 @@ const createHiddenEditorManager = (deps) => {
292
307
  const executeCanonicalCommand = (command) => {
293
308
  if (!view || editorSession.type !== "canonical") return void 0;
294
309
  if (deps.getReadOnly()) return false;
310
+ if (command === pasteWithoutFormatting) return command(view.state, (transaction) => view?.dispatch(transaction), view);
295
311
  if (editorSession.session.isComposing) {
296
312
  refuse("Composition must finish before formatting.");
297
313
  return false;
@@ -305,11 +321,12 @@ const createHiddenEditorManager = (deps) => {
305
321
  }, view);
306
322
  const prepared = prepareCanonicalCommands(editorSession.session, view.state, intents);
307
323
  if (prepared.isErr()) {
308
- if (prepared.error.reason !== "noChange") refuse(prepared.error.message);
324
+ if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
309
325
  return false;
310
326
  }
311
327
  return publishCommit(prepared.value);
312
328
  };
329
+ let clipboardDrag = { type: "idle" };
313
330
  let lastInputRule;
314
331
  const canonicalStructuralInput = {
315
332
  command: (name) => {
@@ -324,7 +341,7 @@ const createHiddenEditorManager = (deps) => {
324
341
  if (mark !== void 0) command = name === "toggleUnderline" ? toggleUnderlineMark(mark) : toggleMarkForAllScripts(mark, name === "toggleBold" ? "bold" : "italic");
325
342
  }
326
343
  if (command === void 0) {
327
- refuse("The formatting command is unavailable.");
344
+ refuse("The formatting command is unavailable.", CANONICAL_GAP.commands);
328
345
  return;
329
346
  }
330
347
  if (executeCanonicalCommand(command) === void 0) command(view.state, (transaction) => view?.dispatch(transaction), view);
@@ -336,7 +353,7 @@ const createHiddenEditorManager = (deps) => {
336
353
  const state = view.state;
337
354
  const selection = session.projection.selectionAt(state);
338
355
  if (selection.isErr()) {
339
- refuse(selection.error.message);
356
+ refuse(selection.error.message, selection.error.gap);
340
357
  return;
341
358
  }
342
359
  let prepared;
@@ -386,11 +403,11 @@ const createHiddenEditorManager = (deps) => {
386
403
  const from = session.projection.addressAt(state.selection.from);
387
404
  const to = session.projection.addressAt(state.selection.to);
388
405
  if (from.isErr()) {
389
- refuse(from.error.message);
406
+ refuse(from.error.message, from.error.gap);
390
407
  return;
391
408
  }
392
409
  if (to.isErr()) {
393
- refuse(to.error.message);
410
+ refuse(to.error.message, to.error.gap);
394
411
  return;
395
412
  }
396
413
  prepared = session.prepareIntent(state, {
@@ -407,7 +424,7 @@ const createHiddenEditorManager = (deps) => {
407
424
  default: return type;
408
425
  }
409
426
  if (prepared.isErr()) {
410
- if (prepared.error.reason !== "noChange") refuse(prepared.error.message);
427
+ if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
411
428
  return;
412
429
  }
413
430
  publishCommit(prepared.value);
@@ -421,7 +438,7 @@ const createHiddenEditorManager = (deps) => {
421
438
  if (deps.getReadOnly() || editorSession.type !== "canonical") return false;
422
439
  const begun = editorSession.session.beginComposition();
423
440
  if (begun.isErr()) {
424
- refuse(begun.error.message);
441
+ refuse(begun.error.message, begun.error.gap);
425
442
  return false;
426
443
  }
427
444
  return true;
@@ -431,6 +448,52 @@ const createHiddenEditorManager = (deps) => {
431
448
  }
432
449
  };
433
450
  const input = createCanonicalInputBoundary({
451
+ pastePlainText: (pmView) => {
452
+ if (deps.getReadOnly()) {
453
+ deps.onReadOnlyEditAttempt();
454
+ return;
455
+ }
456
+ pasteWithoutFormatting(pmView.state, (transaction) => pmView.dispatch(transaction), pmView);
457
+ },
458
+ cut: (pmView, event) => {
459
+ event.preventDefault();
460
+ if (deps.getReadOnly()) {
461
+ deps.onReadOnlyEditAttempt();
462
+ return true;
463
+ }
464
+ if (editorSession.type !== "canonical" || pmView.state.selection.empty) return true;
465
+ if (event.clipboardData === null) {
466
+ refuse("The clipboard cannot receive the cut content.");
467
+ return true;
468
+ }
469
+ syncCanonicalMode();
470
+ const session = editorSession.session;
471
+ const { from, to } = pmView.state.selection;
472
+ const prepared = session.prepareReplace(pmView.state, {
473
+ from,
474
+ to,
475
+ text: "",
476
+ semantic: "replacement"
477
+ });
478
+ if (prepared.isErr()) {
479
+ refuse(prepared.error.message, prepared.error.gap);
480
+ return true;
481
+ }
482
+ const copied = Result.try({
483
+ try: () => {
484
+ const serialized = pmView.serializeForClipboard(pmView.state.selection.content());
485
+ event.clipboardData?.setData("text/html", serialized.dom.innerHTML);
486
+ event.clipboardData?.setData("text/plain", serialized.text);
487
+ },
488
+ catch: () => new CanonicalSessionRefusalError({
489
+ gap: CANONICAL_GAP.dispatch,
490
+ message: "The clipboard could not receive the cut content."
491
+ })
492
+ });
493
+ if (copied.isErr()) refuse(copied.error.message, copied.error.gap);
494
+ else publishCommit(prepared.value);
495
+ return true;
496
+ },
434
497
  ...canonicalInputLifecycle,
435
498
  ...canonicalStructuralInput,
436
499
  replace: (intent) => {
@@ -439,7 +502,7 @@ const createHiddenEditorManager = (deps) => {
439
502
  const rule = prepareCanonicalAutoformat(editorSession.session, view.state, intent);
440
503
  const prepared = rule ?? editorSession.session.prepareReplace(view.state, intent);
441
504
  if (prepared.isErr()) {
442
- if (prepared.error.reason !== "noChange") refuse(prepared.error.message);
505
+ if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
443
506
  return;
444
507
  }
445
508
  const session = editorSession.session;
@@ -464,14 +527,14 @@ const createHiddenEditorManager = (deps) => {
464
527
  if (!host) return;
465
528
  const collaboration = deps.getCollaboration();
466
529
  const collaborationModules = deps.getCollaborationModules();
467
- if (collaboration && !collaborationModules && deps.getExperimentalSession?.() !== "canonical") return;
530
+ if (collaboration && !collaborationModules && !usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) return;
468
531
  const precomputedInitialState = deps.getPrecomputedInitialState();
469
532
  const document = deps.getDocument();
470
533
  const styles = deps.getStyles();
471
534
  const extensionManager = deps.getExtensionManager();
472
535
  const externalPlugins = deps.getExternalPlugins();
473
- if (!seedSession(document)) return;
474
536
  input.reset();
537
+ if (!seedSession(document)) return;
475
538
  const editorProps = {
476
539
  state: (() => {
477
540
  if (editorSession.type === "canonical") return canonicalState(editorSession.session);
@@ -533,16 +596,79 @@ const createHiddenEditorManager = (deps) => {
533
596
  return deps.onKeyDown(pmView, event);
534
597
  },
535
598
  handleTextInput: (pmView, from, to, text) => editorSession.type === "canonical" ? input.handleTextInput(pmView, from, to, text) : false,
599
+ handlePaste: (pmView, _event, slice) => {
600
+ if (editorSession.type !== "canonical") return false;
601
+ if (deps.getReadOnly()) {
602
+ deps.onReadOnlyEditAttempt();
603
+ return true;
604
+ }
605
+ syncCanonicalMode();
606
+ const prepared = prepareCanonicalPaste({
607
+ session: editorSession.session,
608
+ state: pmView.state,
609
+ slice
610
+ });
611
+ if (prepared.isErr()) {
612
+ if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
613
+ } else publishCommit(prepared.value);
614
+ return true;
615
+ },
616
+ handleDrop: (pmView, event, slice, moved) => {
617
+ if (editorSession.type !== "canonical") return false;
618
+ if (deps.getReadOnly()) {
619
+ deps.onReadOnlyEditAttempt();
620
+ return true;
621
+ }
622
+ const target = pmView.posAtCoords({
623
+ left: event.clientX,
624
+ top: event.clientY
625
+ })?.pos;
626
+ if (target === void 0) {
627
+ refuse("The drop has no document destination.");
628
+ return true;
629
+ }
630
+ const captured = clipboardDrag;
631
+ clipboardDrag = { type: "idle" };
632
+ if (moved && (captured.type !== "dragging" || captured.session !== editorSession.session || captured.version !== editorSession.session.version)) {
633
+ refuse("The dragged content changed or has no captured source.");
634
+ return true;
635
+ }
636
+ const source = captured.type === "dragging" ? {
637
+ from: captured.from,
638
+ to: captured.to
639
+ } : pmView.state.selection;
640
+ if (moved && target >= source.from && target <= source.to) return true;
641
+ syncCanonicalMode();
642
+ const prepared = prepareCanonicalPaste({
643
+ session: editorSession.session,
644
+ state: pmView.state,
645
+ slice,
646
+ ...moved ? {
647
+ moveTarget: target,
648
+ moveSource: {
649
+ from: source.from,
650
+ to: source.to
651
+ }
652
+ } : { pasteTarget: target }
653
+ });
654
+ if (prepared.isErr()) {
655
+ if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
656
+ } else publishCommit(prepared.value);
657
+ return true;
658
+ },
536
659
  handleScrollToSelection: suppressHiddenEditorScrollToSelection,
537
660
  handleDOMEvents: {
661
+ keydown: (pmView, event) => editorSession.type === "canonical" ? input.handleDOMEvents.keydown(pmView, event) : false,
538
662
  focus: () => false,
539
663
  blur: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.blur(pmView) : false,
540
664
  ...createHiddenEditorClipboardHandlers(deps),
541
- mousedown: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.mousedown(pmView) : false,
542
665
  compositionstart: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.compositionstart(pmView) : false,
543
666
  compositionend: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.compositionend(pmView) : false,
544
667
  input: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.input(pmView) : false,
545
- paste: (pmView, event) => editorSession.type === "canonical" ? input.handleDOMEvents.paste(pmView, event) : createHiddenEditorClipboardHandlers(deps).paste(pmView, event),
668
+ paste: (pmView, event) => {
669
+ if (editorSession.type === "canonical" && !deps.getReadOnly()) return input.handleDOMEvents.paste(pmView, event);
670
+ return createHiddenEditorClipboardHandlers(deps).paste(pmView, event);
671
+ },
546
672
  cut: (pmView, event) => editorSession.type === "canonical" ? input.handleDOMEvents.cut(pmView, event) : createHiddenEditorClipboardHandlers(deps).cut(pmView, event),
547
673
  beforeinput: (_view, event) => {
548
674
  if (editorSession.type === "canonical" && !deps.getReadOnly()) return input.handleDOMEvents.beforeinput(_view, event);
@@ -551,8 +677,22 @@ const createHiddenEditorManager = (deps) => {
551
677
  event.preventDefault();
552
678
  return true;
553
679
  },
680
+ dragstart: (pmView) => {
681
+ if (editorSession.type === "canonical") clipboardDrag = {
682
+ type: "dragging",
683
+ session: editorSession.session,
684
+ version: editorSession.session.version,
685
+ from: pmView.state.selection.from,
686
+ to: pmView.state.selection.to
687
+ };
688
+ return false;
689
+ },
690
+ dragend: () => {
691
+ clipboardDrag = { type: "idle" };
692
+ return false;
693
+ },
554
694
  drop: (_view, event) => {
555
- if (editorSession.type === "canonical") return input.handleDOMEvents.drop(_view, event);
695
+ if (editorSession.type === "canonical" && !deps.getReadOnly()) return input.handleDOMEvents.drop(_view, event);
556
696
  if (!deps.getReadOnly()) return false;
557
697
  deps.onReadOnlyEditAttempt();
558
698
  event.preventDefault();
@@ -562,6 +702,25 @@ const createHiddenEditorManager = (deps) => {
562
702
  };
563
703
  const viewStartedAt = performance.now();
564
704
  view = new EditorView(host, editorProps);
705
+ if (editorSession.type === "canonical") registerClipboardIntentHandler(view, (slice, plain) => {
706
+ if (!view || editorSession.type !== "canonical") return false;
707
+ if (deps.getReadOnly()) {
708
+ deps.onReadOnlyEditAttempt();
709
+ return false;
710
+ }
711
+ syncCanonicalMode();
712
+ const prepared = prepareCanonicalPaste({
713
+ session: editorSession.session,
714
+ state: view.state,
715
+ slice,
716
+ plain
717
+ });
718
+ if (prepared.isErr()) {
719
+ if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
720
+ return false;
721
+ }
722
+ return publishCommit(prepared.value);
723
+ });
565
724
  releaseCommandOwner = registerEditorCommandOwner(view, executeCanonicalCommand);
566
725
  recordHiddenEditorPhase("mount", "editor-view", performance.now() - viewStartedAt);
567
726
  syncHiddenEditorAccessibility(view, deps.getReadOnly());
@@ -594,19 +753,19 @@ const createHiddenEditorManager = (deps) => {
594
753
  if (!view || isDestroying) return;
595
754
  const collaboration = deps.getCollaboration();
596
755
  const collaborationModules = deps.getCollaborationModules();
597
- if (collaboration && !collaborationModules && deps.getExperimentalSession?.() !== "canonical") return;
756
+ if (collaboration && !collaborationModules && !usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) return;
598
757
  const document = deps.getDocument();
599
758
  const currentDocId = deps.getDocumentIdentity();
600
759
  const currentCollaborationFragment = collaboration?.yXmlFragment ?? null;
601
760
  const collaborationSourceChanged = currentCollaborationFragment !== lastCollaborationFragment;
602
- const sessionChanged = editorSession.type !== "prosemirror" !== (deps.getExperimentalSession?.() === "canonical");
761
+ const sessionChanged = editorSession.type !== "prosemirror" !== usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting);
603
762
  if (collaboration && !collaborationSourceChanged && !sessionChanged) return;
604
763
  if (isInitialized && currentDocId === lastDocumentId && !collaborationSourceChanged && !sessionChanged) return;
764
+ input.reset();
605
765
  if (!seedSession(document)) {
606
766
  destroyView();
607
767
  return;
608
768
  }
609
- input.reset();
610
769
  isInitialized = true;
611
770
  lastDocumentId = currentDocId;
612
771
  lastCollaborationFragment = currentCollaborationFragment;
@@ -632,7 +791,7 @@ const createHiddenEditorManager = (deps) => {
632
791
  const publishStoryCommit = (storyView, commit) => {
633
792
  if (!view || editorSession.type !== "canonical") return false;
634
793
  if (deps.getEditingMode?.() === "suggesting") {
635
- refuse("Suggesting is unavailable in the experimental canonical session.");
794
+ refuse("Suggesting is unavailable in the experimental canonical session.", CANONICAL_GAP.suggesting);
636
795
  return false;
637
796
  }
638
797
  const session = editorSession.session;
@@ -651,7 +810,7 @@ const createHiddenEditorManager = (deps) => {
651
810
  session
652
811
  });
653
812
  if (staged.isErr()) {
654
- refuse(staged.error.message);
813
+ refuse(staged.error.message, staged.error.gap);
655
814
  return false;
656
815
  }
657
816
  storyView.updateState(staged.value.state);
@@ -664,6 +823,22 @@ const createHiddenEditorManager = (deps) => {
664
823
  deps.onSelectionChange(view.state);
665
824
  return true;
666
825
  };
826
+ let publicOperations = null;
827
+ const getPublicOperations = () => {
828
+ if (editorSession.type !== "canonical") return null;
829
+ const session = editorSession.session;
830
+ if (publicOperations?.session === session) return publicOperations.executor;
831
+ const executor = new CanonicalPublicOperations({
832
+ session,
833
+ getState: (story) => story === OP_STORIES.MAIN && !deps.getReadOnly() && !isDestroying ? view?.state ?? null : null,
834
+ publish: publishCommit
835
+ });
836
+ publicOperations = {
837
+ session,
838
+ executor
839
+ };
840
+ return executor;
841
+ };
667
842
  return {
668
843
  ensureView,
669
844
  retryViewCreation,
@@ -676,6 +851,8 @@ const createHiddenEditorManager = (deps) => {
676
851
  api: createHiddenEditorApi({
677
852
  getView: () => view,
678
853
  getDocumentContext: () => editorSession.type === "refused" ? null : deps.getDocumentContext(),
854
+ isCanonicalSaveCurrent: (version) => editorSession.type === "canonical" && !editorSession.session.isComposing && editorSession.session.version === version,
855
+ captureCanonicalSave: () => editorSession.type === "canonical" ? editorSession.session.captureSaveSnapshot() : null,
679
856
  getCanonicalDocument: () => editorSession.type === "canonical" ? editorSession.session.document : null,
680
857
  setCanonicalMode: (mode) => {
681
858
  if (editorSession.type !== "canonical") return false;
@@ -690,7 +867,7 @@ const createHiddenEditorManager = (deps) => {
690
867
  resolution
691
868
  });
692
869
  if (prepared.isErr()) {
693
- if (prepared.error.reason !== "noChange") refuse(prepared.error.message);
870
+ if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
694
871
  return false;
695
872
  }
696
873
  return publishCommit(prepared.value);
@@ -703,6 +880,11 @@ const createHiddenEditorManager = (deps) => {
703
880
  canRedo: () => editorSession.type === "canonical" && editorSession.session.canRedo
704
881
  } : null,
705
882
  canonicalOperations: {
883
+ applyCanonicalDocumentOperations: (options) => {
884
+ ensureView();
885
+ return getPublicOperations()?.apply(options) ?? null;
886
+ },
887
+ undoCanonicalDocumentOperations: (handle) => getPublicOperations()?.undo(handle) ?? null,
706
888
  updateCanonicalInputLifecycle: (action) => {
707
889
  if (editorSession.type !== "canonical") return false;
708
890
  switch (action) {
@@ -736,7 +918,7 @@ const createHiddenEditorManager = (deps) => {
736
918
  if (direction === "undo" ? !session.canUndo : !session.canRedo) return false;
737
919
  const prepared = direction === "undo" ? session.prepareUndo(storyView.state, story) : session.prepareRedo(storyView.state, story);
738
920
  if (prepared.isErr()) {
739
- refuse(prepared.error.message);
921
+ refuse(prepared.error.message, prepared.error.gap);
740
922
  return false;
741
923
  }
742
924
  return publishStoryCommit(storyView, prepared.value);
@@ -746,17 +928,17 @@ const createHiddenEditorManager = (deps) => {
746
928
  if (!view || editorSession.type !== "canonical" || deps.getReadOnly()) return false;
747
929
  const prepared = editorSession.session.prepareOperations(view.state, ops);
748
930
  if (prepared.isErr()) {
749
- refuse(prepared.error.message);
931
+ refuse(prepared.error.message, prepared.error.gap);
750
932
  return false;
751
933
  }
752
934
  return publishCommit(prepared.value);
753
935
  },
754
936
  getCanonicalStoryProjection: (story) => {
755
- if (deps.getExperimentalSession?.() === "canonical") ensureView();
937
+ if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) ensureView();
756
938
  if (editorSession.type !== "canonical" || editorSession.session.isComposing) return null;
757
939
  const result = editorSession.session.projectStory(story);
758
940
  if (result.isErr()) {
759
- refuse(result.error.message);
941
+ refuse(result.error.message, result.error.gap);
760
942
  return null;
761
943
  }
762
944
  return result.value.doc;
@@ -768,7 +950,7 @@ const createHiddenEditorManager = (deps) => {
768
950
  story
769
951
  });
770
952
  if (prepared.isErr()) {
771
- refuse(prepared.error.message);
953
+ refuse(prepared.error.message, prepared.error.gap);
772
954
  return false;
773
955
  }
774
956
  return publishStoryCommit(storyView, prepared.value);
@@ -1,4 +1,5 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
+ import { CanonicalGap } from "../types/canonicalCapabilities.js";
2
3
  import { HiddenEditorApi } from "./hiddenEditorApi.js";
3
4
  import { NoteStoryKey } from "../types/editor-story.js";
4
5
  import { Plugin } from "prosemirror-state";
@@ -15,7 +16,7 @@ type NoteEditorManagerDeps = {
15
16
  getDocument: () => document_d_exports.Document | null;
16
17
  getCanonicalApi?: (() => HiddenEditorApi | null) | undefined;
17
18
  getExperimentalSession?: (() => "canonical" | undefined) | undefined;
18
- onSessionRefusal?: ((reason: string) => void) | undefined;
19
+ onSessionRefusal?: ((reason: string, gap: CanonicalGap) => void) | undefined;
19
20
  getHost: () => HTMLElement | null;
20
21
  getPlugins?: (() => Plugin[]) | undefined;
21
22
  getStyles: () => document_d_exports.StyleDefinitions | null | undefined;
@@ -11,6 +11,7 @@ import { createDocumentNumberingPlugin } from "../prosemirror/plugins/documentNu
11
11
  import { createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
12
12
  import { schema } from "../prosemirror/schema/index.js";
13
13
  import { storyListNumbering } from "../prosemirror/storyListNumbering.js";
14
+ import { CANONICAL_GAP, usesCanonicalSession } from "../types/canonicalCapabilities.js";
14
15
  import { createCanonicalStoryEditor } from "./canonicalStoryEditor.js";
15
16
  import { OP_STORIES } from "@stll/docx-core/ops";
16
17
  import { EditorState, TextSelection } from "prosemirror-state";
@@ -90,8 +91,8 @@ const createNoteEditorManager = (deps) => {
90
91
  const sync = () => {
91
92
  const host = deps.getHost();
92
93
  if (!host) return;
93
- if (deps.getExperimentalSession?.() === "canonical" && !deps.getCanonicalApi?.()?.getCanonicalStoryProjection(OP_STORIES.MAIN)) return;
94
- const document = deps.getExperimentalSession?.() === "canonical" ? deps.getCanonicalApi?.()?.getCanonicalDocument() ?? deps.getDocument() : 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();
95
96
  const styles = deps.getStyles();
96
97
  const theme = deps.getTheme();
97
98
  const numbering = document?.package.numbering;
@@ -115,7 +116,7 @@ const createNoteEditorManager = (deps) => {
115
116
  const existing = mounted.get(key);
116
117
  if (existing) {
117
118
  if (existing.mountNode.parentElement !== host) host.append(existing.mountNode);
118
- if (deps.getExperimentalSession?.() === "canonical") {
119
+ if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories)) {
119
120
  const projected = deps.getCanonicalApi?.()?.getCanonicalStoryProjection({
120
121
  kind: storyKey.kind,
121
122
  id: storyKey.noteId
@@ -175,7 +176,7 @@ const createNoteEditorManager = (deps) => {
175
176
  },
176
177
  getView: () => view,
177
178
  getApi: () => deps.getCanonicalApi?.() ?? null,
178
- enabled: () => deps.getExperimentalSession?.() === "canonical",
179
+ enabled: () => usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories),
179
180
  onRefusal: deps.onSessionRefusal,
180
181
  onSelectionChange: () => deps.onTransaction?.({
181
182
  ...storyKey,
@@ -184,11 +185,11 @@ const createNoteEditorManager = (deps) => {
184
185
  selectionChanged: true
185
186
  })
186
187
  });
187
- const canonicalProjection = deps.getExperimentalSession?.() === "canonical" ? deps.getCanonicalApi?.()?.getCanonicalStoryProjection({
188
+ const canonicalProjection = usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories) ? deps.getCanonicalApi?.()?.getCanonicalStoryProjection({
188
189
  kind: storyKey.kind,
189
190
  id: storyKey.noteId
190
191
  }) : null;
191
- if (deps.getExperimentalSession?.() === "canonical" && !canonicalProjection) {
192
+ if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories) && !canonicalProjection) {
192
193
  manager.destroy();
193
194
  mountNode.remove();
194
195
  continue;
@@ -246,7 +247,7 @@ const createNoteEditorManager = (deps) => {
246
247
  getView: (story) => mounted.get(storyMapKey(story))?.view ?? null,
247
248
  listStories: () => enumerateDocumentNoteStories(deps.getDocument()),
248
249
  snapshotDocument: (document) => {
249
- if (deps.getExperimentalSession?.() === "canonical") return deps.getCanonicalApi?.()?.getCanonicalDocument() ?? document;
250
+ if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories)) return deps.getCanonicalApi?.()?.getCanonicalDocument() ?? document;
250
251
  let footnotes = document.package.footnotes;
251
252
  let endnotes = document.package.endnotes;
252
253
  let footnotesChanged = false;
@@ -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 };
@@ -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