@ecsplico/editor 2.1.2 → 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 (692) hide show
  1. package/CHANGELOG.md +68 -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/config/index.d.ts +105 -0
  41. package/dist/config/index.js +95 -0
  42. package/dist/config/index.js.map +1 -0
  43. package/dist/core/abilities.js +1 -0
  44. package/dist/core/abilities.js.map +1 -1
  45. package/dist/{adapters/routes.js → core/api-routes.js} +5 -3
  46. package/dist/core/api-routes.js.map +1 -0
  47. package/dist/core/backend-capability.d.ts +7 -0
  48. package/dist/core/backend-capability.js +17 -0
  49. package/dist/core/backend-capability.js.map +1 -0
  50. package/dist/core/backend-types.d.ts +245 -0
  51. package/dist/core/backend-types.js +17 -0
  52. package/dist/core/backend-types.js.map +1 -0
  53. package/dist/core/backend.d.ts +108 -0
  54. package/dist/core/backend.js +14 -0
  55. package/dist/core/backend.js.map +1 -0
  56. package/dist/core/block-convert.d.ts +7 -5
  57. package/dist/core/block-convert.js +28 -5
  58. package/dist/core/block-convert.js.map +1 -1
  59. package/dist/core/command-types.d.ts +89 -0
  60. package/dist/core/commands.d.ts +40 -0
  61. package/dist/core/commands.js +151 -0
  62. package/dist/core/commands.js.map +1 -0
  63. package/dist/core/context.d.ts +17 -20
  64. package/dist/core/context.js +24 -21
  65. package/dist/core/context.js.map +1 -1
  66. package/dist/core/core-feature.d.ts +22 -7
  67. package/dist/core/core-feature.js +51 -18
  68. package/dist/core/core-feature.js.map +1 -1
  69. package/dist/core/define-editor.d.ts +4 -3
  70. package/dist/core/define-editor.js +14 -7
  71. package/dist/core/define-editor.js.map +1 -1
  72. package/dist/core/document-markdown.js +12 -3
  73. package/dist/core/document-markdown.js.map +1 -1
  74. package/dist/core/editor-ui.d.ts +8 -1
  75. package/dist/core/editor-ui.js +9 -8
  76. package/dist/core/editor-ui.js.map +1 -1
  77. package/dist/core/extension-points.d.ts +3 -15
  78. package/dist/core/feature-context.d.ts +8 -7
  79. package/dist/core/feature-context.js +12 -11
  80. package/dist/core/feature-context.js.map +1 -1
  81. package/dist/core/feature.d.ts +35 -19
  82. package/dist/core/feature.js.map +1 -1
  83. package/dist/core/fences.d.ts +2 -1
  84. package/dist/core/fences.js +3 -2
  85. package/dist/core/fences.js.map +1 -1
  86. package/dist/core/fetch-error.d.ts +1 -1
  87. package/dist/core/fetch-error.js +3 -1
  88. package/dist/core/fetch-error.js.map +1 -1
  89. package/dist/core/hash.d.ts +5 -0
  90. package/dist/core/hash.js +11 -0
  91. package/dist/core/hash.js.map +1 -0
  92. package/dist/core/http-backend.d.ts +11 -0
  93. package/dist/core/http-backend.js +195 -0
  94. package/dist/core/http-backend.js.map +1 -0
  95. package/dist/core/index.d.ts +14 -9
  96. package/dist/core/index.js +12 -9
  97. package/dist/core/palette.d.ts +48 -0
  98. package/dist/core/palette.js +95 -0
  99. package/dist/core/palette.js.map +1 -0
  100. package/dist/core/schema/abilities.d.ts +2 -1
  101. package/dist/core/schema/abilities.js +5 -1
  102. package/dist/core/schema/abilities.js.map +1 -1
  103. package/dist/core/schema/index.d.ts +11 -5
  104. package/dist/core/schema/index.js +13 -8
  105. package/dist/core/schema/index.js.map +1 -1
  106. package/dist/core/schema/mark-flags.d.ts +8 -1
  107. package/dist/core/schema/of-features.d.ts +13 -0
  108. package/dist/core/schema/of-features.js +14 -0
  109. package/dist/core/schema/of-features.js.map +1 -0
  110. package/dist/core/slash.d.ts +8 -6
  111. package/dist/core/slash.js +24 -16
  112. package/dist/core/slash.js.map +1 -1
  113. package/dist/core/surface-session.js +13 -5
  114. package/dist/core/surface-session.js.map +1 -1
  115. package/dist/core/toolbar-items.d.ts +10 -4
  116. package/dist/core/toolbar-items.js +269 -195
  117. package/dist/core/toolbar-items.js.map +1 -1
  118. package/dist/core/util.js +11 -0
  119. package/dist/core/util.js.map +1 -0
  120. package/dist/document/DocumentSurface.d.ts +1 -1
  121. package/dist/features/ai/agent-op-review.d.ts +1 -1
  122. package/dist/features/ai/agent-op-review.js +1 -1
  123. package/dist/features/ai/agent-ops.js +1 -1
  124. package/dist/features/ai/ai-apply.d.ts +2 -2
  125. package/dist/features/ai/ai-apply.js +1 -1
  126. package/dist/features/ai/ai-review.js +1 -1
  127. package/dist/features/ai/ai-sse.d.ts +6 -6
  128. package/dist/features/ai/ai-sse.js +20 -63
  129. package/dist/features/ai/ai-sse.js.map +1 -1
  130. package/dist/features/ai/assistant.d.ts +8 -7
  131. package/dist/features/ai/assistant.js +3 -3
  132. package/dist/features/ai/assistant.js.map +1 -1
  133. package/dist/features/ai/block-actions.d.ts +3 -2
  134. package/dist/features/ai/block-actions.js +3 -2
  135. package/dist/features/ai/block-actions.js.map +1 -1
  136. package/dist/features/ai/components/AiSelectionMenu.js +1 -1
  137. package/dist/features/ai/components/DocumentChatAnswer.js +1 -1
  138. package/dist/features/ai/components/DocumentChatOps.vue.d.ts +1 -1
  139. package/dist/features/ai/components/SettingsModelProfiles.js +8 -8
  140. package/dist/features/ai/components/SettingsModelProfiles.js.map +1 -1
  141. package/dist/features/ai/document-chat-model.d.ts +8 -7
  142. package/dist/features/ai/document-chat-model.js +5 -5
  143. package/dist/features/ai/document-chat-model.js.map +1 -1
  144. package/dist/features/ai/document-chat.js +1 -1
  145. package/dist/features/ai/feature.js +27 -14
  146. package/dist/features/ai/feature.js.map +1 -1
  147. package/dist/features/ai/ghost-autocomplete.d.ts +7 -6
  148. package/dist/features/ai/ghost-autocomplete.js +6 -9
  149. package/dist/features/ai/ghost-autocomplete.js.map +1 -1
  150. package/dist/features/ai/index.d.ts +4 -3
  151. package/dist/features/ai/index.js +10 -10
  152. package/dist/features/ai/model-profiles.d.ts +5 -4
  153. package/dist/features/ai/model-profiles.js +2 -2
  154. package/dist/features/ai/model-profiles.js.map +1 -1
  155. package/dist/features/ai/protocol/block-lines.js +1 -1
  156. package/dist/features/ai/protocol/block-lines.js.map +1 -1
  157. package/dist/features/ai/protocol/chat.js +4 -1
  158. package/dist/features/ai/protocol/chat.js.map +1 -1
  159. package/dist/features/ai/protocol/index.d.ts +3 -2
  160. package/dist/features/ai/protocol/models.d.ts +2 -16
  161. package/dist/features/ai/protocol/models.js.map +1 -1
  162. package/dist/features/ai/rate-limit.d.ts +1 -1
  163. package/dist/features/ai/rate-limit.js +3 -1
  164. package/dist/features/ai/rate-limit.js.map +1 -1
  165. package/dist/features/ai/react/AiSelectionMenu.js +2 -2
  166. package/dist/features/ai/react/AiSidebar.js +4 -4
  167. package/dist/features/ai/react/DocumentChatAnswer.js +1 -1
  168. package/dist/features/ai/react/DocumentChatOps.d.ts +1 -1
  169. package/dist/features/ai/react/DocumentChatOps.js +1 -1
  170. package/dist/features/ai/react/SettingsModelProfiles.js +8 -10
  171. package/dist/features/ai/react/SettingsModelProfiles.js.map +1 -1
  172. package/dist/features/ai/react/use-ai-assistant.d.ts +1 -1
  173. package/dist/features/ai/react/use-ai-assistant.js +3 -3
  174. package/dist/features/ai/react/use-ai-assistant.js.map +1 -1
  175. package/dist/features/ai/react/use-document-chat.js +2 -2
  176. package/dist/features/ai/react/use-document-chat.js.map +1 -1
  177. package/dist/features/ai/react/use-model-profiles.d.ts +2 -1
  178. package/dist/features/ai/selection-flow.d.ts +1 -1
  179. package/dist/features/ai/selection-flow.js +1 -1
  180. package/dist/features/ai/sidebar-flow.d.ts +1 -1
  181. package/dist/features/ai/sidebar-flow.js +1 -1
  182. package/dist/features/ai/use-ai-assistant.d.ts +1 -1
  183. package/dist/features/ai/use-ai-assistant.js +3 -3
  184. package/dist/features/ai/use-ai-assistant.js.map +1 -1
  185. package/dist/features/ai/use-document-chat.js +2 -2
  186. package/dist/features/ai/use-document-chat.js.map +1 -1
  187. package/dist/features/ai/use-model-profiles.d.ts +2 -1
  188. package/dist/features/authors/attribution.d.ts +1 -1
  189. package/dist/features/authors/feature.js +12 -11
  190. package/dist/features/authors/feature.js.map +1 -1
  191. package/dist/features/block-ui/block-actions.d.ts +1 -1
  192. package/dist/features/block-ui/block-actions.js +1 -1
  193. package/dist/features/block-ui/block-actions.js.map +1 -1
  194. package/dist/features/block-ui/components/BlockUi.js +1 -1
  195. package/dist/features/block-ui/feature.js +1 -0
  196. package/dist/features/block-ui/feature.js.map +1 -1
  197. package/dist/features/block-ui/react/BlockUi.js +1 -1
  198. package/dist/features/collab/anchor-resolver.js +1 -1
  199. package/dist/features/collab/feature.js +2 -0
  200. package/dist/features/collab/feature.js.map +1 -1
  201. package/dist/features/comments/components/CommentThreadView.vue.d.ts +2 -1
  202. package/dist/features/comments/feature.js +12 -11
  203. package/dist/features/comments/feature.js.map +1 -1
  204. package/dist/features/comments/index.d.ts +3 -2
  205. package/dist/features/comments/index.js +1 -1
  206. package/dist/features/comments/margin-layout.d.ts +3 -2
  207. package/dist/features/comments/model.d.ts +3 -67
  208. package/dist/features/comments/model.js +2 -2
  209. package/dist/features/comments/model.js.map +1 -1
  210. package/dist/features/comments/react/CommentThreadView.d.ts +3 -2
  211. package/dist/features/comments/react/use-comments.d.ts +2 -1
  212. package/dist/features/comments/react.d.ts +1 -1
  213. package/dist/features/comments/schema.d.ts +2 -52
  214. package/dist/features/comments/schema.js.map +1 -1
  215. package/dist/features/comments/snapshot-equality.js.map +1 -1
  216. package/dist/features/comments/use-comments.d.ts +3 -2
  217. package/dist/features/comments/vue.d.ts +1 -1
  218. package/dist/features/composites/accepted-children.d.ts +1 -0
  219. package/dist/features/composites/accepted-children.js +16 -1
  220. package/dist/features/composites/accepted-children.js.map +1 -1
  221. package/dist/features/composites/ai-brief.js +31 -0
  222. package/dist/features/composites/ai-brief.js.map +1 -1
  223. package/dist/features/composites/bibliography-command.d.ts +11 -0
  224. package/dist/features/composites/bibliography-form.js +90 -0
  225. package/dist/features/composites/bibliography-form.js.map +1 -0
  226. package/dist/features/composites/bibliography.d.ts +33 -0
  227. package/dist/features/composites/bibliography.js +120 -0
  228. package/dist/features/composites/bibliography.js.map +1 -0
  229. package/dist/features/composites/components/BibliographyEditor.js +261 -0
  230. package/dist/features/composites/components/BibliographyEditor.js.map +1 -0
  231. package/dist/features/composites/components/CompositeChrome.js +75 -26
  232. package/dist/features/composites/components/CompositeChrome.js.map +1 -1
  233. package/dist/features/composites/components/CompositeDetails.js +46 -11
  234. package/dist/features/composites/components/CompositeDetails.js.map +1 -1
  235. package/dist/features/composites/components/CompositeDetails.vue.d.ts +2 -1
  236. package/dist/features/composites/components/CompositeFieldEditor.js +37 -4
  237. package/dist/features/composites/components/CompositeFieldEditor.js.map +1 -1
  238. package/dist/features/composites/components/CompositeInspector.js +17 -5
  239. package/dist/features/composites/components/CompositeInspector.js.map +1 -1
  240. package/dist/features/composites/components/CompositeTable.js +13 -4
  241. package/dist/features/composites/components/CompositeTable.js.map +1 -1
  242. package/dist/features/composites/components/CompositeTagsEditor.js +1 -1
  243. package/dist/features/composites/components/CompositeView.js +11 -1
  244. package/dist/features/composites/components/CompositeView.js.map +1 -1
  245. package/dist/features/composites/components/DerivationBadge.js +103 -0
  246. package/dist/features/composites/components/DerivationBadge.js.map +1 -0
  247. package/dist/features/composites/components/ReferenceFieldSelect.js +60 -0
  248. package/dist/features/composites/components/ReferenceFieldSelect.js.map +1 -0
  249. package/dist/features/composites/components/ReferenceView.js +122 -0
  250. package/dist/features/composites/components/ReferenceView.js.map +1 -0
  251. package/dist/features/composites/components/ReferenceView.vue.d.ts +96 -0
  252. package/dist/features/composites/components/SettingsEditingTab.js +1 -1
  253. package/dist/features/composites/convert.js +2 -2
  254. package/dist/features/composites/convert.js.map +1 -1
  255. package/dist/features/composites/derivation.d.ts +61 -0
  256. package/dist/features/composites/derivation.js +98 -0
  257. package/dist/features/composites/derivation.js.map +1 -0
  258. package/dist/features/composites/derived-chrome.js +69 -0
  259. package/dist/features/composites/derived-chrome.js.map +1 -0
  260. package/dist/features/composites/feature.js +159 -109
  261. package/dist/features/composites/feature.js.map +1 -1
  262. package/dist/features/composites/fences.d.ts +4 -3
  263. package/dist/features/composites/fences.js +51 -7
  264. package/dist/features/composites/fences.js.map +1 -1
  265. package/dist/features/composites/index.d.ts +12 -3
  266. package/dist/features/composites/index.js +15 -6
  267. package/dist/features/composites/inspector-model.d.ts +4 -1
  268. package/dist/features/composites/inspector-model.js +8 -4
  269. package/dist/features/composites/inspector-model.js.map +1 -1
  270. package/dist/features/composites/kinds.d.ts +8 -1
  271. package/dist/features/composites/kinds.js +145 -6
  272. package/dist/features/composites/kinds.js.map +1 -1
  273. package/dist/features/composites/legacy.d.ts +4 -1
  274. package/dist/features/composites/legacy.js +56 -1
  275. package/dist/features/composites/legacy.js.map +1 -1
  276. package/dist/features/composites/meta-display.js +40 -1
  277. package/dist/features/composites/meta-display.js.map +1 -1
  278. package/dist/features/composites/meta-keys.d.ts +7 -0
  279. package/dist/features/composites/meta-keys.js +21 -0
  280. package/dist/features/composites/meta-keys.js.map +1 -0
  281. package/dist/features/composites/node-views.d.ts +6 -3
  282. package/dist/features/composites/node-views.js +7 -3
  283. package/dist/features/composites/node-views.js.map +1 -1
  284. package/dist/features/composites/nodes.d.ts +6 -1
  285. package/dist/features/composites/nodes.js +33 -7
  286. package/dist/features/composites/nodes.js.map +1 -1
  287. package/dist/features/composites/react/BibliographyEditor.js +229 -0
  288. package/dist/features/composites/react/BibliographyEditor.js.map +1 -0
  289. package/dist/features/composites/react/CompositeChrome.js +65 -17
  290. package/dist/features/composites/react/CompositeChrome.js.map +1 -1
  291. package/dist/features/composites/react/CompositeDetails.d.ts +2 -1
  292. package/dist/features/composites/react/CompositeDetails.js +45 -6
  293. package/dist/features/composites/react/CompositeDetails.js.map +1 -1
  294. package/dist/features/composites/react/CompositeFieldEditor.d.ts +1 -1
  295. package/dist/features/composites/react/CompositeFieldEditor.js +24 -1
  296. package/dist/features/composites/react/CompositeFieldEditor.js.map +1 -1
  297. package/dist/features/composites/react/CompositeInspector.js +11 -5
  298. package/dist/features/composites/react/CompositeInspector.js.map +1 -1
  299. package/dist/features/composites/react/CompositeStatusMenu.js +1 -1
  300. package/dist/features/composites/react/CompositeSummaryEditor.js +1 -1
  301. package/dist/features/composites/react/CompositeTable.js +16 -2
  302. package/dist/features/composites/react/CompositeTable.js.map +1 -1
  303. package/dist/features/composites/react/CompositeTagsEditor.js +2 -2
  304. package/dist/features/composites/react/CompositeView.js +6 -1
  305. package/dist/features/composites/react/CompositeView.js.map +1 -1
  306. package/dist/features/composites/react/DerivationBadge.js +116 -0
  307. package/dist/features/composites/react/DerivationBadge.js.map +1 -0
  308. package/dist/features/composites/react/ReferenceFieldSelect.js +52 -0
  309. package/dist/features/composites/react/ReferenceFieldSelect.js.map +1 -0
  310. package/dist/features/composites/react/ReferenceView.d.ts +11 -0
  311. package/dist/features/composites/react/ReferenceView.js +115 -0
  312. package/dist/features/composites/react/ReferenceView.js.map +1 -0
  313. package/dist/features/composites/react/SettingsEditingTab.js +2 -2
  314. package/dist/features/composites/react.d.ts +2 -1
  315. package/dist/features/composites/react.js +7 -3
  316. package/dist/features/composites/react.js.map +1 -1
  317. package/dist/features/composites/reference-ai.js +16 -0
  318. package/dist/features/composites/reference-ai.js.map +1 -0
  319. package/dist/features/composites/reference-label.d.ts +19 -0
  320. package/dist/features/composites/reference-label.js +58 -0
  321. package/dist/features/composites/reference-label.js.map +1 -0
  322. package/dist/features/composites/reference-suggestion.d.ts +10 -0
  323. package/dist/features/composites/reference-suggestion.js +41 -0
  324. package/dist/features/composites/reference-suggestion.js.map +1 -0
  325. package/dist/features/composites/reference-text.d.ts +18 -0
  326. package/dist/features/composites/reference-text.js +89 -0
  327. package/dist/features/composites/reference-text.js.map +1 -0
  328. package/dist/features/composites/reference.d.ts +44 -0
  329. package/dist/features/composites/reference.js +148 -0
  330. package/dist/features/composites/reference.js.map +1 -0
  331. package/dist/features/composites/reveal-source.d.ts +32 -0
  332. package/dist/features/composites/reveal-source.js +89 -0
  333. package/dist/features/composites/reveal-source.js.map +1 -0
  334. package/dist/features/composites/rows.d.ts +21 -2
  335. package/dist/features/composites/rows.js +63 -9
  336. package/dist/features/composites/rows.js.map +1 -1
  337. package/dist/features/composites/schema.d.ts +9 -3
  338. package/dist/features/composites/schema.js +11 -4
  339. package/dist/features/composites/schema.js.map +1 -1
  340. package/dist/features/composites/table-model.js +12 -21
  341. package/dist/features/composites/table-model.js.map +1 -1
  342. package/dist/features/composites/vue.d.ts +3 -2
  343. package/dist/features/composites/vue.js +8 -4
  344. package/dist/features/composites/vue.js.map +1 -1
  345. package/dist/features/media/assets.d.ts +2 -0
  346. package/dist/features/media/assets.js +3 -2
  347. package/dist/features/media/assets.js.map +1 -1
  348. package/dist/features/media/components/FileView.js +13 -4
  349. package/dist/features/media/components/FileView.js.map +1 -1
  350. package/dist/features/media/feature.d.ts +3 -3
  351. package/dist/features/media/feature.js +21 -28
  352. package/dist/features/media/feature.js.map +1 -1
  353. package/dist/features/media/file-import.js +2 -2
  354. package/dist/features/media/file-import.js.map +1 -1
  355. package/dist/features/media/index.d.ts +2 -2
  356. package/dist/features/media/index.js +2 -2
  357. package/dist/features/media/react/FileView.js +19 -2
  358. package/dist/features/media/react/FileView.js.map +1 -1
  359. package/dist/features/media/schema.d.ts +8 -0
  360. package/dist/features/media/schema.js +126 -11
  361. package/dist/features/media/schema.js.map +1 -1
  362. package/dist/features/media/upload.d.ts +16 -14
  363. package/dist/features/media/upload.js +13 -19
  364. package/dist/features/media/upload.js.map +1 -1
  365. package/dist/features/mentions/index.d.ts +4 -3
  366. package/dist/features/mentions/index.js +4 -1
  367. package/dist/features/mentions/index.js.map +1 -1
  368. package/dist/features/mentions/mention-text.d.ts +1 -1
  369. package/dist/features/mentions/mention-text.js.map +1 -1
  370. package/dist/features/mentions/mention.d.ts +0 -6
  371. package/dist/features/mentions/mention.js.map +1 -1
  372. package/dist/features/mentions/metadata-defaults.d.ts +2 -2
  373. package/dist/features/mentions/metadata-defaults.js +3 -9
  374. package/dist/features/mentions/metadata-defaults.js.map +1 -1
  375. package/dist/features/mentions/schema.d.ts +2 -1
  376. package/dist/features/mentions/schema.js.map +1 -1
  377. package/dist/features/tables/feature.d.ts +2 -1
  378. package/dist/features/tables/feature.js +90 -70
  379. package/dist/features/tables/feature.js.map +1 -1
  380. package/dist/features/themes/components/SettingsAppearanceTab.js +6 -9
  381. package/dist/features/themes/components/SettingsAppearanceTab.js.map +1 -1
  382. package/dist/features/themes/feature.js +2 -0
  383. package/dist/features/themes/feature.js.map +1 -1
  384. package/dist/features/themes/index.d.ts +2 -1
  385. package/dist/features/themes/react/SettingsAppearanceTab.js +7 -10
  386. package/dist/features/themes/react/SettingsAppearanceTab.js.map +1 -1
  387. package/dist/features/themes/schema.d.ts +2 -6
  388. package/dist/features/themes/schema.js.map +1 -1
  389. package/dist/features/themes/theme-runtime.d.ts +1 -1
  390. package/dist/features/themes/theme-runtime.js +4 -2
  391. package/dist/features/themes/theme-runtime.js.map +1 -1
  392. package/dist/features/transcript/TranscriptSegmentView.js +48 -28
  393. package/dist/features/transcript/TranscriptSegmentView.js.map +1 -1
  394. package/dist/features/transcript/feature.js +21 -19
  395. package/dist/features/transcript/feature.js.map +1 -1
  396. package/dist/features/transcript/react/TranscriptSegmentView.js +55 -36
  397. package/dist/features/transcript/react/TranscriptSegmentView.js.map +1 -1
  398. package/dist/features/transcript/segment-node.d.ts +2 -0
  399. package/dist/features/transcript/segment-node.js +35 -7
  400. package/dist/features/transcript/segment-node.js.map +1 -1
  401. package/dist/i18n/de/composites.js +91 -1
  402. package/dist/i18n/de/composites.js.map +1 -1
  403. package/dist/i18n/de/integrations.js +49 -8
  404. package/dist/i18n/de/integrations.js.map +1 -1
  405. package/dist/i18n/de/media.js +0 -1
  406. package/dist/i18n/de/media.js.map +1 -1
  407. package/dist/i18n/de/palette.js +22 -0
  408. package/dist/i18n/de/palette.js.map +1 -0
  409. package/dist/i18n/de/tables.js +0 -1
  410. package/dist/i18n/de/tables.js.map +1 -1
  411. package/dist/i18n/de/transcript.js +2 -1
  412. package/dist/i18n/de/transcript.js.map +1 -1
  413. package/dist/i18n/de/tree.js +3 -0
  414. package/dist/i18n/de/tree.js.map +1 -1
  415. package/dist/i18n/de.d.ts +157 -11
  416. package/dist/i18n/de.js +3 -1
  417. package/dist/i18n/de.js.map +1 -1
  418. package/dist/i18n/en/composites.js +89 -1
  419. package/dist/i18n/en/composites.js.map +1 -1
  420. package/dist/i18n/en/integrations.js +49 -8
  421. package/dist/i18n/en/integrations.js.map +1 -1
  422. package/dist/i18n/en/media.js +0 -1
  423. package/dist/i18n/en/media.js.map +1 -1
  424. package/dist/i18n/en/palette.js +22 -0
  425. package/dist/i18n/en/palette.js.map +1 -0
  426. package/dist/i18n/en/tables.js +0 -1
  427. package/dist/i18n/en/tables.js.map +1 -1
  428. package/dist/i18n/en/transcript.js +2 -1
  429. package/dist/i18n/en/transcript.js.map +1 -1
  430. package/dist/i18n/en/tree.js +3 -0
  431. package/dist/i18n/en/tree.js.map +1 -1
  432. package/dist/i18n/en.js +3 -1
  433. package/dist/i18n/en.js.map +1 -1
  434. package/dist/index.d.ts +4 -3
  435. package/dist/integrations/composite-ai/bibliography-fetch.d.ts +31 -0
  436. package/dist/integrations/composite-ai/bibliography-fetch.js +159 -0
  437. package/dist/integrations/composite-ai/bibliography-fetch.js.map +1 -0
  438. package/dist/integrations/composite-ai/composite-fill.d.ts +30 -8
  439. package/dist/integrations/composite-ai/composite-fill.js +97 -56
  440. package/dist/integrations/composite-ai/composite-fill.js.map +1 -1
  441. package/dist/integrations/composite-ai/composite-summary.d.ts +4 -12
  442. package/dist/integrations/composite-ai/composite-summary.js +7 -26
  443. package/dist/integrations/composite-ai/composite-summary.js.map +1 -1
  444. package/dist/integrations/composite-ai/derive.d.ts +29 -0
  445. package/dist/integrations/composite-ai/derive.js +173 -0
  446. package/dist/integrations/composite-ai/derive.js.map +1 -0
  447. package/dist/integrations/composite-ai/index.d.ts +11 -7
  448. package/dist/integrations/composite-ai/index.js +72 -14
  449. package/dist/integrations/composite-ai/index.js.map +1 -1
  450. package/dist/integrations/composite-ai/rendition.d.ts +45 -0
  451. package/dist/integrations/composite-ai/rendition.js +314 -0
  452. package/dist/integrations/composite-ai/rendition.js.map +1 -0
  453. package/dist/integrations/composite-media/index.d.ts +7 -5
  454. package/dist/integrations/composite-media/index.js +86 -13
  455. package/dist/integrations/composite-media/index.js.map +1 -1
  456. package/dist/integrations/transcript-ai/index.d.ts +1 -1
  457. package/dist/integrations/transcript-ai/index.js +5 -2
  458. package/dist/integrations/transcript-ai/index.js.map +1 -1
  459. package/dist/integrations/transcript-ai/protocol.d.ts +2 -12
  460. package/dist/integrations/transcript-ai/protocol.js +0 -2
  461. package/dist/integrations/transcript-ai/protocol.js.map +1 -1
  462. package/dist/integrations/transcript-ai/transcript-cleanup.d.ts +5 -5
  463. package/dist/integrations/transcript-ai/transcript-cleanup.js +7 -10
  464. package/dist/integrations/transcript-ai/transcript-cleanup.js.map +1 -1
  465. package/dist/markdown/MarkdownSurface.vue.d.ts +6 -5
  466. package/dist/markdown/MarkdownSurface2.js +3 -6
  467. package/dist/markdown/MarkdownSurface2.js.map +1 -1
  468. package/dist/markdown/document.js +1 -1
  469. package/dist/markdown/source-mode.d.ts +1 -1
  470. package/dist/nuxt/module.d.ts +1402 -54
  471. package/dist/nuxt/module.js +6 -49
  472. package/dist/nuxt/module.js.map +1 -1
  473. package/dist/nuxt/runtime/install-context.d.ts +7 -3
  474. package/dist/nuxt/runtime/install-context.js +14 -8
  475. package/dist/nuxt/runtime/install-context.js.map +1 -1
  476. package/dist/nuxt/runtime/plugins/editor-context-nuxt-ui.client.ts +2 -2
  477. package/dist/nuxt/runtime/server/plugins/editor-server.js +20 -12
  478. package/dist/nuxt/runtime/server/plugins/editor-server.js.map +1 -1
  479. package/dist/presets/compose.d.ts +94 -0
  480. package/dist/presets/compose.js +164 -0
  481. package/dist/presets/compose.js.map +1 -0
  482. package/dist/react/AdvancedEditor.d.ts +15 -15
  483. package/dist/react/AdvancedEditor.js +15 -13
  484. package/dist/react/AdvancedEditor.js.map +1 -1
  485. package/dist/react/EditorCommandPalette.d.ts +13 -0
  486. package/dist/react/EditorCommandPalette.js +118 -0
  487. package/dist/react/EditorCommandPalette.js.map +1 -0
  488. package/dist/react/EditorSettingsModal.d.ts +5 -5
  489. package/dist/react/EditorSettingsModal.js +7 -4
  490. package/dist/react/EditorSettingsModal.js.map +1 -1
  491. package/dist/react/EditorSettingsPanel.d.ts +7 -7
  492. package/dist/react/EditorSettingsPanel.js +8 -5
  493. package/dist/react/EditorSettingsPanel.js.map +1 -1
  494. package/dist/react/EditorSurface.d.ts +7 -7
  495. package/dist/react/EditorSurface.js +10 -6
  496. package/dist/react/EditorSurface.js.map +1 -1
  497. package/dist/react/EditorToolbar.d.ts +4 -6
  498. package/dist/react/EditorToolbar.js +29 -37
  499. package/dist/react/EditorToolbar.js.map +1 -1
  500. package/dist/react/SimpleEditor.d.ts +22 -23
  501. package/dist/react/SimpleEditor.js +21 -7
  502. package/dist/react/SimpleEditor.js.map +1 -1
  503. package/dist/react/advanced.d.ts +4 -3
  504. package/dist/react/advanced.js +2 -2
  505. package/dist/react/compose.d.ts +20 -0
  506. package/dist/react/compose.js +49 -0
  507. package/dist/react/compose.js.map +1 -0
  508. package/dist/react/composed-surface.d.ts +39 -0
  509. package/dist/react/composed-surface.js +71 -0
  510. package/dist/react/composed-surface.js.map +1 -0
  511. package/dist/react/context.js +6 -2
  512. package/dist/react/context.js.map +1 -1
  513. package/dist/react/index.d.ts +2 -1
  514. package/dist/react/index.js +2 -1
  515. package/dist/react/key-labels.js +15 -0
  516. package/dist/react/key-labels.js.map +1 -0
  517. package/dist/react/settings.d.ts +1 -1
  518. package/dist/react/simple.d.ts +2 -2
  519. package/dist/react/ui/command.js +36 -1
  520. package/dist/react/ui/command.js.map +1 -1
  521. package/dist/schema/advanced.d.ts +6 -6
  522. package/dist/schema/advanced.js +26 -29
  523. package/dist/schema/advanced.js.map +1 -1
  524. package/dist/server/ai.d.ts +5 -16
  525. package/dist/server/ai.js.map +1 -1
  526. package/dist/server/auth.d.ts +9 -0
  527. package/dist/server/collab-state.d.ts +1 -1
  528. package/dist/server/collab-state.js.map +1 -1
  529. package/dist/server/collab.d.ts +13 -13
  530. package/dist/server/collab.js +34 -18
  531. package/dist/server/collab.js.map +1 -1
  532. package/dist/server/crossref.js +78 -0
  533. package/dist/server/crossref.js.map +1 -0
  534. package/dist/server/errors.d.ts +1 -1
  535. package/dist/server/errors.js +1 -1
  536. package/dist/server/errors.js.map +1 -1
  537. package/dist/server/extract.js +308 -0
  538. package/dist/server/extract.js.map +1 -0
  539. package/dist/{nuxt/runtime/server/utils/editor-route.js → server/h3.js} +8 -16
  540. package/dist/server/h3.js.map +1 -0
  541. package/dist/server/handlers/ai.d.ts +30 -9
  542. package/dist/server/handlers/ai.js +170 -36
  543. package/dist/server/handlers/ai.js.map +1 -1
  544. package/dist/server/handlers/context.d.ts +12 -5
  545. package/dist/server/handlers/context.js +10 -4
  546. package/dist/server/handlers/context.js.map +1 -1
  547. package/dist/server/handlers/editor.d.ts +19 -13
  548. package/dist/server/handlers/editor.js +49 -38
  549. package/dist/server/handlers/editor.js.map +1 -1
  550. package/dist/server/handlers/index.d.ts +4 -4
  551. package/dist/server/handlers/index.js +4 -4
  552. package/dist/server/host.d.ts +16 -25
  553. package/dist/server/host.js +58 -41
  554. package/dist/server/host.js.map +1 -1
  555. package/dist/server/index.d.ts +6 -4
  556. package/dist/server/index.js +3 -2
  557. package/dist/server/pdf.js +97 -0
  558. package/dist/server/pdf.js.map +1 -0
  559. package/dist/server/{adapter.d.ts → ports.d.ts} +81 -30
  560. package/dist/server/ports.js +29 -0
  561. package/dist/server/ports.js.map +1 -0
  562. package/dist/server/routes.js +144 -0
  563. package/dist/server/routes.js.map +1 -0
  564. package/dist/settings/index.d.ts +1 -1
  565. package/dist/settings/index.js.map +1 -1
  566. package/dist/styles/composites.css +25 -0
  567. package/dist/tree/DocumentTree.js +56 -29
  568. package/dist/tree/DocumentTree.js.map +1 -1
  569. package/dist/tree/react/DocumentTree.js +23 -0
  570. package/dist/tree/react/DocumentTree.js.map +1 -1
  571. package/dist/tree/tree-host.js +2 -2
  572. package/dist/tree/tree-items.js +1 -1
  573. package/dist/vue/AdvancedEditor.js +30 -9
  574. package/dist/vue/AdvancedEditor.js.map +1 -1
  575. package/dist/vue/AdvancedEditor.vue.d.ts +28 -8
  576. package/dist/vue/SimpleEditor.js +62 -16
  577. package/dist/vue/SimpleEditor.js.map +1 -1
  578. package/dist/vue/SimpleEditor.vue.d.ts +37 -7
  579. package/dist/vue/advanced.d.ts +3 -2
  580. package/dist/vue/advanced.js +2 -2
  581. package/dist/vue/components/EditorCommandPalette.js +91 -0
  582. package/dist/vue/components/EditorCommandPalette.js.map +1 -0
  583. package/dist/vue/components/EditorCommandPalette.vue.d.ts +15 -0
  584. package/dist/vue/components/EditorSettingsModal.js +10 -6
  585. package/dist/vue/components/EditorSettingsModal.js.map +1 -1
  586. package/dist/vue/components/EditorSettingsModal.vue.d.ts +4 -4
  587. package/dist/vue/components/EditorSettingsPanel.js +10 -6
  588. package/dist/vue/components/EditorSettingsPanel.js.map +1 -1
  589. package/dist/vue/components/EditorSettingsPanel.vue.d.ts +6 -6
  590. package/dist/vue/components/EditorSurface.js +11 -6
  591. package/dist/vue/components/EditorSurface.js.map +1 -1
  592. package/dist/vue/components/EditorSurface.vue.d.ts +7 -7
  593. package/dist/vue/components/EditorToolbar.js +41 -49
  594. package/dist/vue/components/EditorToolbar.js.map +1 -1
  595. package/dist/vue/components/EditorToolbar.vue.d.ts +2 -4
  596. package/dist/vue/compose.d.ts +17 -0
  597. package/dist/vue/compose.js +51 -0
  598. package/dist/vue/compose.js.map +1 -0
  599. package/dist/vue/context-key.d.ts +6 -0
  600. package/dist/vue/context-key.js +6 -0
  601. package/dist/vue/context-key.js.map +1 -0
  602. package/dist/vue/context.d.ts +8 -6
  603. package/dist/vue/context.js +6 -5
  604. package/dist/vue/context.js.map +1 -1
  605. package/dist/vue/index.d.ts +10 -8
  606. package/dist/vue/index.js +10 -8
  607. package/dist/vue/kit/index.d.ts +2 -2
  608. package/dist/vue/kit/nuxt-ui.js +23 -0
  609. package/dist/vue/kit/nuxt-ui.js.map +1 -1
  610. package/dist/vue/kit/types.d.ts +40 -1
  611. package/package.json +30 -16
  612. package/dist/adapters/comments/client.d.ts +0 -64
  613. package/dist/adapters/comments/client.js.map +0 -1
  614. package/dist/adapters/routes.js.map +0 -1
  615. package/dist/core/toolbar.d.ts +0 -74
  616. package/dist/core/toolbar.js +0 -45
  617. package/dist/core/toolbar.js.map +0 -1
  618. package/dist/integrations/composite-ai/document-transcribe.d.ts +0 -14
  619. package/dist/integrations/composite-ai/document-transcribe.js +0 -89
  620. package/dist/integrations/composite-ai/document-transcribe.js.map +0 -1
  621. package/dist/nuxt/runtime/server/api/ai/chat.post.d.ts +0 -5
  622. package/dist/nuxt/runtime/server/api/ai/chat.post.js +0 -8
  623. package/dist/nuxt/runtime/server/api/ai/chat.post.js.map +0 -1
  624. package/dist/nuxt/runtime/server/api/ai/complete.post.d.ts +0 -5
  625. package/dist/nuxt/runtime/server/api/ai/complete.post.js +0 -8
  626. package/dist/nuxt/runtime/server/api/ai/complete.post.js.map +0 -1
  627. package/dist/nuxt/runtime/server/api/ai/generate.post.d.ts +0 -5
  628. package/dist/nuxt/runtime/server/api/ai/generate.post.js +0 -8
  629. package/dist/nuxt/runtime/server/api/ai/generate.post.js.map +0 -1
  630. package/dist/nuxt/runtime/server/api/ai/models.get.d.ts +0 -5
  631. package/dist/nuxt/runtime/server/api/ai/models.get.js +0 -8
  632. package/dist/nuxt/runtime/server/api/ai/models.get.js.map +0 -1
  633. package/dist/nuxt/runtime/server/api/ai/transcribe.post.d.ts +0 -5
  634. package/dist/nuxt/runtime/server/api/ai/transcribe.post.js +0 -8
  635. package/dist/nuxt/runtime/server/api/ai/transcribe.post.js.map +0 -1
  636. package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.d.ts +0 -5
  637. package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.js +0 -8
  638. package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.js.map +0 -1
  639. package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.d.ts +0 -5
  640. package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.js +0 -8
  641. package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.js.map +0 -1
  642. package/dist/nuxt/runtime/server/api/editor/assets/[id].post.d.ts +0 -5
  643. package/dist/nuxt/runtime/server/api/editor/assets/[id].post.js +0 -8
  644. package/dist/nuxt/runtime/server/api/editor/assets/[id].post.js.map +0 -1
  645. package/dist/nuxt/runtime/server/api/editor/settings.get.d.ts +0 -5
  646. package/dist/nuxt/runtime/server/api/editor/settings.get.js +0 -8
  647. package/dist/nuxt/runtime/server/api/editor/settings.get.js.map +0 -1
  648. package/dist/nuxt/runtime/server/api/editor/settings.put.d.ts +0 -5
  649. package/dist/nuxt/runtime/server/api/editor/settings.put.js +0 -8
  650. package/dist/nuxt/runtime/server/api/editor/settings.put.js.map +0 -1
  651. package/dist/nuxt/runtime/server/api/editor/tags.get.d.ts +0 -5
  652. package/dist/nuxt/runtime/server/api/editor/tags.get.js +0 -8
  653. package/dist/nuxt/runtime/server/api/editor/tags.get.js.map +0 -1
  654. package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.d.ts +0 -5
  655. package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.js +0 -8
  656. package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.js.map +0 -1
  657. package/dist/nuxt/runtime/server/api/editor/themes/[id].get.d.ts +0 -5
  658. package/dist/nuxt/runtime/server/api/editor/themes/[id].get.js +0 -8
  659. package/dist/nuxt/runtime/server/api/editor/themes/[id].get.js.map +0 -1
  660. package/dist/nuxt/runtime/server/api/editor/themes/index.get.d.ts +0 -5
  661. package/dist/nuxt/runtime/server/api/editor/themes/index.get.js +0 -8
  662. package/dist/nuxt/runtime/server/api/editor/themes/index.get.js.map +0 -1
  663. package/dist/nuxt/runtime/server/api/editor/themes/index.post.d.ts +0 -5
  664. package/dist/nuxt/runtime/server/api/editor/themes/index.post.js +0 -8
  665. package/dist/nuxt/runtime/server/api/editor/themes/index.post.js.map +0 -1
  666. package/dist/nuxt/runtime/server/api/editor/users.get.d.ts +0 -5
  667. package/dist/nuxt/runtime/server/api/editor/users.get.js +0 -8
  668. package/dist/nuxt/runtime/server/api/editor/users.get.js.map +0 -1
  669. package/dist/nuxt/runtime/server/plugins/collab.d.ts +0 -5
  670. package/dist/nuxt/runtime/server/plugins/collab.js +0 -10
  671. package/dist/nuxt/runtime/server/plugins/collab.js.map +0 -1
  672. package/dist/nuxt/runtime/server/routes/collab/[id].d.ts +0 -5
  673. package/dist/nuxt/runtime/server/routes/collab/[id].js +0 -35
  674. package/dist/nuxt/runtime/server/routes/collab/[id].js.map +0 -1
  675. package/dist/nuxt/runtime/server/utils/editor-route.d.ts +0 -11
  676. package/dist/nuxt/runtime/server/utils/editor-route.js.map +0 -1
  677. package/dist/presets/advanced.d.ts +0 -33
  678. package/dist/presets/advanced.js +0 -50
  679. package/dist/presets/advanced.js.map +0 -1
  680. package/dist/presets/simple.d.ts +0 -9
  681. package/dist/presets/simple.js +0 -12
  682. package/dist/presets/simple.js.map +0 -1
  683. package/dist/react/advanced-preset.d.ts +0 -11
  684. package/dist/react/advanced-preset.js +0 -31
  685. package/dist/react/advanced-preset.js.map +0 -1
  686. package/dist/vue/advanced-preset.d.ts +0 -13
  687. package/dist/vue/advanced-preset.js +0 -33
  688. package/dist/vue/advanced-preset.js.map +0 -1
  689. package/docs/extending.md +0 -538
  690. package/docs/integration.md +0 -632
  691. package/docs/llms.md +0 -383
  692. package/docs/usage.md +0 -1076
@@ -1,53 +1,67 @@
1
1
  import { HttpError } from "./errors.js";
2
- import { createAiModels } from "./ai.js";
3
- import { createCollabServer } from "./collab.js";
4
- import { createRateLimiter } from "./rate-limit.js";
5
2
  import { enforceRateLimit } from "./handlers/context.js";
6
3
  //#region src/server/host.ts
7
- let adapter;
8
- let config = {};
4
+ let ports;
5
+ let schema;
6
+ /** Identity of the live installation; `adoptEditorServer` sets it, its release clears it. */
7
+ let installation;
9
8
  let collab;
10
9
  let models;
11
10
  let limiter;
12
- /** Registers the host's adapter; the collaboration server and the AI models are created from it on first use. Replaces (and closes) those of a previous adapter. */
13
- function setEditorAdapter(next) {
14
- const previous = collab;
15
- adapter = next;
16
- collab = void 0;
17
- models = void 0;
18
- if (previous) previous.close();
11
+ function installed() {
12
+ if (!installation) throw new Error("@ecsplico/editor: server not installed");
19
13
  }
20
- function useEditorAdapter() {
21
- if (!adapter) throw new Error("tiptap-editor: setEditorAdapter() wurde nicht aufgerufen");
22
- return adapter;
14
+ /**
15
+ * Registers the host's ports for installers that read them later (the Nuxt module's server plugin installs on the first
16
+ * request, after every Nitro plugin has run). `options.schema`: the collaboration schema, see `CollabServerOptions.schema`.
17
+ */
18
+ function setEditorPorts(next, options = {}) {
19
+ ports = next;
20
+ schema = options.schema;
23
21
  }
24
- /** Sets the AI configuration and the rate limit of the process-wide server. Call before the first request. */
25
- function configureEditorServer(next) {
26
- config = next;
27
- models = void 0;
28
- limiter = void 0;
22
+ function useEditorPorts() {
23
+ if (!ports) throw new Error("@ecsplico/editor: setEditorPorts() was not called");
24
+ return ports;
29
25
  }
30
- /** The process-wide collaboration server, created from the registered adapter on first use. */
26
+ /** The collaboration schema registered with `setEditorPorts`, for installers that build the collaboration server themselves. */
27
+ function useEditorSchema() {
28
+ return schema;
29
+ }
30
+ /**
31
+ * Makes the server `installEditorServer` built the process-wide one, so host code (`useCollabServer`, `useAiModels`,
32
+ * `liveContent`, `enforceAiRateLimit`, …) reaches the same instances the routes use. Returns the function that drops them
33
+ * again (only when no later installation replaced them); the installer calls it when its host closes.
34
+ */
35
+ function adoptEditorServer(server) {
36
+ const own = {};
37
+ installation = own;
38
+ ports = server.ports;
39
+ schema = server.schema;
40
+ collab = server.collab;
41
+ models = server.models;
42
+ limiter = server.limiter;
43
+ return () => {
44
+ if (installation !== own) return;
45
+ installation = collab = models = limiter = void 0;
46
+ };
47
+ }
48
+ /** The process-wide collaboration server of the installed server. Throws when none is installed or `collab: false`. */
31
49
  function useCollabServer() {
32
- return collab ??= createCollabServer({ adapter: useEditorAdapter() });
50
+ installed();
51
+ if (!collab) throw new Error("@ecsplico/editor: collaboration is off (installEditorServer with collab: false)");
52
+ return collab;
33
53
  }
34
- /** The process-wide AI models: the configured presets, with the adapter's `languageModel`/`listModels` hooks. */
54
+ /** The process-wide AI models of the installed server: its configured presets, with the `models` port's `languageModel`/`listModels` hooks. Throws when none is installed or it was installed without `ai`. */
35
55
  function useAiModels() {
36
- if (models) return models;
37
- const current = useEditorAdapter();
38
- return models = createAiModels({
39
- presets: {},
40
- languageModel: current.languageModel && ((ref, user) => current.languageModel(ref, user)),
41
- listModels: current.listModels && ((user) => current.listModels(user)),
42
- ...config.ai
43
- });
44
- }
45
- /** The process-wide AI rate limiter. */
56
+ installed();
57
+ if (!models) throw new Error("@ecsplico/editor: AI is off (installEditorServer without ai)");
58
+ return models;
59
+ }
60
+ /** The process-wide AI rate limiter of the installed server (present with `ai`). */
46
61
  function useRateLimiter() {
47
- return limiter ??= createRateLimiter(config.rateLimit ?? {
48
- max: 30,
49
- windowMs: 6e4
50
- });
62
+ installed();
63
+ if (!limiter) throw new Error("@ecsplico/editor: AI is off (installEditorServer without ai)");
64
+ return limiter;
51
65
  }
52
66
  /** Closes the process-wide collaboration server (pending stores are written first) and forgets it. */
53
67
  async function closeEditorServer() {
@@ -55,8 +69,9 @@ async function closeEditorServer() {
55
69
  collab = void 0;
56
70
  await open?.close();
57
71
  }
58
- /** Open collaboration connections and loaded documents of this process (zeros before the first connection). */
72
+ /** Open collaboration connections and loaded documents of this process (zeros when collaboration is off). */
59
73
  function collabStats() {
74
+ installed();
60
75
  return collab?.stats() ?? {
61
76
  connections: 0,
62
77
  documents: 0
@@ -68,10 +83,12 @@ function forgetCollabDocument(id) {
68
83
  }
69
84
  /** Current content of a document that is open in the collaboration server (unsaved edits included), `null` when nobody has it open. */
70
85
  function liveContent(id) {
86
+ installed();
71
87
  return collab?.liveContent(id) ?? null;
72
88
  }
73
89
  /** The host rewrote a document's content (an agent wrote the file): merge it into the open document now, see `CollabServer.contentChanged`. */
74
90
  function collabContentChanged(id) {
91
+ installed();
75
92
  return collab?.contentChanged(id) ?? Promise.resolve();
76
93
  }
77
94
  /** AI SDK language model for `ref`, see `AiModels.resolveModel`. */
@@ -84,13 +101,13 @@ function listAiModels(user) {
84
101
  }
85
102
  /**
86
103
  * Per-user limit for host-defined AI routes: the same limiter as the editor's own AI endpoints. Call first in the route.
87
- * Throws 401 (`HttpError`) without a user, 429 when exceeded; returns the user the adapter authenticated, for `resolveModel`.
104
+ * Throws 401 (`HttpError`) without a user, 429 when exceeded; returns the user the identity port authenticated, for `resolveModel`.
88
105
  * With a Node-backed request (`event.node.res`, as h3 events have) the 429's `Retry-After` header is set on the response too.
89
106
  */
90
107
  async function enforceAiRateLimit(request) {
91
108
  try {
92
109
  return await enforceRateLimit({
93
- adapter: useEditorAdapter(),
110
+ ports: useEditorPorts(),
94
111
  ai: useAiModels(),
95
112
  limiter: useRateLimiter()
96
113
  }, { headers: request.headers });
@@ -100,6 +117,6 @@ async function enforceAiRateLimit(request) {
100
117
  }
101
118
  }
102
119
  //#endregion
103
- export { closeEditorServer, collabContentChanged, collabStats, configureEditorServer, enforceAiRateLimit, forgetCollabDocument, listAiModels, liveContent, resolveModel, setEditorAdapter, useAiModels, useCollabServer, useEditorAdapter, useRateLimiter };
120
+ export { adoptEditorServer, closeEditorServer, collabContentChanged, collabStats, enforceAiRateLimit, forgetCollabDocument, listAiModels, liveContent, resolveModel, setEditorPorts, useAiModels, useCollabServer, useEditorPorts, useEditorSchema, useRateLimiter };
104
121
 
105
122
  //# sourceMappingURL=host.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"host.js","names":[],"sources":["../../src/server/host.ts"],"sourcesContent":["import type { JSONContent } from '@tiptap/core'\nimport type { LanguageModel } from 'ai'\nimport type { ModelProfile, ModelRef } from '../features/ai/protocol'\nimport type { EditorAdapter } from './adapter'\nimport { type AiModels, type AiModelsConfig, createAiModels } from './ai'\nimport { type CollabServer, createCollabServer } from './collab'\nimport { HttpError } from './errors'\nimport { enforceRateLimit } from './handlers/context'\nimport { createRateLimiter, type RateLimiter } from './rate-limit'\n\n// The process-wide editor server of hosts that wire the editor once at startup (the Nuxt module, a script with several\n// modules): one adapter, one collaboration server, one set of AI models, one rate limiter. Everything here is a\n// convenience over `createCollabServer` / `createAiModels` / `createRateLimiter`, which take their configuration\n// explicitly and can be instantiated any number of times (tests, several tenants).\n\nexport interface EditorServerConfig {\n /**\n * The AI models: presets, shared key, transcription, slots. `languageModel`/`listModels` default to the adapter's\n * methods of the same names.\n */\n ai?: Partial<AiModelsConfig>\n /** Per-user limit shared by the AI endpoints. Default 30 requests per minute. */\n rateLimit?: { max: number, windowMs: number }\n}\n\nlet adapter: EditorAdapter | undefined\nlet config: EditorServerConfig = {}\nlet collab: CollabServer | undefined\nlet models: AiModels | undefined\nlet limiter: RateLimiter | undefined\n\n/** Registers the host's adapter; the collaboration server and the AI models are created from it on first use. Replaces (and closes) those of a previous adapter. */\nexport function setEditorAdapter(next: EditorAdapter) {\n const previous = collab\n adapter = next\n collab = undefined\n models = undefined\n if (previous) void previous.close()\n}\n\nexport function useEditorAdapter(): EditorAdapter {\n if (!adapter) throw new Error('tiptap-editor: setEditorAdapter() wurde nicht aufgerufen')\n return adapter\n}\n\n/** Sets the AI configuration and the rate limit of the process-wide server. Call before the first request. */\nexport function configureEditorServer(next: EditorServerConfig) {\n config = next\n models = undefined\n limiter = undefined\n}\n\n/** The process-wide collaboration server, created from the registered adapter on first use. */\nexport function useCollabServer(): CollabServer {\n return collab ??= createCollabServer({ adapter: useEditorAdapter() })\n}\n\n/** The process-wide AI models: the configured presets, with the adapter's `languageModel`/`listModels` hooks. */\nexport function useAiModels(): AiModels {\n if (models) return models\n const current = useEditorAdapter()\n return models = createAiModels({\n presets: {},\n languageModel: current.languageModel && ((ref, user) => current.languageModel!(ref, user)),\n listModels: current.listModels && (user => current.listModels!(user)),\n ...config.ai,\n })\n}\n\n/** The process-wide AI rate limiter. */\nexport function useRateLimiter(): RateLimiter {\n return limiter ??= createRateLimiter(config.rateLimit ?? { max: 30, windowMs: 60_000 })\n}\n\n/** Closes the process-wide collaboration server (pending stores are written first) and forgets it. */\nexport async function closeEditorServer() {\n const open = collab\n collab = undefined\n await open?.close()\n}\n\n/** Open collaboration connections and loaded documents of this process (zeros before the first connection). */\nexport function collabStats(): { connections: number, documents: number } {\n return collab?.stats() ?? { connections: 0, documents: 0 }\n}\n\n/** Tell connected clients the document is gone, disconnect them and drop the Yjs state. Call before removing the JSON. */\nexport function forgetCollabDocument(id: string): Promise<void> {\n return useCollabServer().forgetDocument(id)\n}\n\n/** Current content of a document that is open in the collaboration server (unsaved edits included), `null` when nobody has it open. */\nexport function liveContent(id: string): JSONContent | null {\n return collab?.liveContent(id) ?? null\n}\n\n/** The host rewrote a document's content (an agent wrote the file): merge it into the open document now, see `CollabServer.contentChanged`. */\nexport function collabContentChanged(id: string): Promise<void> {\n return collab?.contentChanged(id) ?? Promise.resolve()\n}\n\n/** AI SDK language model for `ref`, see `AiModels.resolveModel`. */\nexport function resolveModel(ref: ModelRef, user: object | null): Promise<LanguageModel> {\n return useAiModels().resolveModel(ref, user)\n}\n\n/** The models listed for `user`, see `AiModels.listModels`. */\nexport function listAiModels(user: object | null): Promise<ModelProfile[]> {\n return useAiModels().listModels(user)\n}\n\n/**\n * Per-user limit for host-defined AI routes: the same limiter as the editor's own AI endpoints. Call first in the route.\n * Throws 401 (`HttpError`) without a user, 429 when exceeded; returns the user the adapter authenticated, for `resolveModel`.\n * With a Node-backed request (`event.node.res`, as h3 events have) the 429's `Retry-After` header is set on the response too.\n */\nexport async function enforceAiRateLimit(request: { headers: Headers, node?: { res: { setHeader(name: string, value: string): unknown } } }): Promise<object> {\n try {\n return await enforceRateLimit({ adapter: useEditorAdapter(), ai: useAiModels(), limiter: useRateLimiter() }, { headers: request.headers })\n }\n catch (error) {\n if (error instanceof HttpError) for (const [name, value] of Object.entries(error.headers)) request.node?.res.setHeader(name, value)\n throw error\n }\n}\n"],"mappings":";;;;;;AAyBA,IAAI;AACJ,IAAI,SAA6B,CAAC;AAClC,IAAI;AACJ,IAAI;AACJ,IAAI;;AAGJ,SAAgB,iBAAiB,MAAqB;CACpD,MAAM,WAAW;CACjB,UAAU;CACV,SAAS,KAAA;CACT,SAAS,KAAA;CACT,IAAI,UAAU,SAAc,MAAM;AACpC;AAEA,SAAgB,mBAAkC;CAChD,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,0DAA0D;CACxF,OAAO;AACT;;AAGA,SAAgB,sBAAsB,MAA0B;CAC9D,SAAS;CACT,SAAS,KAAA;CACT,UAAU,KAAA;AACZ;;AAGA,SAAgB,kBAAgC;CAC9C,OAAO,WAAW,mBAAmB,EAAE,SAAS,iBAAiB,EAAE,CAAC;AACtE;;AAGA,SAAgB,cAAwB;CACtC,IAAI,QAAQ,OAAO;CACnB,MAAM,UAAU,iBAAiB;CACjC,OAAO,SAAS,eAAe;EAC7B,SAAS,CAAC;EACV,eAAe,QAAQ,mBAAmB,KAAK,SAAS,QAAQ,cAAe,KAAK,IAAI;EACxF,YAAY,QAAQ,gBAAe,SAAQ,QAAQ,WAAY,IAAI;EACnE,GAAG,OAAO;CACZ,CAAC;AACH;;AAGA,SAAgB,iBAA8B;CAC5C,OAAO,YAAY,kBAAkB,OAAO,aAAa;EAAE,KAAK;EAAI,UAAU;CAAO,CAAC;AACxF;;AAGA,eAAsB,oBAAoB;CACxC,MAAM,OAAO;CACb,SAAS,KAAA;CACT,MAAM,MAAM,MAAM;AACpB;;AAGA,SAAgB,cAA0D;CACxE,OAAO,QAAQ,MAAM,KAAK;EAAE,aAAa;EAAG,WAAW;CAAE;AAC3D;;AAGA,SAAgB,qBAAqB,IAA2B;CAC9D,OAAO,gBAAgB,CAAC,CAAC,eAAe,EAAE;AAC5C;;AAGA,SAAgB,YAAY,IAAgC;CAC1D,OAAO,QAAQ,YAAY,EAAE,KAAK;AACpC;;AAGA,SAAgB,qBAAqB,IAA2B;CAC9D,OAAO,QAAQ,eAAe,EAAE,KAAK,QAAQ,QAAQ;AACvD;;AAGA,SAAgB,aAAa,KAAe,MAA6C;CACvF,OAAO,YAAY,CAAC,CAAC,aAAa,KAAK,IAAI;AAC7C;;AAGA,SAAgB,aAAa,MAA8C;CACzE,OAAO,YAAY,CAAC,CAAC,WAAW,IAAI;AACtC;;;;;;AAOA,eAAsB,mBAAmB,SAAqH;CAC5J,IAAI;EACF,OAAO,MAAM,iBAAiB;GAAE,SAAS,iBAAiB;GAAG,IAAI,YAAY;GAAG,SAAS,eAAe;EAAE,GAAG,EAAE,SAAS,QAAQ,QAAQ,CAAC;CAC3I,SACO,OAAO;EACZ,IAAI,iBAAiB,WAAW,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,MAAM,OAAO,GAAG,QAAQ,MAAM,IAAI,UAAU,MAAM,KAAK;EAClI,MAAM;CACR;AACF"}
1
+ {"version":3,"file":"host.js","names":[],"sources":["../../src/server/host.ts"],"sourcesContent":["import type { AnyExtension, JSONContent } from '@tiptap/core'\nimport type { LanguageModel } from 'ai'\nimport type { ModelProfile, ModelRef } from '../features/ai/protocol'\nimport type { AiModels } from './ai'\nimport type { CollabServer } from './collab'\nimport { HttpError } from './errors'\nimport { enforceRateLimit } from './handlers/context'\nimport type { EditorPorts } from './ports'\nimport type { RateLimiter } from './rate-limit'\n\n// The process-wide editor server of hosts that wire the editor once at startup (the Nuxt module, a script with several\n// modules): the ports, collaboration server, AI models and rate limiter `installEditorServer` built, reachable from host\n// code (`useCollabServer`, `resolveModel`, `liveContent`, …). Their configuration is the installer's options (see\n// `defineEditorConfig` for the defaults); instances for tests or several tenants come from `createCollabServer` /\n// `createAiModels` / `createRateLimiter`, which take their configuration explicitly.\n\nlet ports: EditorPorts | undefined\nlet schema: (() => AnyExtension[]) | undefined\n/** Identity of the live installation; `adoptEditorServer` sets it, its release clears it. */\nlet installation: object | undefined\nlet collab: CollabServer | undefined\nlet models: AiModels | undefined\nlet limiter: RateLimiter | undefined\n\nfunction installed() {\n if (!installation) throw new Error('@ecsplico/editor: server not installed')\n}\n\n/**\n * Registers the host's ports for installers that read them later (the Nuxt module's server plugin installs on the first\n * request, after every Nitro plugin has run). `options.schema`: the collaboration schema, see `CollabServerOptions.schema`.\n */\nexport function setEditorPorts(next: EditorPorts, options: { schema?: () => AnyExtension[] } = {}) {\n ports = next\n schema = options.schema\n}\n\nexport function useEditorPorts(): EditorPorts {\n if (!ports) throw new Error('@ecsplico/editor: setEditorPorts() was not called')\n return ports\n}\n\n/** The collaboration schema registered with `setEditorPorts`, for installers that build the collaboration server themselves. */\nexport function useEditorSchema(): (() => AnyExtension[]) | undefined {\n return schema\n}\n\n/**\n * Makes the server `installEditorServer` built the process-wide one, so host code (`useCollabServer`, `useAiModels`,\n * `liveContent`, `enforceAiRateLimit`, …) reaches the same instances the routes use. Returns the function that drops them\n * again (only when no later installation replaced them); the installer calls it when its host closes.\n */\nexport function adoptEditorServer(server: { ports: EditorPorts, schema?: () => AnyExtension[], collab?: CollabServer, models?: AiModels, limiter?: RateLimiter }): () => void {\n const own = {}\n installation = own\n ports = server.ports\n schema = server.schema\n collab = server.collab\n models = server.models\n limiter = server.limiter\n return () => {\n if (installation !== own) return\n installation = collab = models = limiter = undefined\n }\n}\n\n/** The process-wide collaboration server of the installed server. Throws when none is installed or `collab: false`. */\nexport function useCollabServer(): CollabServer {\n installed()\n if (!collab) throw new Error('@ecsplico/editor: collaboration is off (installEditorServer with collab: false)')\n return collab\n}\n\n/** The process-wide AI models of the installed server: its configured presets, with the `models` port's `languageModel`/`listModels` hooks. Throws when none is installed or it was installed without `ai`. */\nexport function useAiModels(): AiModels {\n installed()\n if (!models) throw new Error('@ecsplico/editor: AI is off (installEditorServer without ai)')\n return models\n}\n\n/** The process-wide AI rate limiter of the installed server (present with `ai`). */\nexport function useRateLimiter(): RateLimiter {\n installed()\n if (!limiter) throw new Error('@ecsplico/editor: AI is off (installEditorServer without ai)')\n return limiter\n}\n\n/** Closes the process-wide collaboration server (pending stores are written first) and forgets it. */\nexport async function closeEditorServer() {\n const open = collab\n collab = undefined\n await open?.close()\n}\n\n/** Open collaboration connections and loaded documents of this process (zeros when collaboration is off). */\nexport function collabStats(): { connections: number, documents: number } {\n installed()\n return collab?.stats() ?? { connections: 0, documents: 0 }\n}\n\n/** Tell connected clients the document is gone, disconnect them and drop the Yjs state. Call before removing the JSON. */\nexport function forgetCollabDocument(id: string): Promise<void> {\n return useCollabServer().forgetDocument(id)\n}\n\n/** Current content of a document that is open in the collaboration server (unsaved edits included), `null` when nobody has it open. */\nexport function liveContent(id: string): JSONContent | null {\n installed()\n return collab?.liveContent(id) ?? null\n}\n\n/** The host rewrote a document's content (an agent wrote the file): merge it into the open document now, see `CollabServer.contentChanged`. */\nexport function collabContentChanged(id: string): Promise<void> {\n installed()\n return collab?.contentChanged(id) ?? Promise.resolve()\n}\n\n/** AI SDK language model for `ref`, see `AiModels.resolveModel`. */\nexport function resolveModel(ref: ModelRef, user: object | null): Promise<LanguageModel> {\n return useAiModels().resolveModel(ref, user)\n}\n\n/** The models listed for `user`, see `AiModels.listModels`. */\nexport function listAiModels(user: object | null): Promise<ModelProfile[]> {\n return useAiModels().listModels(user)\n}\n\n/**\n * Per-user limit for host-defined AI routes: the same limiter as the editor's own AI endpoints. Call first in the route.\n * Throws 401 (`HttpError`) without a user, 429 when exceeded; returns the user the identity port authenticated, for `resolveModel`.\n * With a Node-backed request (`event.node.res`, as h3 events have) the 429's `Retry-After` header is set on the response too.\n */\nexport async function enforceAiRateLimit(request: { headers: Headers, node?: { res: { setHeader(name: string, value: string): unknown } } }): Promise<object> {\n try {\n return await enforceRateLimit({ ports: useEditorPorts(), ai: useAiModels(), limiter: useRateLimiter() }, { headers: request.headers })\n }\n catch (error) {\n if (error instanceof HttpError) for (const [name, value] of Object.entries(error.headers)) request.node?.res.setHeader(name, value)\n throw error\n }\n}\n"],"mappings":";;;AAgBA,IAAI;AACJ,IAAI;;AAEJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AAEJ,SAAS,YAAY;CACnB,IAAI,CAAC,cAAc,MAAM,IAAI,MAAM,wCAAwC;AAC7E;;;;;AAMA,SAAgB,eAAe,MAAmB,UAA6C,CAAC,GAAG;CACjG,QAAQ;CACR,SAAS,QAAQ;AACnB;AAEA,SAAgB,iBAA8B;CAC5C,IAAI,CAAC,OAAO,MAAM,IAAI,MAAM,mDAAmD;CAC/E,OAAO;AACT;;AAGA,SAAgB,kBAAsD;CACpE,OAAO;AACT;;;;;;AAOA,SAAgB,kBAAkB,QAA4I;CAC5K,MAAM,MAAM,CAAC;CACb,eAAe;CACf,QAAQ,OAAO;CACf,SAAS,OAAO;CAChB,SAAS,OAAO;CAChB,SAAS,OAAO;CAChB,UAAU,OAAO;CACjB,aAAa;EACX,IAAI,iBAAiB,KAAK;EAC1B,eAAe,SAAS,SAAS,UAAU,KAAA;CAC7C;AACF;;AAGA,SAAgB,kBAAgC;CAC9C,UAAU;CACV,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,iFAAiF;CAC9G,OAAO;AACT;;AAGA,SAAgB,cAAwB;CACtC,UAAU;CACV,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,8DAA8D;CAC3F,OAAO;AACT;;AAGA,SAAgB,iBAA8B;CAC5C,UAAU;CACV,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,8DAA8D;CAC5F,OAAO;AACT;;AAGA,eAAsB,oBAAoB;CACxC,MAAM,OAAO;CACb,SAAS,KAAA;CACT,MAAM,MAAM,MAAM;AACpB;;AAGA,SAAgB,cAA0D;CACxE,UAAU;CACV,OAAO,QAAQ,MAAM,KAAK;EAAE,aAAa;EAAG,WAAW;CAAE;AAC3D;;AAGA,SAAgB,qBAAqB,IAA2B;CAC9D,OAAO,gBAAgB,CAAC,CAAC,eAAe,EAAE;AAC5C;;AAGA,SAAgB,YAAY,IAAgC;CAC1D,UAAU;CACV,OAAO,QAAQ,YAAY,EAAE,KAAK;AACpC;;AAGA,SAAgB,qBAAqB,IAA2B;CAC9D,UAAU;CACV,OAAO,QAAQ,eAAe,EAAE,KAAK,QAAQ,QAAQ;AACvD;;AAGA,SAAgB,aAAa,KAAe,MAA6C;CACvF,OAAO,YAAY,CAAC,CAAC,aAAa,KAAK,IAAI;AAC7C;;AAGA,SAAgB,aAAa,MAA8C;CACzE,OAAO,YAAY,CAAC,CAAC,WAAW,IAAI;AACtC;;;;;;AAOA,eAAsB,mBAAmB,SAAqH;CAC5J,IAAI;EACF,OAAO,MAAM,iBAAiB;GAAE,OAAO,eAAe;GAAG,IAAI,YAAY;GAAG,SAAS,eAAe;EAAE,GAAG,EAAE,SAAS,QAAQ,QAAQ,CAAC;CACvI,SACO,OAAO;EACZ,IAAI,iBAAiB,WAAW,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,MAAM,OAAO,GAAG,QAAQ,MAAM,IAAI,UAAU,MAAM,KAAK;EAClI,MAAM;CACR;AACF"}
@@ -1,8 +1,10 @@
1
- import { AuthenticateRequest, EditorAdapter } from "./adapter.js";
1
+ import { PresetConfig, TranscriptionConfig } from "../config/index.js";
2
+ import { AuthenticateRequest } from "./auth.js";
2
3
  import { HttpError } from "./errors.js";
3
- import { AiModels, AiModelsConfig, ChatMessage, ChatTurnPart, PresetConfig, TranscriptionConfig, createAiModels, streamChat, streamChatTurn, upstreamError } from "./ai.js";
4
+ import { AiModels, AiModelsConfig, ChatMessage, ChatTurnPart, createAiModels, streamChat, streamChatTurn, upstreamError } from "./ai.js";
5
+ import { AssetStore, CollabStateStore, Directory, DocumentAdmin, DocumentStore, EditorPorts, Identity, ModelProvider, PORT_CAPABILITY, SettingsStore, ThemeStore, serverCapabilities } from "./ports.js";
4
6
  import { COLLAB_FIELD, CollabConnection, CollabServer, CollabServerOptions, WebSocketLike, createCollabServer } from "./collab.js";
5
7
  import { decodeCollabState, encodeCollabState, isStateStale } from "./collab-state.js";
6
8
  import { RateLimiter, RateLimiterOptions, createRateLimiter, userKey } from "./rate-limit.js";
7
- import { EditorServerConfig, closeEditorServer, collabContentChanged, collabStats, configureEditorServer, enforceAiRateLimit, forgetCollabDocument, listAiModels, liveContent, resolveModel, setEditorAdapter, useAiModels, useCollabServer, useEditorAdapter } from "./host.js";
8
- export { type AiModels, type AiModelsConfig, type AuthenticateRequest, COLLAB_FIELD, type ChatMessage, type ChatTurnPart, type CollabConnection, type CollabServer, type CollabServerOptions, type EditorAdapter, type EditorServerConfig, HttpError, type PresetConfig, type RateLimiter, type RateLimiterOptions, type TranscriptionConfig, type WebSocketLike, closeEditorServer, collabContentChanged, collabStats, configureEditorServer, createAiModels, createCollabServer, createRateLimiter, decodeCollabState, encodeCollabState, enforceAiRateLimit, forgetCollabDocument, isStateStale, listAiModels, liveContent, resolveModel, setEditorAdapter, streamChat, streamChatTurn, upstreamError, useAiModels, useCollabServer, useEditorAdapter, userKey };
9
+ import { closeEditorServer, collabContentChanged, collabStats, enforceAiRateLimit, forgetCollabDocument, listAiModels, liveContent, resolveModel, setEditorPorts, useAiModels, useCollabServer, useEditorPorts } from "./host.js";
10
+ export { type AiModels, type AiModelsConfig, type AssetStore, type AuthenticateRequest, COLLAB_FIELD, type ChatMessage, type ChatTurnPart, type CollabConnection, type CollabServer, type CollabServerOptions, type CollabStateStore, type Directory, type DocumentAdmin, type DocumentStore, type EditorPorts, HttpError, type Identity, type ModelProvider, PORT_CAPABILITY, type PresetConfig, type RateLimiter, type RateLimiterOptions, type SettingsStore, type ThemeStore, type TranscriptionConfig, type WebSocketLike, closeEditorServer, collabContentChanged, collabStats, createAiModels, createCollabServer, createRateLimiter, decodeCollabState, encodeCollabState, enforceAiRateLimit, forgetCollabDocument, isStateStale, listAiModels, liveContent, resolveModel, serverCapabilities, setEditorPorts, streamChat, streamChatTurn, upstreamError, useAiModels, useCollabServer, useEditorPorts, userKey };
@@ -3,5 +3,6 @@ import { createAiModels, streamChat, streamChatTurn, upstreamError } from "./ai.
3
3
  import { decodeCollabState, encodeCollabState, isStateStale } from "./collab-state.js";
4
4
  import { COLLAB_FIELD, createCollabServer } from "./collab.js";
5
5
  import { createRateLimiter, userKey } from "./rate-limit.js";
6
- import { closeEditorServer, collabContentChanged, collabStats, configureEditorServer, enforceAiRateLimit, forgetCollabDocument, listAiModels, liveContent, resolveModel, setEditorAdapter, useAiModels, useCollabServer, useEditorAdapter } from "./host.js";
7
- export { COLLAB_FIELD, HttpError, closeEditorServer, collabContentChanged, collabStats, configureEditorServer, createAiModels, createCollabServer, createRateLimiter, decodeCollabState, encodeCollabState, enforceAiRateLimit, forgetCollabDocument, isStateStale, listAiModels, liveContent, resolveModel, setEditorAdapter, streamChat, streamChatTurn, upstreamError, useAiModels, useCollabServer, useEditorAdapter, userKey };
6
+ import { closeEditorServer, collabContentChanged, collabStats, enforceAiRateLimit, forgetCollabDocument, listAiModels, liveContent, resolveModel, setEditorPorts, useAiModels, useCollabServer, useEditorPorts } from "./host.js";
7
+ import { PORT_CAPABILITY, serverCapabilities } from "./ports.js";
8
+ export { COLLAB_FIELD, HttpError, PORT_CAPABILITY, closeEditorServer, collabContentChanged, collabStats, createAiModels, createCollabServer, createRateLimiter, decodeCollabState, encodeCollabState, enforceAiRateLimit, forgetCollabDocument, isStateStale, listAiModels, liveContent, resolveModel, serverCapabilities, setEditorPorts, streamChat, streamChatTurn, upstreamError, useAiModels, useCollabServer, useEditorPorts, userKey };
@@ -0,0 +1,97 @@
1
+ import { HttpError } from "./errors.js";
2
+ //#region src/server/pdf.ts
3
+ const size = (value) => Math.max(1, Math.ceil(value));
4
+ /** The canvas module of `@napi-rs/canvas`, or `null` when the optional dependency is not installed (or its native part does not load). */
5
+ async function loadCanvas() {
6
+ try {
7
+ return await import("@napi-rs/canvas");
8
+ } catch {
9
+ return null;
10
+ }
11
+ }
12
+ /** The class `getDocument` takes as `CanvasFactory`: pdfjs creates the canvases of images and patterns through `@napi-rs/canvas`. */
13
+ function canvasFactoryOf(canvasModule) {
14
+ return class NodeCanvasFactory {
15
+ create(width, height) {
16
+ const canvas = canvasModule.createCanvas(size(width), size(height));
17
+ return {
18
+ canvas,
19
+ context: canvas.getContext("2d")
20
+ };
21
+ }
22
+ reset({ canvas }, width, height) {
23
+ if (!canvas) return;
24
+ canvas.width = size(width);
25
+ canvas.height = size(height);
26
+ }
27
+ destroy(canvasAndContext) {
28
+ if (canvasAndContext.canvas) {
29
+ canvasAndContext.canvas.width = 0;
30
+ canvasAndContext.canvas.height = 0;
31
+ }
32
+ canvasAndContext.canvas = null;
33
+ canvasAndContext.context = null;
34
+ }
35
+ };
36
+ }
37
+ /** Opens `data`; 422 when it is no readable PDF. `data` is copied (pdfjs takes over the buffer it is given). */
38
+ async function openPdf(data) {
39
+ const pdfjs = await import("pdfjs-dist/legacy/build/pdf.mjs");
40
+ const canvasModule = await loadCanvas();
41
+ const task = pdfjs.getDocument({
42
+ data: Uint8Array.from(data),
43
+ useSystemFonts: true,
44
+ verbosity: 0,
45
+ ...canvasModule && { CanvasFactory: canvasFactoryOf(canvasModule) }
46
+ });
47
+ let doc;
48
+ try {
49
+ doc = await task.promise;
50
+ } catch (error) {
51
+ await task.destroy().catch(() => {});
52
+ throw new HttpError(422, `PDF nicht lesbar: ${error instanceof Error ? error.message : String(error)}`.slice(0, 300));
53
+ }
54
+ return {
55
+ pageCount: doc.numPages,
56
+ async pageText(pageNumber) {
57
+ const page = await doc.getPage(pageNumber);
58
+ try {
59
+ const content = await page.getTextContent();
60
+ let text = "";
61
+ let baseline = null;
62
+ for (const item of content.items) {
63
+ if (!("str" in item)) continue;
64
+ const y = item.transform[5];
65
+ if (text && baseline !== null && Math.abs(y - baseline) > 1 && !text.endsWith("\n")) text += "\n";
66
+ text += item.str;
67
+ if (item.hasEOL) text += "\n";
68
+ baseline = y;
69
+ }
70
+ return text.trim();
71
+ } finally {
72
+ page.cleanup();
73
+ }
74
+ },
75
+ async pagePng(pageNumber, scale) {
76
+ if (!canvasModule) throw new Error("@napi-rs/canvas fehlt");
77
+ const page = await doc.getPage(pageNumber);
78
+ try {
79
+ const viewport = page.getViewport({ scale });
80
+ const canvas = canvasModule.createCanvas(size(viewport.width), size(viewport.height));
81
+ await page.render({
82
+ canvas,
83
+ canvasContext: canvas.getContext("2d"),
84
+ viewport
85
+ }).promise;
86
+ return canvas.toBuffer("image/png");
87
+ } finally {
88
+ page.cleanup();
89
+ }
90
+ },
91
+ close: () => task.destroy()
92
+ };
93
+ }
94
+ //#endregion
95
+ export { openPdf };
96
+
97
+ //# sourceMappingURL=pdf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdf.js","names":[],"sources":["../../src/server/pdf.ts"],"sourcesContent":["import type { Canvas } from '@napi-rs/canvas'\nimport type * as CanvasModule from '@napi-rs/canvas'\nimport type { PDFDocumentProxy } from 'pdfjs-dist/legacy/build/pdf.mjs'\n// pdf.js's render parameters, typed against the DOM canvas (which a server tsconfig without the `dom` lib does not name); not re-exported from the package entry.\nimport type { RenderParameters } from 'pdfjs-dist/types/src/display/api'\nimport { HttpError } from './errors'\n\n// PDF reading for `POST /api/ai/extract`: the text layer per page, and page rasterisation for OCR. `pdfjs-dist` and the\n// optional `@napi-rs/canvas` are imported on first use: a server that never extracts a PDF does not load them, and the\n// canvas package may be absent or fail to load its native part, which a static import could not survive.\n\ntype CanvasApi = typeof CanvasModule\n\nconst size = (value: number) => Math.max(1, Math.ceil(value))\n\n/** An opened PDF: `pageCount` pages, `close` releases the parser. */\nexport interface PdfFile {\n pageCount: number\n /** The text layer of page `pageNumber` (1-based): items joined, a newline where a line ends or the baseline moves. */\n pageText: (pageNumber: number) => Promise<string>\n /** Page `pageNumber` as PNG at `scale`; throws when no canvas is available or rendering fails. */\n pagePng: (pageNumber: number, scale: number) => Promise<Uint8Array>\n close: () => Promise<void>\n}\n\n/** The canvas module of `@napi-rs/canvas`, or `null` when the optional dependency is not installed (or its native part does not load). */\nasync function loadCanvas(): Promise<CanvasApi | null> {\n try {\n return await import('@napi-rs/canvas')\n }\n catch {\n return null\n }\n}\n\n/** The class `getDocument` takes as `CanvasFactory`: pdfjs creates the canvases of images and patterns through `@napi-rs/canvas`. */\nfunction canvasFactoryOf(canvasModule: CanvasApi) {\n interface CanvasAndContext { canvas: Canvas | null, context: unknown }\n return class NodeCanvasFactory {\n create(width: number, height: number): CanvasAndContext {\n const canvas = canvasModule.createCanvas(size(width), size(height))\n return { canvas, context: canvas.getContext('2d') }\n }\n\n reset({ canvas }: CanvasAndContext, width: number, height: number): void {\n if (!canvas) return\n canvas.width = size(width)\n canvas.height = size(height)\n }\n\n destroy(canvasAndContext: CanvasAndContext): void {\n if (canvasAndContext.canvas) {\n canvasAndContext.canvas.width = 0\n canvasAndContext.canvas.height = 0\n }\n canvasAndContext.canvas = null\n canvasAndContext.context = null\n }\n }\n}\n\n/** Opens `data`; 422 when it is no readable PDF. `data` is copied (pdfjs takes over the buffer it is given). */\nexport async function openPdf(data: Uint8Array): Promise<PdfFile> {\n const pdfjs = await import('pdfjs-dist/legacy/build/pdf.mjs')\n const canvasModule = await loadCanvas()\n const task = pdfjs.getDocument({\n data: Uint8Array.from(data),\n useSystemFonts: true,\n verbosity: 0,\n ...(canvasModule && { CanvasFactory: canvasFactoryOf(canvasModule) }),\n })\n let doc: PDFDocumentProxy\n try {\n doc = await task.promise\n }\n catch (error) {\n await task.destroy().catch(() => {})\n throw new HttpError(422, `PDF nicht lesbar: ${error instanceof Error ? error.message : String(error)}`.slice(0, 300))\n }\n\n return {\n pageCount: doc.numPages,\n async pageText(pageNumber) {\n const page = await doc.getPage(pageNumber)\n try {\n const content = await page.getTextContent()\n let text = ''\n let baseline: number | null = null\n for (const item of content.items) {\n if (!('str' in item)) continue\n const y = item.transform[5] as number\n if (text && baseline !== null && Math.abs(y - baseline) > 1 && !text.endsWith('\\n')) text += '\\n'\n text += item.str\n if (item.hasEOL) text += '\\n'\n baseline = y\n }\n return text.trim()\n }\n finally {\n page.cleanup()\n }\n },\n async pagePng(pageNumber, scale) {\n if (!canvasModule) throw new Error('@napi-rs/canvas fehlt')\n const page = await doc.getPage(pageNumber)\n try {\n const viewport = page.getViewport({ scale })\n const canvas = canvasModule.createCanvas(size(viewport.width), size(viewport.height))\n await page.render({\n canvas: canvas as unknown as RenderParameters['canvas'],\n canvasContext: canvas.getContext('2d') as unknown as RenderParameters['canvasContext'],\n viewport,\n }).promise\n return canvas.toBuffer('image/png')\n }\n finally {\n page.cleanup()\n }\n },\n close: () => task.destroy(),\n }\n}\n"],"mappings":";;AAaA,MAAM,QAAQ,UAAkB,KAAK,IAAI,GAAG,KAAK,KAAK,KAAK,CAAC;;AAa5D,eAAe,aAAwC;CACrD,IAAI;EACF,OAAO,MAAM,OAAO;CACtB,QACM;EACJ,OAAO;CACT;AACF;;AAGA,SAAS,gBAAgB,cAAyB;CAEhD,OAAO,MAAM,kBAAkB;EAC7B,OAAO,OAAe,QAAkC;GACtD,MAAM,SAAS,aAAa,aAAa,KAAK,KAAK,GAAG,KAAK,MAAM,CAAC;GAClE,OAAO;IAAE;IAAQ,SAAS,OAAO,WAAW,IAAI;GAAE;EACpD;EAEA,MAAM,EAAE,UAA4B,OAAe,QAAsB;GACvE,IAAI,CAAC,QAAQ;GACb,OAAO,QAAQ,KAAK,KAAK;GACzB,OAAO,SAAS,KAAK,MAAM;EAC7B;EAEA,QAAQ,kBAA0C;GAChD,IAAI,iBAAiB,QAAQ;IAC3B,iBAAiB,OAAO,QAAQ;IAChC,iBAAiB,OAAO,SAAS;GACnC;GACA,iBAAiB,SAAS;GAC1B,iBAAiB,UAAU;EAC7B;CACF;AACF;;AAGA,eAAsB,QAAQ,MAAoC;CAChE,MAAM,QAAQ,MAAM,OAAO;CAC3B,MAAM,eAAe,MAAM,WAAW;CACtC,MAAM,OAAO,MAAM,YAAY;EAC7B,MAAM,WAAW,KAAK,IAAI;EAC1B,gBAAgB;EAChB,WAAW;EACX,GAAI,gBAAgB,EAAE,eAAe,gBAAgB,YAAY,EAAE;CACrE,CAAC;CACD,IAAI;CACJ,IAAI;EACF,MAAM,MAAM,KAAK;CACnB,SACO,OAAO;EACZ,MAAM,KAAK,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC;EACnC,MAAM,IAAI,UAAU,KAAK,qBAAqB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,IAAI,MAAM,GAAG,GAAG,CAAC;CACtH;CAEA,OAAO;EACL,WAAW,IAAI;EACf,MAAM,SAAS,YAAY;GACzB,MAAM,OAAO,MAAM,IAAI,QAAQ,UAAU;GACzC,IAAI;IACF,MAAM,UAAU,MAAM,KAAK,eAAe;IAC1C,IAAI,OAAO;IACX,IAAI,WAA0B;IAC9B,KAAK,MAAM,QAAQ,QAAQ,OAAO;KAChC,IAAI,EAAE,SAAS,OAAO;KACtB,MAAM,IAAI,KAAK,UAAU;KACzB,IAAI,QAAQ,aAAa,QAAQ,KAAK,IAAI,IAAI,QAAQ,IAAI,KAAK,CAAC,KAAK,SAAS,IAAI,GAAG,QAAQ;KAC7F,QAAQ,KAAK;KACb,IAAI,KAAK,QAAQ,QAAQ;KACzB,WAAW;IACb;IACA,OAAO,KAAK,KAAK;GACnB,UACQ;IACN,KAAK,QAAQ;GACf;EACF;EACA,MAAM,QAAQ,YAAY,OAAO;GAC/B,IAAI,CAAC,cAAc,MAAM,IAAI,MAAM,uBAAuB;GAC1D,MAAM,OAAO,MAAM,IAAI,QAAQ,UAAU;GACzC,IAAI;IACF,MAAM,WAAW,KAAK,YAAY,EAAE,MAAM,CAAC;IAC3C,MAAM,SAAS,aAAa,aAAa,KAAK,SAAS,KAAK,GAAG,KAAK,SAAS,MAAM,CAAC;IACpF,MAAM,KAAK,OAAO;KACR;KACR,eAAe,OAAO,WAAW,IAAI;KACrC;IACF,CAAC,CAAC,CAAC;IACH,OAAO,OAAO,SAAS,WAAW;GACpC,UACQ;IACN,KAAK,QAAQ;GACf;EACF;EACA,aAAa,KAAK,QAAQ;CAC5B;AACF"}
@@ -1,21 +1,18 @@
1
- import { EditorSettings } from "../settings/index.js";
2
1
  import { AssetRecord } from "../features/media/assets.js";
3
2
  import "../features/media/schema.js";
4
- import { MentionUser } from "../features/mentions/mention.js";
3
+ import { EditorSettings } from "../settings/index.js";
4
+ import { BackendCapability } from "../core/backend-capability.js";
5
+ import { MentionUser, ModelProfile, ModelRef, ThemeRecord } from "../core/backend-types.js";
5
6
  import "../features/mentions/schema.js";
6
- import { ModelProfile, ModelRef } from "../features/ai/protocol/models.js";
7
+ import { AuthenticateRequest } from "./auth.js";
7
8
  import "../features/ai/protocol/index.js";
8
- import { ThemeRecord } from "../features/themes/schema.js";
9
- import { AnyExtension, JSONContent } from "@tiptap/core";
9
+ import { CommentStore } from "../adapters/comments/types.js";
10
+ import "../features/themes/schema.js";
11
+ import { JSONContent } from "@tiptap/core";
10
12
  import { LanguageModel } from "ai";
11
- //#region src/server/adapter.d.ts
12
- /** What `EditorAdapter.authenticate` gets: the headers of the request (the websocket upgrade for collaboration) and the connection's `token`. */
13
- export interface AuthenticateRequest {
14
- headers: Headers;
15
- /** The collaboration client's token (`HocuspocusProvider` `token`, sent right after the socket opened); absent for plain HTTP requests and token-less clients. */
16
- token?: string;
17
- }
18
- export interface EditorAdapter {
13
+ //#region src/server/ports.d.ts
14
+ /** Who a request or websocket connection belongs to, and which documents that user may open. */
15
+ export interface Identity {
19
16
  /**
20
17
  * The user behind a request, `null` = not authenticated (HTTP routes answer 401). Collaboration: called in Hocuspocus
21
18
  * `onAuthenticate` with the upgrade request's `headers` and the client's `token` (`undefined` when it sent none, so cookie
@@ -32,6 +29,13 @@ export interface EditorAdapter {
32
29
  authorize?(user: object, id: string): Promise<{
33
30
  readOnly: boolean;
34
31
  } | null>;
32
+ }
33
+ /** The stored TipTap JSON of the workspace's documents. */
34
+ export interface DocumentStore {
35
+ /** TipTap JSON to seed a document's Y.Doc from; `null` = the document does not exist. */
36
+ loadContent(id: string): Promise<JSONContent | null>;
37
+ /** Mirror of the current Yjs state, called debounced after edits and on shutdown. Must tolerate ids deleted meanwhile. */
38
+ storeContent(id: string, content: JSONContent): Promise<void>;
35
39
  /**
36
40
  * Opaque version of the stored content of a document (mtime, hash, revision), `null` = unknown, no NUL. The collab server
37
41
  * keeps it next to the Yjs state. When it differs from the live version (the content changed behind the editor's back) the
@@ -41,25 +45,37 @@ export interface EditorAdapter {
41
45
  * Omit it to never discard state.
42
46
  */
43
47
  contentVersion?(id: string): Promise<string | null>;
44
- /** TipTap extensions of host-defined nodes and marks, appended to `advancedSchemaExtensions()` in the server's collab schema so they survive JSON↔Yjs conversion. Vue-free node files only, no node views. */
45
- schemaExtensions?(): AnyExtension[];
46
- /** TipTap JSON to seed a document's Y.Doc from; `null` = the document does not exist. */
47
- loadContent(id: string): Promise<JSONContent | null>;
48
- /** Mirror of the current Yjs state, called debounced after edits and on shutdown. Must tolerate ids deleted meanwhile. */
49
- storeContent(id: string, content: JSONContent): Promise<void>;
50
- /** All users that can be `@`-mentioned (served by `GET /api/editor/users`); must not include credentials. */
51
- listUsers(): Promise<MentionUser[]>;
52
48
  /** Stored TipTap JSON of every document in the workspace, e.g. to collect the `#` tags in use (`GET /api/editor/tags`). */
53
49
  listContents(): Promise<{
54
50
  id: string;
55
51
  content: JSONContent;
56
52
  }[]>;
53
+ }
54
+ /** Document management a host needs next to the editor's own storage methods: `DocumentStore.storeContent` only updates. */
55
+ export interface DocumentAdmin {
56
+ /** Creates the document or replaces its content; the content version changes. */
57
+ putDocument(id: string, content: JSONContent): Promise<void>;
58
+ /** Removes the content, the Yjs state and the assets of a document; unknown ids are fine. Call `forgetCollabDocument(id)` first when it may be open. */
59
+ deleteDocument(id: string): Promise<void>;
60
+ /** Ids of all stored documents. */
61
+ listDocumentIds(): Promise<string[]>;
62
+ }
63
+ /** Where the collaboration server keeps the Yjs state of open documents. */
64
+ export interface CollabStateStore {
57
65
  /** The bytes `storeState` stored (opaque to the host: the Yjs update behind a content-version prefix; state stored by earlier releases is a raw update and still loads); `null` = none yet (the Y.Doc is then seeded from `loadContent`). */
58
66
  loadState(id: string): Promise<Uint8Array | null>;
59
67
  /** Persists the state bytes unchanged; called on every store and when block IDs were backfilled. Must tolerate ids deleted meanwhile. */
60
68
  storeState(id: string, state: Uint8Array): Promise<void>;
61
69
  /** Drops the Yjs state of a deleted document (the next load re-seeds from `loadContent`). */
62
70
  removeState(id: string): Promise<void>;
71
+ }
72
+ /** The users that can be `@`-mentioned. */
73
+ export interface Directory {
74
+ /** All users that can be `@`-mentioned (served by `GET /api/editor/users`); must not include credentials. */
75
+ listUsers(): Promise<MentionUser[]>;
76
+ }
77
+ /** Uploaded files. */
78
+ export interface AssetStore {
63
79
  /** Stores an uploaded file (`GET /api/editor/assets/:id/:name` serves it). `id` is a document id or `SCRATCH_DOCUMENT_ID`; it may name no existing document. */
64
80
  storeAsset(id: string, asset: AssetRecord & {
65
81
  data: Buffer;
@@ -69,21 +85,30 @@ export interface EditorAdapter {
69
85
  record: AssetRecord;
70
86
  data: Buffer;
71
87
  } | null>;
72
- /** Per-user editor settings as stored (`null` = none yet), validated by `GET /api/editor/settings`. Omit both settings methods to let the client keep settings in localStorage only. */
73
- loadSettings?(user: object): Promise<unknown | null>;
88
+ }
89
+ /** Per-user editor settings. Without this port the client keeps settings in localStorage only. */
90
+ export interface SettingsStore {
91
+ /** Per-user editor settings as stored (`null` = none yet), validated by `GET /api/editor/settings`. */
92
+ loadSettings(user: object): Promise<unknown | null>;
74
93
  /** Stores validated settings for the user from `authenticate`. */
75
- storeSettings?(user: object, settings: EditorSettings): Promise<void>;
76
- /** Theme library shared by all users (`GET /api/editor/themes`). Omit the theme methods to leave the themes feature uninstalled: its routes answer 501. */
77
- listThemes?(): Promise<ThemeRecord[]>;
94
+ storeSettings(user: object, settings: EditorSettings): Promise<void>;
95
+ }
96
+ /** The theme library shared by all users. Without this port the themes feature is uninstalled: its routes answer 501. */
97
+ export interface ThemeStore {
98
+ /** All themes (`GET /api/editor/themes`). */
99
+ listThemes(): Promise<ThemeRecord[]>;
78
100
  /** A theme's record and `theme.css` (`GET /api/editor/themes/:id`); `null` = unknown id. */
79
- loadTheme?(id: string): Promise<{
101
+ loadTheme(id: string): Promise<{
80
102
  record: ThemeRecord;
81
103
  css: string;
82
104
  } | null>;
83
105
  /** Stores an uploaded theme (`POST /api/editor/themes`). */
84
- storeTheme?(record: Omit<ThemeRecord, 'builtin'>, css: string): Promise<void>;
106
+ storeTheme(record: Omit<ThemeRecord, 'builtin'>, css: string): Promise<void>;
85
107
  /** Deletes an uploaded theme (`DELETE /api/editor/themes/:id`); `false` = not found or builtin. */
86
- removeTheme?(id: string): Promise<boolean>;
108
+ removeTheme(id: string): Promise<boolean>;
109
+ }
110
+ /** The host's own language models for the AI endpoints; both members fall through to the runtime-config presets. */
111
+ export interface ModelProvider {
87
112
  /**
88
113
  * The language model for `ref`, so the AI endpoints use the host's own providers; consulted before the runtime-config
89
114
  * presets for every model reference. `user` is what `authenticate` returned. `null` falls through to the presets
@@ -97,5 +122,31 @@ export interface EditorAdapter {
97
122
  */
98
123
  listModels?(user: object | null): Promise<ModelProfile[] | null>;
99
124
  }
125
+ /** Everything the editor's server reads from the host, one port per capability. Only `identity` and `documents` are required. */
126
+ export interface EditorPorts {
127
+ identity: Identity;
128
+ documents: DocumentStore & Partial<DocumentAdmin>;
129
+ /** Required by the collaboration server. */
130
+ collabState?: CollabStateStore;
131
+ directory?: Directory;
132
+ assets?: AssetStore;
133
+ settings?: SettingsStore;
134
+ themes?: ThemeStore;
135
+ models?: ModelProvider;
136
+ /** Where the comment threads live (`adapters/comments/{json,drizzle}`). */
137
+ comments?: CommentStore;
138
+ }
139
+ /** The capability each optional port provides; `identity` is no capability, `tags` derive from `documents` (see `serverCapabilities`). */
140
+ export declare const PORT_CAPABILITY: Record<Exclude<keyof EditorPorts, 'identity'>, BackendCapability>;
141
+ /**
142
+ * The capabilities `ports` serves: those of every present port, plus `tags` (derived from `documents.listContents`).
143
+ * Two capabilities depend on more than a port: `ai` (the AI routes need configured models) and `collaboration` (the
144
+ * websocket needs the collab server). `served` states what the installed server really mounts and overrides the port-based
145
+ * answer for them; omitted keys follow the ports.
146
+ */
147
+ export declare function serverCapabilities(ports: EditorPorts, served?: {
148
+ ai?: boolean;
149
+ collaboration?: boolean;
150
+ }): BackendCapability[];
100
151
  //#endregion
101
- //# sourceMappingURL=adapter.d.ts.map
152
+ //# sourceMappingURL=ports.d.ts.map
@@ -0,0 +1,29 @@
1
+ //#region src/server/ports.ts
2
+ /** The capability each optional port provides; `identity` is no capability, `tags` derive from `documents` (see `serverCapabilities`). */
3
+ const PORT_CAPABILITY = {
4
+ documents: "documents",
5
+ collabState: "collaboration",
6
+ directory: "users",
7
+ assets: "assets",
8
+ settings: "settings",
9
+ themes: "themes",
10
+ models: "ai",
11
+ comments: "comments"
12
+ };
13
+ /**
14
+ * The capabilities `ports` serves: those of every present port, plus `tags` (derived from `documents.listContents`).
15
+ * Two capabilities depend on more than a port: `ai` (the AI routes need configured models) and `collaboration` (the
16
+ * websocket needs the collab server). `served` states what the installed server really mounts and overrides the port-based
17
+ * answer for them; omitted keys follow the ports.
18
+ */
19
+ function serverCapabilities(ports, served = {}) {
20
+ const capabilities = new Set(Object.keys(PORT_CAPABILITY).filter((port) => ports[port] !== void 0).map((port) => PORT_CAPABILITY[port]));
21
+ for (const capability of ["ai", "collaboration"]) if (served[capability] === true) capabilities.add(capability);
22
+ else if (served[capability] === false) capabilities.delete(capability);
23
+ if (ports.documents) capabilities.add("tags");
24
+ return [...capabilities];
25
+ }
26
+ //#endregion
27
+ export { PORT_CAPABILITY, serverCapabilities };
28
+
29
+ //# sourceMappingURL=ports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ports.js","names":[],"sources":["../../src/server/ports.ts"],"sourcesContent":["import type { JSONContent } from '@tiptap/core'\nimport type { LanguageModel } from 'ai'\nimport type { CommentStore } from '../adapters/comments/types'\nimport type { BackendCapability } from '../core/backend-capability'\nimport type { ModelProfile, ModelRef } from '../features/ai/protocol'\nimport type { AssetRecord } from '../features/media/schema'\nimport type { MentionUser } from '../features/mentions/schema'\nimport type { ThemeRecord } from '../features/themes/schema'\nimport type { EditorSettings } from '../settings'\nimport type { AuthenticateRequest } from './auth'\n\n// The server side of the editor's backend, split by capability: a host (or an adapter) implements the ports it serves\n// and leaves the others out; routes and features that need an absent port answer 501.\n\n/** Who a request or websocket connection belongs to, and which documents that user may open. */\nexport interface Identity {\n /**\n * The user behind a request, `null` = not authenticated (HTTP routes answer 401). Collaboration: called in Hocuspocus\n * `onAuthenticate` with the upgrade request's `headers` and the client's `token` (`undefined` when it sent none, so cookie\n * hosts keep working and bearer-only hosts read `token`); `null` closes the connection with 4401. With the Nuxt module\n * option `collab.authenticateUpgrade` it runs once at the upgrade with the `headers` only and `null` refuses the upgrade\n * with HTTP 401. The value becomes the connection context's `user`.\n */\n authenticate(request: AuthenticateRequest): Promise<object | null>\n /**\n * Per-document access for the collaboration websocket, called in Hocuspocus `onAuthenticate` (right after `authenticate`) with the user.\n * `null` rejects the connection; `{ readOnly: true }` lets it sync but applies none of its edits. Omit it to let every\n * authenticated user edit every document.\n */\n authorize?(user: object, id: string): Promise<{ readOnly: boolean } | null>\n}\n\n/** The stored TipTap JSON of the workspace's documents. */\nexport interface DocumentStore {\n /** TipTap JSON to seed a document's Y.Doc from; `null` = the document does not exist. */\n loadContent(id: string): Promise<JSONContent | null>\n /** Mirror of the current Yjs state, called debounced after edits and on shutdown. Must tolerate ids deleted meanwhile. */\n storeContent(id: string, content: JSONContent): Promise<void>\n /**\n * Opaque version of the stored content of a document (mtime, hash, revision), `null` = unknown, no NUL. The collab server\n * keeps it next to the Yjs state. When it differs from the live version (the content changed behind the editor's back) the\n * state is discarded on load, removed through `removeState` and the document is re-seeded from `loadContent`. A document\n * that is open when its version moves is not written back: the next store merges the new `loadContent` into the open\n * Y.Doc. The version is read right after every `storeContent`, so it must reflect what the editor itself just wrote.\n * Omit it to never discard state.\n */\n contentVersion?(id: string): Promise<string | null>\n /** Stored TipTap JSON of every document in the workspace, e.g. to collect the `#` tags in use (`GET /api/editor/tags`). */\n listContents(): Promise<{ id: string, content: JSONContent }[]>\n}\n\n/** Document management a host needs next to the editor's own storage methods: `DocumentStore.storeContent` only updates. */\nexport interface DocumentAdmin {\n /** Creates the document or replaces its content; the content version changes. */\n putDocument(id: string, content: JSONContent): Promise<void>\n /** Removes the content, the Yjs state and the assets of a document; unknown ids are fine. Call `forgetCollabDocument(id)` first when it may be open. */\n deleteDocument(id: string): Promise<void>\n /** Ids of all stored documents. */\n listDocumentIds(): Promise<string[]>\n}\n\n/** Where the collaboration server keeps the Yjs state of open documents. */\nexport interface CollabStateStore {\n /** The bytes `storeState` stored (opaque to the host: the Yjs update behind a content-version prefix; state stored by earlier releases is a raw update and still loads); `null` = none yet (the Y.Doc is then seeded from `loadContent`). */\n loadState(id: string): Promise<Uint8Array | null>\n /** Persists the state bytes unchanged; called on every store and when block IDs were backfilled. Must tolerate ids deleted meanwhile. */\n storeState(id: string, state: Uint8Array): Promise<void>\n /** Drops the Yjs state of a deleted document (the next load re-seeds from `loadContent`). */\n removeState(id: string): Promise<void>\n}\n\n/** The users that can be `@`-mentioned. */\nexport interface Directory {\n /** All users that can be `@`-mentioned (served by `GET /api/editor/users`); must not include credentials. */\n listUsers(): Promise<MentionUser[]>\n}\n\n/** Uploaded files. */\nexport interface AssetStore {\n /** Stores an uploaded file (`GET /api/editor/assets/:id/:name` serves it). `id` is a document id or `SCRATCH_DOCUMENT_ID`; it may name no existing document. */\n storeAsset(id: string, asset: AssetRecord & { data: Buffer }): Promise<void>\n /** A stored file with its record; `null` = unknown id or name. */\n loadAsset(id: string, name: string): Promise<{ record: AssetRecord, data: Buffer } | null>\n}\n\n/** Per-user editor settings. Without this port the client keeps settings in localStorage only. */\nexport interface SettingsStore {\n /** Per-user editor settings as stored (`null` = none yet), validated by `GET /api/editor/settings`. */\n loadSettings(user: object): Promise<unknown | null>\n /** Stores validated settings for the user from `authenticate`. */\n storeSettings(user: object, settings: EditorSettings): Promise<void>\n}\n\n/** The theme library shared by all users. Without this port the themes feature is uninstalled: its routes answer 501. */\nexport interface ThemeStore {\n /** All themes (`GET /api/editor/themes`). */\n listThemes(): Promise<ThemeRecord[]>\n /** A theme's record and `theme.css` (`GET /api/editor/themes/:id`); `null` = unknown id. */\n loadTheme(id: string): Promise<{ record: ThemeRecord, css: string } | null>\n /** Stores an uploaded theme (`POST /api/editor/themes`). */\n storeTheme(record: Omit<ThemeRecord, 'builtin'>, css: string): Promise<void>\n /** Deletes an uploaded theme (`DELETE /api/editor/themes/:id`); `false` = not found or builtin. */\n removeTheme(id: string): Promise<boolean>\n}\n\n/** The host's own language models for the AI endpoints; both members fall through to the runtime-config presets. */\nexport interface ModelProvider {\n /**\n * The language model for `ref`, so the AI endpoints use the host's own providers; consulted before the runtime-config\n * presets for every model reference. `user` is what `authenticate` returned. `null` falls through to the presets\n * (and answers 400 for a preset that is not configured either).\n */\n languageModel?(ref: ModelRef, user: object | null): Promise<LanguageModel | null>\n /**\n * The models `GET /api/ai/models` lists for `user`, instead of the runtime-config presets (list them with\n * `source: 'preset'` and the `id` that `languageModel` receives as `{ preset: id }`). `null` (or omitting the method)\n * lists the presets.\n */\n listModels?(user: object | null): Promise<ModelProfile[] | null>\n}\n\n/** Everything the editor's server reads from the host, one port per capability. Only `identity` and `documents` are required. */\nexport interface EditorPorts {\n identity: Identity\n documents: DocumentStore & Partial<DocumentAdmin>\n /** Required by the collaboration server. */\n collabState?: CollabStateStore\n directory?: Directory\n assets?: AssetStore\n settings?: SettingsStore\n themes?: ThemeStore\n models?: ModelProvider\n /** Where the comment threads live (`adapters/comments/{json,drizzle}`). */\n comments?: CommentStore\n}\n\n/** The capability each optional port provides; `identity` is no capability, `tags` derive from `documents` (see `serverCapabilities`). */\nexport const PORT_CAPABILITY: Record<Exclude<keyof EditorPorts, 'identity'>, BackendCapability> = {\n documents: 'documents',\n collabState: 'collaboration',\n directory: 'users',\n assets: 'assets',\n settings: 'settings',\n themes: 'themes',\n models: 'ai',\n comments: 'comments',\n}\n\n/**\n * The capabilities `ports` serves: those of every present port, plus `tags` (derived from `documents.listContents`).\n * Two capabilities depend on more than a port: `ai` (the AI routes need configured models) and `collaboration` (the\n * websocket needs the collab server). `served` states what the installed server really mounts and overrides the port-based\n * answer for them; omitted keys follow the ports.\n */\nexport function serverCapabilities(ports: EditorPorts, served: { ai?: boolean, collaboration?: boolean } = {}): BackendCapability[] {\n const capabilities = new Set<BackendCapability>(\n (Object.keys(PORT_CAPABILITY) as (keyof typeof PORT_CAPABILITY)[])\n .filter(port => ports[port] !== undefined)\n .map(port => PORT_CAPABILITY[port]),\n )\n for (const capability of ['ai', 'collaboration'] as const) {\n if (served[capability] === true) capabilities.add(capability)\n else if (served[capability] === false) capabilities.delete(capability)\n }\n if (ports.documents) capabilities.add('tags')\n return [...capabilities]\n}\n"],"mappings":";;AAyIA,MAAa,kBAAqF;CAChG,WAAW;CACX,aAAa;CACb,WAAW;CACX,QAAQ;CACR,UAAU;CACV,QAAQ;CACR,QAAQ;CACR,UAAU;AACZ;;;;;;;AAQA,SAAgB,mBAAmB,OAAoB,SAAoD,CAAC,GAAwB;CAClI,MAAM,eAAe,IAAI,IACtB,OAAO,KAAK,eAAe,CAAC,CAC1B,QAAO,SAAQ,MAAM,UAAU,KAAA,CAAS,CAAC,CACzC,KAAI,SAAQ,gBAAgB,KAAK,CACtC;CACA,KAAK,MAAM,cAAc,CAAC,MAAM,eAAe,GAC7C,IAAI,OAAO,gBAAgB,MAAM,aAAa,IAAI,UAAU;MACvD,IAAI,OAAO,gBAAgB,OAAO,aAAa,OAAO,UAAU;CAEvE,IAAI,MAAM,WAAW,aAAa,IAAI,MAAM;CAC5C,OAAO,CAAC,GAAG,YAAY;AACzB"}