@stll/folio-core 0.4.0 → 0.5.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 (99) hide show
  1. package/dist/ai-edits/apply.d.ts +3 -9
  2. package/dist/ai-edits/apply.js +94 -14
  3. package/dist/ai-edits/blockRange.d.ts +33 -0
  4. package/dist/ai-edits/blockRange.js +58 -0
  5. package/dist/ai-edits/headless.d.ts +33 -4
  6. package/dist/ai-edits/headless.js +83 -15
  7. package/dist/ai-edits/index.d.ts +5 -3
  8. package/dist/ai-edits/index.js +3 -2
  9. package/dist/ai-edits/snapshot.d.ts +14 -2
  10. package/dist/ai-edits/snapshot.js +12 -1
  11. package/dist/ai-edits/types.d.ts +42 -3
  12. package/dist/compat/eigenpal.d.ts +3 -2
  13. package/dist/compat/eigenpal.js +6 -5
  14. package/dist/controller/layoutPipeline.d.ts +1 -0
  15. package/dist/controller/layoutPipeline.js +35 -137
  16. package/dist/controller/layoutScheduler.d.ts +2 -1
  17. package/dist/controller/layoutScheduler.js +6 -0
  18. package/dist/document-operations.d.ts +122 -0
  19. package/dist/document-operations.js +575 -0
  20. package/dist/docx/blockContentParser.js +17 -7
  21. package/dist/docx/encryption/agileDecryption.js +2 -1
  22. package/dist/docx/encryption/compoundFile.js +4 -2
  23. package/dist/docx/footnoteParser.d.ts +1 -17
  24. package/dist/docx/footnoteParser.js +1 -27
  25. package/dist/docx/groupDrawingParser.d.ts +8 -0
  26. package/dist/docx/groupDrawingParser.js +131 -0
  27. package/dist/docx/numberingParser.d.ts +3 -1
  28. package/dist/docx/numberingParser.js +8 -2
  29. package/dist/docx/paragraphParser.js +9 -3
  30. package/dist/docx/runParser.js +8 -1
  31. package/dist/docx/selectiveXmlPatch.js +4 -10
  32. package/dist/docx/serializer/numberingSerializer.js +3 -1
  33. package/dist/docx/settingsParser.d.ts +6 -3
  34. package/dist/docx/settingsParser.js +2 -0
  35. package/dist/docx/xmlParser.js +11 -4
  36. package/dist/index.d.ts +3 -2
  37. package/dist/index.js +6 -5
  38. package/dist/layout-bridge/convert/footnoteLayout.d.ts +37 -1
  39. package/dist/layout-bridge/convert/footnoteLayout.js +138 -14
  40. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +5 -7
  41. package/dist/layout-bridge/convert/headerFooterLayout.js +5 -7
  42. package/dist/layout-bridge/convert/toFlowBlocks.js +56 -19
  43. package/dist/layout-engine/index.d.ts +6 -5
  44. package/dist/layout-engine/index.js +89 -26
  45. package/dist/layout-engine/keep-together.d.ts +13 -8
  46. package/dist/layout-engine/keep-together.js +40 -25
  47. package/dist/layout-engine/layoutInstrumentation.d.ts +11 -1
  48. package/dist/layout-engine/layoutInstrumentation.js +10 -1
  49. package/dist/layout-engine/measure/measureBlocks.js +28 -18
  50. package/dist/layout-engine/measure/measureParagraph.js +61 -15
  51. package/dist/layout-engine/paginator.d.ts +2 -1
  52. package/dist/layout-engine/paginator.js +9 -3
  53. package/dist/layout-engine/textBoxGroup.d.ts +7 -0
  54. package/dist/layout-engine/textBoxGroup.js +8 -0
  55. package/dist/layout-engine/types.d.ts +30 -9
  56. package/dist/layout-engine/types.js +20 -2
  57. package/dist/layout-painter/renderPage.d.ts +15 -1
  58. package/dist/layout-painter/renderPage.js +27 -11
  59. package/dist/layout-painter/renderParagraph.js +18 -8
  60. package/dist/layout-painter/renderTable.js +10 -7
  61. package/dist/managers/DocumentLoaderManager.js +12 -5
  62. package/dist/managers/TableSelectionManager.js +1 -1
  63. package/dist/model.js +1 -1
  64. package/dist/paged-layout/pageText.d.ts +14 -0
  65. package/dist/paged-layout/pageText.js +21 -0
  66. package/dist/prosemirror/attrs/index.js +2 -0
  67. package/dist/prosemirror/commands/comments.js +75 -5
  68. package/dist/prosemirror/commands/hyperlink.js +4 -2
  69. package/dist/prosemirror/commands/image.js +2 -1
  70. package/dist/prosemirror/commands/index.js +1 -1
  71. package/dist/prosemirror/commands/propertyChangeScope.d.ts +68 -0
  72. package/dist/prosemirror/commands/propertyChangeScope.js +242 -0
  73. package/dist/prosemirror/conversion/fromProseDoc.js +14 -3
  74. package/dist/prosemirror/conversion/toProseDoc.js +29 -8
  75. package/dist/prosemirror/extensions/core/ParagraphExtension.js +2 -0
  76. package/dist/prosemirror/extensions/features/ListExtension.js +6 -0
  77. package/dist/prosemirror/extensions/nodes/TableExtension.js +10 -11
  78. package/dist/prosemirror/findReplaceSelection.js +2 -1
  79. package/dist/prosemirror/index.js +1 -1
  80. package/dist/prosemirror/insertOperations.js +1 -1
  81. package/dist/prosemirror/schema/nodes.d.ts +10 -5
  82. package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
  83. package/dist/prosemirror/utils/tabCalculator.js +4 -2
  84. package/dist/redline.d.ts +20 -0
  85. package/dist/redline.js +127 -0
  86. package/dist/server.d.ts +7 -3
  87. package/dist/server.js +6 -2
  88. package/dist/symbols.d.ts +35 -0
  89. package/dist/symbols.js +512 -0
  90. package/dist/utils/clipboard.js +3 -3
  91. package/dist/utils/fontLoader.js +3 -0
  92. package/dist/utils/fontResolver.js +48 -1
  93. package/dist/utils/zoom.d.ts +21 -0
  94. package/dist/utils/zoom.js +21 -0
  95. package/dist/version-comparison.d.ts +92 -0
  96. package/dist/version-comparison.js +436 -0
  97. package/package.json +3 -3
  98. package/dist/paged-layout/headerFooterMargins.d.ts +0 -75
  99. package/dist/paged-layout/headerFooterMargins.js +0 -122
@@ -45,6 +45,27 @@ type FolioAIEditReviewMeta = {
45
45
  severity?: FolioAIEditSeverity;
46
46
  area?: string;
47
47
  };
48
+ type FolioAIEditPrecondition = {
49
+ blockTextHash: string;
50
+ };
51
+ /**
52
+ * A serializable range over the visible, post-tracked-changes text of one
53
+ * block. Offsets are zero-based UTF-16 boundaries, matching JavaScript string
54
+ * slicing; `selectedTextHash` makes a shifted or changed selection fail stale.
55
+ */
56
+ type FolioAITextRangeHandle = {
57
+ type: "textRange";
58
+ story: "main";
59
+ blockId: string;
60
+ startOffset: number;
61
+ endOffset: number;
62
+ selectedTextHash: string;
63
+ };
64
+ type FolioAIInlineFormatting = {
65
+ bold?: boolean;
66
+ italic?: boolean;
67
+ underline?: boolean;
68
+ };
48
69
  /**
49
70
  * A party in an `insertSignatureTable` op. Mirrors the
50
71
  * `signatureTable` helper in `docx-core/legal-source/compile.ts`:
@@ -56,13 +77,31 @@ type FolioAISignatureParty = {
56
77
  signatory?: string;
57
78
  title?: string;
58
79
  };
59
- type FolioAIEditOperation = FolioAIEditReviewMeta & ({
80
+ type FolioAIEditOperation = FolioAIEditReviewMeta & {
81
+ precondition?: FolioAIEditPrecondition;
82
+ } & ({
60
83
  id: string;
61
84
  type: "replaceInBlock";
62
85
  blockId: string;
63
86
  find: string;
64
87
  replace: string;
65
88
  comment?: FolioAIComment;
89
+ } | {
90
+ id: string;
91
+ type: "replaceRange";
92
+ range: FolioAITextRangeHandle;
93
+ replace: string;
94
+ comment?: FolioAIComment;
95
+ } | {
96
+ id: string;
97
+ type: "commentOnRange";
98
+ range: FolioAITextRangeHandle;
99
+ comment: FolioAIComment;
100
+ } | {
101
+ id: string;
102
+ type: "formatRange";
103
+ range: FolioAITextRangeHandle;
104
+ formatting: FolioAIInlineFormatting;
66
105
  } | {
67
106
  id: string;
68
107
  type: "insertAfterBlock" | "insertBeforeBlock";
@@ -116,7 +155,7 @@ type FolioAIEditOperation = FolioAIEditReviewMeta & ({
116
155
  comment?: FolioAIComment;
117
156
  });
118
157
  type FolioAIEditApplyMode = "direct" | "tracked-changes";
119
- type FolioAIEditSkipReason = "missingBlock" | "changedBlock" | "ambiguousFind" | "missingFind" | "unsupportedBlock" | "emptyOperation"
158
+ type FolioAIEditSkipReason = "missingBlock" | "changedBlock" | "ambiguousFind" | "missingFind" | "unsupportedBlock" | "unsupportedMode" | "atomicBatchRejected" | "preconditionFailed" | "staleRange" | "emptyOperation"
120
159
  /**
121
160
  * The operation would not change the document — find equals
122
161
  * replace, or replaceBlock's `text` matches the live block.
@@ -153,4 +192,4 @@ type FolioAIEditApplyResult = {
153
192
  skipped: FolioAIEditSkippedOperation[];
154
193
  };
155
194
  //#endregion
156
- export { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIComment, FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditOperation, FolioAIEditReviewMeta, FolioAIEditSeverity, FolioAIEditSkipReason, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAISignatureParty };
195
+ export { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIComment, FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditReviewMeta, FolioAIEditSeverity, FolioAIEditSkipReason, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAIInlineFormatting, FolioAISignatureParty, FolioAITextRangeHandle };
@@ -1,6 +1,7 @@
1
- import { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIComment, FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditOperation, FolioAIEditReviewMeta, FolioAIEditSeverity, FolioAIEditSkipReason, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAISignatureParty } from "../ai-edits/types.js";
1
+ import { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIComment, FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditReviewMeta, FolioAIEditSeverity, FolioAIEditSkipReason, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAISignatureParty } from "../ai-edits/types.js";
2
2
  import { applyFolioAIEditOperations } from "../ai-edits/apply.js";
3
3
  import { document_d_exports } from "../types/document.js";
4
+ import { ApplyFolioDocumentOperationsOptions, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FolioDocumentOperation, FolioDocumentOperationAffectedTarget, FolioDocumentOperationBatch, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationStatus, FolioDocumentOperationType, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch } from "../document-operations.js";
4
5
  import { createFolioAIEditSnapshot, hashFolioAIBlockText, normalizeFolioAIBlockText } from "../ai-edits/snapshot.js";
5
6
  import { DeriveBlockIdInput, FolioBlockId, deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "../types/block-id.js";
6
7
  import { WordDiffSegment, diffWordSegments } from "../ai-edits/word-diff.js";
@@ -26,4 +27,4 @@ import { toMarkdown, toMarkdownResult } from "../markdown/index.js";
26
27
  import { EmbeddedFont, EmbeddedFontParts, extractEmbeddedFonts, getEmbeddedFontFaces } from "../fonts/embeddedFonts.js";
27
28
  import { getGoogleFontsEnabled, setGoogleFontsEnabled } from "../utils/fontResolver.js";
28
29
  type Document = document_d_exports.Document;
29
- export { type AIBarStatus, type AIChatMode, type AICitation, type AICitationRange, type AICitationSource, type AIGenerateInput, type AISuggestion, type AISuggestionApplyMode, type AISuggestionPreset, type AISuggestionSeverity, type AISuggestionStatus, type AcceptAutocompleteResult, type AnonymizationMatch, type AnonymizationTerm, type ApplyResult, type AutocompleteSuggestionPluginOptions, type AutocompleteSuggestionState, type AutocompleteSuggestionStatus, type AutocompleteTriggerCheck, type AutocompleteTriggerOptions, type AutocompleteTriggerSkipReason, type CreateEmptyDocumentOptions, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, type DeriveBlockIdInput, type DirectiveKind, type DirectiveRange, type Document, type DocxCompatibility, type EmbeddedFont, type EmbeddedFontParts, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIComment, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyResult, type FolioAIEditOperation, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAISignatureParty, type FolioBlockId, type ImageMeta, type ImageRef, type MarkdownOptions, type MarkdownResult, type PositionalText, type ResolvedAnchor, type TemplatePreviewSpan, type TemplatePreviewValue, type TemplatePreviewValues, type TemplateSlashMenuKeyAction, type TemplateSlashMenuState, type WordDiffSegment, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applySuggestions, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, deriveBlockId, diffWordSegments, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, isFolioBlockId, isSequentialFolioBlockId, isSuggestionStale, normalizeFolioAIBlockText, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
30
+ export { type AIBarStatus, type AIChatMode, type AICitation, type AICitationRange, type AICitationSource, type AIGenerateInput, type AISuggestion, type AISuggestionApplyMode, type AISuggestionPreset, type AISuggestionSeverity, type AISuggestionStatus, type AcceptAutocompleteResult, type AnonymizationMatch, type AnonymizationTerm, type ApplyFolioDocumentOperationsOptions, type ApplyResult, type AutocompleteSuggestionPluginOptions, type AutocompleteSuggestionState, type AutocompleteSuggestionStatus, type AutocompleteTriggerCheck, type AutocompleteTriggerOptions, type AutocompleteTriggerSkipReason, type CreateEmptyDocumentOptions, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, type DeriveBlockIdInput, type DirectiveKind, type DirectiveRange, type Document, type DocxCompatibility, type EmbeddedFont, type EmbeddedFontParts, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIComment, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyResult, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAISignatureParty, type FolioBlockId, type FolioDocumentOperation, type FolioDocumentOperationAffectedTarget, type FolioDocumentOperationBatch, type FolioDocumentOperationCapabilities, type FolioDocumentOperationIssue, type FolioDocumentOperationMode, type FolioDocumentOperationPrecondition, type FolioDocumentOperationReceipt, type FolioDocumentOperationRecovery, type FolioDocumentOperationResult, type FolioDocumentOperationStatus, type FolioDocumentOperationType, type ImageMeta, type ImageRef, InvalidFolioDocumentOperationBatchError, type MarkdownOptions, type MarkdownResult, type PositionalText, type ResolvedAnchor, type TemplatePreviewSpan, type TemplatePreviewValue, type TemplatePreviewValues, type TemplateSlashMenuKeyAction, type TemplateSlashMenuState, UnsupportedFolioDocumentOperationVersionError, type WordDiffSegment, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, deriveBlockId, diffWordSegments, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
@@ -1,13 +1,14 @@
1
+ import { deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "../types/block-id.js";
2
+ import { createFolioAIEditSnapshot, hashFolioAIBlockText, normalizeFolioAIBlockText } from "../ai-edits/snapshot.js";
3
+ import { diffWordSegments } from "../ai-edits/word-diff.js";
4
+ import { applyFolioAIEditOperations } from "../ai-edits/apply.js";
5
+ import { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch } from "../document-operations.js";
1
6
  import { createEmptyDocument } from "../utils/createDocument.js";
2
7
  import { createDocx } from "../docx/rezip.js";
3
- import { deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "../types/block-id.js";
4
8
  import { DEFAULT_AI_SUGGESTION_PRESETS } from "../ai-suggestions/types.js";
5
9
  import { buildPositionalText } from "../ai-suggestions/text-positions.js";
6
10
  import { isSuggestionStale, resolveSuggestionAnchor } from "../ai-suggestions/conflict.js";
7
11
  import { applySuggestions } from "../ai-suggestions/apply.js";
8
- import { createFolioAIEditSnapshot, hashFolioAIBlockText, normalizeFolioAIBlockText } from "../ai-edits/snapshot.js";
9
- import { diffWordSegments } from "../ai-edits/word-diff.js";
10
- import { applyFolioAIEditOperations } from "../ai-edits/apply.js";
11
12
  import { setAISuggestionsMeta, setFocusedSuggestionMeta } from "../prosemirror/plugins/aiSuggestionDecorations.js";
12
13
  import { getGoogleFontsEnabled, setGoogleFontsEnabled } from "../utils/fontResolver.js";
13
14
  import { scrollFolioPositionIntoView } from "../paged-layout/scrollToPmPosition.js";
@@ -21,4 +22,4 @@ import { DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, acceptAutocompleteSuggestion, acc
21
22
  import { fromMarkdown } from "../markdown/fromMarkdown.js";
22
23
  import { toMarkdown, toMarkdownResult } from "../markdown/index.js";
23
24
  import { extractEmbeddedFonts, getEmbeddedFontFaces } from "../fonts/embeddedFonts.js";
24
- export { DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applySuggestions, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, deriveBlockId, diffWordSegments, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, isFolioBlockId, isSequentialFolioBlockId, isSuggestionStale, normalizeFolioAIBlockText, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
25
+ export { DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, deriveBlockId, diffWordSegments, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
@@ -45,6 +45,7 @@ type LayoutPipelineDeps<THfPMs> = {
45
45
  sectionProperties: document_d_exports.SectionProperties | null | undefined;
46
46
  document: document_d_exports.Document | null;
47
47
  defaultTabStop: number | undefined;
48
+ mirrorMargins: boolean;
48
49
  styles: document_d_exports.StyleDefinitions | null | undefined;
49
50
  layout: Layout | null;
50
51
  hfPMs: THfPMs;
@@ -2,32 +2,24 @@ import "../layout-engine/types.js";
2
2
  import { renderPages } from "../layout-painter/renderPage.js";
3
3
  import { templatePreviewValuesKey } from "../prosemirror/plugins/templatePreviewValues.js";
4
4
  import { toFlowBlocks } from "../layout-bridge/convert/toFlowBlocks.js";
5
- import { recordLayoutComplete, recordLayoutError, recordLayoutPhase } from "../layout-engine/layoutInstrumentation.js";
5
+ import { recordLayoutComplete, recordLayoutError, recordLayoutPhase, recordLayoutStart } from "../layout-engine/layoutInstrumentation.js";
6
6
  import { buildBookmarkPageMap } from "../fields/bookmarkPages.js";
7
7
  import { buildBookmarkText } from "../fields/bookmarkText.js";
8
8
  import { buildHeaderFooterFieldValues, fieldValuesEqual, resolveFieldValues } from "../fields/resolveFieldValues.js";
9
9
  import { buildSectionPageCounts } from "../fields/sectionPageCounts.js";
10
10
  import { buildSeqValues } from "../fields/seqValues.js";
11
11
  import { installCanvasMeasureProvider } from "../layout-engine/measure/measureContainer.js";
12
- import { buildFootnoteContentMap, collectFootnoteRefs } from "../layout-bridge/convert/footnoteLayout.js";
12
+ import { buildFootnoteContentMap, collectEndnoteRefs, collectFootnoteRefs, computeNoteDisplayNumbers, remapNoteMarkerText } from "../layout-bridge/convert/footnoteLayout.js";
13
13
  import { applyTemplatePreviewToBlocks } from "../layout-bridge/convert/templatePreviewFlow.js";
14
14
  import { layoutDocument } from "../layout-engine/index.js";
15
15
  import { measureBlocks, measureSingleBlockWithoutFloatingZones } from "../layout-engine/measure/measureBlocks.js";
16
- import { computeFirstPageHeaderFooterMarginExtender, computeHeaderFooterMarginExtender, extendSectionBreakMargins } from "../paged-layout/headerFooterMargins.js";
17
16
  import { tryBuildIncrementalMeasures } from "../paged-layout/incrementalMeasure.js";
18
17
  import { computePerBlockMeasureInputs } from "../paged-layout/sectionBlockWidths.js";
19
- import { twipsToPixels } from "../paged-layout/sectionGeometry.js";
18
+ import { getMargins, getPageSize, twipsToPixels } from "../paged-layout/sectionGeometry.js";
20
19
  import { getDocumentWatermark } from "../watermark/index.js";
21
20
  //#region src/controller/layoutPipeline.ts
22
- function pageMarginsEqual(left, right) {
23
- return left.top === right.top && left.right === right.right && left.bottom === right.bottom && left.left === right.left && left.header === right.header && left.footer === right.footer;
24
- }
25
- function optionalPageMarginsEqual(left, right) {
26
- if (left === void 0 || right === void 0) return left === right;
27
- return pageMarginsEqual(left, right);
28
- }
29
21
  function runLayoutPipeline(deps, state, options = {}) {
30
- const { contentWidth, columns, pageSize, margins, pageGap, syncCoordinator, headerContent, footerContent, firstPageHeaderContent, firstPageFooterContent, headerContentRId, footerContentRId, firstPageHeaderContentRId, firstPageFooterContentRId, sectionHeaderFooterRefs, theme: _theme, sectionProperties, document, defaultTabStop, styles, layout, hfPMs, painter, pagesContainer, session, renderHfFromContentOrPm, renderHeaderFooterContentByRId, documentFontsAreLoaded, buildFootnoteRenderItems, describeInvalidHighlightMarks, emptyTemplatePreviewEntries: EMPTY_TEMPLATE_PREVIEW_ENTRIES } = deps;
22
+ const { contentWidth, columns, pageSize, margins, pageGap, syncCoordinator, headerContent, footerContent, firstPageHeaderContent, firstPageFooterContent, headerContentRId, footerContentRId, firstPageHeaderContentRId, firstPageFooterContentRId, sectionHeaderFooterRefs, theme: _theme, sectionProperties, document, defaultTabStop, mirrorMargins, styles, layout, hfPMs, painter, pagesContainer, session, renderHfFromContentOrPm, renderHeaderFooterContentByRId, documentFontsAreLoaded, buildFootnoteRenderItems, describeInvalidHighlightMarks, emptyTemplatePreviewEntries: EMPTY_TEMPLATE_PREVIEW_ENTRIES } = deps;
31
23
  let outcome = {};
32
24
  let pendingArtifacts;
33
25
  let pendingTemplatePreview;
@@ -37,6 +29,7 @@ function runLayoutPipeline(deps, state, options = {}) {
37
29
  recordLayoutPhase(reason, phase, performance.now() - startedAt);
38
30
  };
39
31
  const currentEpoch = syncCoordinator.getStateSeq();
32
+ recordLayoutStart(reason);
40
33
  syncCoordinator.onLayoutStart();
41
34
  try {
42
35
  let phaseStartedAt = performance.now();
@@ -61,6 +54,14 @@ function runLayoutPipeline(deps, state, options = {}) {
61
54
  const footnoteRefs = collectFootnoteRefs(newBlocks);
62
55
  const documentFootnotes = document?.package.footnotes;
63
56
  const hasFootnotes = footnoteRefs.length > 0 && documentFootnotes !== void 0;
57
+ const footnoteDisplayNumbers = documentFootnotes ? computeNoteDisplayNumbers(documentFootnotes, footnoteRefs.map((ref) => ref.footnoteId)) : void 0;
58
+ const documentEndnotes = document?.package.endnotes;
59
+ const endnoteDisplayNumbers = documentEndnotes ? computeNoteDisplayNumbers(documentEndnotes, collectEndnoteRefs(newBlocks).map((ref) => ref.endnoteId)) : void 0;
60
+ newBlocks = remapNoteMarkerText(newBlocks, {
61
+ ...footnoteDisplayNumbers ? { footnoteNumbers: footnoteDisplayNumbers } : {},
62
+ ...endnoteDisplayNumbers ? { endnoteNumbers: endnoteDisplayNumbers } : {}
63
+ });
64
+ outcome.blocks = newBlocks;
64
65
  const hfMetricsHeader = {
65
66
  section: "header",
66
67
  pageSize,
@@ -90,73 +91,19 @@ function runLayoutPipeline(deps, state, options = {}) {
90
91
  let firstPageFooterForRender = hasTitlePg ? renderHfFromContentOrPm(firstPageFooterContent, firstPageFooterContentRId, hfPMs, contentWidth, hfMetricsFooter, hfOptions) : void 0;
91
92
  let headerContentByRId = renderHeaderFooterContentByRId(document?.package.headers, hfPMs, contentWidth, hfMetricsHeader, hfOptions);
92
93
  let footerContentByRId = renderHeaderFooterContentByRId(document?.package.footers, hfPMs, contentWidth, hfMetricsFooter, hfOptions);
93
- const hfExtenderContent = {
94
- headerContent: headerContentForRender,
95
- footerContent: footerContentForRender,
96
- firstPageHeaderContent: firstPageHeaderForRender,
97
- firstPageFooterContent: firstPageFooterForRender
98
- };
99
- const buildSectionHfExtenderContent = () => {
100
- if (!sectionHeaderFooterRefs) return;
101
- return sectionHeaderFooterRefs.map((refs) => ({
102
- headerContent: pickSectionHeaderFooterContent(headerContentByRId, refs.headerDefault, refs.evenAndOddHeaders === true ? refs.headerEven : void 0),
103
- footerContent: pickSectionHeaderFooterContent(footerContentByRId, refs.footerDefault, refs.evenAndOddHeaders === true ? refs.footerEven : void 0),
104
- firstPageHeaderContent: refs.titlePg === true ? headerContentByRId?.get(refs.headerFirst ?? "") : void 0,
105
- firstPageFooterContent: refs.titlePg === true ? footerContentByRId?.get(refs.footerFirst ?? "") : void 0
106
- }));
107
- };
108
- const hfWarn = (msg) => {
109
- console.warn(`[PagedEditor] ${msg}`);
110
- };
111
- const extendForHfOverflow = computeHeaderFooterMarginExtender({
112
- ...hfExtenderContent,
113
- pageSize,
114
- warn: hfWarn
115
- });
116
- const extendForFirstPage = computeFirstPageHeaderFooterMarginExtender({
117
- ...hfExtenderContent,
118
- pageSize,
119
- warn: hfWarn
120
- });
121
- let effectiveMargins = extendForHfOverflow(margins);
122
- let effectiveFirstPageMargins = hasTitlePg ? extendForFirstPage(margins) : void 0;
123
- const sectionBreaks = newBlocks.filter((block) => block.kind === "sectionBreak");
124
- const originalSectionBreakMargins = /* @__PURE__ */ new Map();
125
- for (const sectionBreak of sectionBreaks) originalSectionBreakMargins.set(sectionBreak.id, sectionBreak.margins ? { ...sectionBreak.margins } : void 0);
126
- const restoreSectionBreakMargins = () => {
127
- for (const sectionBreak of sectionBreaks) {
128
- const originalMargins = originalSectionBreakMargins.get(sectionBreak.id);
129
- if (originalMargins === void 0) {
130
- delete sectionBreak.margins;
131
- continue;
132
- }
133
- sectionBreak.margins = { ...originalMargins };
134
- }
135
- };
136
- const applySectionBreakMargins = (content, bodyMargins) => {
137
- restoreSectionBreakMargins();
138
- extendSectionBreakMargins(sectionBreaks, {
139
- content,
140
- sectionContent: buildSectionHfExtenderContent(),
141
- bodyPageSize: pageSize,
142
- bodyMargins,
143
- warn: hfWarn
144
- });
145
- };
146
- applySectionBreakMargins(hfExtenderContent, effectiveMargins);
147
94
  recordPhaseDuration("header-footer", phaseStartedAt);
148
95
  phaseStartedAt = performance.now();
149
- let bodyLayoutConfig = {
96
+ const bodyLayoutConfig = {
150
97
  pageSize,
151
- margins: effectiveMargins
98
+ margins
152
99
  };
153
100
  if (columns !== void 0) bodyLayoutConfig.columns = columns;
154
- let blockMeasureInputs = computePerBlockMeasureInputs({
101
+ const blockMeasureInputs = computePerBlockMeasureInputs({
155
102
  blocks: newBlocks,
156
103
  bodyConfig: bodyLayoutConfig,
157
104
  finalConfig: bodyLayoutConfig
158
105
  });
159
- let blockWidths = blockMeasureInputs.widths;
106
+ const blockWidths = blockMeasureInputs.widths;
160
107
  const previousArtifacts = session.artifacts;
161
108
  const incrementalResult = options.dirtyRange && !options.forceFull && previousArtifacts ? tryBuildIncrementalMeasures({
162
109
  previousBlocks: previousArtifacts.blocks,
@@ -183,19 +130,31 @@ function runLayoutPipeline(deps, state, options = {}) {
183
130
  let pageFootnoteMap = /* @__PURE__ */ new Map();
184
131
  let footnoteContentMap = /* @__PURE__ */ new Map();
185
132
  const bodyBreakType = sectionProperties?.sectionStart;
186
- const buildLayoutOpts = (nextMargins, nextFirstPageMargins) => {
133
+ const buildLayoutOpts = () => {
187
134
  const nextLayoutOpts = {
188
135
  pageSize,
189
- margins: nextMargins,
190
- pageGap
136
+ margins,
137
+ pageGap,
138
+ mirrorMargins
191
139
  };
192
- if (nextFirstPageMargins !== void 0) nextLayoutOpts.firstPageMargins = nextFirstPageMargins;
140
+ if (hasTitlePg && firstPageHeaderForRender) {
141
+ const headerBottom = (margins.header ?? 0) + (firstPageHeaderForRender.marginPushBottom ?? firstPageHeaderForRender.height);
142
+ if (headerBottom > margins.top) nextLayoutOpts.firstPageMargins = {
143
+ ...margins,
144
+ top: headerBottom
145
+ };
146
+ }
147
+ const finalSection = document?.package.document.sections?.at(-1);
148
+ if (finalSection) {
149
+ nextLayoutOpts.finalPageSize = getPageSize(finalSection.properties);
150
+ nextLayoutOpts.finalMargins = getMargins(finalSection.properties);
151
+ }
193
152
  if (columns !== void 0) nextLayoutOpts.columns = columns;
194
153
  if (bodyBreakType !== void 0) nextLayoutOpts.bodyBreakType = bodyBreakType;
195
154
  if (sectionHeaderFooterRefs !== void 0) nextLayoutOpts.sectionHeaderFooterRefs = sectionHeaderFooterRefs;
196
155
  return nextLayoutOpts;
197
156
  };
198
- const layoutOpts = buildLayoutOpts(effectiveMargins, effectiveFirstPageMargins);
157
+ const layoutOpts = buildLayoutOpts();
199
158
  let layoutOptsUsed = layoutOpts;
200
159
  if (hasFootnotes) {
201
160
  footnoteContentMap = buildFootnoteContentMap(documentFootnotes, footnoteRefs, contentWidth, (() => {
@@ -292,57 +251,8 @@ function runLayoutPipeline(deps, state, options = {}) {
292
251
  firstPageFooterForRender = hasTitlePg ? renderHfFromContentOrPm(firstPageFooterContent, firstPageFooterContentRId, hfPMs, contentWidth, hfMetricsFooter, finalHfOptions) : void 0;
293
252
  headerContentByRId = renderHeaderFooterContentByRId(document?.package.headers, hfPMs, contentWidth, hfMetricsHeader, finalHfOptions);
294
253
  footerContentByRId = renderHeaderFooterContentByRId(document?.package.footers, hfPMs, contentWidth, hfMetricsFooter, finalHfOptions);
295
- return {
296
- headerContent: headerContentForRender,
297
- footerContent: footerContentForRender,
298
- firstPageHeaderContent: firstPageHeaderForRender,
299
- firstPageFooterContent: firstPageFooterForRender
300
- };
301
254
  };
302
- const MAX_HEADER_FOOTER_STABILIZATION_PASSES = 3;
303
- for (let pass = 0; pass < MAX_HEADER_FOOTER_STABILIZATION_PASSES; pass++) {
304
- const finalHfExtenderContent = rebuildHeaderFooterForLayout();
305
- const finalEffectiveMargins = computeHeaderFooterMarginExtender({
306
- ...finalHfExtenderContent,
307
- pageSize,
308
- warn: hfWarn
309
- })(margins);
310
- const finalEffectiveFirstPageMargins = hasTitlePg ? computeFirstPageHeaderFooterMarginExtender({
311
- ...finalHfExtenderContent,
312
- pageSize,
313
- warn: hfWarn
314
- })(margins) : void 0;
315
- if (!pageMarginsEqual(effectiveMargins, finalEffectiveMargins) || !optionalPageMarginsEqual(effectiveFirstPageMargins, finalEffectiveFirstPageMargins)) {
316
- effectiveMargins = finalEffectiveMargins;
317
- effectiveFirstPageMargins = finalEffectiveFirstPageMargins;
318
- applySectionBreakMargins(finalHfExtenderContent, effectiveMargins);
319
- bodyLayoutConfig = {
320
- pageSize,
321
- margins: effectiveMargins
322
- };
323
- if (columns !== void 0) bodyLayoutConfig.columns = columns;
324
- blockMeasureInputs = computePerBlockMeasureInputs({
325
- blocks: newBlocks,
326
- bodyConfig: bodyLayoutConfig,
327
- finalConfig: bodyLayoutConfig
328
- });
329
- blockWidths = blockMeasureInputs.widths;
330
- newMeasures = measureBlocks(newBlocks, blockWidths, blockMeasureInputs.marginTops, {
331
- pageHeight: blockMeasureInputs.pageHeights,
332
- marginBottom: blockMeasureInputs.marginBottoms
333
- });
334
- pendingArtifacts = {
335
- blocks: newBlocks,
336
- blockWidths,
337
- measures: newMeasures
338
- };
339
- outcome.measures = newMeasures;
340
- relayoutWithCurrentMeasures(buildLayoutOpts(effectiveMargins, effectiveFirstPageMargins));
341
- stabilizeFieldWidths();
342
- continue;
343
- }
344
- break;
345
- }
255
+ rebuildHeaderFooterForLayout();
346
256
  outcome.layout = newLayout;
347
257
  recordPhaseDuration("layout-document", phaseStartedAt);
348
258
  if (pagesContainer && painter) {
@@ -412,17 +322,5 @@ function runLayoutPipeline(deps, state, options = {}) {
412
322
  syncCoordinator.onLayoutComplete(currentEpoch);
413
323
  return outcome;
414
324
  }
415
- function pickSectionHeaderFooterContent(byRId, defaultRId, evenRId) {
416
- const defaultContent = defaultRId ? byRId?.get(defaultRId) : void 0;
417
- const evenContent = evenRId ? byRId?.get(evenRId) : void 0;
418
- if (!defaultContent) return evenContent;
419
- if (!evenContent) return defaultContent;
420
- return headerFooterMarginPushHeight(evenContent) > headerFooterMarginPushHeight(defaultContent) ? evenContent : defaultContent;
421
- }
422
- function headerFooterMarginPushHeight(content) {
423
- const bottom = content.marginPushBottom ?? content.visualBottom ?? content.height;
424
- const top = content.marginPushTop ?? content.visualTop ?? 0;
425
- return Math.max(bottom - top, content.height);
426
- }
427
325
  //#endregion
428
326
  export { runLayoutPipeline };
@@ -18,7 +18,8 @@ type SchedulerClock = {
18
18
  declare const browserClock: SchedulerClock;
19
19
  type LayoutSchedulerConfig<TState> = {
20
20
  runLayout: RunLayout<TState>; /** Quiet-window debounce before an interactive layout pass. */
21
- debounceMs: number; /** Hard cap on latency from the first edit in a burst. */
21
+ debounceMs: number; /** Run the first edit after a max-delay-sized idle period on the next frame. */
22
+ leadingFrame?: boolean; /** Hard cap on latency from the first edit in a burst. */
22
23
  maxDelayMs: number;
23
24
  /**
24
25
  * Timing source. Pass `browserClock` in the browser; a host injects its own
@@ -9,6 +9,7 @@ const browserClock = {
9
9
  };
10
10
  const createLayoutScheduler = (config) => {
11
11
  const clock = config.clock;
12
+ let lastRunAt = null;
12
13
  let pending = null;
13
14
  const flushPending = () => {
14
15
  if (!pending || pending.rafId !== null) return;
@@ -17,6 +18,7 @@ const createLayoutScheduler = (config) => {
17
18
  const latest = pending;
18
19
  pending = null;
19
20
  if (!latest) return;
21
+ lastRunAt = clock.now();
20
22
  const options = { reason: "transaction" };
21
23
  if (latest.dirtyRange) options.dirtyRange = latest.dirtyRange;
22
24
  config.runLayout(latest.state, options);
@@ -45,6 +47,10 @@ const createLayoutScheduler = (config) => {
45
47
  timerId: null
46
48
  };
47
49
  pending = next;
50
+ if (config.leadingFrame && (lastRunAt === null || clock.now() - lastRunAt >= config.maxDelayMs)) {
51
+ flushPending();
52
+ return;
53
+ }
48
54
  armTimer(next);
49
55
  },
50
56
  dispose() {
@@ -0,0 +1,122 @@
1
+ import { FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAITextRangeHandle } from "./ai-edits/types.js";
2
+ import { FolioAIEditView } from "./ai-edits/apply.js";
3
+
4
+ //#region src/document-operations.d.ts
5
+ declare const FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION: 1;
6
+ declare const FOLIO_DOCUMENT_OPERATION_TYPES: readonly ["replaceInBlock", "replaceRange", "commentOnRange", "formatRange", "insertAfterBlock", "insertBeforeBlock", "replaceBlock", "deleteBlock", "commentOnBlock", "insertSignatureTable"];
7
+ declare const FOLIO_DOCUMENT_OPERATION_MODES: readonly ["direct", "tracked-changes"];
8
+ declare const FOLIO_DOCUMENT_OPERATION_STORIES: readonly ["main"];
9
+ declare const FOLIO_DOCUMENT_OPERATION_PRECONDITIONS: readonly ["blockTextHash"];
10
+ declare const FOLIO_DOCUMENT_OPERATION_BATCH_MODES: readonly ["best-effort", "atomic"];
11
+ type FolioDocumentOperation = FolioAIEditOperation;
12
+ type FolioDocumentOperationMode = FolioAIEditApplyMode;
13
+ type FolioDocumentOperationPrecondition = FolioAIEditPrecondition;
14
+ type FolioDocumentOperationType = FolioDocumentOperation["type"];
15
+ declare const FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE: Readonly<{
16
+ readonly replaceInBlock: readonly ["direct", "tracked-changes"];
17
+ readonly replaceRange: readonly ["direct", "tracked-changes"];
18
+ readonly commentOnRange: readonly ["direct", "tracked-changes"];
19
+ readonly formatRange: readonly ["direct"];
20
+ readonly insertAfterBlock: readonly ["direct", "tracked-changes"];
21
+ readonly insertBeforeBlock: readonly ["direct", "tracked-changes"];
22
+ readonly replaceBlock: readonly ["direct", "tracked-changes"];
23
+ readonly deleteBlock: readonly ["direct", "tracked-changes"];
24
+ readonly commentOnBlock: readonly ["direct", "tracked-changes"];
25
+ readonly insertSignatureTable: readonly ["direct"];
26
+ }>;
27
+ type FolioDocumentOperationCapabilities = {
28
+ readonly version: typeof FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION;
29
+ readonly operationTypes: typeof FOLIO_DOCUMENT_OPERATION_TYPES;
30
+ readonly modes: typeof FOLIO_DOCUMENT_OPERATION_MODES;
31
+ readonly modesByOperationType: typeof FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE;
32
+ readonly batchModes: typeof FOLIO_DOCUMENT_OPERATION_BATCH_MODES;
33
+ readonly dryRun: true;
34
+ readonly preconditions: typeof FOLIO_DOCUMENT_OPERATION_PRECONDITIONS;
35
+ readonly stories: typeof FOLIO_DOCUMENT_OPERATION_STORIES;
36
+ };
37
+ declare const getFolioDocumentOperationCapabilities: () => FolioDocumentOperationCapabilities;
38
+ declare const isFolioDocumentOperationModeSupported: (operationType: FolioDocumentOperationType, mode: FolioDocumentOperationMode) => boolean;
39
+ declare const isSupportedFolioDocumentOperationVersion: (value: unknown) => value is typeof FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION;
40
+ declare const UnsupportedFolioDocumentOperationVersionError_base: import("better-result").TaggedErrorClass<"UnsupportedFolioDocumentOperationVersionError", {
41
+ message: string;
42
+ receivedVersion: unknown;
43
+ }>;
44
+ declare class UnsupportedFolioDocumentOperationVersionError extends UnsupportedFolioDocumentOperationVersionError_base {}
45
+ declare const InvalidFolioDocumentOperationBatchError_base: import("better-result").TaggedErrorClass<"InvalidFolioDocumentOperationBatchError", {
46
+ message: string;
47
+ path: string;
48
+ reason: string;
49
+ }>;
50
+ declare class InvalidFolioDocumentOperationBatchError extends InvalidFolioDocumentOperationBatchError_base {}
51
+ declare const assertSupportedFolioDocumentOperationVersion: (value: unknown) => typeof FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION;
52
+ type FolioDocumentOperationBatch = {
53
+ readonly version: typeof FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION;
54
+ operations: FolioDocumentOperation[];
55
+ mode?: FolioDocumentOperationMode;
56
+ atomic?: boolean;
57
+ dryRun?: boolean;
58
+ };
59
+ declare const parseFolioDocumentOperationBatch: (value: unknown) => FolioDocumentOperationBatch;
60
+ type FolioDocumentOperationStatus = "committed" | "previewed" | "rejected";
61
+ type FolioDocumentOperationRecovery = "refreshDocument" | "narrowMatch" | "changeMode" | "changeTarget" | "removeOperation" | "inspectBatch";
62
+ type FolioDocumentOperationIssue = {
63
+ operationId: string;
64
+ operationIndex: number;
65
+ path: `$.operations[${number}]`;
66
+ code: FolioAIEditSkippedOperation["reason"];
67
+ retryable: boolean;
68
+ recovery: FolioDocumentOperationRecovery;
69
+ };
70
+ /** One typed target affected by a successfully applied document operation. */
71
+ type FolioDocumentOperationAffectedTarget = {
72
+ type: "block";
73
+ story: "main";
74
+ blockId: string;
75
+ effect: "updated" | "deleted" | "commented";
76
+ } | {
77
+ type: "textRange";
78
+ range: FolioAITextRangeHandle;
79
+ effect: "formatted" | "commented";
80
+ } | {
81
+ type: "insertion";
82
+ story: "main";
83
+ anchorBlockId: string;
84
+ position: "before" | "after";
85
+ content: "block" | "signatureTable";
86
+ } | {
87
+ type: "comment";
88
+ commentId: number;
89
+ };
90
+ /** Input-ordered effect receipt for one successfully applied operation. */
91
+ type FolioDocumentOperationReceipt = {
92
+ operationId: string;
93
+ operationIndex: number;
94
+ affected: FolioDocumentOperationAffectedTarget[];
95
+ };
96
+ type FolioDocumentOperationResult = {
97
+ version: typeof FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION;
98
+ status: FolioDocumentOperationStatus;
99
+ applied: FolioAIEditAppliedOperation[];
100
+ skipped: FolioAIEditSkippedOperation[];
101
+ issues: FolioDocumentOperationIssue[]; /** Successful effects in input-operation order; skipped operations are omitted. */
102
+ receipts: FolioDocumentOperationReceipt[];
103
+ };
104
+ declare const getFolioDocumentOperationIssues: (operations: readonly FolioDocumentOperation[], skipped: readonly FolioAIEditSkippedOperation[]) => FolioDocumentOperationIssue[];
105
+ /** Build deterministic affected-target receipts from operations and their applied entries. */
106
+ declare const getFolioDocumentOperationReceipts: (operations: readonly FolioDocumentOperation[], applied: readonly FolioAIEditAppliedOperation[]) => FolioDocumentOperationReceipt[];
107
+ type ApplyFolioDocumentOperationsOptions = {
108
+ view: FolioAIEditView;
109
+ snapshot: FolioAIEditSnapshot;
110
+ batch: FolioDocumentOperationBatch;
111
+ author?: string;
112
+ createCommentId?: (text: string) => number;
113
+ };
114
+ declare const applyFolioDocumentOperations: ({
115
+ view,
116
+ snapshot,
117
+ batch,
118
+ author,
119
+ createCommentId
120
+ }: ApplyFolioDocumentOperationsOptions) => FolioDocumentOperationResult;
121
+ //#endregion
122
+ export { ApplyFolioDocumentOperationsOptions, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FolioDocumentOperation, FolioDocumentOperationAffectedTarget, FolioDocumentOperationBatch, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationStatus, FolioDocumentOperationType, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch };