@ecsplico/editor 2.1.1 → 3.0.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 (701) hide show
  1. package/CHANGELOG.md +74 -1
  2. package/README.md +39 -156
  3. package/dist/adapters/comments/drizzle.d.ts +1 -1
  4. package/dist/adapters/comments/{client.js → rest-model.js} +3 -3
  5. package/dist/adapters/comments/rest-model.js.map +1 -0
  6. package/dist/adapters/comments/types.d.ts +2 -2
  7. package/dist/adapters/document-state.d.ts +23 -0
  8. package/dist/adapters/document-state.js +66 -0
  9. package/dist/adapters/document-state.js.map +1 -0
  10. package/dist/adapters/documents.js +14 -11
  11. package/dist/adapters/documents.js.map +1 -1
  12. package/dist/adapters/drizzle.d.ts +2 -2
  13. package/dist/adapters/drizzle.js +97 -88
  14. package/dist/adapters/drizzle.js.map +1 -1
  15. package/dist/adapters/forge.d.ts +12 -7
  16. package/dist/adapters/forge.js +38 -45
  17. package/dist/adapters/forge.js.map +1 -1
  18. package/dist/adapters/http.d.ts +20 -0
  19. package/dist/adapters/http.js +68 -0
  20. package/dist/adapters/http.js.map +1 -0
  21. package/dist/adapters/index.d.ts +5 -5
  22. package/dist/adapters/json.d.ts +3 -3
  23. package/dist/adapters/json.js +58 -49
  24. package/dist/adapters/json.js.map +1 -1
  25. package/dist/adapters/memory.d.ts +21 -0
  26. package/dist/adapters/memory.js +53 -0
  27. package/dist/adapters/memory.js.map +1 -0
  28. package/dist/adapters/nitro.d.ts +23 -20
  29. package/dist/adapters/nitro.js +58 -163
  30. package/dist/adapters/nitro.js.map +1 -1
  31. package/dist/adapters/react.d.ts +55 -0
  32. package/dist/adapters/react.js +209 -0
  33. package/dist/adapters/react.js.map +1 -0
  34. package/dist/adapters/shared.d.ts +15 -21
  35. package/dist/adapters/shared.js +10 -8
  36. package/dist/adapters/shared.js.map +1 -1
  37. package/dist/adapters/vue.d.ts +15 -30
  38. package/dist/adapters/vue.js +36 -87
  39. package/dist/adapters/vue.js.map +1 -1
  40. package/dist/code/CodeSurface.vue.d.ts +3 -3
  41. package/dist/config/index.d.ts +105 -0
  42. package/dist/config/index.js +95 -0
  43. package/dist/config/index.js.map +1 -0
  44. package/dist/core/abilities.js +1 -0
  45. package/dist/core/abilities.js.map +1 -1
  46. package/dist/{adapters/routes.js → core/api-routes.js} +5 -3
  47. package/dist/core/api-routes.js.map +1 -0
  48. package/dist/core/backend-capability.d.ts +7 -0
  49. package/dist/core/backend-capability.js +17 -0
  50. package/dist/core/backend-capability.js.map +1 -0
  51. package/dist/core/backend-types.d.ts +245 -0
  52. package/dist/core/backend-types.js +17 -0
  53. package/dist/core/backend-types.js.map +1 -0
  54. package/dist/core/backend.d.ts +108 -0
  55. package/dist/core/backend.js +14 -0
  56. package/dist/core/backend.js.map +1 -0
  57. package/dist/core/block-convert.d.ts +7 -5
  58. package/dist/core/block-convert.js +28 -5
  59. package/dist/core/block-convert.js.map +1 -1
  60. package/dist/core/command-types.d.ts +89 -0
  61. package/dist/core/commands.d.ts +40 -0
  62. package/dist/core/commands.js +151 -0
  63. package/dist/core/commands.js.map +1 -0
  64. package/dist/core/context.d.ts +17 -20
  65. package/dist/core/context.js +24 -21
  66. package/dist/core/context.js.map +1 -1
  67. package/dist/core/core-feature.d.ts +22 -7
  68. package/dist/core/core-feature.js +51 -18
  69. package/dist/core/core-feature.js.map +1 -1
  70. package/dist/core/define-editor.d.ts +4 -3
  71. package/dist/core/define-editor.js +14 -7
  72. package/dist/core/define-editor.js.map +1 -1
  73. package/dist/core/document-markdown.js +12 -3
  74. package/dist/core/document-markdown.js.map +1 -1
  75. package/dist/core/editor-ui.d.ts +8 -1
  76. package/dist/core/editor-ui.js +9 -8
  77. package/dist/core/editor-ui.js.map +1 -1
  78. package/dist/core/extension-points.d.ts +3 -15
  79. package/dist/core/feature-context.d.ts +8 -7
  80. package/dist/core/feature-context.js +12 -11
  81. package/dist/core/feature-context.js.map +1 -1
  82. package/dist/core/feature.d.ts +35 -19
  83. package/dist/core/feature.js.map +1 -1
  84. package/dist/core/fences.d.ts +2 -1
  85. package/dist/core/fences.js +3 -2
  86. package/dist/core/fences.js.map +1 -1
  87. package/dist/core/fetch-error.d.ts +1 -1
  88. package/dist/core/fetch-error.js +3 -1
  89. package/dist/core/fetch-error.js.map +1 -1
  90. package/dist/core/hash.d.ts +5 -0
  91. package/dist/core/hash.js +11 -0
  92. package/dist/core/hash.js.map +1 -0
  93. package/dist/core/http-backend.d.ts +11 -0
  94. package/dist/core/http-backend.js +195 -0
  95. package/dist/core/http-backend.js.map +1 -0
  96. package/dist/core/index.d.ts +14 -9
  97. package/dist/core/index.js +12 -9
  98. package/dist/core/palette.d.ts +48 -0
  99. package/dist/core/palette.js +95 -0
  100. package/dist/core/palette.js.map +1 -0
  101. package/dist/core/schema/abilities.d.ts +2 -1
  102. package/dist/core/schema/abilities.js +5 -1
  103. package/dist/core/schema/abilities.js.map +1 -1
  104. package/dist/core/schema/index.d.ts +11 -5
  105. package/dist/core/schema/index.js +13 -8
  106. package/dist/core/schema/index.js.map +1 -1
  107. package/dist/core/schema/mark-flags.d.ts +8 -1
  108. package/dist/core/schema/of-features.d.ts +13 -0
  109. package/dist/core/schema/of-features.js +14 -0
  110. package/dist/core/schema/of-features.js.map +1 -0
  111. package/dist/core/slash.d.ts +8 -6
  112. package/dist/core/slash.js +24 -16
  113. package/dist/core/slash.js.map +1 -1
  114. package/dist/core/surface-session.js +13 -5
  115. package/dist/core/surface-session.js.map +1 -1
  116. package/dist/core/toolbar-items.d.ts +10 -4
  117. package/dist/core/toolbar-items.js +269 -195
  118. package/dist/core/toolbar-items.js.map +1 -1
  119. package/dist/core/util.js +11 -0
  120. package/dist/core/util.js.map +1 -0
  121. package/dist/document/DocumentSurface.d.ts +1 -1
  122. package/dist/document/DocumentSurface.vue.d.ts +3 -3
  123. package/dist/features/ai/agent-op-review.d.ts +1 -1
  124. package/dist/features/ai/agent-op-review.js +1 -1
  125. package/dist/features/ai/agent-ops.js +1 -1
  126. package/dist/features/ai/ai-apply.d.ts +2 -2
  127. package/dist/features/ai/ai-apply.js +1 -1
  128. package/dist/features/ai/ai-review.js +1 -1
  129. package/dist/features/ai/ai-sse.d.ts +6 -6
  130. package/dist/features/ai/ai-sse.js +20 -63
  131. package/dist/features/ai/ai-sse.js.map +1 -1
  132. package/dist/features/ai/assistant.d.ts +8 -7
  133. package/dist/features/ai/assistant.js +3 -3
  134. package/dist/features/ai/assistant.js.map +1 -1
  135. package/dist/features/ai/block-actions.d.ts +3 -2
  136. package/dist/features/ai/block-actions.js +3 -2
  137. package/dist/features/ai/block-actions.js.map +1 -1
  138. package/dist/features/ai/components/AiSelectionMenu.js +1 -1
  139. package/dist/features/ai/components/DocumentChatAnswer.js +1 -1
  140. package/dist/features/ai/components/DocumentChatOps.vue.d.ts +1 -1
  141. package/dist/features/ai/components/SettingsModelProfiles.js +8 -8
  142. package/dist/features/ai/components/SettingsModelProfiles.js.map +1 -1
  143. package/dist/features/ai/document-chat-model.d.ts +8 -7
  144. package/dist/features/ai/document-chat-model.js +5 -5
  145. package/dist/features/ai/document-chat-model.js.map +1 -1
  146. package/dist/features/ai/document-chat.js +1 -1
  147. package/dist/features/ai/feature.js +27 -14
  148. package/dist/features/ai/feature.js.map +1 -1
  149. package/dist/features/ai/ghost-autocomplete.d.ts +7 -6
  150. package/dist/features/ai/ghost-autocomplete.js +6 -9
  151. package/dist/features/ai/ghost-autocomplete.js.map +1 -1
  152. package/dist/features/ai/index.d.ts +4 -3
  153. package/dist/features/ai/index.js +10 -10
  154. package/dist/features/ai/model-profiles.d.ts +5 -4
  155. package/dist/features/ai/model-profiles.js +2 -2
  156. package/dist/features/ai/model-profiles.js.map +1 -1
  157. package/dist/features/ai/protocol/block-lines.js +1 -1
  158. package/dist/features/ai/protocol/block-lines.js.map +1 -1
  159. package/dist/features/ai/protocol/chat.js +4 -1
  160. package/dist/features/ai/protocol/chat.js.map +1 -1
  161. package/dist/features/ai/protocol/index.d.ts +3 -2
  162. package/dist/features/ai/protocol/models.d.ts +2 -16
  163. package/dist/features/ai/protocol/models.js.map +1 -1
  164. package/dist/features/ai/rate-limit.d.ts +1 -1
  165. package/dist/features/ai/rate-limit.js +3 -1
  166. package/dist/features/ai/rate-limit.js.map +1 -1
  167. package/dist/features/ai/react/AiSelectionMenu.js +2 -2
  168. package/dist/features/ai/react/AiSidebar.js +4 -4
  169. package/dist/features/ai/react/DocumentChatAnswer.js +1 -1
  170. package/dist/features/ai/react/DocumentChatOps.d.ts +1 -1
  171. package/dist/features/ai/react/DocumentChatOps.js +1 -1
  172. package/dist/features/ai/react/SettingsModelProfiles.js +8 -10
  173. package/dist/features/ai/react/SettingsModelProfiles.js.map +1 -1
  174. package/dist/features/ai/react/use-ai-assistant.d.ts +1 -1
  175. package/dist/features/ai/react/use-ai-assistant.js +3 -3
  176. package/dist/features/ai/react/use-ai-assistant.js.map +1 -1
  177. package/dist/features/ai/react/use-document-chat.js +2 -2
  178. package/dist/features/ai/react/use-document-chat.js.map +1 -1
  179. package/dist/features/ai/react/use-model-profiles.d.ts +2 -1
  180. package/dist/features/ai/selection-flow.d.ts +1 -1
  181. package/dist/features/ai/selection-flow.js +1 -1
  182. package/dist/features/ai/sidebar-flow.d.ts +1 -1
  183. package/dist/features/ai/sidebar-flow.js +1 -1
  184. package/dist/features/ai/use-ai-assistant.d.ts +1 -1
  185. package/dist/features/ai/use-ai-assistant.js +3 -3
  186. package/dist/features/ai/use-ai-assistant.js.map +1 -1
  187. package/dist/features/ai/use-document-chat.js +2 -2
  188. package/dist/features/ai/use-document-chat.js.map +1 -1
  189. package/dist/features/ai/use-model-profiles.d.ts +2 -1
  190. package/dist/features/authors/attribution.d.ts +1 -1
  191. package/dist/features/authors/feature.js +12 -11
  192. package/dist/features/authors/feature.js.map +1 -1
  193. package/dist/features/block-ui/block-actions.d.ts +22 -1
  194. package/dist/features/block-ui/block-actions.js +26 -2
  195. package/dist/features/block-ui/block-actions.js.map +1 -1
  196. package/dist/features/block-ui/components/BlockActionsOverlay.js +33 -4
  197. package/dist/features/block-ui/components/BlockActionsOverlay.js.map +1 -1
  198. package/dist/features/block-ui/components/BlockActionsOverlay.vue.d.ts +4 -0
  199. package/dist/features/block-ui/components/BlockUi.js +1 -1
  200. package/dist/features/block-ui/feature.js +1 -0
  201. package/dist/features/block-ui/feature.js.map +1 -1
  202. package/dist/features/block-ui/index.d.ts +2 -2
  203. package/dist/features/block-ui/index.js +2 -2
  204. package/dist/features/block-ui/react/BlockActionsOverlay.d.ts +4 -0
  205. package/dist/features/block-ui/react/BlockActionsOverlay.js +38 -12
  206. package/dist/features/block-ui/react/BlockActionsOverlay.js.map +1 -1
  207. package/dist/features/block-ui/react/BlockUi.js +1 -1
  208. package/dist/features/collab/anchor-resolver.js +1 -1
  209. package/dist/features/collab/feature.js +2 -0
  210. package/dist/features/collab/feature.js.map +1 -1
  211. package/dist/features/comments/components/CommentThreadView.vue.d.ts +2 -1
  212. package/dist/features/comments/feature.js +12 -11
  213. package/dist/features/comments/feature.js.map +1 -1
  214. package/dist/features/comments/index.d.ts +3 -2
  215. package/dist/features/comments/index.js +1 -1
  216. package/dist/features/comments/margin-layout.d.ts +3 -2
  217. package/dist/features/comments/model.d.ts +3 -67
  218. package/dist/features/comments/model.js +2 -2
  219. package/dist/features/comments/model.js.map +1 -1
  220. package/dist/features/comments/react/CommentThreadView.d.ts +3 -2
  221. package/dist/features/comments/react/use-comments.d.ts +2 -1
  222. package/dist/features/comments/react.d.ts +1 -1
  223. package/dist/features/comments/schema.d.ts +2 -52
  224. package/dist/features/comments/schema.js.map +1 -1
  225. package/dist/features/comments/snapshot-equality.js.map +1 -1
  226. package/dist/features/comments/use-comments.d.ts +3 -2
  227. package/dist/features/comments/vue.d.ts +1 -1
  228. package/dist/features/composites/accepted-children.d.ts +1 -0
  229. package/dist/features/composites/accepted-children.js +16 -1
  230. package/dist/features/composites/accepted-children.js.map +1 -1
  231. package/dist/features/composites/ai-brief.js +31 -0
  232. package/dist/features/composites/ai-brief.js.map +1 -1
  233. package/dist/features/composites/bibliography-command.d.ts +11 -0
  234. package/dist/features/composites/bibliography-form.js +90 -0
  235. package/dist/features/composites/bibliography-form.js.map +1 -0
  236. package/dist/features/composites/bibliography.d.ts +33 -0
  237. package/dist/features/composites/bibliography.js +120 -0
  238. package/dist/features/composites/bibliography.js.map +1 -0
  239. package/dist/features/composites/components/BibliographyEditor.js +261 -0
  240. package/dist/features/composites/components/BibliographyEditor.js.map +1 -0
  241. package/dist/features/composites/components/CompositeChrome.js +75 -26
  242. package/dist/features/composites/components/CompositeChrome.js.map +1 -1
  243. package/dist/features/composites/components/CompositeDetails.js +46 -11
  244. package/dist/features/composites/components/CompositeDetails.js.map +1 -1
  245. package/dist/features/composites/components/CompositeDetails.vue.d.ts +2 -1
  246. package/dist/features/composites/components/CompositeFieldEditor.js +37 -4
  247. package/dist/features/composites/components/CompositeFieldEditor.js.map +1 -1
  248. package/dist/features/composites/components/CompositeInspector.js +17 -5
  249. package/dist/features/composites/components/CompositeInspector.js.map +1 -1
  250. package/dist/features/composites/components/CompositeTable.js +13 -4
  251. package/dist/features/composites/components/CompositeTable.js.map +1 -1
  252. package/dist/features/composites/components/CompositeTagsEditor.js +1 -1
  253. package/dist/features/composites/components/CompositeView.js +11 -1
  254. package/dist/features/composites/components/CompositeView.js.map +1 -1
  255. package/dist/features/composites/components/DerivationBadge.js +103 -0
  256. package/dist/features/composites/components/DerivationBadge.js.map +1 -0
  257. package/dist/features/composites/components/ReferenceFieldSelect.js +60 -0
  258. package/dist/features/composites/components/ReferenceFieldSelect.js.map +1 -0
  259. package/dist/features/composites/components/ReferenceView.js +122 -0
  260. package/dist/features/composites/components/ReferenceView.js.map +1 -0
  261. package/dist/features/composites/components/ReferenceView.vue.d.ts +96 -0
  262. package/dist/features/composites/components/SettingsEditingTab.js +1 -1
  263. package/dist/features/composites/convert.js +2 -2
  264. package/dist/features/composites/convert.js.map +1 -1
  265. package/dist/features/composites/derivation.d.ts +61 -0
  266. package/dist/features/composites/derivation.js +98 -0
  267. package/dist/features/composites/derivation.js.map +1 -0
  268. package/dist/features/composites/derived-chrome.js +69 -0
  269. package/dist/features/composites/derived-chrome.js.map +1 -0
  270. package/dist/features/composites/feature.js +159 -109
  271. package/dist/features/composites/feature.js.map +1 -1
  272. package/dist/features/composites/fences.d.ts +4 -3
  273. package/dist/features/composites/fences.js +51 -7
  274. package/dist/features/composites/fences.js.map +1 -1
  275. package/dist/features/composites/index.d.ts +12 -3
  276. package/dist/features/composites/index.js +15 -6
  277. package/dist/features/composites/inspector-model.d.ts +4 -1
  278. package/dist/features/composites/inspector-model.js +8 -4
  279. package/dist/features/composites/inspector-model.js.map +1 -1
  280. package/dist/features/composites/kinds.d.ts +8 -1
  281. package/dist/features/composites/kinds.js +145 -6
  282. package/dist/features/composites/kinds.js.map +1 -1
  283. package/dist/features/composites/legacy.d.ts +4 -1
  284. package/dist/features/composites/legacy.js +56 -1
  285. package/dist/features/composites/legacy.js.map +1 -1
  286. package/dist/features/composites/meta-display.js +40 -1
  287. package/dist/features/composites/meta-display.js.map +1 -1
  288. package/dist/features/composites/meta-keys.d.ts +7 -0
  289. package/dist/features/composites/meta-keys.js +21 -0
  290. package/dist/features/composites/meta-keys.js.map +1 -0
  291. package/dist/features/composites/node-views.d.ts +6 -3
  292. package/dist/features/composites/node-views.js +7 -3
  293. package/dist/features/composites/node-views.js.map +1 -1
  294. package/dist/features/composites/nodes.d.ts +6 -1
  295. package/dist/features/composites/nodes.js +33 -7
  296. package/dist/features/composites/nodes.js.map +1 -1
  297. package/dist/features/composites/react/BibliographyEditor.js +229 -0
  298. package/dist/features/composites/react/BibliographyEditor.js.map +1 -0
  299. package/dist/features/composites/react/CompositeChrome.js +65 -17
  300. package/dist/features/composites/react/CompositeChrome.js.map +1 -1
  301. package/dist/features/composites/react/CompositeDetails.d.ts +2 -1
  302. package/dist/features/composites/react/CompositeDetails.js +45 -6
  303. package/dist/features/composites/react/CompositeDetails.js.map +1 -1
  304. package/dist/features/composites/react/CompositeFieldEditor.d.ts +1 -1
  305. package/dist/features/composites/react/CompositeFieldEditor.js +24 -1
  306. package/dist/features/composites/react/CompositeFieldEditor.js.map +1 -1
  307. package/dist/features/composites/react/CompositeInspector.js +11 -5
  308. package/dist/features/composites/react/CompositeInspector.js.map +1 -1
  309. package/dist/features/composites/react/CompositeStatusMenu.js +1 -1
  310. package/dist/features/composites/react/CompositeSummaryEditor.js +1 -1
  311. package/dist/features/composites/react/CompositeTable.js +16 -2
  312. package/dist/features/composites/react/CompositeTable.js.map +1 -1
  313. package/dist/features/composites/react/CompositeTagsEditor.js +2 -2
  314. package/dist/features/composites/react/CompositeView.js +6 -1
  315. package/dist/features/composites/react/CompositeView.js.map +1 -1
  316. package/dist/features/composites/react/DerivationBadge.js +116 -0
  317. package/dist/features/composites/react/DerivationBadge.js.map +1 -0
  318. package/dist/features/composites/react/ReferenceFieldSelect.js +52 -0
  319. package/dist/features/composites/react/ReferenceFieldSelect.js.map +1 -0
  320. package/dist/features/composites/react/ReferenceView.d.ts +11 -0
  321. package/dist/features/composites/react/ReferenceView.js +115 -0
  322. package/dist/features/composites/react/ReferenceView.js.map +1 -0
  323. package/dist/features/composites/react/SettingsEditingTab.js +2 -2
  324. package/dist/features/composites/react.d.ts +2 -1
  325. package/dist/features/composites/react.js +7 -3
  326. package/dist/features/composites/react.js.map +1 -1
  327. package/dist/features/composites/reference-ai.js +16 -0
  328. package/dist/features/composites/reference-ai.js.map +1 -0
  329. package/dist/features/composites/reference-label.d.ts +19 -0
  330. package/dist/features/composites/reference-label.js +58 -0
  331. package/dist/features/composites/reference-label.js.map +1 -0
  332. package/dist/features/composites/reference-suggestion.d.ts +10 -0
  333. package/dist/features/composites/reference-suggestion.js +41 -0
  334. package/dist/features/composites/reference-suggestion.js.map +1 -0
  335. package/dist/features/composites/reference-text.d.ts +18 -0
  336. package/dist/features/composites/reference-text.js +89 -0
  337. package/dist/features/composites/reference-text.js.map +1 -0
  338. package/dist/features/composites/reference.d.ts +44 -0
  339. package/dist/features/composites/reference.js +148 -0
  340. package/dist/features/composites/reference.js.map +1 -0
  341. package/dist/features/composites/reveal-source.d.ts +32 -0
  342. package/dist/features/composites/reveal-source.js +89 -0
  343. package/dist/features/composites/reveal-source.js.map +1 -0
  344. package/dist/features/composites/rows.d.ts +21 -2
  345. package/dist/features/composites/rows.js +63 -9
  346. package/dist/features/composites/rows.js.map +1 -1
  347. package/dist/features/composites/schema.d.ts +9 -3
  348. package/dist/features/composites/schema.js +11 -4
  349. package/dist/features/composites/schema.js.map +1 -1
  350. package/dist/features/composites/table-model.js +12 -21
  351. package/dist/features/composites/table-model.js.map +1 -1
  352. package/dist/features/composites/vue.d.ts +3 -2
  353. package/dist/features/composites/vue.js +8 -4
  354. package/dist/features/composites/vue.js.map +1 -1
  355. package/dist/features/media/assets.d.ts +2 -0
  356. package/dist/features/media/assets.js +3 -2
  357. package/dist/features/media/assets.js.map +1 -1
  358. package/dist/features/media/components/FileView.js +13 -4
  359. package/dist/features/media/components/FileView.js.map +1 -1
  360. package/dist/features/media/feature.d.ts +3 -3
  361. package/dist/features/media/feature.js +21 -28
  362. package/dist/features/media/feature.js.map +1 -1
  363. package/dist/features/media/file-import.js +2 -2
  364. package/dist/features/media/file-import.js.map +1 -1
  365. package/dist/features/media/index.d.ts +2 -2
  366. package/dist/features/media/index.js +2 -2
  367. package/dist/features/media/react/FileView.js +19 -2
  368. package/dist/features/media/react/FileView.js.map +1 -1
  369. package/dist/features/media/schema.d.ts +8 -0
  370. package/dist/features/media/schema.js +126 -11
  371. package/dist/features/media/schema.js.map +1 -1
  372. package/dist/features/media/upload.d.ts +16 -14
  373. package/dist/features/media/upload.js +13 -19
  374. package/dist/features/media/upload.js.map +1 -1
  375. package/dist/features/mentions/index.d.ts +4 -3
  376. package/dist/features/mentions/index.js +4 -1
  377. package/dist/features/mentions/index.js.map +1 -1
  378. package/dist/features/mentions/mention-text.d.ts +1 -1
  379. package/dist/features/mentions/mention-text.js.map +1 -1
  380. package/dist/features/mentions/mention.d.ts +0 -6
  381. package/dist/features/mentions/mention.js.map +1 -1
  382. package/dist/features/mentions/metadata-defaults.d.ts +2 -2
  383. package/dist/features/mentions/metadata-defaults.js +3 -9
  384. package/dist/features/mentions/metadata-defaults.js.map +1 -1
  385. package/dist/features/mentions/schema.d.ts +2 -1
  386. package/dist/features/mentions/schema.js.map +1 -1
  387. package/dist/features/tables/feature.d.ts +2 -1
  388. package/dist/features/tables/feature.js +90 -70
  389. package/dist/features/tables/feature.js.map +1 -1
  390. package/dist/features/themes/components/SettingsAppearanceTab.js +6 -9
  391. package/dist/features/themes/components/SettingsAppearanceTab.js.map +1 -1
  392. package/dist/features/themes/feature.js +2 -0
  393. package/dist/features/themes/feature.js.map +1 -1
  394. package/dist/features/themes/index.d.ts +2 -1
  395. package/dist/features/themes/react/SettingsAppearanceTab.js +7 -10
  396. package/dist/features/themes/react/SettingsAppearanceTab.js.map +1 -1
  397. package/dist/features/themes/schema.d.ts +2 -6
  398. package/dist/features/themes/schema.js.map +1 -1
  399. package/dist/features/themes/theme-runtime.d.ts +1 -1
  400. package/dist/features/themes/theme-runtime.js +4 -2
  401. package/dist/features/themes/theme-runtime.js.map +1 -1
  402. package/dist/features/transcript/TranscriptSegmentView.js +48 -28
  403. package/dist/features/transcript/TranscriptSegmentView.js.map +1 -1
  404. package/dist/features/transcript/feature.js +21 -19
  405. package/dist/features/transcript/feature.js.map +1 -1
  406. package/dist/features/transcript/react/TranscriptSegmentView.js +55 -36
  407. package/dist/features/transcript/react/TranscriptSegmentView.js.map +1 -1
  408. package/dist/features/transcript/segment-node.d.ts +2 -0
  409. package/dist/features/transcript/segment-node.js +35 -7
  410. package/dist/features/transcript/segment-node.js.map +1 -1
  411. package/dist/i18n/de/composites.js +91 -1
  412. package/dist/i18n/de/composites.js.map +1 -1
  413. package/dist/i18n/de/integrations.js +49 -8
  414. package/dist/i18n/de/integrations.js.map +1 -1
  415. package/dist/i18n/de/media.js +0 -1
  416. package/dist/i18n/de/media.js.map +1 -1
  417. package/dist/i18n/de/palette.js +22 -0
  418. package/dist/i18n/de/palette.js.map +1 -0
  419. package/dist/i18n/de/tables.js +0 -1
  420. package/dist/i18n/de/tables.js.map +1 -1
  421. package/dist/i18n/de/transcript.js +2 -1
  422. package/dist/i18n/de/transcript.js.map +1 -1
  423. package/dist/i18n/de/tree.js +3 -0
  424. package/dist/i18n/de/tree.js.map +1 -1
  425. package/dist/i18n/de.d.ts +157 -11
  426. package/dist/i18n/de.js +3 -1
  427. package/dist/i18n/de.js.map +1 -1
  428. package/dist/i18n/en/composites.js +89 -1
  429. package/dist/i18n/en/composites.js.map +1 -1
  430. package/dist/i18n/en/integrations.js +49 -8
  431. package/dist/i18n/en/integrations.js.map +1 -1
  432. package/dist/i18n/en/media.js +0 -1
  433. package/dist/i18n/en/media.js.map +1 -1
  434. package/dist/i18n/en/palette.js +22 -0
  435. package/dist/i18n/en/palette.js.map +1 -0
  436. package/dist/i18n/en/tables.js +0 -1
  437. package/dist/i18n/en/tables.js.map +1 -1
  438. package/dist/i18n/en/transcript.js +2 -1
  439. package/dist/i18n/en/transcript.js.map +1 -1
  440. package/dist/i18n/en/tree.js +3 -0
  441. package/dist/i18n/en/tree.js.map +1 -1
  442. package/dist/i18n/en.js +3 -1
  443. package/dist/i18n/en.js.map +1 -1
  444. package/dist/index.d.ts +4 -3
  445. package/dist/integrations/composite-ai/bibliography-fetch.d.ts +31 -0
  446. package/dist/integrations/composite-ai/bibliography-fetch.js +159 -0
  447. package/dist/integrations/composite-ai/bibliography-fetch.js.map +1 -0
  448. package/dist/integrations/composite-ai/composite-fill.d.ts +30 -8
  449. package/dist/integrations/composite-ai/composite-fill.js +97 -56
  450. package/dist/integrations/composite-ai/composite-fill.js.map +1 -1
  451. package/dist/integrations/composite-ai/composite-summary.d.ts +4 -12
  452. package/dist/integrations/composite-ai/composite-summary.js +7 -26
  453. package/dist/integrations/composite-ai/composite-summary.js.map +1 -1
  454. package/dist/integrations/composite-ai/derive.d.ts +29 -0
  455. package/dist/integrations/composite-ai/derive.js +173 -0
  456. package/dist/integrations/composite-ai/derive.js.map +1 -0
  457. package/dist/integrations/composite-ai/index.d.ts +11 -7
  458. package/dist/integrations/composite-ai/index.js +72 -14
  459. package/dist/integrations/composite-ai/index.js.map +1 -1
  460. package/dist/integrations/composite-ai/rendition.d.ts +45 -0
  461. package/dist/integrations/composite-ai/rendition.js +314 -0
  462. package/dist/integrations/composite-ai/rendition.js.map +1 -0
  463. package/dist/integrations/composite-media/index.d.ts +7 -5
  464. package/dist/integrations/composite-media/index.js +86 -13
  465. package/dist/integrations/composite-media/index.js.map +1 -1
  466. package/dist/integrations/transcript-ai/index.d.ts +1 -1
  467. package/dist/integrations/transcript-ai/index.js +5 -2
  468. package/dist/integrations/transcript-ai/index.js.map +1 -1
  469. package/dist/integrations/transcript-ai/protocol.d.ts +2 -12
  470. package/dist/integrations/transcript-ai/protocol.js +0 -2
  471. package/dist/integrations/transcript-ai/protocol.js.map +1 -1
  472. package/dist/integrations/transcript-ai/transcript-cleanup.d.ts +5 -5
  473. package/dist/integrations/transcript-ai/transcript-cleanup.js +7 -10
  474. package/dist/integrations/transcript-ai/transcript-cleanup.js.map +1 -1
  475. package/dist/markdown/MarkdownSurface.vue.d.ts +10 -9
  476. package/dist/markdown/MarkdownSurface2.js +3 -6
  477. package/dist/markdown/MarkdownSurface2.js.map +1 -1
  478. package/dist/markdown/document.js +1 -1
  479. package/dist/markdown/source-mode.d.ts +1 -1
  480. package/dist/nuxt/module.d.ts +1402 -54
  481. package/dist/nuxt/module.js +6 -49
  482. package/dist/nuxt/module.js.map +1 -1
  483. package/dist/nuxt/runtime/install-context.d.ts +7 -3
  484. package/dist/nuxt/runtime/install-context.js +14 -8
  485. package/dist/nuxt/runtime/install-context.js.map +1 -1
  486. package/dist/nuxt/runtime/plugins/editor-context-nuxt-ui.client.ts +2 -2
  487. package/dist/nuxt/runtime/server/plugins/editor-server.js +20 -12
  488. package/dist/nuxt/runtime/server/plugins/editor-server.js.map +1 -1
  489. package/dist/presets/compose.d.ts +94 -0
  490. package/dist/presets/compose.js +164 -0
  491. package/dist/presets/compose.js.map +1 -0
  492. package/dist/react/AdvancedEditor.d.ts +15 -15
  493. package/dist/react/AdvancedEditor.js +15 -13
  494. package/dist/react/AdvancedEditor.js.map +1 -1
  495. package/dist/react/EditorCommandPalette.d.ts +13 -0
  496. package/dist/react/EditorCommandPalette.js +118 -0
  497. package/dist/react/EditorCommandPalette.js.map +1 -0
  498. package/dist/react/EditorSettingsModal.d.ts +5 -5
  499. package/dist/react/EditorSettingsModal.js +7 -4
  500. package/dist/react/EditorSettingsModal.js.map +1 -1
  501. package/dist/react/EditorSettingsPanel.d.ts +7 -7
  502. package/dist/react/EditorSettingsPanel.js +8 -5
  503. package/dist/react/EditorSettingsPanel.js.map +1 -1
  504. package/dist/react/EditorSurface.d.ts +7 -7
  505. package/dist/react/EditorSurface.js +10 -6
  506. package/dist/react/EditorSurface.js.map +1 -1
  507. package/dist/react/EditorToolbar.d.ts +4 -6
  508. package/dist/react/EditorToolbar.js +29 -37
  509. package/dist/react/EditorToolbar.js.map +1 -1
  510. package/dist/react/SimpleEditor.d.ts +22 -23
  511. package/dist/react/SimpleEditor.js +21 -7
  512. package/dist/react/SimpleEditor.js.map +1 -1
  513. package/dist/react/advanced.d.ts +4 -3
  514. package/dist/react/advanced.js +2 -2
  515. package/dist/react/compose.d.ts +20 -0
  516. package/dist/react/compose.js +49 -0
  517. package/dist/react/compose.js.map +1 -0
  518. package/dist/react/composed-surface.d.ts +39 -0
  519. package/dist/react/composed-surface.js +71 -0
  520. package/dist/react/composed-surface.js.map +1 -0
  521. package/dist/react/context.js +6 -2
  522. package/dist/react/context.js.map +1 -1
  523. package/dist/react/index.d.ts +2 -1
  524. package/dist/react/index.js +2 -1
  525. package/dist/react/key-labels.js +15 -0
  526. package/dist/react/key-labels.js.map +1 -0
  527. package/dist/react/settings.d.ts +1 -1
  528. package/dist/react/simple.d.ts +2 -2
  529. package/dist/react/ui/command.js +36 -1
  530. package/dist/react/ui/command.js.map +1 -1
  531. package/dist/schema/advanced.d.ts +6 -6
  532. package/dist/schema/advanced.js +26 -29
  533. package/dist/schema/advanced.js.map +1 -1
  534. package/dist/server/ai.d.ts +5 -16
  535. package/dist/server/ai.js.map +1 -1
  536. package/dist/server/auth.d.ts +9 -0
  537. package/dist/server/collab-state.d.ts +1 -1
  538. package/dist/server/collab-state.js.map +1 -1
  539. package/dist/server/collab.d.ts +13 -13
  540. package/dist/server/collab.js +34 -18
  541. package/dist/server/collab.js.map +1 -1
  542. package/dist/server/crossref.js +78 -0
  543. package/dist/server/crossref.js.map +1 -0
  544. package/dist/server/errors.d.ts +1 -1
  545. package/dist/server/errors.js +1 -1
  546. package/dist/server/errors.js.map +1 -1
  547. package/dist/server/extract.js +308 -0
  548. package/dist/server/extract.js.map +1 -0
  549. package/dist/{nuxt/runtime/server/utils/editor-route.js → server/h3.js} +8 -16
  550. package/dist/server/h3.js.map +1 -0
  551. package/dist/server/handlers/ai.d.ts +30 -9
  552. package/dist/server/handlers/ai.js +170 -36
  553. package/dist/server/handlers/ai.js.map +1 -1
  554. package/dist/server/handlers/context.d.ts +12 -5
  555. package/dist/server/handlers/context.js +10 -4
  556. package/dist/server/handlers/context.js.map +1 -1
  557. package/dist/server/handlers/editor.d.ts +19 -13
  558. package/dist/server/handlers/editor.js +49 -38
  559. package/dist/server/handlers/editor.js.map +1 -1
  560. package/dist/server/handlers/index.d.ts +4 -4
  561. package/dist/server/handlers/index.js +4 -4
  562. package/dist/server/host.d.ts +16 -25
  563. package/dist/server/host.js +58 -41
  564. package/dist/server/host.js.map +1 -1
  565. package/dist/server/index.d.ts +6 -4
  566. package/dist/server/index.js +3 -2
  567. package/dist/server/pdf.js +97 -0
  568. package/dist/server/pdf.js.map +1 -0
  569. package/dist/server/{adapter.d.ts → ports.d.ts} +81 -30
  570. package/dist/server/ports.js +29 -0
  571. package/dist/server/ports.js.map +1 -0
  572. package/dist/server/routes.js +144 -0
  573. package/dist/server/routes.js.map +1 -0
  574. package/dist/settings/index.d.ts +1 -1
  575. package/dist/settings/index.js.map +1 -1
  576. package/dist/styles/composites.css +25 -0
  577. package/dist/tree/DocumentTree.js +56 -29
  578. package/dist/tree/DocumentTree.js.map +1 -1
  579. package/dist/tree/react/DocumentTree.js +23 -0
  580. package/dist/tree/react/DocumentTree.js.map +1 -1
  581. package/dist/tree/tree-host.js +1 -1
  582. package/dist/vue/AdvancedEditor.js +30 -9
  583. package/dist/vue/AdvancedEditor.js.map +1 -1
  584. package/dist/vue/AdvancedEditor.vue.d.ts +32 -12
  585. package/dist/vue/SimpleEditor.js +62 -16
  586. package/dist/vue/SimpleEditor.js.map +1 -1
  587. package/dist/vue/SimpleEditor.vue.d.ts +37 -7
  588. package/dist/vue/advanced.d.ts +3 -2
  589. package/dist/vue/advanced.js +2 -2
  590. package/dist/vue/components/EditorCommandPalette.js +91 -0
  591. package/dist/vue/components/EditorCommandPalette.js.map +1 -0
  592. package/dist/vue/components/EditorCommandPalette.vue.d.ts +15 -0
  593. package/dist/vue/components/EditorSettingsModal.js +10 -6
  594. package/dist/vue/components/EditorSettingsModal.js.map +1 -1
  595. package/dist/vue/components/EditorSettingsModal.vue.d.ts +4 -4
  596. package/dist/vue/components/EditorSettingsPanel.js +10 -6
  597. package/dist/vue/components/EditorSettingsPanel.js.map +1 -1
  598. package/dist/vue/components/EditorSettingsPanel.vue.d.ts +6 -6
  599. package/dist/vue/components/EditorSurface.js +11 -6
  600. package/dist/vue/components/EditorSurface.js.map +1 -1
  601. package/dist/vue/components/EditorSurface.vue.d.ts +11 -11
  602. package/dist/vue/components/EditorToolbar.js +41 -49
  603. package/dist/vue/components/EditorToolbar.js.map +1 -1
  604. package/dist/vue/components/EditorToolbar.vue.d.ts +2 -4
  605. package/dist/vue/compose.d.ts +17 -0
  606. package/dist/vue/compose.js +51 -0
  607. package/dist/vue/compose.js.map +1 -0
  608. package/dist/vue/context-key.d.ts +6 -0
  609. package/dist/vue/context-key.js +6 -0
  610. package/dist/vue/context-key.js.map +1 -0
  611. package/dist/vue/context.d.ts +8 -6
  612. package/dist/vue/context.js +6 -5
  613. package/dist/vue/context.js.map +1 -1
  614. package/dist/vue/index.d.ts +10 -8
  615. package/dist/vue/index.js +10 -8
  616. package/dist/vue/kit/index.d.ts +2 -2
  617. package/dist/vue/kit/nuxt-ui.js +23 -0
  618. package/dist/vue/kit/nuxt-ui.js.map +1 -1
  619. package/dist/vue/kit/types.d.ts +40 -1
  620. package/package.json +30 -16
  621. package/dist/adapters/comments/client.d.ts +0 -64
  622. package/dist/adapters/comments/client.js.map +0 -1
  623. package/dist/adapters/routes.js.map +0 -1
  624. package/dist/core/toolbar.d.ts +0 -74
  625. package/dist/core/toolbar.js +0 -45
  626. package/dist/core/toolbar.js.map +0 -1
  627. package/dist/integrations/composite-ai/document-transcribe.d.ts +0 -14
  628. package/dist/integrations/composite-ai/document-transcribe.js +0 -89
  629. package/dist/integrations/composite-ai/document-transcribe.js.map +0 -1
  630. package/dist/nuxt/runtime/server/api/ai/chat.post.d.ts +0 -5
  631. package/dist/nuxt/runtime/server/api/ai/chat.post.js +0 -8
  632. package/dist/nuxt/runtime/server/api/ai/chat.post.js.map +0 -1
  633. package/dist/nuxt/runtime/server/api/ai/complete.post.d.ts +0 -5
  634. package/dist/nuxt/runtime/server/api/ai/complete.post.js +0 -8
  635. package/dist/nuxt/runtime/server/api/ai/complete.post.js.map +0 -1
  636. package/dist/nuxt/runtime/server/api/ai/generate.post.d.ts +0 -5
  637. package/dist/nuxt/runtime/server/api/ai/generate.post.js +0 -8
  638. package/dist/nuxt/runtime/server/api/ai/generate.post.js.map +0 -1
  639. package/dist/nuxt/runtime/server/api/ai/models.get.d.ts +0 -5
  640. package/dist/nuxt/runtime/server/api/ai/models.get.js +0 -8
  641. package/dist/nuxt/runtime/server/api/ai/models.get.js.map +0 -1
  642. package/dist/nuxt/runtime/server/api/ai/transcribe.post.d.ts +0 -5
  643. package/dist/nuxt/runtime/server/api/ai/transcribe.post.js +0 -8
  644. package/dist/nuxt/runtime/server/api/ai/transcribe.post.js.map +0 -1
  645. package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.d.ts +0 -5
  646. package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.js +0 -8
  647. package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.js.map +0 -1
  648. package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.d.ts +0 -5
  649. package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.js +0 -8
  650. package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.js.map +0 -1
  651. package/dist/nuxt/runtime/server/api/editor/assets/[id].post.d.ts +0 -5
  652. package/dist/nuxt/runtime/server/api/editor/assets/[id].post.js +0 -8
  653. package/dist/nuxt/runtime/server/api/editor/assets/[id].post.js.map +0 -1
  654. package/dist/nuxt/runtime/server/api/editor/settings.get.d.ts +0 -5
  655. package/dist/nuxt/runtime/server/api/editor/settings.get.js +0 -8
  656. package/dist/nuxt/runtime/server/api/editor/settings.get.js.map +0 -1
  657. package/dist/nuxt/runtime/server/api/editor/settings.put.d.ts +0 -5
  658. package/dist/nuxt/runtime/server/api/editor/settings.put.js +0 -8
  659. package/dist/nuxt/runtime/server/api/editor/settings.put.js.map +0 -1
  660. package/dist/nuxt/runtime/server/api/editor/tags.get.d.ts +0 -5
  661. package/dist/nuxt/runtime/server/api/editor/tags.get.js +0 -8
  662. package/dist/nuxt/runtime/server/api/editor/tags.get.js.map +0 -1
  663. package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.d.ts +0 -5
  664. package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.js +0 -8
  665. package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.js.map +0 -1
  666. package/dist/nuxt/runtime/server/api/editor/themes/[id].get.d.ts +0 -5
  667. package/dist/nuxt/runtime/server/api/editor/themes/[id].get.js +0 -8
  668. package/dist/nuxt/runtime/server/api/editor/themes/[id].get.js.map +0 -1
  669. package/dist/nuxt/runtime/server/api/editor/themes/index.get.d.ts +0 -5
  670. package/dist/nuxt/runtime/server/api/editor/themes/index.get.js +0 -8
  671. package/dist/nuxt/runtime/server/api/editor/themes/index.get.js.map +0 -1
  672. package/dist/nuxt/runtime/server/api/editor/themes/index.post.d.ts +0 -5
  673. package/dist/nuxt/runtime/server/api/editor/themes/index.post.js +0 -8
  674. package/dist/nuxt/runtime/server/api/editor/themes/index.post.js.map +0 -1
  675. package/dist/nuxt/runtime/server/api/editor/users.get.d.ts +0 -5
  676. package/dist/nuxt/runtime/server/api/editor/users.get.js +0 -8
  677. package/dist/nuxt/runtime/server/api/editor/users.get.js.map +0 -1
  678. package/dist/nuxt/runtime/server/plugins/collab.d.ts +0 -5
  679. package/dist/nuxt/runtime/server/plugins/collab.js +0 -10
  680. package/dist/nuxt/runtime/server/plugins/collab.js.map +0 -1
  681. package/dist/nuxt/runtime/server/routes/collab/[id].d.ts +0 -5
  682. package/dist/nuxt/runtime/server/routes/collab/[id].js +0 -35
  683. package/dist/nuxt/runtime/server/routes/collab/[id].js.map +0 -1
  684. package/dist/nuxt/runtime/server/utils/editor-route.d.ts +0 -11
  685. package/dist/nuxt/runtime/server/utils/editor-route.js.map +0 -1
  686. package/dist/presets/advanced.d.ts +0 -33
  687. package/dist/presets/advanced.js +0 -50
  688. package/dist/presets/advanced.js.map +0 -1
  689. package/dist/presets/simple.d.ts +0 -9
  690. package/dist/presets/simple.js +0 -12
  691. package/dist/presets/simple.js.map +0 -1
  692. package/dist/react/advanced-preset.d.ts +0 -11
  693. package/dist/react/advanced-preset.js +0 -31
  694. package/dist/react/advanced-preset.js.map +0 -1
  695. package/dist/vue/advanced-preset.d.ts +0 -13
  696. package/dist/vue/advanced-preset.js +0 -33
  697. package/dist/vue/advanced-preset.js.map +0 -1
  698. package/docs/extending.md +0 -538
  699. package/docs/integration.md +0 -630
  700. package/docs/llms.md +0 -383
  701. package/docs/usage.md +0 -1076
@@ -1,135 +1,26 @@
1
- import { HttpError } from "../server/errors.js";
1
+ import { COLLAB_PATH } from "../core/api-routes.js";
2
2
  import { createAiModels } from "../server/ai.js";
3
3
  import { createCollabServer } from "../server/collab.js";
4
4
  import { createRateLimiter } from "../server/rate-limit.js";
5
- import { chatPost, completePost, generatePost, modelsGet, transcribePost, transcriptCleanupPost } from "../server/handlers/ai.js";
6
- import { assetGet, assetPost, settingsGet, settingsPut, tagsGet, themeDelete, themeGet, themePost, themesGet, usersGet } from "../server/handlers/editor.js";
7
- import { AI_API, COLLAB_PATH, COMMENTS_ROUTE, DOCUMENT_ROUTE, EDITOR_API } from "./routes.js";
8
- import { commentsGet, commentsPost, documentGet, documentPut } from "./documents.js";
9
- import { createError, defineEventHandler, defineWebSocketHandler, getQuery, getRouterParams, readBody, readFormData, setResponseHeaders, setResponseStatus } from "h3";
5
+ import { adoptEditorServer } from "../server/host.js";
6
+ import { defineEditorConfig } from "../config/index.js";
7
+ import { routeOf } from "../server/h3.js";
8
+ import { serverRoutesOf } from "../server/routes.js";
9
+ import { defineWebSocketHandler } from "h3";
10
10
  //#region src/adapters/nitro.ts
11
- const API = EDITOR_API;
12
- /** The `HandlerRequest` of a Nitro event. `signal` aborts when the client goes away. */
13
- function requestOf(event) {
14
- const abort = new AbortController();
15
- event.node.res.once("close", () => abort.abort());
16
- return {
17
- headers: event.headers,
18
- params: getRouterParams(event, { decode: true }),
19
- query: Object.fromEntries(Object.entries(getQuery(event)).map(([key, value]) => [key, value === void 0 ? void 0 : String(value)])),
20
- readJson: () => readBody(event),
21
- readForm: () => readFormData(event),
22
- signal: abort.signal
23
- };
24
- }
25
- /** An event handler that runs `handler` with `ctx` and sends its `HandlerResponse`; an `HttpError` becomes Nitro's error response. */
26
- function routeOf(ctx, handler) {
27
- return defineEventHandler(async (event) => {
28
- let response;
29
- try {
30
- response = await handler(ctx, requestOf(event));
31
- } catch (error) {
32
- if (!(error instanceof HttpError)) throw error;
33
- setResponseHeaders(event, error.headers);
34
- throw createError({
35
- statusCode: error.statusCode,
36
- statusMessage: error.statusMessage,
37
- message: error.statusMessage,
38
- data: error.data
39
- });
40
- }
41
- setResponseStatus(event, response.status);
42
- setResponseHeaders(event, response.headers);
43
- return response.body;
44
- });
45
- }
46
- const editorRoutes = [
47
- [
48
- "get",
49
- `${API}/settings`,
50
- settingsGet
51
- ],
52
- [
53
- "put",
54
- `${API}/settings`,
55
- settingsPut
56
- ],
57
- [
58
- "get",
59
- `${API}/users`,
60
- usersGet
61
- ],
62
- [
63
- "get",
64
- `${API}/tags`,
65
- tagsGet
66
- ],
67
- [
68
- "post",
69
- `${API}/assets/:id`,
70
- assetPost
71
- ],
72
- [
73
- "get",
74
- `${API}/assets/:id/:name`,
75
- assetGet
76
- ],
77
- [
78
- "get",
79
- `${API}/themes`,
80
- themesGet
81
- ],
82
- [
83
- "post",
84
- `${API}/themes`,
85
- themePost
86
- ],
87
- [
88
- "get",
89
- `${API}/themes/:id`,
90
- themeGet
91
- ],
92
- [
93
- "delete",
94
- `${API}/themes/:id`,
95
- themeDelete
96
- ]
97
- ];
98
- const aiRoutes = [
99
- [
100
- "get",
101
- `${AI_API}/models`,
102
- modelsGet
103
- ],
104
- [
105
- "post",
106
- `${AI_API}/chat`,
107
- chatPost
108
- ],
109
- [
110
- "post",
111
- `${AI_API}/complete`,
112
- completePost
113
- ],
114
- [
115
- "post",
116
- `${AI_API}/generate`,
117
- generatePost
118
- ],
119
- [
120
- "post",
121
- `${AI_API}/transcribe`,
122
- transcribePost
123
- ],
124
- [
125
- "post",
126
- `${AI_API}/transcript-cleanup`,
127
- transcriptCleanupPost
128
- ]
129
- ];
130
- const collabRoute = (collab) => defineWebSocketHandler({
11
+ const collabRoute = (collab, ports, authenticateUpgrade) => defineWebSocketHandler({
12
+ async upgrade(request) {
13
+ if (!authenticateUpgrade) return;
14
+ const user = await ports.identity.authenticate({ headers: request.headers });
15
+ if (!user) return new Response(null, {
16
+ status: 401,
17
+ statusText: "Unauthorized"
18
+ });
19
+ request.context.user = user;
20
+ },
131
21
  open(peer) {
132
- peer._hocuspocus = collab.handleConnection(peer.websocket, peer.request);
22
+ const user = peer.context.user;
23
+ peer._hocuspocus = collab.handleConnection(peer.websocket, peer.request, user && { user });
133
24
  },
134
25
  message(peer, message) {
135
26
  peer._hocuspocus?.handleMessage(message.uint8Array());
@@ -147,60 +38,64 @@ const collabRoute = (collab) => defineWebSocketHandler({
147
38
  /**
148
39
  * Wires the editor backend into `nitroApp` (call it from a Nitro plugin):
149
40
  *
150
- * /api/editor/{settings,users,tags,assets/…,themes/…} the editor's own endpoints
41
+ * /api/editor/{capabilities,settings,users,tags,assets/…,themes/…} the editor's own endpoints, each with its port; `capabilities` lists what is served
151
42
  * /api/editor/documents/:id GET/PUT a document's TipTap JSON (what `useEditorDocument` uses)
152
- * /api/editor/comments/:id GET/POST comments, with `comments`
153
- * /api/ai/{models,chat,complete,generate,transcribe,transcript-cleanup} with `ai`
43
+ * /api/editor/comments/:id GET/POST comments, with `ports.comments`
44
+ * /api/ai/{models,chat,complete,generate,extract,transcript-cleanup} with `ai`
154
45
  * /collab/:id the collaboration websocket, unless `collab: false`
155
46
  *
156
- * Every route authenticates through `adapter.authenticate`. The collaboration server is closed with Nitro's `close`
157
- * hook. The paths are the ones `@ecsplico/editor/nuxt` serves, so the editor's client works unchanged.
47
+ * Every route authenticates through `ports.identity.authenticate`. The collaboration server is closed with Nitro's `close`
48
+ * hook. The installed server is also the process-wide one of `@ecsplico/editor/server` (`useCollabServer`, `useAiModels`,
49
+ * `liveContent`, …) until it closes. The paths are the ones the editor's client (`createHttpBackend`) calls.
158
50
  */
159
51
  function installEditorServer(nitroApp, options) {
160
- const { adapter } = options;
52
+ const { ports, schema } = options;
53
+ const { authenticateUpgrade = false, ...collabOptions } = options.collab || {};
161
54
  const collab = options.collab === false ? void 0 : createCollabServer({
162
- adapter,
163
- ...options.collab
55
+ ports,
56
+ ...schema && { schema },
57
+ ...collabOptions
164
58
  });
59
+ const provider = ports.models;
165
60
  const models = options.ai && createAiModels({
166
61
  presets: {},
167
- languageModel: adapter.languageModel && ((ref, user) => adapter.languageModel(ref, user)),
168
- listModels: adapter.listModels && ((user) => adapter.listModels(user)),
62
+ languageModel: provider?.languageModel && ((ref, user) => provider.languageModel(ref, user)),
63
+ listModels: provider?.listModels && ((user) => provider.listModels(user)),
169
64
  ...options.ai
170
65
  });
66
+ const limiter = models && createRateLimiter(options.rateLimit ?? defineEditorConfig().ai.rateLimit);
171
67
  const context = {
172
- adapter,
173
- ...collab && { collab }
68
+ ports,
69
+ ...collab && { collab },
70
+ served: {
71
+ ai: models !== void 0,
72
+ collaboration: collab !== void 0
73
+ }
174
74
  };
175
- for (const [method, path, handler] of editorRoutes) nitroApp.router.add(path, routeOf(context, handler), method);
176
- nitroApp.router.add(DOCUMENT_ROUTE, routeOf(context, documentGet), "get");
177
- nitroApp.router.add(DOCUMENT_ROUTE, routeOf(context, documentPut), "put");
178
- if (options.comments) {
179
- const comments = {
180
- ...context,
181
- store: options.comments.store
182
- };
183
- nitroApp.router.add(COMMENTS_ROUTE, routeOf(comments, commentsGet), "get");
184
- nitroApp.router.add(COMMENTS_ROUTE, routeOf(comments, commentsPost), "post");
185
- }
186
- if (models) {
187
- const ai = {
188
- ...context,
189
- ai: models,
190
- limiter: createRateLimiter(options.rateLimit ?? {
191
- max: 30,
192
- windowMs: 6e4
193
- })
194
- };
195
- for (const [method, path, handler] of aiRoutes) nitroApp.router.add(path, routeOf(ai, handler), method);
75
+ const aiContext = models && limiter && {
76
+ ...context,
77
+ ai: models,
78
+ limiter
79
+ };
80
+ for (const route of serverRoutesOf(ports, { ai: aiContext !== void 0 })) {
81
+ const handler = route.port === "ai" ? routeOf(aiContext, route.handler) : routeOf(context, route.handler);
82
+ nitroApp.router.add(route.path, handler, route.method);
196
83
  }
197
- if (collab) nitroApp.router.use(`${COLLAB_PATH}/:id`, collabRoute(collab));
84
+ if (collab) nitroApp.router.use(`${COLLAB_PATH}/:id`, collabRoute(collab, ports, authenticateUpgrade));
85
+ const release = adoptEditorServer({
86
+ ports,
87
+ schema,
88
+ collab,
89
+ models,
90
+ limiter
91
+ });
198
92
  const server = {
199
- adapter,
93
+ ports,
200
94
  collab,
201
95
  models,
202
- close: async () => {
96
+ async close() {
203
97
  await collab?.close();
98
+ release();
204
99
  }
205
100
  };
206
101
  nitroApp.hooks.hook("close", () => server.close());
@@ -1 +1 @@
1
- {"version":3,"file":"nitro.js","names":[],"sources":["../../src/adapters/nitro.ts"],"sourcesContent":["import { type AiModels, type AiModelsConfig, type CollabConnection, type CollabServer, type CollabServerOptions, createAiModels, createCollabServer, createRateLimiter, type EditorAdapter, HttpError, type RateLimiterOptions } from '../server'\nimport {\n type AiHandlerContext,\n assetGet,\n assetPost,\n chatPost,\n completePost,\n generatePost,\n type HandlerContext,\n type HandlerRequest,\n type HandlerResponse,\n modelsGet,\n settingsGet,\n settingsPut,\n tagsGet,\n themeDelete,\n themeGet,\n themePost,\n themesGet,\n transcribePost,\n transcriptCleanupPost,\n usersGet,\n} from '../server/handlers'\nimport { createError, defineEventHandler, defineWebSocketHandler, getQuery, getRouterParams, type H3Event, readBody, readFormData, type Router, setResponseHeaders, setResponseStatus } from 'h3'\nimport type { DocumentAdmin } from './shared'\nimport type { CommentStore } from './comments/types'\nimport { AI_API, COLLAB_PATH, COMMENTS_ROUTE, DOCUMENT_ROUTE, EDITOR_API } from './routes'\nimport { commentsGet, type CommentsRouteContext, commentsPost, type DocumentsContext, documentGet, documentPut } from './documents'\n\n// The editor backend on a plain Nitro app (nitropack 2, no Nuxt module): the framework's own routes (settings, users,\n// tags, assets, themes, the optional AI endpoints), the collaboration websocket and this package's document and comments\n// routes, registered in one call from a Nitro plugin. It is the explicit-wiring twin of `@ecsplico/editor/nuxt`, which\n// registers the same routes by scanning files; both end in the same `@ecsplico/editor/server/handlers`.\n\n/** The part of a Nitro app this entry uses; `nitroApp` of a Nitro plugin fits. */\nexport interface NitroHost {\n router: Pick<Router, 'add' | 'use'>\n hooks: { hook(name: 'close', listener: () => void | Promise<void>): unknown }\n}\n\nexport interface EditorServerOptions {\n /** Storage and identity. An adapter that also manages documents (`json`, `drizzle`) lets `PUT /api/editor/documents/:id` create them. */\n adapter: EditorAdapter & Partial<DocumentAdmin>\n /**\n * The collaboration websocket (`/collab/:id`). Extensions, hooks and Hocuspocus configuration of `createCollabServer`;\n * `{}` takes everything from the adapter. `false` mounts no websocket (documents then only load and save over HTTP).\n * Needs `experimental: { websocket: true }` in the Nitro config.\n */\n collab: Omit<CollabServerOptions, 'adapter'> | false\n /**\n * Mounts the AI endpoints (`/api/ai/*`): presets, shared key, transcription, slots of `createAiModels`; `languageModel`\n * and `listModels` default to the adapter's. Omitted: no AI routes.\n */\n ai?: Partial<AiModelsConfig>\n /** Per-user limit of the AI endpoints; default 30 requests per minute. */\n rateLimit?: RateLimiterOptions\n /** Mounts the comments endpoint (`/api/editor/comments/:id`) over this store; omitted: no comments routes. */\n comments?: { store: CommentStore }\n}\n\nexport interface EditorServer {\n adapter: EditorServerOptions['adapter']\n /** The collaboration server, `undefined` with `collab: false`. */\n collab: CollabServer | undefined\n /** The AI models, `undefined` without `ai`. */\n models: AiModels | undefined\n /** Writes pending collaboration stores and disconnects every client. Nitro's `close` hook calls it. */\n close(): Promise<void>\n}\n\ntype Method = 'get' | 'post' | 'put' | 'delete'\ntype Handler<C> = (ctx: C, request: HandlerRequest) => Promise<HandlerResponse>\n\nconst API = EDITOR_API\n\n/** The `HandlerRequest` of a Nitro event. `signal` aborts when the client goes away. */\nfunction requestOf(event: H3Event): HandlerRequest {\n const abort = new AbortController()\n event.node.res.once('close', () => abort.abort())\n return {\n headers: event.headers,\n params: getRouterParams(event, { decode: true }),\n query: Object.fromEntries(Object.entries(getQuery(event)).map(([key, value]) => [key, value === undefined ? undefined : String(value)])),\n readJson: () => readBody(event),\n readForm: () => readFormData(event),\n signal: abort.signal,\n }\n}\n\n/** An event handler that runs `handler` with `ctx` and sends its `HandlerResponse`; an `HttpError` becomes Nitro's error response. */\nfunction routeOf<C>(ctx: C, handler: Handler<C>) {\n return defineEventHandler(async (event) => {\n let response: HandlerResponse\n try {\n response = await handler(ctx, requestOf(event))\n }\n catch (error) {\n if (!(error instanceof HttpError)) throw error\n setResponseHeaders(event, error.headers)\n throw createError({ statusCode: error.statusCode, statusMessage: error.statusMessage, message: error.statusMessage, data: error.data })\n }\n setResponseStatus(event, response.status)\n setResponseHeaders(event, response.headers)\n // `null` ends the response without a body and keeps the status set above.\n return response.body\n })\n}\n\nconst editorRoutes: [Method, string, Handler<HandlerContext>][] = [\n ['get', `${API}/settings`, settingsGet],\n ['put', `${API}/settings`, settingsPut],\n ['get', `${API}/users`, usersGet],\n ['get', `${API}/tags`, tagsGet],\n ['post', `${API}/assets/:id`, assetPost],\n ['get', `${API}/assets/:id/:name`, assetGet],\n ['get', `${API}/themes`, themesGet],\n ['post', `${API}/themes`, themePost],\n ['get', `${API}/themes/:id`, themeGet],\n ['delete', `${API}/themes/:id`, themeDelete],\n]\n\nconst aiRoutes: [Method, string, Handler<AiHandlerContext>][] = [\n ['get', `${AI_API}/models`, modelsGet],\n ['post', `${AI_API}/chat`, chatPost],\n ['post', `${AI_API}/complete`, completePost],\n ['post', `${AI_API}/generate`, generatePost],\n ['post', `${AI_API}/transcribe`, transcribePost],\n ['post', `${AI_API}/transcript-cleanup`, transcriptCleanupPost],\n]\n\ntype CollabPeer = { _hocuspocus?: CollabConnection }\n\nconst collabRoute = (collab: CollabServer) => defineWebSocketHandler({\n open(peer) {\n ;(peer as unknown as CollabPeer)._hocuspocus = collab.handleConnection(peer.websocket as unknown as Parameters<CollabServer['handleConnection']>[0], peer.request as Request)\n },\n message(peer, message) {\n ;(peer as unknown as CollabPeer)._hocuspocus?.handleMessage(message.uint8Array())\n },\n close(peer, details) {\n ;(peer as unknown as CollabPeer)._hocuspocus?.handleClose({ code: details.code ?? 1000, reason: details.reason ?? '' } as CloseEvent)\n },\n error(peer, error) {\n console.error('[collab]', peer.id, error)\n },\n})\n\n/**\n * Wires the editor backend into `nitroApp` (call it from a Nitro plugin):\n *\n * /api/editor/{settings,users,tags,assets/…,themes/…} the editor's own endpoints\n * /api/editor/documents/:id GET/PUT a document's TipTap JSON (what `useEditorDocument` uses)\n * /api/editor/comments/:id GET/POST comments, with `comments`\n * /api/ai/{models,chat,complete,generate,transcribe,transcript-cleanup} with `ai`\n * /collab/:id the collaboration websocket, unless `collab: false`\n *\n * Every route authenticates through `adapter.authenticate`. The collaboration server is closed with Nitro's `close`\n * hook. The paths are the ones `@ecsplico/editor/nuxt` serves, so the editor's client works unchanged.\n */\nexport function installEditorServer(nitroApp: NitroHost, options: EditorServerOptions): EditorServer {\n const { adapter } = options\n const collab = options.collab === false ? undefined : createCollabServer({ adapter, ...options.collab })\n const models = options.ai && createAiModels({\n presets: {},\n languageModel: adapter.languageModel && ((ref, user) => adapter.languageModel!(ref, user)),\n listModels: adapter.listModels && (user => adapter.listModels!(user)),\n ...options.ai,\n })\n\n const context: DocumentsContext = { adapter, ...(collab && { collab }) }\n for (const [method, path, handler] of editorRoutes) nitroApp.router.add(path, routeOf<HandlerContext>(context, handler), method)\n nitroApp.router.add(DOCUMENT_ROUTE, routeOf(context, documentGet), 'get')\n nitroApp.router.add(DOCUMENT_ROUTE, routeOf(context, documentPut), 'put')\n\n if (options.comments) {\n const comments: CommentsRouteContext = { ...context, store: options.comments.store }\n nitroApp.router.add(COMMENTS_ROUTE, routeOf(comments, commentsGet), 'get')\n nitroApp.router.add(COMMENTS_ROUTE, routeOf(comments, commentsPost), 'post')\n }\n if (models) {\n const ai: AiHandlerContext = { ...context, ai: models, limiter: createRateLimiter(options.rateLimit ?? { max: 30, windowMs: 60_000 }) }\n for (const [method, path, handler] of aiRoutes) nitroApp.router.add(path, routeOf(ai, handler), method)\n }\n // No method: the websocket upgrade resolves its handler by path only.\n if (collab) nitroApp.router.use(`${COLLAB_PATH}/:id`, collabRoute(collab))\n\n const server: EditorServer = { adapter, collab, models, close: async () => { await collab?.close() } }\n nitroApp.hooks.hook('close', () => server.close())\n return server\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"nitro.js","names":[],"sources":["../../src/adapters/nitro.ts"],"sourcesContent":["import type { AnyExtension } from '@tiptap/core'\nimport { type AiModels, type AiModelsConfig, type CollabConnection, type CollabServer, type CollabServerOptions, createAiModels, createCollabServer, createRateLimiter, type EditorPorts, type RateLimiter, type RateLimiterOptions } from '../server'\nimport { defineEditorConfig } from '../config'\nimport { routeOf } from '../server/h3'\nimport type { AiHandlerContext, HandlerContext } from '../server/handlers'\nimport { adoptEditorServer } from '../server/host'\nimport { serverRoutesOf } from '../server/routes'\nimport { defineWebSocketHandler, type Router } from 'h3'\nimport { COLLAB_PATH } from '../core/api-routes'\n\n// The editor backend on a Nitro app: the routes the ports can serve (`serverRoutesOf`: settings, users, tags, assets,\n// themes, documents, comments, the optional AI endpoints) and the collaboration websocket, registered in one call from a\n// Nitro plugin. One installer serves both hosts: a plain Nitro app (nitropack 2) calls it from its own plugin, the\n// Nuxt module (`@ecsplico/editor/nuxt`) from its server plugin. Both end in the same `@ecsplico/editor/server/handlers`.\n\n/** The part of a Nitro app this entry uses; `nitroApp` of a Nitro plugin fits. */\nexport interface NitroHost {\n router: Pick<Router, 'add' | 'use'>\n hooks: { hook(name: 'close', listener: () => void | Promise<void>): unknown }\n}\n\nexport interface EditorServerOptions {\n /** Identity, storage and everything else the backend serves, one port per capability: a route is mounted only when its port is present. A documents port that also manages documents (`json`, `drizzle`) lets `PUT /api/editor/documents/:id` create them; the `comments` port mounts the comments endpoint, `models` the host's language models. */\n ports: EditorPorts\n /**\n * The collaboration websocket (`/collab/:id`). Schema, hooks and Hocuspocus configuration of `createCollabServer`;\n * `{}` takes everything from the ports (the `collabState` port is required). `false` mounts no websocket (documents then only load and save over HTTP).\n * `authenticateUpgrade`: authenticate the upgrade request itself (`Identity.authenticate` with its headers; cookies,\n * not the provider's `token`) and refuse it with HTTP 401, instead of closing an unauthenticated socket with 4401\n * after the upgrade; the user then travels with the connection and is not authenticated a second time.\n * Needs `experimental: { websocket: true }` in the Nitro config.\n */\n collab: (Omit<CollabServerOptions, 'ports'> & { authenticateUpgrade?: boolean }) | false\n /**\n * Mounts the AI endpoints (`/api/ai/*`): presets, shared key, transcription, slots of `createAiModels`; `languageModel`\n * and `listModels` default to those of the `models` port. Omitted: no AI routes.\n */\n ai?: Partial<AiModelsConfig>\n /** Per-user limit of the AI endpoints; default: that of `defineEditorConfig` (30 requests per minute). */\n rateLimit?: RateLimiterOptions\n /** The collaboration schema (see `CollabServerOptions.schema`); default `advancedSchemaExtensions()`, host nodes: `() => [...advancedSchemaExtensions(), Callout]`. */\n schema?: () => AnyExtension[]\n}\n\nexport interface EditorServer {\n ports: EditorPorts\n /** The collaboration server, `undefined` with `collab: false`. */\n collab: CollabServer | undefined\n /** The AI models, `undefined` without `ai`. */\n models: AiModels | undefined\n /** Writes pending collaboration stores and disconnects every client. Nitro's `close` hook calls it. */\n close(): Promise<void>\n}\n\ntype CollabPeer = { _hocuspocus?: CollabConnection }\n\n// Same crossws wiring as Hocuspocus' own Server; the document name comes from the provider's `name`. By default the user\n// is authenticated in Hocuspocus' `onAuthenticate` (cookie headers of the upgrade request or the provider's `token`), so\n// the upgrade always succeeds and an unauthenticated socket is closed with 4401 afterwards. With `authenticateUpgrade` the\n// upgrade request itself is authenticated (headers only) and refused with HTTP 401.\nconst collabRoute = (collab: CollabServer, ports: EditorPorts, authenticateUpgrade: boolean) => defineWebSocketHandler({\n async upgrade(request) {\n if (!authenticateUpgrade) return\n const user = await ports.identity.authenticate({ headers: request.headers })\n // No body: crossws' node adapter writes the response headers percent-encoded, which would mangle an automatic `content-type`.\n if (!user) return new Response(null, { status: 401, statusText: 'Unauthorized' })\n // crossws creates the context before it calls the hook (its type is optional only for other callers); `open` reads it as `peer.context`.\n request.context!.user = user\n },\n open(peer) {\n const user = peer.context.user as object | undefined\n ;(peer as unknown as CollabPeer)._hocuspocus = collab.handleConnection(peer.websocket as unknown as Parameters<CollabServer['handleConnection']>[0], peer.request as Request, user && { user })\n },\n message(peer, message) {\n ;(peer as unknown as CollabPeer)._hocuspocus?.handleMessage(message.uint8Array())\n },\n close(peer, details) {\n ;(peer as unknown as CollabPeer)._hocuspocus?.handleClose({ code: details.code ?? 1000, reason: details.reason ?? '' } as CloseEvent)\n },\n error(peer, error) {\n console.error('[collab]', peer.id, error)\n },\n})\n\n/**\n * Wires the editor backend into `nitroApp` (call it from a Nitro plugin):\n *\n * /api/editor/{capabilities,settings,users,tags,assets/…,themes/…} the editor's own endpoints, each with its port; `capabilities` lists what is served\n * /api/editor/documents/:id GET/PUT a document's TipTap JSON (what `useEditorDocument` uses)\n * /api/editor/comments/:id GET/POST comments, with `ports.comments`\n * /api/ai/{models,chat,complete,generate,extract,transcript-cleanup} with `ai`\n * /collab/:id the collaboration websocket, unless `collab: false`\n *\n * Every route authenticates through `ports.identity.authenticate`. The collaboration server is closed with Nitro's `close`\n * hook. The installed server is also the process-wide one of `@ecsplico/editor/server` (`useCollabServer`, `useAiModels`,\n * `liveContent`, …) until it closes. The paths are the ones the editor's client (`createHttpBackend`) calls.\n */\nexport function installEditorServer(nitroApp: NitroHost, options: EditorServerOptions): EditorServer {\n const { ports, schema } = options\n const { authenticateUpgrade = false, ...collabOptions }: Exclude<EditorServerOptions['collab'], false> = options.collab || {}\n const collab = options.collab === false ? undefined : createCollabServer({ ports, ...(schema && { schema }), ...collabOptions })\n const provider = ports.models\n const models = options.ai && createAiModels({\n presets: {},\n languageModel: provider?.languageModel && ((ref, user) => provider.languageModel!(ref, user)),\n listModels: provider?.listModels && (user => provider.listModels!(user)),\n ...options.ai,\n })\n const limiter: RateLimiter | undefined = models && createRateLimiter(options.rateLimit ?? defineEditorConfig().ai.rateLimit)\n\n const context: HandlerContext = { ports, ...(collab && { collab }), served: { ai: models !== undefined, collaboration: collab !== undefined } }\n const aiContext: AiHandlerContext | undefined = models && limiter && { ...context, ai: models, limiter }\n for (const route of serverRoutesOf(ports, { ai: aiContext !== undefined })) {\n // `serverRoutesOf` returns the AI routes only with `ai`, so `aiContext` is set for them.\n const handler = route.port === 'ai' ? routeOf(aiContext!, route.handler) : routeOf(context, route.handler)\n nitroApp.router.add(route.path, handler, route.method)\n }\n // No method: the websocket upgrade resolves its handler by path only.\n if (collab) nitroApp.router.use(`${COLLAB_PATH}/:id`, collabRoute(collab, ports, authenticateUpgrade))\n\n const release = adoptEditorServer({ ports, schema, collab, models, limiter })\n const server: EditorServer = {\n ports,\n collab,\n models,\n async close() {\n await collab?.close()\n release()\n },\n }\n nitroApp.hooks.hook('close', () => server.close())\n return server\n}\n"],"mappings":";;;;;;;;;;AA4DA,MAAM,eAAe,QAAsB,OAAoB,wBAAiC,uBAAuB;CACrH,MAAM,QAAQ,SAAS;EACrB,IAAI,CAAC,qBAAqB;EAC1B,MAAM,OAAO,MAAM,MAAM,SAAS,aAAa,EAAE,SAAS,QAAQ,QAAQ,CAAC;EAE3E,IAAI,CAAC,MAAM,OAAO,IAAI,SAAS,MAAM;GAAE,QAAQ;GAAK,YAAY;EAAe,CAAC;EAEhF,QAAQ,QAAS,OAAO;CAC1B;CACA,KAAK,MAAM;EACT,MAAM,OAAO,KAAK,QAAQ;EACzB,KAAgC,cAAc,OAAO,iBAAiB,KAAK,WAAyE,KAAK,SAAoB,QAAQ,EAAE,KAAK,CAAC;CAChM;CACA,QAAQ,MAAM,SAAS;EACpB,KAAgC,aAAa,cAAc,QAAQ,WAAW,CAAC;CAClF;CACA,MAAM,MAAM,SAAS;EAClB,KAAgC,aAAa,YAAY;GAAE,MAAM,QAAQ,QAAQ;GAAM,QAAQ,QAAQ,UAAU;EAAG,CAAe;CACtI;CACA,MAAM,MAAM,OAAO;EACjB,QAAQ,MAAM,YAAY,KAAK,IAAI,KAAK;CAC1C;AACF,CAAC;;;;;;;;;;;;;;AAeD,SAAgB,oBAAoB,UAAqB,SAA4C;CACnG,MAAM,EAAE,OAAO,WAAW;CAC1B,MAAM,EAAE,sBAAsB,OAAO,GAAG,kBAAiE,QAAQ,UAAU,CAAC;CAC5H,MAAM,SAAS,QAAQ,WAAW,QAAQ,KAAA,IAAY,mBAAmB;EAAE;EAAO,GAAI,UAAU,EAAE,OAAO;EAAI,GAAG;CAAc,CAAC;CAC/H,MAAM,WAAW,MAAM;CACvB,MAAM,SAAS,QAAQ,MAAM,eAAe;EAC1C,SAAS,CAAC;EACV,eAAe,UAAU,mBAAmB,KAAK,SAAS,SAAS,cAAe,KAAK,IAAI;EAC3F,YAAY,UAAU,gBAAe,SAAQ,SAAS,WAAY,IAAI;EACtE,GAAG,QAAQ;CACb,CAAC;CACD,MAAM,UAAmC,UAAU,kBAAkB,QAAQ,aAAa,mBAAmB,CAAC,CAAC,GAAG,SAAS;CAE3H,MAAM,UAA0B;EAAE;EAAO,GAAI,UAAU,EAAE,OAAO;EAAI,QAAQ;GAAE,IAAI,WAAW,KAAA;GAAW,eAAe,WAAW,KAAA;EAAU;CAAE;CAC9I,MAAM,YAA0C,UAAU,WAAW;EAAE,GAAG;EAAS,IAAI;EAAQ;CAAQ;CACvG,KAAK,MAAM,SAAS,eAAe,OAAO,EAAE,IAAI,cAAc,KAAA,EAAU,CAAC,GAAG;EAE1E,MAAM,UAAU,MAAM,SAAS,OAAO,QAAQ,WAAY,MAAM,OAAO,IAAI,QAAQ,SAAS,MAAM,OAAO;EACzG,SAAS,OAAO,IAAI,MAAM,MAAM,SAAS,MAAM,MAAM;CACvD;CAEA,IAAI,QAAQ,SAAS,OAAO,IAAI,GAAG,YAAY,OAAO,YAAY,QAAQ,OAAO,mBAAmB,CAAC;CAErG,MAAM,UAAU,kBAAkB;EAAE;EAAO;EAAQ;EAAQ;EAAQ;CAAQ,CAAC;CAC5E,MAAM,SAAuB;EAC3B;EACA;EACA;EACA,MAAM,QAAQ;GACZ,MAAM,QAAQ,MAAM;GACpB,QAAQ;EACV;CACF;CACA,SAAS,MAAM,KAAK,eAAe,OAAO,MAAM,CAAC;CACjD,OAAO;AACT"}
@@ -0,0 +1,55 @@
1
+ import { CollaborationSession } from "../core/feature.js";
2
+ import { CommentsModel } from "../core/backend-types.js";
3
+ import "../core/index.js";
4
+ import { EditorDocumentOptions } from "./document-state.js";
5
+ import { Editor, JSONContent } from "@tiptap/core";
6
+ //#region src/adapters/react.d.ts
7
+ /** The props of the editor surface (`EditorSurface`, `AdvancedEditor`) that `useEditorDocument` fills. */
8
+ export interface EditorDocumentBinding {
9
+ /** The document (standalone mode); `undefined` in collaboration mode and until it has loaded. */
10
+ value: JSONContent | undefined;
11
+ onChange: (content: JSONContent) => void;
12
+ /** Hands the live editor to the comments model. */
13
+ onReady: (editor: Editor) => void;
14
+ collaboration: CollaborationSession | undefined;
15
+ }
16
+ export interface EditorDocument {
17
+ /** The document's TipTap JSON: the surface's `value`. `undefined` until loaded, and always in collaboration mode. */
18
+ modelValue: JSONContent | undefined;
19
+ /** Replaces `modelValue` (the surface's `onChange`). */
20
+ onChange: (content: JSONContent) => void;
21
+ /** `true` once the surface can be mounted: the content has loaded (a missing document starts empty), or the collaboration session exists. Mount with `key` = the id, so a changed id remounts it. */
22
+ ready: boolean;
23
+ /** Edits since the content was loaded or last saved. */
24
+ dirty: boolean;
25
+ /** Stores the current content (`backend.documents.save`); several calls run one after another and an edit made while one is in flight stays dirty. Rejects with the backend's refusal. */
26
+ save: () => Promise<void>;
27
+ /** Loads the content again and drops unsaved edits (in collaboration mode: reconnects). */
28
+ reload: () => Promise<void>;
29
+ /** The last load or save error, `null` while all is well. */
30
+ error: Error | null;
31
+ /** The collaboration session for the surface's `collaboration` prop; `undefined` without the `collaboration` option, and never the session of another document. */
32
+ collaboration: CollaborationSession | undefined;
33
+ /**
34
+ * The comments model of this document, made by `backend.comments` (`undefined` when the backend has none, and until
35
+ * the first effect ran). A new one per id. The feature's `model` factory runs when the editor is created, so read it
36
+ * through a ref the host keeps current: `commentsFeature({ model: () => commentsRef.current! })`.
37
+ */
38
+ comments: CommentsModel | undefined;
39
+ /** The live editor, once the surface reported it. */
40
+ editor: Editor | undefined;
41
+ /** Spread target for the surface: `<AdvancedEditor key={id} {...bind} />` once `ready`. */
42
+ bind: EditorDocumentBinding;
43
+ }
44
+ /**
45
+ * Loads document `id` through `backend.documents` (a missing document starts empty; the first `save()` creates it),
46
+ * tracks edits, saves, and prepares the collaboration session (`backend.collaboration`) and comments model
47
+ * (`backend.comments`) for the editor surface. The backend is `options.backend`, else the editor context's
48
+ * (`EditorContextProvider`); keep it stable across renders (a new object reloads the document). A changed `id` loads the
49
+ * other document and replaces the session and the comments model. Throws when `collaboration` is set and the backend
50
+ * cannot collaborate, or when it keeps no documents.
51
+ */
52
+ export declare function useEditorDocument(documentId: string | null | undefined, options?: EditorDocumentOptions): EditorDocument;
53
+ //#endregion
54
+ export type { EditorDocumentOptions };
55
+ //# sourceMappingURL=react.d.ts.map
@@ -0,0 +1,209 @@
1
+ import { useOptionalEditorContext } from "../react/context.js";
2
+ import { errorOf, fingerprintToSave, isDirty, loadedDocument, openSession, requireCapability } from "./document-state.js";
3
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
+ //#region src/adapters/react.ts
5
+ const fresh = (id) => ({
6
+ id,
7
+ ready: false,
8
+ modelValue: void 0,
9
+ saved: null,
10
+ error: null,
11
+ session: void 0,
12
+ editor: void 0
13
+ });
14
+ /**
15
+ * Loads document `id` through `backend.documents` (a missing document starts empty; the first `save()` creates it),
16
+ * tracks edits, saves, and prepares the collaboration session (`backend.collaboration`) and comments model
17
+ * (`backend.comments`) for the editor surface. The backend is `options.backend`, else the editor context's
18
+ * (`EditorContextProvider`); keep it stable across renders (a new object reloads the document). A changed `id` loads the
19
+ * other document and replaces the session and the comments model. Throws when `collaboration` is set and the backend
20
+ * cannot collaborate, or when it keeps no documents.
21
+ */
22
+ function useEditorDocument(documentId, options = {}) {
23
+ /** `''` = no document open (the host has none yet, e.g. it still waits for the signed-in user): the hook stays idle. */
24
+ const id = documentId ?? "";
25
+ const context = useOptionalEditorContext();
26
+ const backend = options.backend ?? context?.backend;
27
+ if (!backend) throw new Error("@ecsplico/editor: useEditorDocument needs a backend: pass `backend` or wrap the tree in <EditorContextProvider context={createEditorContext()}>");
28
+ const collaborating = Boolean(options.collaboration);
29
+ const documents = collaborating ? void 0 : requireCapability(backend, "documents");
30
+ const collaborationPort = collaborating ? requireCapability(backend, "collaboration") : void 0;
31
+ const [state, setState] = useState(() => fresh(id));
32
+ const [comments, setComments] = useState();
33
+ const [attempt, setAttempt] = useState(0);
34
+ /** What the callbacks read: the open id, and the latest options and values (an edit just reported is here before the next render). */
35
+ const live = useRef({
36
+ id,
37
+ options,
38
+ modelValue: void 0,
39
+ saved: null,
40
+ ready: false,
41
+ missing: false,
42
+ editor: void 0
43
+ });
44
+ live.current.id = id;
45
+ live.current.options = options;
46
+ const generation = useRef(0);
47
+ const tail = useRef(Promise.resolve());
48
+ const current = state.id === id ? state : fresh(id);
49
+ const userOf = useCallback(() => {
50
+ const { user } = live.current.options;
51
+ return (typeof user === "function" ? user() : user) ?? null;
52
+ }, []);
53
+ const commit = useCallback((documentId, change) => {
54
+ if (documentId !== live.current.id) return;
55
+ if ("modelValue" in change) live.current.modelValue = change.modelValue;
56
+ if ("saved" in change) live.current.saved = change.saved ?? null;
57
+ if ("ready" in change) live.current.ready = change.ready ?? false;
58
+ if ("editor" in change) live.current.editor = change.editor;
59
+ setState((previous) => previous.id === documentId ? {
60
+ ...previous,
61
+ ...change
62
+ } : previous);
63
+ }, []);
64
+ const fetchContent = useCallback(async (documentId, mine) => {
65
+ try {
66
+ const content = await documents.load(documentId);
67
+ if (mine !== generation.current) return;
68
+ const { modelValue, saved, missing } = loadedDocument(content);
69
+ live.current.missing = missing;
70
+ commit(documentId, {
71
+ modelValue,
72
+ saved,
73
+ ready: true
74
+ });
75
+ } catch (cause) {
76
+ if (mine === generation.current) commit(documentId, { error: errorOf(cause) });
77
+ }
78
+ }, [documents, commit]);
79
+ const start = useCallback((documentId) => {
80
+ const mine = ++generation.current;
81
+ Object.assign(live.current, {
82
+ modelValue: void 0,
83
+ saved: null,
84
+ ready: false,
85
+ missing: false,
86
+ editor: void 0
87
+ });
88
+ setState(fresh(documentId));
89
+ return mine;
90
+ }, []);
91
+ useEffect(() => {
92
+ const mine = start(id);
93
+ if (!id) return;
94
+ if (collaborationPort) {
95
+ const { session, close } = openSession(collaborationPort, id, live.current.options.collaboration, userOf());
96
+ commit(id, {
97
+ session,
98
+ ready: true
99
+ });
100
+ return () => {
101
+ generation.current++;
102
+ close();
103
+ };
104
+ }
105
+ fetchContent(id, mine);
106
+ return () => {
107
+ generation.current++;
108
+ };
109
+ }, [
110
+ id,
111
+ collaborationPort,
112
+ attempt,
113
+ start,
114
+ commit,
115
+ fetchContent,
116
+ userOf
117
+ ]);
118
+ useEffect(() => {
119
+ if (!id) return;
120
+ const model = backend.comments?.(id, {
121
+ user: userOf,
122
+ canComment: () => {
123
+ const { canComment } = live.current.options;
124
+ return (typeof canComment === "function" ? canComment() : canComment) ?? true;
125
+ },
126
+ getEditor: () => live.current.editor,
127
+ onError: (cause) => commit(id, { error: cause })
128
+ });
129
+ setComments(model);
130
+ return () => {
131
+ model?.dispose();
132
+ setComments(void 0);
133
+ };
134
+ }, [
135
+ backend,
136
+ id,
137
+ userOf,
138
+ commit
139
+ ]);
140
+ const save = useCallback(() => {
141
+ if (!documents) return Promise.resolve();
142
+ const run = async () => {
143
+ const documentId = live.current.id;
144
+ const content = live.current.modelValue;
145
+ const saved = fingerprintToSave(content, live.current.ready, live.current.saved, live.current.missing);
146
+ if (content === void 0 || saved === null) return;
147
+ try {
148
+ await documents.save(documentId, content);
149
+ } catch (cause) {
150
+ commit(documentId, { error: errorOf(cause) });
151
+ throw cause;
152
+ }
153
+ if (documentId === live.current.id) live.current.missing = false;
154
+ commit(documentId, {
155
+ saved,
156
+ error: null
157
+ });
158
+ };
159
+ const result = tail.current.then(run, run);
160
+ tail.current = result.catch(() => {});
161
+ return result;
162
+ }, [documents, commit]);
163
+ const reload = useCallback(async () => {
164
+ if (collaborationPort) {
165
+ setAttempt((count) => count + 1);
166
+ return;
167
+ }
168
+ await fetchContent(live.current.id, start(live.current.id));
169
+ }, [
170
+ collaborationPort,
171
+ fetchContent,
172
+ start
173
+ ]);
174
+ const onChange = useCallback((content) => commit(live.current.id, { modelValue: content }), [commit]);
175
+ const onReady = useCallback((editor) => commit(live.current.id, { editor }), [commit]);
176
+ const dirty = useMemo(() => isDirty(collaborating, current.modelValue, current.saved), [
177
+ collaborating,
178
+ current.modelValue,
179
+ current.saved
180
+ ]);
181
+ const bind = useMemo(() => ({
182
+ value: current.modelValue,
183
+ onChange,
184
+ onReady,
185
+ collaboration: current.session
186
+ }), [
187
+ current.modelValue,
188
+ current.session,
189
+ onChange,
190
+ onReady
191
+ ]);
192
+ return {
193
+ modelValue: current.modelValue,
194
+ onChange,
195
+ ready: current.ready,
196
+ dirty,
197
+ save,
198
+ reload,
199
+ error: current.error,
200
+ collaboration: current.session,
201
+ comments,
202
+ editor: current.editor,
203
+ bind
204
+ };
205
+ }
206
+ //#endregion
207
+ export { useEditorDocument };
208
+
209
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.js","names":[],"sources":["../../src/adapters/react.ts"],"sourcesContent":["import type { Editor, JSONContent } from '@tiptap/core'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { CollaborationSession } from '../core'\nimport type { CommentsModel } from '../core/backend-types'\nimport { useOptionalEditorContext } from '../react/context'\nimport { type EditorDocumentOptions, errorOf, fingerprintToSave, isDirty, loadedDocument, openSession, requireCapability } from './document-state'\n\n// The React side of an editor document, the twin of `useEditorDocument` in `./adapters/vue`: load it through the\n// backend's `documents`, keep track of unsaved edits, save it, and hand the editor surface what it needs (value and\n// onChange, collaboration session, comments model). All three go through `EditorBackend`; nothing here knows a URL.\n\nexport type { EditorDocumentOptions } from './document-state'\n\n/** The props of the editor surface (`EditorSurface`, `AdvancedEditor`) that `useEditorDocument` fills. */\nexport interface EditorDocumentBinding {\n /** The document (standalone mode); `undefined` in collaboration mode and until it has loaded. */\n value: JSONContent | undefined\n onChange: (content: JSONContent) => void\n /** Hands the live editor to the comments model. */\n onReady: (editor: Editor) => void\n collaboration: CollaborationSession | undefined\n}\n\nexport interface EditorDocument {\n /** The document's TipTap JSON: the surface's `value`. `undefined` until loaded, and always in collaboration mode. */\n modelValue: JSONContent | undefined\n /** Replaces `modelValue` (the surface's `onChange`). */\n onChange: (content: JSONContent) => void\n /** `true` once the surface can be mounted: the content has loaded (a missing document starts empty), or the collaboration session exists. Mount with `key` = the id, so a changed id remounts it. */\n ready: boolean\n /** Edits since the content was loaded or last saved. */\n dirty: boolean\n /** Stores the current content (`backend.documents.save`); several calls run one after another and an edit made while one is in flight stays dirty. Rejects with the backend's refusal. */\n save: () => Promise<void>\n /** Loads the content again and drops unsaved edits (in collaboration mode: reconnects). */\n reload: () => Promise<void>\n /** The last load or save error, `null` while all is well. */\n error: Error | null\n /** The collaboration session for the surface's `collaboration` prop; `undefined` without the `collaboration` option, and never the session of another document. */\n collaboration: CollaborationSession | undefined\n /**\n * The comments model of this document, made by `backend.comments` (`undefined` when the backend has none, and until\n * the first effect ran). A new one per id. The feature's `model` factory runs when the editor is created, so read it\n * through a ref the host keeps current: `commentsFeature({ model: () => commentsRef.current! })`.\n */\n comments: CommentsModel | undefined\n /** The live editor, once the surface reported it. */\n editor: Editor | undefined\n /** Spread target for the surface: `<AdvancedEditor key={id} {...bind} />` once `ready`. */\n bind: EditorDocumentBinding\n}\n\n/** What the hook shows of one document; a state of another id is never shown. */\ninterface DocumentState {\n id: string\n ready: boolean\n modelValue: JSONContent | undefined\n /** Fingerprint (`fingerprint`) of the JSON the backend holds (the empty document while it does not exist), `null` before the first load. */\n saved: string | null\n error: Error | null\n session: CollaborationSession | undefined\n editor: Editor | undefined\n}\n\nconst fresh = (id: string): DocumentState => ({ id, ready: false, modelValue: undefined, saved: null, error: null, session: undefined, editor: undefined })\n\n/**\n * Loads document `id` through `backend.documents` (a missing document starts empty; the first `save()` creates it),\n * tracks edits, saves, and prepares the collaboration session (`backend.collaboration`) and comments model\n * (`backend.comments`) for the editor surface. The backend is `options.backend`, else the editor context's\n * (`EditorContextProvider`); keep it stable across renders (a new object reloads the document). A changed `id` loads the\n * other document and replaces the session and the comments model. Throws when `collaboration` is set and the backend\n * cannot collaborate, or when it keeps no documents.\n */\nexport function useEditorDocument(documentId: string | null | undefined, options: EditorDocumentOptions = {}): EditorDocument {\n /** `''` = no document open (the host has none yet, e.g. it still waits for the signed-in user): the hook stays idle. */\n const id = documentId ?? ''\n const context = useOptionalEditorContext()\n const backend = options.backend ?? context?.backend\n if (!backend) throw new Error('@ecsplico/editor: useEditorDocument needs a backend: pass `backend` or wrap the tree in <EditorContextProvider context={createEditorContext()}>')\n const collaborating = Boolean(options.collaboration)\n const documents = collaborating ? undefined : requireCapability(backend, 'documents')\n const collaborationPort = collaborating ? requireCapability(backend, 'collaboration') : undefined\n\n const [state, setState] = useState(() => fresh(id))\n const [comments, setComments] = useState<CommentsModel>()\n const [attempt, setAttempt] = useState(0)\n /** What the callbacks read: the open id, and the latest options and values (an edit just reported is here before the next render). */\n const live = useRef({ id, options, modelValue: undefined as JSONContent | undefined, saved: null as string | null, ready: false, missing: false, editor: undefined as Editor | undefined })\n live.current.id = id\n live.current.options = options\n const generation = useRef(0)\n const tail = useRef<Promise<unknown>>(Promise.resolve())\n const current = state.id === id ? state : fresh(id)\n\n const userOf = useCallback(() => {\n const { user } = live.current.options\n return (typeof user === 'function' ? user() : user) ?? null\n }, [])\n\n const commit = useCallback((documentId: string, change: Partial<Omit<DocumentState, 'id'>>) => {\n if (documentId !== live.current.id) return\n if ('modelValue' in change) live.current.modelValue = change.modelValue\n if ('saved' in change) live.current.saved = change.saved ?? null\n if ('ready' in change) live.current.ready = change.ready ?? false\n if ('editor' in change) live.current.editor = change.editor\n setState(previous => (previous.id === documentId ? { ...previous, ...change } : previous))\n }, [])\n\n const fetchContent = useCallback(async (documentId: string, mine: number) => {\n try {\n const content = await documents!.load(documentId)\n if (mine !== generation.current) return\n const { modelValue, saved, missing } = loadedDocument(content)\n live.current.missing = missing\n commit(documentId, { modelValue, saved, ready: true })\n }\n catch (cause) {\n if (mine === generation.current) commit(documentId, { error: errorOf(cause) })\n }\n }, [documents, commit])\n\n const start = useCallback((documentId: string): number => {\n const mine = ++generation.current\n Object.assign(live.current, { modelValue: undefined, saved: null, ready: false, missing: false, editor: undefined })\n setState(fresh(documentId))\n return mine\n }, [])\n\n // The document, or its collaboration session (created in the effect, not during render, so StrictMode's double mount\n // leaves exactly one live provider).\n useEffect(() => {\n const mine = start(id)\n if (!id) return\n if (collaborationPort) {\n const { session, close } = openSession(collaborationPort, id, live.current.options.collaboration, userOf())\n commit(id, { session, ready: true })\n return () => {\n generation.current++\n close()\n }\n }\n void fetchContent(id, mine)\n return () => { generation.current++ }\n }, [id, collaborationPort, attempt, start, commit, fetchContent, userOf])\n\n // The comments model of the open document.\n useEffect(() => {\n if (!id) return\n const model = backend.comments?.(id, {\n user: userOf,\n canComment: () => {\n const { canComment } = live.current.options\n return (typeof canComment === 'function' ? canComment() : canComment) ?? true\n },\n getEditor: () => live.current.editor,\n onError: cause => commit(id, { error: cause }),\n })\n setComments(model)\n return () => {\n model?.dispose()\n setComments(undefined)\n }\n }, [backend, id, userOf, commit])\n\n const save = useCallback((): Promise<void> => {\n if (!documents) return Promise.resolve()\n const run = async () => {\n const documentId = live.current.id\n const content = live.current.modelValue\n const saved = fingerprintToSave(content, live.current.ready, live.current.saved, live.current.missing)\n if (content === undefined || saved === null) return\n try {\n await documents.save(documentId, content)\n }\n catch (cause) {\n commit(documentId, { error: errorOf(cause) })\n throw cause\n }\n // Only if the document did not change to another id while the request was in flight.\n if (documentId === live.current.id) live.current.missing = false\n commit(documentId, { saved, error: null })\n }\n const result = tail.current.then(run, run)\n tail.current = result.catch(() => {})\n return result\n }, [documents, commit])\n\n const reload = useCallback(async () => {\n if (collaborationPort) {\n setAttempt(count => count + 1)\n return\n }\n await fetchContent(live.current.id, start(live.current.id))\n }, [collaborationPort, fetchContent, start])\n\n const onChange = useCallback((content: JSONContent) => commit(live.current.id, { modelValue: content }), [commit])\n const onReady = useCallback((editor: Editor) => commit(live.current.id, { editor }), [commit])\n const dirty = useMemo(() => isDirty(collaborating, current.modelValue, current.saved), [collaborating, current.modelValue, current.saved])\n const bind = useMemo<EditorDocumentBinding>(\n () => ({ value: current.modelValue, onChange, onReady, collaboration: current.session }),\n [current.modelValue, current.session, onChange, onReady],\n )\n\n return { modelValue: current.modelValue, onChange, ready: current.ready, dirty, save, reload, error: current.error, collaboration: current.session, comments, editor: current.editor, bind }\n}\n"],"mappings":"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"}