@stll/folio-core 0.55.0 → 0.57.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 (225) hide show
  1. package/dist/ai-edits/apply.js +214 -52
  2. package/dist/ai-edits/batch-claims.d.ts +3 -1
  3. package/dist/ai-edits/batch-claims.js +25 -1
  4. package/dist/ai-edits/headless.js +2 -2
  5. package/dist/ai-edits/table-row-column-mutations.js +17 -3
  6. package/dist/ai-edits/types.d.ts +7 -1
  7. package/dist/ai-suggestions/apply.js +20 -1
  8. package/dist/compare/compare.js +1 -0
  9. package/dist/compare/inline-atoms.js +40 -16
  10. package/dist/compare/inline-provenance.js +12 -5
  11. package/dist/compare/reproducible-package.d.ts +0 -17
  12. package/dist/compare/reproducible-package.js +12 -18
  13. package/dist/compat/eigenpal.d.ts +2 -1
  14. package/dist/compat/eigenpal.js +2 -1
  15. package/dist/controller/canonicalClipboard.d.ts +23 -0
  16. package/dist/controller/canonicalClipboard.js +482 -0
  17. package/dist/controller/canonicalClipboardResources.d.ts +21 -0
  18. package/dist/controller/canonicalClipboardResources.js +382 -0
  19. package/dist/controller/canonicalComments.d.ts +41 -0
  20. package/dist/controller/canonicalComments.js +152 -0
  21. package/dist/controller/canonicalComposition.d.ts +24 -3
  22. package/dist/controller/canonicalComposition.js +208 -48
  23. package/dist/controller/canonicalInlineProjection.d.ts +118 -0
  24. package/dist/controller/canonicalInlineProjection.js +476 -0
  25. package/dist/controller/canonicalInput.d.ts +13 -4
  26. package/dist/controller/canonicalInput.js +62 -14
  27. package/dist/controller/canonicalInputTimer.d.ts +16 -0
  28. package/dist/controller/canonicalInputTimer.js +34 -0
  29. package/dist/controller/canonicalPublicOperations.d.ts +48 -0
  30. package/dist/controller/canonicalPublicOperations.js +648 -0
  31. package/dist/controller/canonicalSelection.d.ts +18 -0
  32. package/dist/controller/canonicalSelection.js +32 -0
  33. package/dist/controller/canonicalSession.d.ts +27 -6
  34. package/dist/controller/canonicalSession.js +298 -116
  35. package/dist/controller/canonicalStoryEditor.d.ts +7 -3
  36. package/dist/controller/canonicalStoryEditor.js +27 -2
  37. package/dist/controller/canonicalStructure.js +57 -4
  38. package/dist/controller/canonicalTocSelection.d.ts +11 -0
  39. package/dist/controller/canonicalTocSelection.js +43 -0
  40. package/dist/controller/folioEditor.d.ts +2 -9
  41. package/dist/controller/folioEditor.js +18 -4
  42. package/dist/controller/headerFooterEditorManager.d.ts +2 -1
  43. package/dist/controller/headerFooterEditorManager.js +26 -11
  44. package/dist/controller/hiddenEditorApi.d.ts +24 -3
  45. package/dist/controller/hiddenEditorApi.js +8 -0
  46. package/dist/controller/hiddenEditorManager.d.ts +5 -1
  47. package/dist/controller/hiddenEditorManager.js +378 -43
  48. package/dist/controller/noteEditorManager.d.ts +2 -1
  49. package/dist/controller/noteEditorManager.js +29 -13
  50. package/dist/document-operations.d.ts +8 -1
  51. package/dist/document-operations.js +6 -4
  52. package/dist/docx/blockPlainText.d.ts +1 -1
  53. package/dist/docx/blockPlainText.js +11 -3
  54. package/dist/docx/builtInStyles.js +13 -6
  55. package/dist/docx/canonicalResourceSave.d.ts +16 -0
  56. package/dist/docx/canonicalResourceSave.js +27 -0
  57. package/dist/docx/canonicalSave.d.ts +29 -0
  58. package/dist/docx/canonicalSave.js +101 -0
  59. package/dist/docx/canonicalStoryRepack.d.ts +1 -1
  60. package/dist/docx/canonicalStoryRepack.js +38 -5
  61. package/dist/docx/containerChildren.gen.d.ts +3 -1
  62. package/dist/docx/containerChildren.gen.js +33 -1
  63. package/dist/docx/documentParser.d.ts +1 -13
  64. package/dist/docx/documentParser.js +1 -47
  65. package/dist/docx/ensureParaIds.js +10 -4
  66. package/dist/docx/fieldParser.js +14 -2
  67. package/dist/docx/footnoteParser.d.ts +1 -11
  68. package/dist/docx/footnoteParser.js +1 -16
  69. package/dist/docx/headerFooterParser.d.ts +1 -9
  70. package/dist/docx/headerFooterParser.js +1 -12
  71. package/dist/docx/headerFooterVerbatim.d.ts +26 -1
  72. package/dist/docx/headerFooterVerbatim.js +81 -3
  73. package/dist/docx/hyperlinkParser.d.ts +1 -1
  74. package/dist/docx/hyperlinkParser.js +20 -1
  75. package/dist/docx/imageParser.d.ts +13 -1
  76. package/dist/docx/imageParser.js +20 -11
  77. package/dist/docx/inlineWrapperContent.d.ts +4 -4
  78. package/dist/docx/inlineWrapperContent.js +4 -4
  79. package/dist/docx/linkedSdtPreservation.d.ts +10 -0
  80. package/dist/docx/linkedSdtPreservation.js +37 -0
  81. package/dist/docx/metadataPrivacy.js +6 -1
  82. package/dist/docx/packageParts.js +9 -3
  83. package/dist/docx/paragraphParser.js +88 -67
  84. package/dist/docx/paragraphPropertySource.d.ts +22 -1
  85. package/dist/docx/paragraphPropertySource.js +109 -2
  86. package/dist/docx/parser.js +2 -1
  87. package/dist/docx/preservedRunContent.js +2 -1
  88. package/dist/docx/relsParser.js +26 -2
  89. package/dist/docx/removeHeaderFooterParts.js +17 -6
  90. package/dist/docx/rezip.d.ts +49 -5
  91. package/dist/docx/rezip.js +754 -235
  92. package/dist/docx/saveDiagnostics.d.ts +11 -0
  93. package/dist/docx/selectiveSave.d.ts +2 -1
  94. package/dist/docx/selectiveSave.js +42 -11
  95. package/dist/docx/selectiveXmlPatch.js +7 -5
  96. package/dist/docx/serializer/commentSerializer.d.ts +4 -1
  97. package/dist/docx/serializer/commentSerializer.js +7 -3
  98. package/dist/docx/serializer/documentSerializer.d.ts +9 -2
  99. package/dist/docx/serializer/documentSerializer.js +29 -10
  100. package/dist/docx/serializer/paragraphSerializer.js +207 -94
  101. package/dist/docx/server/applyDocxXmlPatchProposal.js +14 -9
  102. package/dist/docx/server/materializeYjsDocx.js +14 -6
  103. package/dist/docx/server/migrateYjsAttrSchema.js +17 -5
  104. package/dist/docx/storyBlockReplay.d.ts +21 -1
  105. package/dist/docx/storyBlockReplay.js +113 -9
  106. package/dist/docx/storyPlainText.d.ts +20 -0
  107. package/dist/docx/storyPlainText.js +23 -0
  108. package/dist/docx/structuralXmlPatch.js +10 -22
  109. package/dist/docx/styleParser.d.ts +5 -1
  110. package/dist/docx/styleParser.js +1 -1
  111. package/dist/docx/tableParser.d.ts +1 -8
  112. package/dist/docx/tableParser.js +1 -28
  113. package/dist/docx/textBoxParser.d.ts +1 -5
  114. package/dist/docx/textBoxParser.js +1 -20
  115. package/dist/docx/unzip.js +6 -1
  116. package/dist/i18n/messages/ar.gen.js +4 -0
  117. package/dist/i18n/messages/catalogs.gen.d.ts +68 -0
  118. package/dist/i18n/messages/catalogs.gen.js +68 -0
  119. package/dist/i18n/messages/cs.gen.js +4 -0
  120. package/dist/i18n/messages/de.gen.js +4 -0
  121. package/dist/i18n/messages/en.gen.js +4 -0
  122. package/dist/i18n/messages/es.gen.js +4 -0
  123. package/dist/i18n/messages/et.gen.js +4 -0
  124. package/dist/i18n/messages/fr.gen.js +4 -0
  125. package/dist/i18n/messages/he.gen.js +4 -0
  126. package/dist/i18n/messages/hi.gen.js +4 -0
  127. package/dist/i18n/messages/hu.gen.js +4 -0
  128. package/dist/i18n/messages/lt.gen.js +4 -0
  129. package/dist/i18n/messages/lv.gen.js +4 -0
  130. package/dist/i18n/messages/messages.gen.d.ts +4 -0
  131. package/dist/i18n/messages/pl.gen.js +4 -0
  132. package/dist/i18n/messages/pt-BR.gen.js +4 -0
  133. package/dist/i18n/messages/sk.gen.js +4 -0
  134. package/dist/i18n/messages/tr.gen.js +4 -0
  135. package/dist/i18n/messages/zh-CN.gen.js +4 -0
  136. package/dist/index.d.ts +2 -1
  137. package/dist/index.js +2 -1
  138. package/dist/internal/acceptedBlockProjection.d.ts +12 -0
  139. package/dist/internal/acceptedBlockProjection.js +45 -0
  140. package/dist/internal/revisionResolutionInline.js +25 -3
  141. package/dist/managers/DocumentLoaderManager.js +2 -1
  142. package/dist/markdown/escape.d.ts +3 -1
  143. package/dist/markdown/escape.js +9 -2
  144. package/dist/markdown/renderBlock.js +5 -120
  145. package/dist/markdown/renderParagraph.js +4 -2
  146. package/dist/markdown/renderRuns.d.ts +7 -1
  147. package/dist/markdown/renderRuns.js +33 -24
  148. package/dist/panel-layout.d.ts +11 -9
  149. package/dist/panel-layout.js +13 -9
  150. package/dist/prosemirror/addTrackedDeletionMark.d.ts +18 -0
  151. package/dist/prosemirror/addTrackedDeletionMark.js +87 -0
  152. package/dist/prosemirror/attrs/index.js +5 -0
  153. package/dist/prosemirror/canonicalCommands.d.ts +28 -4
  154. package/dist/prosemirror/canonicalCommands.js +11 -4
  155. package/dist/prosemirror/canonicalSelectionRange.d.ts +9 -0
  156. package/dist/prosemirror/canonicalSelectionRange.js +15 -0
  157. package/dist/prosemirror/clipboardIntent.d.ts +7 -0
  158. package/dist/prosemirror/clipboardIntent.js +9 -0
  159. package/dist/prosemirror/commands/comments.js +60 -35
  160. package/dist/prosemirror/commands/pageBreak.js +2 -2
  161. package/dist/prosemirror/commands/pastePlainText.js +2 -1
  162. package/dist/prosemirror/commands/propertyChangeScope.js +3 -6
  163. package/dist/prosemirror/commands/resolveParagraphProperties.js +22 -13
  164. package/dist/prosemirror/commentOps.js +15 -1
  165. package/dist/prosemirror/conversion/fromProseDoc.js +22 -3
  166. package/dist/prosemirror/conversion/hyphenTextCarriers.d.ts +8 -0
  167. package/dist/prosemirror/conversion/hyphenTextCarriers.js +8 -0
  168. package/dist/prosemirror/conversion/toProseDoc.d.ts +7 -1
  169. package/dist/prosemirror/conversion/toProseDoc.js +124 -22
  170. package/dist/prosemirror/extensions/core/ParagraphExtension.js +61 -35
  171. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +74 -25
  172. package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +11 -0
  173. package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +65 -29
  174. package/dist/prosemirror/extensions/marks/markUtils.js +11 -8
  175. package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +5 -2
  176. package/dist/prosemirror/fieldRepresentation.d.ts +8 -0
  177. package/dist/prosemirror/fieldRepresentation.js +18 -0
  178. package/dist/prosemirror/hyperlinkRemoval.d.ts +13 -1
  179. package/dist/prosemirror/hyperlinkRemoval.js +28 -9
  180. package/dist/prosemirror/insertOperations.js +2 -1
  181. package/dist/prosemirror/listNumbering.js +11 -5
  182. package/dist/prosemirror/noteReferenceOccurrenceId.d.ts +5 -0
  183. package/dist/prosemirror/noteReferenceOccurrenceId.js +5 -0
  184. package/dist/prosemirror/noteReferenceOccurrences.d.ts +21 -0
  185. package/dist/prosemirror/noteReferenceOccurrences.js +185 -0
  186. package/dist/prosemirror/noteReferenceReview.js +14 -1
  187. package/dist/prosemirror/paragraphPropertyCarry.d.ts +7 -1
  188. package/dist/prosemirror/paragraphPropertyCarry.js +8 -3
  189. package/dist/prosemirror/plugins/documentStyles.d.ts +4 -1
  190. package/dist/prosemirror/plugins/documentStyles.js +17 -10
  191. package/dist/prosemirror/plugins/suggestionMode.js +48 -48
  192. package/dist/prosemirror/preservedXmlReview.d.ts +6 -0
  193. package/dist/prosemirror/preservedXmlReview.js +35 -0
  194. package/dist/prosemirror/runFormattingFromMarks.js +2 -2
  195. package/dist/prosemirror/runFormattingReconciliation.js +5 -4
  196. package/dist/prosemirror/runPropertyChangeResolution.d.ts +8 -1
  197. package/dist/prosemirror/runPropertyChangeResolution.js +24 -2
  198. package/dist/prosemirror/runStyleFormatting.d.ts +3 -1
  199. package/dist/prosemirror/runStyleFormatting.js +3 -1
  200. package/dist/prosemirror/schema/marks.d.ts +1 -0
  201. package/dist/prosemirror/schema/nodes.d.ts +2 -0
  202. package/dist/prosemirror/styles/paragraphStyleCascade.js +4 -1
  203. package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +15 -15
  204. package/dist/prosemirror/styles/resolvedStyleAttrs.js +69 -28
  205. package/dist/prosemirror/textInput.d.ts +5 -1
  206. package/dist/prosemirror/textInput.js +3 -3
  207. package/dist/prosemirror/trackedRevisionPath.d.ts +5 -1
  208. package/dist/prosemirror/trackedRevisionPath.js +39 -1
  209. package/dist/prosemirror/validation.js +3 -5
  210. package/dist/prosemirror/yjsDocumentMetadata.d.ts +9 -3
  211. package/dist/prosemirror/yjsDocumentMetadata.js +37 -8
  212. package/dist/types/canonicalCapabilities.d.ts +201 -0
  213. package/dist/types/canonicalCapabilities.js +198 -0
  214. package/dist/types/canonicalComments.d.ts +51 -0
  215. package/dist/types/canonicalComments.js +0 -0
  216. package/dist/types/canonicalSave.d.ts +11 -0
  217. package/dist/types/canonicalSave.js +0 -0
  218. package/dist/types/canonicalSections.d.ts +12 -0
  219. package/dist/types/canonicalSections.js +0 -0
  220. package/dist/types/docxSerialization.d.ts +14 -0
  221. package/dist/types/docxSerialization.js +7 -0
  222. package/dist/utils/headingCollector.js +45 -4
  223. package/dist/utils/outlineDepth.d.ts +9 -0
  224. package/dist/utils/outlineDepth.js +9 -0
  225. package/package.json +4 -4
@@ -2,24 +2,34 @@ 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";
8
10
  import { ensureParaIdsInDoc, ensureParaIdsInState } from "../prosemirror/extensions/features/ParaIdAllocatorExtension.js";
9
11
  import { createParagraphChangeTrackerPlugin, markPackageChange } from "../prosemirror/extensions/features/ParagraphChangeTrackerExtension.js";
10
12
  import { toggleMarkForAllScripts, toggleUnderlineMark } from "../prosemirror/extensions/marks/markUtils.js";
13
+ import { HyperlinkRemovalRefusal } from "../prosemirror/hyperlinkRemoval.js";
14
+ import { markNoteReferenceReplay, noteReferenceTransactionIssue } from "../prosemirror/noteReferenceOccurrences.js";
11
15
  import { createDocumentNumberingPlugin } from "../prosemirror/plugins/documentNumbering.js";
12
- import { createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
16
+ import { createDocumentStyleContextPlugin, createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
13
17
  import { schema } from "../prosemirror/schema/index.js";
14
18
  import { createTextInputPlugin } from "../prosemirror/textInput.js";
15
19
  import { applyAttrSchemaMigrations, proseDocumentParagraphSourceContract, readYjsAttrSchemaVersion, readYjsParagraphSourceContract, withParagraphSourceContract, writeYjsDocumentMetadata } from "../prosemirror/yjsDocumentMetadata.js";
20
+ import { CANONICAL_GAP, usesCanonicalSession } from "../types/canonicalCapabilities.js";
21
+ import { prepareCanonicalPaste } from "./canonicalClipboard.js";
22
+ import { canonicalCommentBody, compileCanonicalComments } from "./canonicalComments.js";
16
23
  import { createCanonicalInputBoundary } from "./canonicalInput.js";
24
+ import { createCanonicalSectionPropertiesOperation } from "./canonicalOperations.js";
25
+ import { CanonicalPublicOperations } from "./canonicalPublicOperations.js";
26
+ import { restoreCanonicalSelection } from "./canonicalSelection.js";
17
27
  import { createCanonicalSession, publishCanonicalProjection } from "./canonicalSession.js";
18
28
  import { prepareCanonicalAutoformat, prepareCanonicalCommands } from "./canonicalStructure.js";
19
29
  import { createHiddenEditorApi } from "./hiddenEditorApi.js";
20
30
  import { Result, TaggedError, panic } from "better-result";
21
- import { OP_STORIES } from "@stll/docx-core/ops";
22
- import { EditorState } from "prosemirror-state";
31
+ import { OP_STORIES, freshCommentId } from "@stll/docx-core/ops";
32
+ import { EditorState, Plugin } from "prosemirror-state";
23
33
  import { EditorView } from "prosemirror-view";
24
34
  //#region src/controller/hiddenEditorManager.ts
25
35
  var CanonicalSessionRefusalError = class extends TaggedError("CanonicalSessionRefusalError") {};
@@ -201,6 +211,7 @@ const createHiddenEditorManager = (deps) => {
201
211
  let view = null;
202
212
  let releaseCommandOwner;
203
213
  let editorSession = { type: "prosemirror" };
214
+ let canonicalSessionEpoch = 0;
204
215
  let modeOverride = null;
205
216
  const syncCanonicalMode = () => {
206
217
  if (editorSession.type !== "canonical") return;
@@ -209,12 +220,16 @@ const createHiddenEditorManager = (deps) => {
209
220
  author: deps.getSuggestionAuthor?.() ?? "User"
210
221
  } : { type: "editing" }));
211
222
  };
212
- const refuse = (reason) => {
213
- if (deps.onSessionRefusal) deps.onSessionRefusal(reason);
214
- else throw new CanonicalSessionRefusalError({ message: reason });
223
+ const refuse = (reason, gap = CANONICAL_GAP.dispatch) => {
224
+ const message = reason;
225
+ if (deps.onSessionRefusal) deps.onSessionRefusal(message, gap);
226
+ else throw new CanonicalSessionRefusalError({
227
+ gap,
228
+ message
229
+ });
215
230
  };
216
231
  const seedSession = (document) => {
217
- if (deps.getExperimentalSession?.() !== "canonical") {
232
+ if (!usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) {
218
233
  editorSession = { type: "prosemirror" };
219
234
  return true;
220
235
  }
@@ -227,7 +242,7 @@ const createHiddenEditorManager = (deps) => {
227
242
  reason,
228
243
  documentIdentity
229
244
  };
230
- refuse(reason);
245
+ refuse(reason, CANONICAL_GAP.collaboration);
231
246
  return false;
232
247
  }
233
248
  const result = createCanonicalSession(document, deps.getStyles());
@@ -237,13 +252,14 @@ const createHiddenEditorManager = (deps) => {
237
252
  reason: result.error.message,
238
253
  documentIdentity
239
254
  };
240
- refuse(result.error.message);
255
+ refuse(result.error.message, result.error.gap);
241
256
  return false;
242
257
  }
243
258
  editorSession = {
244
259
  type: "canonical",
245
260
  session: result.value
246
261
  };
262
+ canonicalSessionEpoch += 1;
247
263
  modeOverride = null;
248
264
  syncCanonicalMode();
249
265
  return true;
@@ -252,11 +268,17 @@ const createHiddenEditorManager = (deps) => {
252
268
  doc: session.projection.doc,
253
269
  plugins: [
254
270
  createParagraphChangeTrackerPlugin(),
255
- createDocumentStylesPlugin(deps.getStyles() ?? session.document.package.styles),
256
- createDocumentNumberingPlugin(session.document.package.numbering)
271
+ createDocumentStyleContextPlugin(deps.getStyles() ?? session.document.package.styles),
272
+ createDocumentNumberingPlugin(session.document.package.numbering),
273
+ ...[...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: {
274
+ ...props.transformCopied === void 0 ? {} : { transformCopied: props.transformCopied },
275
+ ...props.clipboardTextSerializer === void 0 ? {} : { clipboardTextSerializer: props.clipboardTextSerializer },
276
+ ...props.transformPastedHTML === void 0 ? {} : { transformPastedHTML: props.transformPastedHTML },
277
+ ...props.transformPasted === void 0 ? {} : { transformPasted: props.transformPasted }
278
+ } })])
257
279
  ]
258
280
  });
259
- const publishCommit = (commit) => {
281
+ const publishCommit = (commit, reportRefusal = refuse) => {
260
282
  if (!view || deps.getReadOnly() || editorSession.type !== "canonical") return false;
261
283
  const session = editorSession.session;
262
284
  const result = publishCanonicalProjection({
@@ -265,7 +287,7 @@ const createHiddenEditorManager = (deps) => {
265
287
  session
266
288
  });
267
289
  if (result.isErr()) {
268
- refuse(result.error.message);
290
+ reportRefusal(result.error.message, result.error.gap);
269
291
  return false;
270
292
  }
271
293
  const staged = result.value;
@@ -284,7 +306,7 @@ const createHiddenEditorManager = (deps) => {
284
306
  if (direction === "undo" ? !session.canUndo : !session.canRedo) return false;
285
307
  const prepared = direction === "undo" ? session.prepareUndo(view.state) : session.prepareRedo(view.state);
286
308
  if (prepared.isErr()) {
287
- if (prepared.error.reason !== "noChange") refuse(prepared.error.message);
309
+ if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
288
310
  return false;
289
311
  }
290
312
  return publishCommit(prepared.value);
@@ -292,11 +314,26 @@ const createHiddenEditorManager = (deps) => {
292
314
  const executeCanonicalCommand = (command) => {
293
315
  if (!view || editorSession.type !== "canonical") return void 0;
294
316
  if (deps.getReadOnly()) return false;
317
+ if (command === pasteWithoutFormatting) return command(view.state, (transaction) => view?.dispatch(transaction), view);
295
318
  if (editorSession.session.isComposing) {
296
319
  refuse("Composition must finish before formatting.");
297
320
  return false;
298
321
  }
299
- const intents = getCanonicalCommandIntents(command, view.state);
322
+ const commandState = view.state;
323
+ const described = Result.try({
324
+ try: () => getCanonicalCommandIntents(command, commandState),
325
+ catch: (error) => error
326
+ });
327
+ if (described.isErr()) {
328
+ if (!(described.error instanceof HyperlinkRemovalRefusal)) throw described.error;
329
+ const refusal = new CanonicalSessionRefusalError({
330
+ gap: CANONICAL_GAP.commands,
331
+ message: described.error.message
332
+ });
333
+ refuse(refusal.message, refusal.gap);
334
+ return false;
335
+ }
336
+ const intents = described.value;
300
337
  if (intents === void 0) return void 0;
301
338
  syncCanonicalMode();
302
339
  editorSession.session.breakUndoGroup();
@@ -305,11 +342,12 @@ const createHiddenEditorManager = (deps) => {
305
342
  }, view);
306
343
  const prepared = prepareCanonicalCommands(editorSession.session, view.state, intents);
307
344
  if (prepared.isErr()) {
308
- if (prepared.error.reason !== "noChange") refuse(prepared.error.message);
345
+ if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
309
346
  return false;
310
347
  }
311
348
  return publishCommit(prepared.value);
312
349
  };
350
+ let clipboardDrag = { type: "idle" };
313
351
  let lastInputRule;
314
352
  const canonicalStructuralInput = {
315
353
  command: (name) => {
@@ -324,7 +362,7 @@ const createHiddenEditorManager = (deps) => {
324
362
  if (mark !== void 0) command = name === "toggleUnderline" ? toggleUnderlineMark(mark) : toggleMarkForAllScripts(mark, name === "toggleBold" ? "bold" : "italic");
325
363
  }
326
364
  if (command === void 0) {
327
- refuse("The formatting command is unavailable.");
365
+ refuse("The formatting command is unavailable.", CANONICAL_GAP.commands);
328
366
  return;
329
367
  }
330
368
  if (executeCanonicalCommand(command) === void 0) command(view.state, (transaction) => view?.dispatch(transaction), view);
@@ -336,7 +374,7 @@ const createHiddenEditorManager = (deps) => {
336
374
  const state = view.state;
337
375
  const selection = session.projection.selectionAt(state);
338
376
  if (selection.isErr()) {
339
- refuse(selection.error.message);
377
+ refuse(selection.error.message, selection.error.gap);
340
378
  return;
341
379
  }
342
380
  let prepared;
@@ -386,11 +424,11 @@ const createHiddenEditorManager = (deps) => {
386
424
  const from = session.projection.addressAt(state.selection.from);
387
425
  const to = session.projection.addressAt(state.selection.to);
388
426
  if (from.isErr()) {
389
- refuse(from.error.message);
427
+ refuse(from.error.message, from.error.gap);
390
428
  return;
391
429
  }
392
430
  if (to.isErr()) {
393
- refuse(to.error.message);
431
+ refuse(to.error.message, to.error.gap);
394
432
  return;
395
433
  }
396
434
  prepared = session.prepareIntent(state, {
@@ -407,7 +445,7 @@ const createHiddenEditorManager = (deps) => {
407
445
  default: return type;
408
446
  }
409
447
  if (prepared.isErr()) {
410
- if (prepared.error.reason !== "noChange") refuse(prepared.error.message);
448
+ if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
411
449
  return;
412
450
  }
413
451
  publishCommit(prepared.value);
@@ -421,7 +459,7 @@ const createHiddenEditorManager = (deps) => {
421
459
  if (deps.getReadOnly() || editorSession.type !== "canonical") return false;
422
460
  const begun = editorSession.session.beginComposition();
423
461
  if (begun.isErr()) {
424
- refuse(begun.error.message);
462
+ refuse(begun.error.message, begun.error.gap);
425
463
  return false;
426
464
  }
427
465
  return true;
@@ -431,6 +469,52 @@ const createHiddenEditorManager = (deps) => {
431
469
  }
432
470
  };
433
471
  const input = createCanonicalInputBoundary({
472
+ pastePlainText: (pmView) => {
473
+ if (deps.getReadOnly()) {
474
+ deps.onReadOnlyEditAttempt();
475
+ return;
476
+ }
477
+ pasteWithoutFormatting(pmView.state, (transaction) => pmView.dispatch(transaction), pmView);
478
+ },
479
+ cut: (pmView, event) => {
480
+ event.preventDefault();
481
+ if (deps.getReadOnly()) {
482
+ deps.onReadOnlyEditAttempt();
483
+ return true;
484
+ }
485
+ if (editorSession.type !== "canonical" || pmView.state.selection.empty) return true;
486
+ if (event.clipboardData === null) {
487
+ refuse("The clipboard cannot receive the cut content.");
488
+ return true;
489
+ }
490
+ syncCanonicalMode();
491
+ const session = editorSession.session;
492
+ const { from, to } = pmView.state.selection;
493
+ const prepared = session.prepareReplace(pmView.state, {
494
+ from,
495
+ to,
496
+ text: "",
497
+ semantic: "replacement"
498
+ });
499
+ if (prepared.isErr()) {
500
+ refuse(prepared.error.message, prepared.error.gap);
501
+ return true;
502
+ }
503
+ const copied = Result.try({
504
+ try: () => {
505
+ const serialized = pmView.serializeForClipboard(pmView.state.selection.content());
506
+ event.clipboardData?.setData("text/html", serialized.dom.innerHTML);
507
+ event.clipboardData?.setData("text/plain", serialized.text);
508
+ },
509
+ catch: () => new CanonicalSessionRefusalError({
510
+ gap: CANONICAL_GAP.dispatch,
511
+ message: "The clipboard could not receive the cut content."
512
+ })
513
+ });
514
+ if (copied.isErr()) refuse(copied.error.message, copied.error.gap);
515
+ else publishCommit(prepared.value);
516
+ return true;
517
+ },
434
518
  ...canonicalInputLifecycle,
435
519
  ...canonicalStructuralInput,
436
520
  replace: (intent) => {
@@ -439,7 +523,7 @@ const createHiddenEditorManager = (deps) => {
439
523
  const rule = prepareCanonicalAutoformat(editorSession.session, view.state, intent);
440
524
  const prepared = rule ?? editorSession.session.prepareReplace(view.state, intent);
441
525
  if (prepared.isErr()) {
442
- if (prepared.error.reason !== "noChange") refuse(prepared.error.message);
526
+ if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
443
527
  return;
444
528
  }
445
529
  const session = editorSession.session;
@@ -464,14 +548,14 @@ const createHiddenEditorManager = (deps) => {
464
548
  if (!host) return;
465
549
  const collaboration = deps.getCollaboration();
466
550
  const collaborationModules = deps.getCollaborationModules();
467
- if (collaboration && !collaborationModules && deps.getExperimentalSession?.() !== "canonical") return;
551
+ if (collaboration && !collaborationModules && !usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) return;
468
552
  const precomputedInitialState = deps.getPrecomputedInitialState();
469
553
  const document = deps.getDocument();
470
554
  const styles = deps.getStyles();
471
555
  const extensionManager = deps.getExtensionManager();
472
556
  const externalPlugins = deps.getExternalPlugins();
473
- if (!seedSession(document)) return;
474
557
  input.reset();
558
+ if (!seedSession(document)) return;
475
559
  const editorProps = {
476
560
  state: (() => {
477
561
  if (editorSession.type === "canonical") return canonicalState(editorSession.session);
@@ -505,7 +589,11 @@ const createHiddenEditorManager = (deps) => {
505
589
  lastInputRule = void 0;
506
590
  editorSession.session.breakUndoGroup();
507
591
  }
592
+ const modules = deps.getCollaborationModules();
593
+ if (modules && transaction.getMeta(modules.yProseMirror.ySyncPluginKey) !== void 0) markNoteReferenceReplay(transaction);
508
594
  const applied = view.state.applyTransaction(transaction);
595
+ const noteIssue = noteReferenceTransactionIssue(transaction);
596
+ if (noteIssue) deps.onSessionRefusal?.(noteIssue.message, CANONICAL_GAP.dispatch, noteIssue);
509
597
  if (editorSession.type === "canonical" && !applied.state.doc.eq(view.state.doc)) {
510
598
  refuse("A plugin attempted an unclassified canonical document mutation.");
511
599
  return;
@@ -533,16 +621,79 @@ const createHiddenEditorManager = (deps) => {
533
621
  return deps.onKeyDown(pmView, event);
534
622
  },
535
623
  handleTextInput: (pmView, from, to, text) => editorSession.type === "canonical" ? input.handleTextInput(pmView, from, to, text) : false,
624
+ handlePaste: (pmView, _event, slice) => {
625
+ if (editorSession.type !== "canonical") return false;
626
+ if (deps.getReadOnly()) {
627
+ deps.onReadOnlyEditAttempt();
628
+ return true;
629
+ }
630
+ syncCanonicalMode();
631
+ const prepared = prepareCanonicalPaste({
632
+ session: editorSession.session,
633
+ state: pmView.state,
634
+ slice
635
+ });
636
+ if (prepared.isErr()) {
637
+ if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
638
+ } else publishCommit(prepared.value);
639
+ return true;
640
+ },
641
+ handleDrop: (pmView, event, slice, moved) => {
642
+ if (editorSession.type !== "canonical") return false;
643
+ if (deps.getReadOnly()) {
644
+ deps.onReadOnlyEditAttempt();
645
+ return true;
646
+ }
647
+ const target = pmView.posAtCoords({
648
+ left: event.clientX,
649
+ top: event.clientY
650
+ })?.pos;
651
+ if (target === void 0) {
652
+ refuse("The drop has no document destination.");
653
+ return true;
654
+ }
655
+ const captured = clipboardDrag;
656
+ clipboardDrag = { type: "idle" };
657
+ if (moved && (captured.type !== "dragging" || captured.session !== editorSession.session || captured.version !== editorSession.session.version)) {
658
+ refuse("The dragged content changed or has no captured source.");
659
+ return true;
660
+ }
661
+ const source = captured.type === "dragging" ? {
662
+ from: captured.from,
663
+ to: captured.to
664
+ } : pmView.state.selection;
665
+ if (moved && target >= source.from && target <= source.to) return true;
666
+ syncCanonicalMode();
667
+ const prepared = prepareCanonicalPaste({
668
+ session: editorSession.session,
669
+ state: pmView.state,
670
+ slice,
671
+ ...moved ? {
672
+ moveTarget: target,
673
+ moveSource: {
674
+ from: source.from,
675
+ to: source.to
676
+ }
677
+ } : { pasteTarget: target }
678
+ });
679
+ if (prepared.isErr()) {
680
+ if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
681
+ } else publishCommit(prepared.value);
682
+ return true;
683
+ },
536
684
  handleScrollToSelection: suppressHiddenEditorScrollToSelection,
537
685
  handleDOMEvents: {
686
+ keydown: (pmView, event) => editorSession.type === "canonical" ? input.handleDOMEvents.keydown(pmView, event) : false,
538
687
  focus: () => false,
539
688
  blur: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.blur(pmView) : false,
540
689
  ...createHiddenEditorClipboardHandlers(deps),
541
- mousedown: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.mousedown(pmView) : false,
542
690
  compositionstart: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.compositionstart(pmView) : false,
543
691
  compositionend: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.compositionend(pmView) : false,
544
692
  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),
693
+ paste: (pmView, event) => {
694
+ if (editorSession.type === "canonical" && !deps.getReadOnly()) return input.handleDOMEvents.paste(pmView, event);
695
+ return createHiddenEditorClipboardHandlers(deps).paste(pmView, event);
696
+ },
546
697
  cut: (pmView, event) => editorSession.type === "canonical" ? input.handleDOMEvents.cut(pmView, event) : createHiddenEditorClipboardHandlers(deps).cut(pmView, event),
547
698
  beforeinput: (_view, event) => {
548
699
  if (editorSession.type === "canonical" && !deps.getReadOnly()) return input.handleDOMEvents.beforeinput(_view, event);
@@ -551,8 +702,22 @@ const createHiddenEditorManager = (deps) => {
551
702
  event.preventDefault();
552
703
  return true;
553
704
  },
705
+ dragstart: (pmView) => {
706
+ if (editorSession.type === "canonical") clipboardDrag = {
707
+ type: "dragging",
708
+ session: editorSession.session,
709
+ version: editorSession.session.version,
710
+ from: pmView.state.selection.from,
711
+ to: pmView.state.selection.to
712
+ };
713
+ return false;
714
+ },
715
+ dragend: () => {
716
+ clipboardDrag = { type: "idle" };
717
+ return false;
718
+ },
554
719
  drop: (_view, event) => {
555
- if (editorSession.type === "canonical") return input.handleDOMEvents.drop(_view, event);
720
+ if (editorSession.type === "canonical" && !deps.getReadOnly()) return input.handleDOMEvents.drop(_view, event);
556
721
  if (!deps.getReadOnly()) return false;
557
722
  deps.onReadOnlyEditAttempt();
558
723
  event.preventDefault();
@@ -562,6 +727,25 @@ const createHiddenEditorManager = (deps) => {
562
727
  };
563
728
  const viewStartedAt = performance.now();
564
729
  view = new EditorView(host, editorProps);
730
+ if (editorSession.type === "canonical") registerClipboardIntentHandler(view, (slice, plain) => {
731
+ if (!view || editorSession.type !== "canonical") return false;
732
+ if (deps.getReadOnly()) {
733
+ deps.onReadOnlyEditAttempt();
734
+ return false;
735
+ }
736
+ syncCanonicalMode();
737
+ const prepared = prepareCanonicalPaste({
738
+ session: editorSession.session,
739
+ state: view.state,
740
+ slice,
741
+ plain
742
+ });
743
+ if (prepared.isErr()) {
744
+ if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
745
+ return false;
746
+ }
747
+ return publishCommit(prepared.value);
748
+ });
565
749
  releaseCommandOwner = registerEditorCommandOwner(view, executeCanonicalCommand);
566
750
  recordHiddenEditorPhase("mount", "editor-view", performance.now() - viewStartedAt);
567
751
  syncHiddenEditorAccessibility(view, deps.getReadOnly());
@@ -592,21 +776,22 @@ const createHiddenEditorManager = (deps) => {
592
776
  };
593
777
  const syncExternalDocument = () => {
594
778
  if (!view || isDestroying) return;
779
+ const canonicalRequested = usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting);
595
780
  const collaboration = deps.getCollaboration();
596
781
  const collaborationModules = deps.getCollaborationModules();
597
- if (collaboration && !collaborationModules && deps.getExperimentalSession?.() !== "canonical") return;
782
+ if (collaboration && !collaborationModules && !canonicalRequested) return;
598
783
  const document = deps.getDocument();
599
784
  const currentDocId = deps.getDocumentIdentity();
600
785
  const currentCollaborationFragment = collaboration?.yXmlFragment ?? null;
601
786
  const collaborationSourceChanged = currentCollaborationFragment !== lastCollaborationFragment;
602
- const sessionChanged = editorSession.type !== "prosemirror" !== (deps.getExperimentalSession?.() === "canonical");
787
+ const sessionChanged = editorSession.type !== "prosemirror" !== canonicalRequested;
603
788
  if (collaboration && !collaborationSourceChanged && !sessionChanged) return;
604
789
  if (isInitialized && currentDocId === lastDocumentId && !collaborationSourceChanged && !sessionChanged) return;
790
+ input.reset();
605
791
  if (!seedSession(document)) {
606
792
  destroyView();
607
793
  return;
608
794
  }
609
- input.reset();
610
795
  isInitialized = true;
611
796
  lastDocumentId = currentDocId;
612
797
  lastCollaborationFragment = currentCollaborationFragment;
@@ -631,13 +816,20 @@ const createHiddenEditorManager = (deps) => {
631
816
  };
632
817
  const publishStoryCommit = (storyView, commit) => {
633
818
  if (!view || editorSession.type !== "canonical") return false;
634
- if (deps.getEditingMode?.() === "suggesting") {
635
- refuse("Suggesting is unavailable in the experimental canonical session.");
636
- return false;
637
- }
638
819
  const session = editorSession.session;
639
820
  const bodyTransaction = view.state.tr;
640
821
  if (!bodyTransaction.doc.eq(commit.bodyProjection.doc)) bodyTransaction.replaceWith(0, bodyTransaction.doc.content.size, commit.bodyProjection.doc.content);
822
+ if (commit.selection.anchor.story === OP_STORIES.MAIN && commit.selection.head.story === OP_STORIES.MAIN) {
823
+ if (!restoreCanonicalSelection({
824
+ transaction: bodyTransaction,
825
+ projection: commit.bodyProjection,
826
+ selection: commit.selection,
827
+ unavailable: { type: "refuse" }
828
+ })) {
829
+ refuse("The canonical body history selection is unavailable.");
830
+ return false;
831
+ }
832
+ }
641
833
  markPackageChange(bodyTransaction);
642
834
  bodyTransaction.setMeta("addToHistory", false);
643
835
  const bodyStaged = Result.try(() => view?.state.applyTransaction(bodyTransaction));
@@ -651,7 +843,7 @@ const createHiddenEditorManager = (deps) => {
651
843
  session
652
844
  });
653
845
  if (staged.isErr()) {
654
- refuse(staged.error.message);
846
+ refuse(staged.error.message, staged.error.gap);
655
847
  return false;
656
848
  }
657
849
  storyView.updateState(staged.value.state);
@@ -664,6 +856,23 @@ const createHiddenEditorManager = (deps) => {
664
856
  deps.onSelectionChange(view.state);
665
857
  return true;
666
858
  };
859
+ let publicOperations = null;
860
+ const getPublicOperations = () => {
861
+ if (editorSession.type !== "canonical") return null;
862
+ const session = editorSession.session;
863
+ if (publicOperations?.session === session) return publicOperations.executor;
864
+ const executor = new CanonicalPublicOperations({
865
+ session,
866
+ getState: (story) => story === OP_STORIES.MAIN && !deps.getReadOnly() && !isDestroying ? view?.state ?? null : null,
867
+ publish: publishCommit
868
+ });
869
+ publicOperations = {
870
+ session,
871
+ executor
872
+ };
873
+ return executor;
874
+ };
875
+ const isCanonicalModelSessionRequested = () => usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting);
667
876
  return {
668
877
  ensureView,
669
878
  retryViewCreation,
@@ -676,6 +885,10 @@ const createHiddenEditorManager = (deps) => {
676
885
  api: createHiddenEditorApi({
677
886
  getView: () => view,
678
887
  getDocumentContext: () => editorSession.type === "refused" ? null : deps.getDocumentContext(),
888
+ getCanonicalComments: () => editorSession.type === "canonical" ? editorSession.session.getCommittedComments() : null,
889
+ getCanonicalCommittedVersion: () => editorSession.type === "canonical" ? `${canonicalSessionEpoch}:${editorSession.session.version}` : null,
890
+ isCanonicalSaveCurrent: (version) => editorSession.type === "canonical" && !editorSession.session.isComposing && editorSession.session.version === version,
891
+ captureCanonicalSave: () => editorSession.type === "canonical" ? editorSession.session.captureSaveSnapshot() : null,
679
892
  getCanonicalDocument: () => editorSession.type === "canonical" ? editorSession.session.document : null,
680
893
  setCanonicalMode: (mode) => {
681
894
  if (editorSession.type !== "canonical") return false;
@@ -690,7 +903,7 @@ const createHiddenEditorManager = (deps) => {
690
903
  resolution
691
904
  });
692
905
  if (prepared.isErr()) {
693
- if (prepared.error.reason !== "noChange") refuse(prepared.error.message);
906
+ if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
694
907
  return false;
695
908
  }
696
909
  return publishCommit(prepared.value);
@@ -703,6 +916,125 @@ const createHiddenEditorManager = (deps) => {
703
916
  canRedo: () => editorSession.type === "canonical" && editorSession.session.canRedo
704
917
  } : null,
705
918
  canonicalOperations: {
919
+ applyCanonicalSectionProperties: (patch) => {
920
+ ensureView();
921
+ const fail = (message) => {
922
+ refuse(message, CANONICAL_GAP.sectionProperties);
923
+ return {
924
+ status: "refused",
925
+ gap: CANONICAL_GAP.sectionProperties,
926
+ message
927
+ };
928
+ };
929
+ if (editorSession.type === "refused") return fail(editorSession.reason);
930
+ if (editorSession.type !== "canonical") {
931
+ if (isCanonicalModelSessionRequested()) return fail("The canonical document is not ready for section changes.");
932
+ return null;
933
+ }
934
+ if (!view || deps.getReadOnly() || isDestroying) return fail("The document is not editable.");
935
+ const session = editorSession.session;
936
+ if (session.isComposing) return fail("Section properties cannot change during composition.");
937
+ const prepared = session.prepareOperations(view.state, [createCanonicalSectionPropertiesOperation(session.document, patch)]);
938
+ if (prepared.isErr()) return fail(prepared.error.message);
939
+ let failureMessage = "The section projection could not publish.";
940
+ if (!publishCommit(prepared.value, (message) => {
941
+ failureMessage = message;
942
+ })) return fail(failureMessage);
943
+ return {
944
+ status: "applied",
945
+ version: session.version
946
+ };
947
+ },
948
+ applyCanonicalComment: (request) => {
949
+ ensureView();
950
+ const fail = (message, retry = "never") => {
951
+ if (retry === "never") refuse(message, CANONICAL_GAP.comments);
952
+ return {
953
+ status: "refused",
954
+ gap: CANONICAL_GAP.comments,
955
+ message,
956
+ retry
957
+ };
958
+ };
959
+ if (editorSession.type === "refused") return fail(editorSession.reason);
960
+ if (editorSession.type !== "canonical") {
961
+ if (isCanonicalModelSessionRequested()) return fail("The canonical document is not ready for comment changes.");
962
+ return null;
963
+ }
964
+ if (!view || deps.getReadOnly()) return fail("The document is not editable.");
965
+ const session = editorSession.session;
966
+ if (session.isComposing) return fail("Comments cannot change during composition.", "afterComposition");
967
+ let command;
968
+ if (request.type === "create") {
969
+ const id = freshCommentId(session.document);
970
+ if (id.isErr()) return fail(id.error.message);
971
+ let anchor;
972
+ switch (request.anchor.kind) {
973
+ case "selection": {
974
+ const projection = session.projectStory(request.anchor.story);
975
+ if (projection.isErr()) return fail(projection.error.message);
976
+ const from = projection.value.addressAt(request.anchor.from);
977
+ const to = projection.value.addressAt(request.anchor.to);
978
+ if (from.isErr()) return fail(from.error.message);
979
+ if (to.isErr()) return fail(to.error.message);
980
+ anchor = request.anchor.from === request.anchor.to ? {
981
+ kind: "point",
982
+ at: from.value
983
+ } : {
984
+ kind: "range",
985
+ from: from.value,
986
+ to: to.value
987
+ };
988
+ break;
989
+ }
990
+ case "reply":
991
+ anchor = {
992
+ kind: "reply",
993
+ parentId: request.anchor.parentId
994
+ };
995
+ break;
996
+ case "revision":
997
+ anchor = {
998
+ kind: "revision",
999
+ story: request.anchor.story,
1000
+ revisionId: request.anchor.revisionId
1001
+ };
1002
+ break;
1003
+ default: return request.anchor;
1004
+ }
1005
+ command = {
1006
+ type: "create",
1007
+ anchor,
1008
+ comment: {
1009
+ id: id.value,
1010
+ author: request.author,
1011
+ done: false,
1012
+ date: request.date ?? (/* @__PURE__ */ new Date()).toISOString(),
1013
+ content: canonicalCommentBody(session.document, request.text)
1014
+ }
1015
+ };
1016
+ } else command = request;
1017
+ const compiled = compileCanonicalComments({
1018
+ document: session.document,
1019
+ command
1020
+ });
1021
+ if (compiled.isErr()) return fail(compiled.error.message);
1022
+ if (compiled.value.ops.length > 0) {
1023
+ const prepared = session.prepareOperations(view.state, compiled.value.ops);
1024
+ if (prepared.isErr()) return fail(prepared.error.message);
1025
+ if (!publishCommit(prepared.value)) return fail("The comment projection could not publish.");
1026
+ }
1027
+ return {
1028
+ status: "applied",
1029
+ comments: session.getCommittedComments(),
1030
+ ...compiled.value.commentId === void 0 ? {} : { commentId: compiled.value.commentId }
1031
+ };
1032
+ },
1033
+ applyCanonicalDocumentOperations: (options) => {
1034
+ ensureView();
1035
+ return getPublicOperations()?.apply(options) ?? null;
1036
+ },
1037
+ undoCanonicalDocumentOperations: (handle) => getPublicOperations()?.undo(handle) ?? null,
706
1038
  updateCanonicalInputLifecycle: (action) => {
707
1039
  if (editorSession.type !== "canonical") return false;
708
1040
  switch (action) {
@@ -732,11 +1064,12 @@ const createHiddenEditorManager = (deps) => {
732
1064
  applyCanonicalStoryHistory: ({ view: storyView, story, direction }) => {
733
1065
  if (story === OP_STORIES.MAIN && storyView === view) return history(direction);
734
1066
  if (!view || editorSession.type !== "canonical" || deps.getReadOnly()) return false;
1067
+ syncCanonicalMode();
735
1068
  const session = editorSession.session;
736
1069
  if (direction === "undo" ? !session.canUndo : !session.canRedo) return false;
737
1070
  const prepared = direction === "undo" ? session.prepareUndo(storyView.state, story) : session.prepareRedo(storyView.state, story);
738
1071
  if (prepared.isErr()) {
739
- refuse(prepared.error.message);
1072
+ refuse(prepared.error.message, prepared.error.gap);
740
1073
  return false;
741
1074
  }
742
1075
  return publishStoryCommit(storyView, prepared.value);
@@ -746,29 +1079,30 @@ const createHiddenEditorManager = (deps) => {
746
1079
  if (!view || editorSession.type !== "canonical" || deps.getReadOnly()) return false;
747
1080
  const prepared = editorSession.session.prepareOperations(view.state, ops);
748
1081
  if (prepared.isErr()) {
749
- refuse(prepared.error.message);
1082
+ refuse(prepared.error.message, prepared.error.gap);
750
1083
  return false;
751
1084
  }
752
1085
  return publishCommit(prepared.value);
753
1086
  },
754
1087
  getCanonicalStoryProjection: (story) => {
755
- if (deps.getExperimentalSession?.() === "canonical") ensureView();
1088
+ if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) ensureView();
756
1089
  if (editorSession.type !== "canonical" || editorSession.session.isComposing) return null;
757
1090
  const result = editorSession.session.projectStory(story);
758
1091
  if (result.isErr()) {
759
- refuse(result.error.message);
1092
+ refuse(result.error.message, result.error.gap);
760
1093
  return null;
761
1094
  }
762
1095
  return result.value.doc;
763
1096
  },
764
1097
  replaceCanonicalStoryText: ({ view: storyView, story, intent }) => {
765
1098
  if (!view || editorSession.type !== "canonical" || deps.getReadOnly()) return false;
1099
+ syncCanonicalMode();
766
1100
  const prepared = editorSession.session.prepareReplace(storyView.state, {
767
1101
  ...intent,
768
1102
  story
769
1103
  });
770
1104
  if (prepared.isErr()) {
771
- refuse(prepared.error.message);
1105
+ refuse(prepared.error.message, prepared.error.gap);
772
1106
  return false;
773
1107
  }
774
1108
  return publishStoryCommit(storyView, prepared.value);
@@ -777,7 +1111,8 @@ const createHiddenEditorManager = (deps) => {
777
1111
  isDestroying: () => isDestroying,
778
1112
  ensureView,
779
1113
  isViewRequested
780
- })
1114
+ }),
1115
+ isCanonicalComposing: () => editorSession.type === "canonical" && editorSession.session.isComposing
781
1116
  };
782
1117
  };
783
1118
  //#endregion