@ecsplico/editor 2.1.2 → 3.1.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 (706) hide show
  1. package/CHANGELOG.md +78 -1
  2. package/README.md +39 -156
  3. package/dist/adapters/comments/drizzle.d.ts +1 -1
  4. package/dist/adapters/comments/record.d.ts +15 -0
  5. package/dist/adapters/comments/{client.js → rest-model.js} +3 -3
  6. package/dist/adapters/comments/rest-model.js.map +1 -0
  7. package/dist/adapters/comments/server.d.ts +2 -1
  8. package/dist/adapters/comments/server.js +2 -1
  9. package/dist/adapters/comments/server.js.map +1 -1
  10. package/dist/adapters/comments/types.d.ts +2 -2
  11. package/dist/adapters/document-state.d.ts +23 -0
  12. package/dist/adapters/document-state.js +66 -0
  13. package/dist/adapters/document-state.js.map +1 -0
  14. package/dist/adapters/documents.js +14 -11
  15. package/dist/adapters/documents.js.map +1 -1
  16. package/dist/adapters/drizzle.d.ts +2 -2
  17. package/dist/adapters/drizzle.js +97 -88
  18. package/dist/adapters/drizzle.js.map +1 -1
  19. package/dist/adapters/forge.d.ts +12 -7
  20. package/dist/adapters/forge.js +38 -45
  21. package/dist/adapters/forge.js.map +1 -1
  22. package/dist/adapters/http.d.ts +20 -0
  23. package/dist/adapters/http.js +68 -0
  24. package/dist/adapters/http.js.map +1 -0
  25. package/dist/adapters/index.d.ts +5 -5
  26. package/dist/adapters/json.d.ts +3 -3
  27. package/dist/adapters/json.js +58 -49
  28. package/dist/adapters/json.js.map +1 -1
  29. package/dist/adapters/memory.d.ts +21 -0
  30. package/dist/adapters/memory.js +53 -0
  31. package/dist/adapters/memory.js.map +1 -0
  32. package/dist/adapters/nitro.d.ts +27 -20
  33. package/dist/adapters/nitro.js +59 -163
  34. package/dist/adapters/nitro.js.map +1 -1
  35. package/dist/adapters/react.d.ts +55 -0
  36. package/dist/adapters/react.js +209 -0
  37. package/dist/adapters/react.js.map +1 -0
  38. package/dist/adapters/shared.d.ts +15 -21
  39. package/dist/adapters/shared.js +10 -8
  40. package/dist/adapters/shared.js.map +1 -1
  41. package/dist/adapters/vue.d.ts +15 -30
  42. package/dist/adapters/vue.js +36 -87
  43. package/dist/adapters/vue.js.map +1 -1
  44. package/dist/code/CodeSurface.vue.d.ts +2 -2
  45. package/dist/config/index.d.ts +105 -0
  46. package/dist/config/index.js +95 -0
  47. package/dist/config/index.js.map +1 -0
  48. package/dist/core/abilities.js +1 -0
  49. package/dist/core/abilities.js.map +1 -1
  50. package/dist/{adapters/routes.js → core/api-routes.js} +5 -3
  51. package/dist/core/api-routes.js.map +1 -0
  52. package/dist/core/backend-capability.d.ts +7 -0
  53. package/dist/core/backend-capability.js +17 -0
  54. package/dist/core/backend-capability.js.map +1 -0
  55. package/dist/core/backend-types.d.ts +245 -0
  56. package/dist/core/backend-types.js +17 -0
  57. package/dist/core/backend-types.js.map +1 -0
  58. package/dist/core/backend.d.ts +108 -0
  59. package/dist/core/backend.js +14 -0
  60. package/dist/core/backend.js.map +1 -0
  61. package/dist/core/block-convert.d.ts +7 -5
  62. package/dist/core/block-convert.js +28 -5
  63. package/dist/core/block-convert.js.map +1 -1
  64. package/dist/core/command-types.d.ts +96 -0
  65. package/dist/core/commands.d.ts +40 -0
  66. package/dist/core/commands.js +151 -0
  67. package/dist/core/commands.js.map +1 -0
  68. package/dist/core/context.d.ts +17 -20
  69. package/dist/core/context.js +24 -21
  70. package/dist/core/context.js.map +1 -1
  71. package/dist/core/core-feature.d.ts +22 -7
  72. package/dist/core/core-feature.js +51 -18
  73. package/dist/core/core-feature.js.map +1 -1
  74. package/dist/core/define-editor.d.ts +4 -3
  75. package/dist/core/define-editor.js +14 -7
  76. package/dist/core/define-editor.js.map +1 -1
  77. package/dist/core/document-markdown.js +12 -3
  78. package/dist/core/document-markdown.js.map +1 -1
  79. package/dist/core/editor-ui.d.ts +8 -1
  80. package/dist/core/editor-ui.js +9 -8
  81. package/dist/core/editor-ui.js.map +1 -1
  82. package/dist/core/extension-points.d.ts +3 -15
  83. package/dist/core/feature-context.d.ts +8 -7
  84. package/dist/core/feature-context.js +12 -11
  85. package/dist/core/feature-context.js.map +1 -1
  86. package/dist/core/feature.d.ts +41 -19
  87. package/dist/core/feature.js.map +1 -1
  88. package/dist/core/fences.d.ts +2 -1
  89. package/dist/core/fences.js +3 -2
  90. package/dist/core/fences.js.map +1 -1
  91. package/dist/core/fetch-error.d.ts +1 -1
  92. package/dist/core/fetch-error.js +3 -1
  93. package/dist/core/fetch-error.js.map +1 -1
  94. package/dist/core/hash.d.ts +5 -0
  95. package/dist/core/hash.js +11 -0
  96. package/dist/core/hash.js.map +1 -0
  97. package/dist/core/http-backend.d.ts +11 -0
  98. package/dist/core/http-backend.js +195 -0
  99. package/dist/core/http-backend.js.map +1 -0
  100. package/dist/core/index.d.ts +15 -9
  101. package/dist/core/index.js +13 -9
  102. package/dist/core/palette.d.ts +48 -0
  103. package/dist/core/palette.js +95 -0
  104. package/dist/core/palette.js.map +1 -0
  105. package/dist/core/schema/abilities.d.ts +2 -1
  106. package/dist/core/schema/abilities.js +5 -1
  107. package/dist/core/schema/abilities.js.map +1 -1
  108. package/dist/core/schema/index.d.ts +11 -5
  109. package/dist/core/schema/index.js +13 -8
  110. package/dist/core/schema/index.js.map +1 -1
  111. package/dist/core/schema/mark-flags.d.ts +8 -1
  112. package/dist/core/schema/of-features.d.ts +13 -0
  113. package/dist/core/schema/of-features.js +14 -0
  114. package/dist/core/schema/of-features.js.map +1 -0
  115. package/dist/core/slash.d.ts +8 -6
  116. package/dist/core/slash.js +24 -16
  117. package/dist/core/slash.js.map +1 -1
  118. package/dist/core/surface-session.js +15 -5
  119. package/dist/core/surface-session.js.map +1 -1
  120. package/dist/core/toolbar-items.d.ts +10 -4
  121. package/dist/core/toolbar-items.js +269 -195
  122. package/dist/core/toolbar-items.js.map +1 -1
  123. package/dist/core/transaction-guards.d.ts +21 -0
  124. package/dist/core/transaction-guards.js +49 -0
  125. package/dist/core/transaction-guards.js.map +1 -0
  126. package/dist/core/util.js +11 -0
  127. package/dist/core/util.js.map +1 -0
  128. package/dist/document/DocumentSurface.d.ts +1 -1
  129. package/dist/document/DocumentSurface.vue.d.ts +2 -2
  130. package/dist/features/ai/agent-op-review.d.ts +1 -1
  131. package/dist/features/ai/agent-op-review.js +1 -1
  132. package/dist/features/ai/agent-ops.js +1 -1
  133. package/dist/features/ai/ai-apply.d.ts +2 -2
  134. package/dist/features/ai/ai-apply.js +1 -1
  135. package/dist/features/ai/ai-review.js +1 -1
  136. package/dist/features/ai/ai-sse.d.ts +6 -6
  137. package/dist/features/ai/ai-sse.js +20 -63
  138. package/dist/features/ai/ai-sse.js.map +1 -1
  139. package/dist/features/ai/assistant.d.ts +8 -7
  140. package/dist/features/ai/assistant.js +3 -3
  141. package/dist/features/ai/assistant.js.map +1 -1
  142. package/dist/features/ai/block-actions.d.ts +3 -2
  143. package/dist/features/ai/block-actions.js +3 -2
  144. package/dist/features/ai/block-actions.js.map +1 -1
  145. package/dist/features/ai/components/AiSelectionMenu.js +1 -1
  146. package/dist/features/ai/components/DocumentChatAnswer.js +1 -1
  147. package/dist/features/ai/components/DocumentChatOps.vue.d.ts +1 -1
  148. package/dist/features/ai/components/SettingsModelProfiles.js +8 -8
  149. package/dist/features/ai/components/SettingsModelProfiles.js.map +1 -1
  150. package/dist/features/ai/document-chat-model.d.ts +8 -7
  151. package/dist/features/ai/document-chat-model.js +5 -5
  152. package/dist/features/ai/document-chat-model.js.map +1 -1
  153. package/dist/features/ai/document-chat.js +1 -1
  154. package/dist/features/ai/feature.js +27 -14
  155. package/dist/features/ai/feature.js.map +1 -1
  156. package/dist/features/ai/ghost-autocomplete.d.ts +7 -6
  157. package/dist/features/ai/ghost-autocomplete.js +6 -9
  158. package/dist/features/ai/ghost-autocomplete.js.map +1 -1
  159. package/dist/features/ai/index.d.ts +4 -3
  160. package/dist/features/ai/index.js +10 -10
  161. package/dist/features/ai/model-profiles.d.ts +5 -4
  162. package/dist/features/ai/model-profiles.js +2 -2
  163. package/dist/features/ai/model-profiles.js.map +1 -1
  164. package/dist/features/ai/protocol/block-lines.js +1 -1
  165. package/dist/features/ai/protocol/block-lines.js.map +1 -1
  166. package/dist/features/ai/protocol/chat.js +6 -2
  167. package/dist/features/ai/protocol/chat.js.map +1 -1
  168. package/dist/features/ai/protocol/index.d.ts +3 -2
  169. package/dist/features/ai/protocol/models.d.ts +2 -16
  170. package/dist/features/ai/protocol/models.js.map +1 -1
  171. package/dist/features/ai/rate-limit.d.ts +1 -1
  172. package/dist/features/ai/rate-limit.js +3 -1
  173. package/dist/features/ai/rate-limit.js.map +1 -1
  174. package/dist/features/ai/react/AiSelectionMenu.js +2 -2
  175. package/dist/features/ai/react/AiSidebar.js +4 -4
  176. package/dist/features/ai/react/DocumentChatAnswer.js +1 -1
  177. package/dist/features/ai/react/DocumentChatOps.d.ts +1 -1
  178. package/dist/features/ai/react/DocumentChatOps.js +1 -1
  179. package/dist/features/ai/react/SettingsModelProfiles.js +8 -10
  180. package/dist/features/ai/react/SettingsModelProfiles.js.map +1 -1
  181. package/dist/features/ai/react/use-ai-assistant.d.ts +1 -1
  182. package/dist/features/ai/react/use-ai-assistant.js +3 -3
  183. package/dist/features/ai/react/use-ai-assistant.js.map +1 -1
  184. package/dist/features/ai/react/use-document-chat.js +2 -2
  185. package/dist/features/ai/react/use-document-chat.js.map +1 -1
  186. package/dist/features/ai/react/use-model-profiles.d.ts +2 -1
  187. package/dist/features/ai/selection-flow.d.ts +1 -1
  188. package/dist/features/ai/selection-flow.js +1 -1
  189. package/dist/features/ai/sidebar-flow.d.ts +1 -1
  190. package/dist/features/ai/sidebar-flow.js +1 -1
  191. package/dist/features/ai/use-ai-assistant.d.ts +1 -1
  192. package/dist/features/ai/use-ai-assistant.js +3 -3
  193. package/dist/features/ai/use-ai-assistant.js.map +1 -1
  194. package/dist/features/ai/use-document-chat.js +2 -2
  195. package/dist/features/ai/use-document-chat.js.map +1 -1
  196. package/dist/features/ai/use-model-profiles.d.ts +2 -1
  197. package/dist/features/authors/attribution.d.ts +1 -1
  198. package/dist/features/authors/feature.js +12 -11
  199. package/dist/features/authors/feature.js.map +1 -1
  200. package/dist/features/block-ui/block-actions.d.ts +1 -1
  201. package/dist/features/block-ui/block-actions.js +1 -1
  202. package/dist/features/block-ui/block-actions.js.map +1 -1
  203. package/dist/features/block-ui/components/BlockUi.js +1 -1
  204. package/dist/features/block-ui/feature.js +1 -0
  205. package/dist/features/block-ui/feature.js.map +1 -1
  206. package/dist/features/block-ui/react/BlockUi.js +1 -1
  207. package/dist/features/collab/anchor-resolver.js +1 -1
  208. package/dist/features/collab/feature.js +2 -0
  209. package/dist/features/collab/feature.js.map +1 -1
  210. package/dist/features/comments/components/CommentThreadView.vue.d.ts +2 -1
  211. package/dist/features/comments/feature.js +12 -11
  212. package/dist/features/comments/feature.js.map +1 -1
  213. package/dist/features/comments/index.d.ts +3 -2
  214. package/dist/features/comments/index.js +1 -1
  215. package/dist/features/comments/margin-layout.d.ts +3 -2
  216. package/dist/features/comments/model.d.ts +3 -67
  217. package/dist/features/comments/model.js +2 -2
  218. package/dist/features/comments/model.js.map +1 -1
  219. package/dist/features/comments/react/CommentThreadView.d.ts +3 -2
  220. package/dist/features/comments/react/use-comments.d.ts +2 -1
  221. package/dist/features/comments/react.d.ts +1 -1
  222. package/dist/features/comments/schema.d.ts +2 -52
  223. package/dist/features/comments/schema.js.map +1 -1
  224. package/dist/features/comments/snapshot-equality.js.map +1 -1
  225. package/dist/features/comments/use-comments.d.ts +3 -2
  226. package/dist/features/comments/vue.d.ts +1 -1
  227. package/dist/features/composites/accepted-children.d.ts +1 -0
  228. package/dist/features/composites/accepted-children.js +16 -1
  229. package/dist/features/composites/accepted-children.js.map +1 -1
  230. package/dist/features/composites/ai-brief.js +39 -0
  231. package/dist/features/composites/ai-brief.js.map +1 -1
  232. package/dist/features/composites/bibliography-command.d.ts +11 -0
  233. package/dist/features/composites/bibliography-form.js +90 -0
  234. package/dist/features/composites/bibliography-form.js.map +1 -0
  235. package/dist/features/composites/bibliography.d.ts +33 -0
  236. package/dist/features/composites/bibliography.js +120 -0
  237. package/dist/features/composites/bibliography.js.map +1 -0
  238. package/dist/features/composites/components/BibliographyEditor.js +261 -0
  239. package/dist/features/composites/components/BibliographyEditor.js.map +1 -0
  240. package/dist/features/composites/components/CompositeChrome.js +78 -29
  241. package/dist/features/composites/components/CompositeChrome.js.map +1 -1
  242. package/dist/features/composites/components/CompositeChrome.vue.d.ts +1 -1
  243. package/dist/features/composites/components/CompositeDetails.js +46 -11
  244. package/dist/features/composites/components/CompositeDetails.js.map +1 -1
  245. package/dist/features/composites/components/CompositeDetails.vue.d.ts +2 -1
  246. package/dist/features/composites/components/CompositeFieldEditor.js +64 -5
  247. package/dist/features/composites/components/CompositeFieldEditor.js.map +1 -1
  248. package/dist/features/composites/components/CompositeInspector.js +20 -7
  249. package/dist/features/composites/components/CompositeInspector.js.map +1 -1
  250. package/dist/features/composites/components/CompositeTable.js +13 -4
  251. package/dist/features/composites/components/CompositeTable.js.map +1 -1
  252. package/dist/features/composites/components/CompositeTagsEditor.js +1 -1
  253. package/dist/features/composites/components/CompositeView.js +11 -1
  254. package/dist/features/composites/components/CompositeView.js.map +1 -1
  255. package/dist/features/composites/components/DerivationBadge.js +103 -0
  256. package/dist/features/composites/components/DerivationBadge.js.map +1 -0
  257. package/dist/features/composites/components/ReferenceFieldSelect.js +60 -0
  258. package/dist/features/composites/components/ReferenceFieldSelect.js.map +1 -0
  259. package/dist/features/composites/components/ReferenceView.js +122 -0
  260. package/dist/features/composites/components/ReferenceView.js.map +1 -0
  261. package/dist/features/composites/components/ReferenceView.vue.d.ts +96 -0
  262. package/dist/features/composites/components/SettingsEditingTab.js +1 -1
  263. package/dist/features/composites/convert.js +2 -2
  264. package/dist/features/composites/convert.js.map +1 -1
  265. package/dist/features/composites/derivation.d.ts +61 -0
  266. package/dist/features/composites/derivation.js +98 -0
  267. package/dist/features/composites/derivation.js.map +1 -0
  268. package/dist/features/composites/derived-chrome.js +69 -0
  269. package/dist/features/composites/derived-chrome.js.map +1 -0
  270. package/dist/features/composites/feature.js +159 -109
  271. package/dist/features/composites/feature.js.map +1 -1
  272. package/dist/features/composites/fences.d.ts +4 -3
  273. package/dist/features/composites/fences.js +51 -7
  274. package/dist/features/composites/fences.js.map +1 -1
  275. package/dist/features/composites/index.d.ts +12 -3
  276. package/dist/features/composites/index.js +15 -6
  277. package/dist/features/composites/inspector-model.d.ts +4 -1
  278. package/dist/features/composites/inspector-model.js +8 -4
  279. package/dist/features/composites/inspector-model.js.map +1 -1
  280. package/dist/features/composites/kinds.d.ts +16 -2
  281. package/dist/features/composites/kinds.js +145 -6
  282. package/dist/features/composites/kinds.js.map +1 -1
  283. package/dist/features/composites/legacy.d.ts +4 -1
  284. package/dist/features/composites/legacy.js +56 -1
  285. package/dist/features/composites/legacy.js.map +1 -1
  286. package/dist/features/composites/meta-display.js +45 -2
  287. package/dist/features/composites/meta-display.js.map +1 -1
  288. package/dist/features/composites/meta-keys.d.ts +7 -0
  289. package/dist/features/composites/meta-keys.js +21 -0
  290. package/dist/features/composites/meta-keys.js.map +1 -0
  291. package/dist/features/composites/node-views.d.ts +6 -3
  292. package/dist/features/composites/node-views.js +7 -3
  293. package/dist/features/composites/node-views.js.map +1 -1
  294. package/dist/features/composites/nodes.d.ts +6 -1
  295. package/dist/features/composites/nodes.js +33 -7
  296. package/dist/features/composites/nodes.js.map +1 -1
  297. package/dist/features/composites/react/BibliographyEditor.js +229 -0
  298. package/dist/features/composites/react/BibliographyEditor.js.map +1 -0
  299. package/dist/features/composites/react/CompositeChrome.js +67 -19
  300. package/dist/features/composites/react/CompositeChrome.js.map +1 -1
  301. package/dist/features/composites/react/CompositeDetails.d.ts +2 -1
  302. package/dist/features/composites/react/CompositeDetails.js +45 -6
  303. package/dist/features/composites/react/CompositeDetails.js.map +1 -1
  304. package/dist/features/composites/react/CompositeFieldEditor.d.ts +1 -1
  305. package/dist/features/composites/react/CompositeFieldEditor.js +43 -1
  306. package/dist/features/composites/react/CompositeFieldEditor.js.map +1 -1
  307. package/dist/features/composites/react/CompositeInspector.js +12 -6
  308. package/dist/features/composites/react/CompositeInspector.js.map +1 -1
  309. package/dist/features/composites/react/CompositeStatusMenu.js +1 -1
  310. package/dist/features/composites/react/CompositeSummaryEditor.js +1 -1
  311. package/dist/features/composites/react/CompositeTable.js +16 -2
  312. package/dist/features/composites/react/CompositeTable.js.map +1 -1
  313. package/dist/features/composites/react/CompositeTagsEditor.js +2 -2
  314. package/dist/features/composites/react/CompositeView.js +6 -1
  315. package/dist/features/composites/react/CompositeView.js.map +1 -1
  316. package/dist/features/composites/react/DerivationBadge.js +116 -0
  317. package/dist/features/composites/react/DerivationBadge.js.map +1 -0
  318. package/dist/features/composites/react/ReferenceFieldSelect.js +52 -0
  319. package/dist/features/composites/react/ReferenceFieldSelect.js.map +1 -0
  320. package/dist/features/composites/react/ReferenceView.d.ts +11 -0
  321. package/dist/features/composites/react/ReferenceView.js +115 -0
  322. package/dist/features/composites/react/ReferenceView.js.map +1 -0
  323. package/dist/features/composites/react/SettingsEditingTab.js +2 -2
  324. package/dist/features/composites/react.d.ts +2 -1
  325. package/dist/features/composites/react.js +7 -3
  326. package/dist/features/composites/react.js.map +1 -1
  327. package/dist/features/composites/reference-ai.js +16 -0
  328. package/dist/features/composites/reference-ai.js.map +1 -0
  329. package/dist/features/composites/reference-label.d.ts +19 -0
  330. package/dist/features/composites/reference-label.js +58 -0
  331. package/dist/features/composites/reference-label.js.map +1 -0
  332. package/dist/features/composites/reference-suggestion.d.ts +10 -0
  333. package/dist/features/composites/reference-suggestion.js +41 -0
  334. package/dist/features/composites/reference-suggestion.js.map +1 -0
  335. package/dist/features/composites/reference-text.d.ts +18 -0
  336. package/dist/features/composites/reference-text.js +89 -0
  337. package/dist/features/composites/reference-text.js.map +1 -0
  338. package/dist/features/composites/reference.d.ts +44 -0
  339. package/dist/features/composites/reference.js +148 -0
  340. package/dist/features/composites/reference.js.map +1 -0
  341. package/dist/features/composites/reveal-source.d.ts +32 -0
  342. package/dist/features/composites/reveal-source.js +89 -0
  343. package/dist/features/composites/reveal-source.js.map +1 -0
  344. package/dist/features/composites/rows.d.ts +25 -3
  345. package/dist/features/composites/rows.js +72 -10
  346. package/dist/features/composites/rows.js.map +1 -1
  347. package/dist/features/composites/schema.d.ts +9 -3
  348. package/dist/features/composites/schema.js +11 -4
  349. package/dist/features/composites/schema.js.map +1 -1
  350. package/dist/features/composites/table-model.js +12 -21
  351. package/dist/features/composites/table-model.js.map +1 -1
  352. package/dist/features/composites/vue.d.ts +3 -2
  353. package/dist/features/composites/vue.js +8 -4
  354. package/dist/features/composites/vue.js.map +1 -1
  355. package/dist/features/media/assets.d.ts +2 -0
  356. package/dist/features/media/assets.js +3 -2
  357. package/dist/features/media/assets.js.map +1 -1
  358. package/dist/features/media/components/FileView.js +13 -4
  359. package/dist/features/media/components/FileView.js.map +1 -1
  360. package/dist/features/media/feature.d.ts +3 -3
  361. package/dist/features/media/feature.js +21 -28
  362. package/dist/features/media/feature.js.map +1 -1
  363. package/dist/features/media/file-import.js +2 -2
  364. package/dist/features/media/file-import.js.map +1 -1
  365. package/dist/features/media/index.d.ts +2 -2
  366. package/dist/features/media/index.js +3 -3
  367. package/dist/features/media/react/AudioRecorderModal.js +1 -1
  368. package/dist/features/media/react/FileView.js +19 -2
  369. package/dist/features/media/react/FileView.js.map +1 -1
  370. package/dist/features/media/react.js +1 -1
  371. package/dist/features/media/schema.d.ts +8 -0
  372. package/dist/features/media/schema.js +126 -11
  373. package/dist/features/media/schema.js.map +1 -1
  374. package/dist/features/media/upload.d.ts +16 -14
  375. package/dist/features/media/upload.js +13 -19
  376. package/dist/features/media/upload.js.map +1 -1
  377. package/dist/features/mentions/index.d.ts +4 -3
  378. package/dist/features/mentions/index.js +4 -1
  379. package/dist/features/mentions/index.js.map +1 -1
  380. package/dist/features/mentions/mention-text.d.ts +1 -1
  381. package/dist/features/mentions/mention-text.js.map +1 -1
  382. package/dist/features/mentions/mention.d.ts +0 -6
  383. package/dist/features/mentions/mention.js.map +1 -1
  384. package/dist/features/mentions/metadata-defaults.d.ts +2 -2
  385. package/dist/features/mentions/metadata-defaults.js +3 -9
  386. package/dist/features/mentions/metadata-defaults.js.map +1 -1
  387. package/dist/features/mentions/schema.d.ts +2 -1
  388. package/dist/features/mentions/schema.js.map +1 -1
  389. package/dist/features/tables/feature.d.ts +2 -1
  390. package/dist/features/tables/feature.js +90 -70
  391. package/dist/features/tables/feature.js.map +1 -1
  392. package/dist/features/themes/components/SettingsAppearanceTab.js +6 -9
  393. package/dist/features/themes/components/SettingsAppearanceTab.js.map +1 -1
  394. package/dist/features/themes/feature.js +2 -0
  395. package/dist/features/themes/feature.js.map +1 -1
  396. package/dist/features/themes/index.d.ts +2 -1
  397. package/dist/features/themes/react/SettingsAppearanceTab.js +7 -10
  398. package/dist/features/themes/react/SettingsAppearanceTab.js.map +1 -1
  399. package/dist/features/themes/schema.d.ts +2 -6
  400. package/dist/features/themes/schema.js.map +1 -1
  401. package/dist/features/themes/theme-runtime.d.ts +1 -1
  402. package/dist/features/themes/theme-runtime.js +4 -2
  403. package/dist/features/themes/theme-runtime.js.map +1 -1
  404. package/dist/features/transcript/TranscriptSegmentView.js +48 -28
  405. package/dist/features/transcript/TranscriptSegmentView.js.map +1 -1
  406. package/dist/features/transcript/feature.js +21 -19
  407. package/dist/features/transcript/feature.js.map +1 -1
  408. package/dist/features/transcript/react/TranscriptSegmentView.js +55 -36
  409. package/dist/features/transcript/react/TranscriptSegmentView.js.map +1 -1
  410. package/dist/features/transcript/segment-node.d.ts +2 -0
  411. package/dist/features/transcript/segment-node.js +35 -7
  412. package/dist/features/transcript/segment-node.js.map +1 -1
  413. package/dist/i18n/de/composites.js +91 -1
  414. package/dist/i18n/de/composites.js.map +1 -1
  415. package/dist/i18n/de/integrations.js +49 -8
  416. package/dist/i18n/de/integrations.js.map +1 -1
  417. package/dist/i18n/de/media.js +0 -1
  418. package/dist/i18n/de/media.js.map +1 -1
  419. package/dist/i18n/de/palette.js +22 -0
  420. package/dist/i18n/de/palette.js.map +1 -0
  421. package/dist/i18n/de/tables.js +0 -1
  422. package/dist/i18n/de/tables.js.map +1 -1
  423. package/dist/i18n/de/transcript.js +2 -1
  424. package/dist/i18n/de/transcript.js.map +1 -1
  425. package/dist/i18n/de/tree.js +3 -0
  426. package/dist/i18n/de/tree.js.map +1 -1
  427. package/dist/i18n/de.d.ts +157 -11
  428. package/dist/i18n/de.js +3 -1
  429. package/dist/i18n/de.js.map +1 -1
  430. package/dist/i18n/en/composites.js +89 -1
  431. package/dist/i18n/en/composites.js.map +1 -1
  432. package/dist/i18n/en/integrations.js +49 -8
  433. package/dist/i18n/en/integrations.js.map +1 -1
  434. package/dist/i18n/en/media.js +0 -1
  435. package/dist/i18n/en/media.js.map +1 -1
  436. package/dist/i18n/en/palette.js +22 -0
  437. package/dist/i18n/en/palette.js.map +1 -0
  438. package/dist/i18n/en/tables.js +0 -1
  439. package/dist/i18n/en/tables.js.map +1 -1
  440. package/dist/i18n/en/transcript.js +2 -1
  441. package/dist/i18n/en/transcript.js.map +1 -1
  442. package/dist/i18n/en/tree.js +3 -0
  443. package/dist/i18n/en/tree.js.map +1 -1
  444. package/dist/i18n/en.js +3 -1
  445. package/dist/i18n/en.js.map +1 -1
  446. package/dist/index.d.ts +4 -3
  447. package/dist/integrations/composite-ai/bibliography-fetch.d.ts +31 -0
  448. package/dist/integrations/composite-ai/bibliography-fetch.js +159 -0
  449. package/dist/integrations/composite-ai/bibliography-fetch.js.map +1 -0
  450. package/dist/integrations/composite-ai/composite-fill.d.ts +30 -8
  451. package/dist/integrations/composite-ai/composite-fill.js +97 -56
  452. package/dist/integrations/composite-ai/composite-fill.js.map +1 -1
  453. package/dist/integrations/composite-ai/composite-summary.d.ts +4 -12
  454. package/dist/integrations/composite-ai/composite-summary.js +7 -26
  455. package/dist/integrations/composite-ai/composite-summary.js.map +1 -1
  456. package/dist/integrations/composite-ai/derive.d.ts +29 -0
  457. package/dist/integrations/composite-ai/derive.js +173 -0
  458. package/dist/integrations/composite-ai/derive.js.map +1 -0
  459. package/dist/integrations/composite-ai/index.d.ts +11 -7
  460. package/dist/integrations/composite-ai/index.js +72 -14
  461. package/dist/integrations/composite-ai/index.js.map +1 -1
  462. package/dist/integrations/composite-ai/rendition.d.ts +45 -0
  463. package/dist/integrations/composite-ai/rendition.js +314 -0
  464. package/dist/integrations/composite-ai/rendition.js.map +1 -0
  465. package/dist/integrations/composite-media/index.d.ts +7 -5
  466. package/dist/integrations/composite-media/index.js +86 -13
  467. package/dist/integrations/composite-media/index.js.map +1 -1
  468. package/dist/integrations/transcript-ai/index.d.ts +1 -1
  469. package/dist/integrations/transcript-ai/index.js +5 -2
  470. package/dist/integrations/transcript-ai/index.js.map +1 -1
  471. package/dist/integrations/transcript-ai/protocol.d.ts +2 -12
  472. package/dist/integrations/transcript-ai/protocol.js +0 -2
  473. package/dist/integrations/transcript-ai/protocol.js.map +1 -1
  474. package/dist/integrations/transcript-ai/transcript-cleanup.d.ts +5 -5
  475. package/dist/integrations/transcript-ai/transcript-cleanup.js +7 -10
  476. package/dist/integrations/transcript-ai/transcript-cleanup.js.map +1 -1
  477. package/dist/markdown/MarkdownSurface.vue.d.ts +12 -11
  478. package/dist/markdown/MarkdownSurface2.js +3 -6
  479. package/dist/markdown/MarkdownSurface2.js.map +1 -1
  480. package/dist/markdown/document.js +1 -1
  481. package/dist/markdown/source-mode.d.ts +1 -1
  482. package/dist/nuxt/module.d.ts +1402 -54
  483. package/dist/nuxt/module.js +6 -49
  484. package/dist/nuxt/module.js.map +1 -1
  485. package/dist/nuxt/runtime/install-context.d.ts +7 -3
  486. package/dist/nuxt/runtime/install-context.js +14 -8
  487. package/dist/nuxt/runtime/install-context.js.map +1 -1
  488. package/dist/nuxt/runtime/plugins/editor-context-nuxt-ui.client.ts +2 -2
  489. package/dist/nuxt/runtime/server/plugins/editor-server.js +20 -12
  490. package/dist/nuxt/runtime/server/plugins/editor-server.js.map +1 -1
  491. package/dist/presets/compose.d.ts +94 -0
  492. package/dist/presets/compose.js +164 -0
  493. package/dist/presets/compose.js.map +1 -0
  494. package/dist/react/AdvancedEditor.d.ts +15 -15
  495. package/dist/react/AdvancedEditor.js +15 -13
  496. package/dist/react/AdvancedEditor.js.map +1 -1
  497. package/dist/react/EditorCommandPalette.d.ts +13 -0
  498. package/dist/react/EditorCommandPalette.js +118 -0
  499. package/dist/react/EditorCommandPalette.js.map +1 -0
  500. package/dist/react/EditorSettingsModal.d.ts +5 -5
  501. package/dist/react/EditorSettingsModal.js +7 -4
  502. package/dist/react/EditorSettingsModal.js.map +1 -1
  503. package/dist/react/EditorSettingsPanel.d.ts +7 -7
  504. package/dist/react/EditorSettingsPanel.js +8 -5
  505. package/dist/react/EditorSettingsPanel.js.map +1 -1
  506. package/dist/react/EditorSurface.d.ts +7 -7
  507. package/dist/react/EditorSurface.js +10 -6
  508. package/dist/react/EditorSurface.js.map +1 -1
  509. package/dist/react/EditorToolbar.d.ts +4 -6
  510. package/dist/react/EditorToolbar.js +29 -37
  511. package/dist/react/EditorToolbar.js.map +1 -1
  512. package/dist/react/SimpleEditor.d.ts +22 -23
  513. package/dist/react/SimpleEditor.js +21 -7
  514. package/dist/react/SimpleEditor.js.map +1 -1
  515. package/dist/react/advanced.d.ts +4 -3
  516. package/dist/react/advanced.js +2 -2
  517. package/dist/react/compose.d.ts +20 -0
  518. package/dist/react/compose.js +49 -0
  519. package/dist/react/compose.js.map +1 -0
  520. package/dist/react/composed-surface.d.ts +39 -0
  521. package/dist/react/composed-surface.js +71 -0
  522. package/dist/react/composed-surface.js.map +1 -0
  523. package/dist/react/context.js +6 -2
  524. package/dist/react/context.js.map +1 -1
  525. package/dist/react/index.d.ts +2 -1
  526. package/dist/react/index.js +2 -1
  527. package/dist/react/key-labels.js +15 -0
  528. package/dist/react/key-labels.js.map +1 -0
  529. package/dist/react/settings.d.ts +1 -1
  530. package/dist/react/simple.d.ts +2 -2
  531. package/dist/react/ui/command.js +36 -1
  532. package/dist/react/ui/command.js.map +1 -1
  533. package/dist/schema/advanced.d.ts +6 -6
  534. package/dist/schema/advanced.js +26 -29
  535. package/dist/schema/advanced.js.map +1 -1
  536. package/dist/server/ai.d.ts +5 -16
  537. package/dist/server/ai.js.map +1 -1
  538. package/dist/server/auth.d.ts +9 -0
  539. package/dist/server/collab-state.d.ts +1 -1
  540. package/dist/server/collab-state.js.map +1 -1
  541. package/dist/server/collab.d.ts +13 -13
  542. package/dist/server/collab.js +34 -18
  543. package/dist/server/collab.js.map +1 -1
  544. package/dist/server/crossref.js +78 -0
  545. package/dist/server/crossref.js.map +1 -0
  546. package/dist/server/errors.d.ts +1 -1
  547. package/dist/server/errors.js +1 -1
  548. package/dist/server/errors.js.map +1 -1
  549. package/dist/server/extract.js +308 -0
  550. package/dist/server/extract.js.map +1 -0
  551. package/dist/server/h3.d.ts +8 -0
  552. package/dist/{nuxt/runtime/server/utils/editor-route.js → server/h3.js} +8 -16
  553. package/dist/server/h3.js.map +1 -0
  554. package/dist/server/handlers/ai.d.ts +32 -10
  555. package/dist/server/handlers/ai.js +172 -37
  556. package/dist/server/handlers/ai.js.map +1 -1
  557. package/dist/server/handlers/context.d.ts +12 -5
  558. package/dist/server/handlers/context.js +10 -4
  559. package/dist/server/handlers/context.js.map +1 -1
  560. package/dist/server/handlers/editor.d.ts +19 -13
  561. package/dist/server/handlers/editor.js +49 -38
  562. package/dist/server/handlers/editor.js.map +1 -1
  563. package/dist/server/handlers/index.d.ts +4 -4
  564. package/dist/server/handlers/index.js +4 -4
  565. package/dist/server/host.d.ts +16 -25
  566. package/dist/server/host.js +58 -41
  567. package/dist/server/host.js.map +1 -1
  568. package/dist/server/index.d.ts +6 -4
  569. package/dist/server/index.js +3 -2
  570. package/dist/server/pdf.js +97 -0
  571. package/dist/server/pdf.js.map +1 -0
  572. package/dist/server/{adapter.d.ts → ports.d.ts} +81 -30
  573. package/dist/server/ports.js +29 -0
  574. package/dist/server/ports.js.map +1 -0
  575. package/dist/server/routes.d.ts +22 -0
  576. package/dist/server/routes.js +144 -0
  577. package/dist/server/routes.js.map +1 -0
  578. package/dist/settings/index.d.ts +1 -1
  579. package/dist/settings/index.js.map +1 -1
  580. package/dist/styles/composites.css +25 -0
  581. package/dist/tree/DocumentTree.js +56 -29
  582. package/dist/tree/DocumentTree.js.map +1 -1
  583. package/dist/tree/react/DocumentTree.js +23 -0
  584. package/dist/tree/react/DocumentTree.js.map +1 -1
  585. package/dist/tree/tree-host.js +2 -2
  586. package/dist/tree/tree-items.js +1 -1
  587. package/dist/vue/AdvancedEditor.js +30 -9
  588. package/dist/vue/AdvancedEditor.js.map +1 -1
  589. package/dist/vue/AdvancedEditor.vue.d.ts +32 -12
  590. package/dist/vue/SimpleEditor.js +62 -16
  591. package/dist/vue/SimpleEditor.js.map +1 -1
  592. package/dist/vue/SimpleEditor.vue.d.ts +39 -9
  593. package/dist/vue/advanced.d.ts +3 -2
  594. package/dist/vue/advanced.js +2 -2
  595. package/dist/vue/components/EditorCommandPalette.js +91 -0
  596. package/dist/vue/components/EditorCommandPalette.js.map +1 -0
  597. package/dist/vue/components/EditorCommandPalette.vue.d.ts +15 -0
  598. package/dist/vue/components/EditorSettingsModal.js +10 -6
  599. package/dist/vue/components/EditorSettingsModal.js.map +1 -1
  600. package/dist/vue/components/EditorSettingsModal.vue.d.ts +4 -4
  601. package/dist/vue/components/EditorSettingsPanel.js +10 -6
  602. package/dist/vue/components/EditorSettingsPanel.js.map +1 -1
  603. package/dist/vue/components/EditorSettingsPanel.vue.d.ts +6 -6
  604. package/dist/vue/components/EditorSurface.js +11 -6
  605. package/dist/vue/components/EditorSurface.js.map +1 -1
  606. package/dist/vue/components/EditorSurface.vue.d.ts +11 -11
  607. package/dist/vue/components/EditorToolbar.js +41 -49
  608. package/dist/vue/components/EditorToolbar.js.map +1 -1
  609. package/dist/vue/components/EditorToolbar.vue.d.ts +2 -4
  610. package/dist/vue/compose.d.ts +17 -0
  611. package/dist/vue/compose.js +51 -0
  612. package/dist/vue/compose.js.map +1 -0
  613. package/dist/vue/context-key.d.ts +6 -0
  614. package/dist/vue/context-key.js +6 -0
  615. package/dist/vue/context-key.js.map +1 -0
  616. package/dist/vue/context.d.ts +8 -6
  617. package/dist/vue/context.js +6 -5
  618. package/dist/vue/context.js.map +1 -1
  619. package/dist/vue/index.d.ts +10 -8
  620. package/dist/vue/index.js +10 -8
  621. package/dist/vue/kit/index.d.ts +2 -2
  622. package/dist/vue/kit/nuxt-ui.js +23 -0
  623. package/dist/vue/kit/nuxt-ui.js.map +1 -1
  624. package/dist/vue/kit/types.d.ts +40 -1
  625. package/package.json +30 -16
  626. package/dist/adapters/comments/client.d.ts +0 -64
  627. package/dist/adapters/comments/client.js.map +0 -1
  628. package/dist/adapters/routes.js.map +0 -1
  629. package/dist/core/toolbar.d.ts +0 -74
  630. package/dist/core/toolbar.js +0 -45
  631. package/dist/core/toolbar.js.map +0 -1
  632. package/dist/integrations/composite-ai/document-transcribe.d.ts +0 -14
  633. package/dist/integrations/composite-ai/document-transcribe.js +0 -89
  634. package/dist/integrations/composite-ai/document-transcribe.js.map +0 -1
  635. package/dist/nuxt/runtime/server/api/ai/chat.post.d.ts +0 -5
  636. package/dist/nuxt/runtime/server/api/ai/chat.post.js +0 -8
  637. package/dist/nuxt/runtime/server/api/ai/chat.post.js.map +0 -1
  638. package/dist/nuxt/runtime/server/api/ai/complete.post.d.ts +0 -5
  639. package/dist/nuxt/runtime/server/api/ai/complete.post.js +0 -8
  640. package/dist/nuxt/runtime/server/api/ai/complete.post.js.map +0 -1
  641. package/dist/nuxt/runtime/server/api/ai/generate.post.d.ts +0 -5
  642. package/dist/nuxt/runtime/server/api/ai/generate.post.js +0 -8
  643. package/dist/nuxt/runtime/server/api/ai/generate.post.js.map +0 -1
  644. package/dist/nuxt/runtime/server/api/ai/models.get.d.ts +0 -5
  645. package/dist/nuxt/runtime/server/api/ai/models.get.js +0 -8
  646. package/dist/nuxt/runtime/server/api/ai/models.get.js.map +0 -1
  647. package/dist/nuxt/runtime/server/api/ai/transcribe.post.d.ts +0 -5
  648. package/dist/nuxt/runtime/server/api/ai/transcribe.post.js +0 -8
  649. package/dist/nuxt/runtime/server/api/ai/transcribe.post.js.map +0 -1
  650. package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.d.ts +0 -5
  651. package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.js +0 -8
  652. package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.js.map +0 -1
  653. package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.d.ts +0 -5
  654. package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.js +0 -8
  655. package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.js.map +0 -1
  656. package/dist/nuxt/runtime/server/api/editor/assets/[id].post.d.ts +0 -5
  657. package/dist/nuxt/runtime/server/api/editor/assets/[id].post.js +0 -8
  658. package/dist/nuxt/runtime/server/api/editor/assets/[id].post.js.map +0 -1
  659. package/dist/nuxt/runtime/server/api/editor/settings.get.d.ts +0 -5
  660. package/dist/nuxt/runtime/server/api/editor/settings.get.js +0 -8
  661. package/dist/nuxt/runtime/server/api/editor/settings.get.js.map +0 -1
  662. package/dist/nuxt/runtime/server/api/editor/settings.put.d.ts +0 -5
  663. package/dist/nuxt/runtime/server/api/editor/settings.put.js +0 -8
  664. package/dist/nuxt/runtime/server/api/editor/settings.put.js.map +0 -1
  665. package/dist/nuxt/runtime/server/api/editor/tags.get.d.ts +0 -5
  666. package/dist/nuxt/runtime/server/api/editor/tags.get.js +0 -8
  667. package/dist/nuxt/runtime/server/api/editor/tags.get.js.map +0 -1
  668. package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.d.ts +0 -5
  669. package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.js +0 -8
  670. package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.js.map +0 -1
  671. package/dist/nuxt/runtime/server/api/editor/themes/[id].get.d.ts +0 -5
  672. package/dist/nuxt/runtime/server/api/editor/themes/[id].get.js +0 -8
  673. package/dist/nuxt/runtime/server/api/editor/themes/[id].get.js.map +0 -1
  674. package/dist/nuxt/runtime/server/api/editor/themes/index.get.d.ts +0 -5
  675. package/dist/nuxt/runtime/server/api/editor/themes/index.get.js +0 -8
  676. package/dist/nuxt/runtime/server/api/editor/themes/index.get.js.map +0 -1
  677. package/dist/nuxt/runtime/server/api/editor/themes/index.post.d.ts +0 -5
  678. package/dist/nuxt/runtime/server/api/editor/themes/index.post.js +0 -8
  679. package/dist/nuxt/runtime/server/api/editor/themes/index.post.js.map +0 -1
  680. package/dist/nuxt/runtime/server/api/editor/users.get.d.ts +0 -5
  681. package/dist/nuxt/runtime/server/api/editor/users.get.js +0 -8
  682. package/dist/nuxt/runtime/server/api/editor/users.get.js.map +0 -1
  683. package/dist/nuxt/runtime/server/plugins/collab.d.ts +0 -5
  684. package/dist/nuxt/runtime/server/plugins/collab.js +0 -10
  685. package/dist/nuxt/runtime/server/plugins/collab.js.map +0 -1
  686. package/dist/nuxt/runtime/server/routes/collab/[id].d.ts +0 -5
  687. package/dist/nuxt/runtime/server/routes/collab/[id].js +0 -35
  688. package/dist/nuxt/runtime/server/routes/collab/[id].js.map +0 -1
  689. package/dist/nuxt/runtime/server/utils/editor-route.d.ts +0 -11
  690. package/dist/nuxt/runtime/server/utils/editor-route.js.map +0 -1
  691. package/dist/presets/advanced.d.ts +0 -33
  692. package/dist/presets/advanced.js +0 -50
  693. package/dist/presets/advanced.js.map +0 -1
  694. package/dist/presets/simple.d.ts +0 -9
  695. package/dist/presets/simple.js +0 -12
  696. package/dist/presets/simple.js.map +0 -1
  697. package/dist/react/advanced-preset.d.ts +0 -11
  698. package/dist/react/advanced-preset.js +0 -31
  699. package/dist/react/advanced-preset.js.map +0 -1
  700. package/dist/vue/advanced-preset.d.ts +0 -13
  701. package/dist/vue/advanced-preset.js +0 -33
  702. package/dist/vue/advanced-preset.js.map +0 -1
  703. package/docs/extending.md +0 -538
  704. package/docs/integration.md +0 -632
  705. package/docs/llms.md +0 -383
  706. package/docs/usage.md +0 -1076
@@ -1,5 +1,11 @@
1
1
  import { HandlerContext, HandlerRequest, HandlerResponse } from "./context.js";
2
2
  //#region src/server/handlers/editor.d.ts
3
+ /**
4
+ * The capabilities this server serves (`BackendCapability[]`, see `serverCapabilities`): what the client's probe
5
+ * (`createHttpBackend({ probe: true })`) prunes its backend to. Requires an authenticated user through the `identity` port, like the
6
+ * routes whose capabilities it lists.
7
+ */
8
+ export declare function capabilitiesGet(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse>;
3
9
  /** Body schema of `settingsPut`: the complete editor settings. */
4
10
  export declare const settingsPutBodySchema: import("zod").ZodObject<{
5
11
  version: import("zod").ZodLiteral<1>;
@@ -58,44 +64,44 @@ export declare const settingsPutBodySchema: import("zod").ZodObject<{
58
64
  }, import("zod/v4/core").$strip>;
59
65
  }, import("zod/v4/core").$strip>;
60
66
  /**
61
- * The authenticated user's editor settings, normalized with `parseEditorSettings`. `204` when the adapter keeps no
62
- * settings (the client stays on localStorage); `200` with JSON `null` when the user has none stored yet (the client
63
- * uploads its local ones).
67
+ * The authenticated user's editor settings, normalized with `parseEditorSettings`. `204` without a `settings` port (the
68
+ * client stays on localStorage); `200` with JSON `null` when the user has none stored yet (the client uploads its local
69
+ * ones).
64
70
  */
65
71
  export declare function settingsGet(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse>;
66
- /** Stores the authenticated user's editor settings (complete, validated: 400 otherwise); `501` when the adapter keeps none. */
72
+ /** Stores the authenticated user's editor settings (complete, validated: 400 otherwise); `501` without a `settings` port. */
67
73
  export declare function settingsPut(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse>;
68
74
  /**
69
75
  * All `#` tag names used in any document, deduplicated and sorted. Documents currently open in the collaboration server
70
76
  * are read from their live Y.Doc (a tag added in document A shows up in document B before the debounced store); all
71
- * others from the adapter's stored content.
77
+ * others from the stored content of `ports.documents`.
72
78
  */
73
- export declare function listWorkspaceTags({ adapter, collab }: HandlerContext): Promise<string[]>;
79
+ export declare function listWorkspaceTags({ ports, collab }: HandlerContext): Promise<string[]>;
74
80
  /**
75
81
  * Tag names for the `#` popup: tags used in any document, filtered by the normalised `?q=` (prefix matches first, then
76
- * substrings). Requires an authenticated user via the adapter.
82
+ * substrings). Requires an authenticated user through the `identity` port.
77
83
  */
78
84
  export declare function tagsGet(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse>;
79
85
  /**
80
86
  * Users for the `@` mention popup, filtered case-insensitively by `?q=` (prefix matches first, then substrings).
81
- * Requires an authenticated user via the adapter.
87
+ * Requires an authenticated user through the `identity` port.
82
88
  */
83
89
  export declare function usersGet(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse>;
84
90
  /**
85
91
  * Stores a file (multipart field `file`) in the package of document `params.id` (or `scratch` for editors not bound to
86
- * a stored document); answers `{ url, name }`. Requires an authenticated user via the adapter.
92
+ * a stored document); answers `{ url, name, sha256 }`. Requires an authenticated user through the `identity` port.
87
93
  */
88
94
  export declare function assetPost(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse>;
89
95
  /**
90
96
  * The stored file `params.name` of document `params.id`, with `Range` support (media elements send the session cookie
91
- * like any same-origin request). Requires an authenticated user via the adapter.
97
+ * like any same-origin request). Requires an authenticated user through the `identity` port.
92
98
  */
93
99
  export declare function assetGet(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse>;
94
- /** The theme library (builtins and uploads) as `ThemeRecord[]`. `501` when the adapter has no theme support. */
100
+ /** The theme library (builtins and uploads) as `ThemeRecord[]`. `501` without a `themes` port. */
95
101
  export declare function themesGet(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse>;
96
- /** `theme.css` of theme `params.id` as `text/css`. `400` for a malformed id, `404` for an unknown one, `501` when the adapter has no theme support. */
102
+ /** `theme.css` of theme `params.id` as `text/css`. `400` for a malformed id, `404` for an unknown one, `501` without a `themes` port. */
97
103
  export declare function themeGet(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse>;
98
- /** Deletes the uploaded theme `params.id` (`204`). `400` for a malformed id, `404` for an unknown one, `403` for a builtin, `501` when the adapter has no theme write support. */
104
+ /** Deletes the uploaded theme `params.id` (`204`). `400` for a malformed id, `404` for an unknown one, `403` for a builtin, `501` without a `themes` port. */
99
105
  export declare function themeDelete(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse>;
100
106
  /**
101
107
  * Uploads an Obsidian theme into the shared library: multipart `css` (File, required), `manifest` (File) and `name`
@@ -4,49 +4,60 @@ import { ASSET_DOCUMENT_ID, ASSET_NAME, assetUrl } from "../../features/media/as
4
4
  import { MAX_MEDIA_BYTES, MEDIA_TYPES, mediaKindOf, mediaMime } from "../../features/media/schema.js";
5
5
  import { collectTagNames, normalizeTagName } from "../../features/mentions/tag.js";
6
6
  import { COLLAB_FIELD } from "../collab.js";
7
- import { authenticated, empty, json, readBody, text } from "./context.js";
7
+ import { authenticated, empty, json, port, readBody, text } from "./context.js";
8
+ import { serverCapabilities } from "../ports.js";
8
9
  import { MAX_THEME_BYTES, themeManifestSchema } from "../../features/themes/schema.js";
10
+ import { createHash } from "node:crypto";
9
11
  import { yDocToProsemirrorJSON } from "@tiptap/y-tiptap";
10
12
  //#region src/server/handlers/editor.ts
13
+ /**
14
+ * The capabilities this server serves (`BackendCapability[]`, see `serverCapabilities`): what the client's probe
15
+ * (`createHttpBackend({ probe: true })`) prunes its backend to. Requires an authenticated user through the `identity` port, like the
16
+ * routes whose capabilities it lists.
17
+ */
18
+ async function capabilitiesGet(ctx, request) {
19
+ await authenticated(ctx, request);
20
+ return json(serverCapabilities(ctx.ports, ctx.served));
21
+ }
11
22
  /** Body schema of `settingsPut`: the complete editor settings. */
12
23
  const settingsPutBodySchema = editorSettingsSchema;
13
24
  const MAX_USERS = 20;
14
25
  const MAX_TAGS = 20;
15
26
  /**
16
- * The authenticated user's editor settings, normalized with `parseEditorSettings`. `204` when the adapter keeps no
17
- * settings (the client stays on localStorage); `200` with JSON `null` when the user has none stored yet (the client
18
- * uploads its local ones).
27
+ * The authenticated user's editor settings, normalized with `parseEditorSettings`. `204` without a `settings` port (the
28
+ * client stays on localStorage); `200` with JSON `null` when the user has none stored yet (the client uploads its local
29
+ * ones).
19
30
  */
20
31
  async function settingsGet(ctx, request) {
21
32
  const user = await authenticated(ctx, request);
22
- if (!ctx.adapter.loadSettings) return empty();
23
- const stored = await ctx.adapter.loadSettings(user);
33
+ if (!ctx.ports.settings) return empty();
34
+ const stored = await ctx.ports.settings.loadSettings(user);
24
35
  if (stored === null || stored === void 0) return json(null);
25
36
  return json(parseEditorSettings(stored));
26
37
  }
27
- /** Stores the authenticated user's editor settings (complete, validated: 400 otherwise); `501` when the adapter keeps none. */
38
+ /** Stores the authenticated user's editor settings (complete, validated: 400 otherwise); `501` without a `settings` port. */
28
39
  async function settingsPut(ctx, request) {
29
40
  const user = await authenticated(ctx, request);
30
- if (!ctx.adapter.storeSettings) throw new HttpError(501, "Einstellungen werden nicht gespeichert");
41
+ const store = port(ctx, "settings");
31
42
  const settings = await readBody(request, settingsPutBodySchema);
32
- await ctx.adapter.storeSettings(user, settings);
43
+ await store.storeSettings(user, settings);
33
44
  return empty();
34
45
  }
35
46
  /**
36
47
  * All `#` tag names used in any document, deduplicated and sorted. Documents currently open in the collaboration server
37
48
  * are read from their live Y.Doc (a tag added in document A shows up in document B before the debounced store); all
38
- * others from the adapter's stored content.
49
+ * others from the stored content of `ports.documents`.
39
50
  */
40
- async function listWorkspaceTags({ adapter, collab }) {
51
+ async function listWorkspaceTags({ ports, collab }) {
41
52
  const names = /* @__PURE__ */ new Set();
42
53
  const open = collab?.hocuspocus.documents;
43
54
  if (open) for (const doc of open.values()) collectTagNames(yDocToProsemirrorJSON(doc, COLLAB_FIELD), names);
44
- for (const { id, content } of await adapter.listContents()) if (!open?.has(id)) collectTagNames(content, names);
55
+ for (const { id, content } of await ports.documents.listContents()) if (!open?.has(id)) collectTagNames(content, names);
45
56
  return [...names].sort((a, b) => a.localeCompare(b, "de"));
46
57
  }
47
58
  /**
48
59
  * Tag names for the `#` popup: tags used in any document, filtered by the normalised `?q=` (prefix matches first, then
49
- * substrings). Requires an authenticated user via the adapter.
60
+ * substrings). Requires an authenticated user through the `identity` port.
50
61
  */
51
62
  async function tagsGet(ctx, request) {
52
63
  await authenticated(ctx, request);
@@ -57,12 +68,12 @@ async function tagsGet(ctx, request) {
57
68
  }
58
69
  /**
59
70
  * Users for the `@` mention popup, filtered case-insensitively by `?q=` (prefix matches first, then substrings).
60
- * Requires an authenticated user via the adapter.
71
+ * Requires an authenticated user through the `identity` port.
61
72
  */
62
73
  async function usersGet(ctx, request) {
63
74
  await authenticated(ctx, request);
64
75
  const q = String(request.query?.q ?? "").trim().toLowerCase();
65
- const matches = (await ctx.adapter.listUsers()).map(({ id, username, color }) => ({
76
+ const matches = (await port(ctx, "directory").listUsers()).map(({ id, username, color }) => ({
66
77
  id,
67
78
  username,
68
79
  color
@@ -72,7 +83,7 @@ async function usersGet(ctx, request) {
72
83
  }
73
84
  /**
74
85
  * Stores a file (multipart field `file`) in the package of document `params.id` (or `scratch` for editors not bound to
75
- * a stored document); answers `{ url, name }`. Requires an authenticated user via the adapter.
86
+ * a stored document); answers `{ url, name, sha256 }`. Requires an authenticated user through the `identity` port.
76
87
  */
77
88
  async function assetPost(ctx, request) {
78
89
  await authenticated(ctx, request);
@@ -86,30 +97,34 @@ async function assetPost(ctx, request) {
86
97
  const nameExt = file.name.includes(".") ? file.name.split(".").pop()?.toLowerCase() : void 0;
87
98
  const ext = MEDIA_TYPES[mime]?.ext ?? (nameExt && /^[a-z0-9]{1,8}$/.test(nameExt) ? nameExt : "bin");
88
99
  const name = `${globalThis.crypto.randomUUID()}.${ext}`;
89
- await ctx.adapter.storeAsset(id, {
100
+ const data = Buffer.from(await file.arrayBuffer());
101
+ const sha256 = createHash("sha256").update(data).digest("hex");
102
+ await port(ctx, "assets").storeAsset(id, {
90
103
  name,
91
104
  filename: file.name.slice(0, 255) || name,
92
105
  mimeType: mime,
93
106
  size: file.size,
94
107
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
95
- data: Buffer.from(await file.arrayBuffer())
108
+ sha256,
109
+ data
96
110
  });
97
111
  return json({
98
112
  url: assetUrl(id, name),
99
- name
113
+ name,
114
+ sha256
100
115
  });
101
116
  }
102
117
  const BYTE_RANGE = /^bytes=(\d*)-(\d*)$/;
103
118
  /**
104
119
  * The stored file `params.name` of document `params.id`, with `Range` support (media elements send the session cookie
105
- * like any same-origin request). Requires an authenticated user via the adapter.
120
+ * like any same-origin request). Requires an authenticated user through the `identity` port.
106
121
  */
107
122
  async function assetGet(ctx, request) {
108
123
  await authenticated(ctx, request);
109
124
  const id = request.params?.id ?? "";
110
125
  const name = request.params?.name ?? "";
111
126
  if (!ASSET_DOCUMENT_ID.test(id) || !ASSET_NAME.test(name)) throw new HttpError(404, "Datei nicht gefunden");
112
- const asset = await ctx.adapter.loadAsset(id, name);
127
+ const asset = await port(ctx, "assets").loadAsset(id, name);
113
128
  if (!asset) throw new HttpError(404, "Datei nicht gefunden");
114
129
  const { record, data } = asset;
115
130
  const total = data.length;
@@ -143,20 +158,18 @@ async function assetGet(ctx, request) {
143
158
  body: data.subarray(start, end + 1)
144
159
  };
145
160
  }
146
- const themesUnsupported = () => new HttpError(501, "Themes werden vom Adapter nicht unterstützt");
147
- /** The theme library (builtins and uploads) as `ThemeRecord[]`. `501` when the adapter has no theme support. */
161
+ /** The theme library (builtins and uploads) as `ThemeRecord[]`. `501` without a `themes` port. */
148
162
  async function themesGet(ctx, request) {
149
163
  await authenticated(ctx, request);
150
- if (!ctx.adapter.listThemes) throw themesUnsupported();
151
- return json(await ctx.adapter.listThemes());
164
+ return json(await port(ctx, "themes").listThemes());
152
165
  }
153
- /** `theme.css` of theme `params.id` as `text/css`. `400` for a malformed id, `404` for an unknown one, `501` when the adapter has no theme support. */
166
+ /** `theme.css` of theme `params.id` as `text/css`. `400` for a malformed id, `404` for an unknown one, `501` without a `themes` port. */
154
167
  async function themeGet(ctx, request) {
155
168
  await authenticated(ctx, request);
156
- if (!ctx.adapter.loadTheme) throw themesUnsupported();
169
+ const themes = port(ctx, "themes");
157
170
  const id = request.params?.id ?? "";
158
171
  if (!THEME_ID.test(id)) throw new HttpError(400, "Ungültige Theme-ID");
159
- const theme = await ctx.adapter.loadTheme(id);
172
+ const theme = await themes.loadTheme(id);
160
173
  if (!theme) throw new HttpError(404, "Theme nicht gefunden");
161
174
  const etag = `"${theme.record.version ?? "0"}-${new TextEncoder().encode(theme.css).length}"`;
162
175
  const headers = {
@@ -166,17 +179,16 @@ async function themeGet(ctx, request) {
166
179
  if (request.headers.get("if-none-match") === etag) return empty(304, headers);
167
180
  return text(theme.css, "text/css; charset=utf-8", headers);
168
181
  }
169
- /** Deletes the uploaded theme `params.id` (`204`). `400` for a malformed id, `404` for an unknown one, `403` for a builtin, `501` when the adapter has no theme write support. */
182
+ /** Deletes the uploaded theme `params.id` (`204`). `400` for a malformed id, `404` for an unknown one, `403` for a builtin, `501` without a `themes` port. */
170
183
  async function themeDelete(ctx, request) {
171
184
  await authenticated(ctx, request);
172
- const { adapter } = ctx;
173
- if (!adapter.listThemes || !adapter.removeTheme) throw themesUnsupported();
185
+ const themes = port(ctx, "themes");
174
186
  const id = request.params?.id ?? "";
175
187
  if (!THEME_ID.test(id)) throw new HttpError(400, "Ungültige Theme-ID");
176
- const record = (await adapter.listThemes()).find((t) => t.id === id);
188
+ const record = (await themes.listThemes()).find((t) => t.id === id);
177
189
  if (!record) throw new HttpError(404, "Theme nicht gefunden");
178
190
  if (record.builtin) throw new HttpError(403, "Mitgelieferte Themes können nicht gelöscht werden");
179
- if (!await adapter.removeTheme(id)) throw new HttpError(404, "Theme nicht gefunden");
191
+ if (!await themes.removeTheme(id)) throw new HttpError(404, "Theme nicht gefunden");
180
192
  return empty();
181
193
  }
182
194
  const MAX_MANIFEST_BYTES = 65536;
@@ -193,8 +205,7 @@ function slugOf(name, max) {
193
205
  */
194
206
  async function themePost(ctx, request) {
195
207
  await authenticated(ctx, request);
196
- const { adapter } = ctx;
197
- if (!adapter.listThemes || !adapter.storeTheme) throw themesUnsupported();
208
+ const themes = port(ctx, "themes");
198
209
  const form = await request.readForm?.().catch(() => null);
199
210
  const cssFile = form?.get("css");
200
211
  if (!(cssFile instanceof File) || cssFile.size === 0) throw new HttpError(400, "Keine CSS-Datei übermittelt");
@@ -218,7 +229,7 @@ async function themePost(ctx, request) {
218
229
  const nameField = form?.get("name");
219
230
  const cssBaseName = cssFile.name.replace(/\.css$/i, "");
220
231
  const name = manifest?.name ?? [typeof nameField === "string" ? nameField : "", cssBaseName].map((n) => n.trim().slice(0, 120)).find(Boolean) ?? "Theme";
221
- const taken = new Set((await adapter.listThemes()).map((t) => t.id));
232
+ const taken = new Set((await themes.listThemes()).map((t) => t.id));
222
233
  let id = slugOf(name, MAX_ID_LENGTH);
223
234
  for (let n = 2; taken.has(id); n++) {
224
235
  const suffix = `-${n}`;
@@ -229,13 +240,13 @@ async function themePost(ctx, request) {
229
240
  name,
230
241
  id
231
242
  };
232
- await adapter.storeTheme(record, css);
243
+ await themes.storeTheme(record, css);
233
244
  return json({
234
245
  ...record,
235
246
  builtin: false
236
247
  }, 201);
237
248
  }
238
249
  //#endregion
239
- export { assetGet, assetPost, listWorkspaceTags, settingsGet, settingsPut, settingsPutBodySchema, tagsGet, themeDelete, themeGet, themePost, themesGet, usersGet };
250
+ export { assetGet, assetPost, capabilitiesGet, listWorkspaceTags, settingsGet, settingsPut, settingsPutBodySchema, tagsGet, themeDelete, themeGet, themePost, themesGet, usersGet };
240
251
 
241
252
  //# sourceMappingURL=editor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"editor.js","names":[],"sources":["../../../src/server/handlers/editor.ts"],"sourcesContent":["import { yDocToProsemirrorJSON } from '@tiptap/y-tiptap'\nimport { ASSET_DOCUMENT_ID, ASSET_NAME, assetUrl, MAX_MEDIA_BYTES, MEDIA_TYPES, mediaKindOf, mediaMime } from '../../features/media/schema'\nimport { collectTagNames, normalizeTagName } from '../../features/mentions/schema'\nimport { MAX_THEME_BYTES, THEME_ID, themeManifestSchema, type ThemeManifest, type ThemeRecord } from '../../features/themes/schema'\nimport { editorSettingsSchema, parseEditorSettings } from '../../settings'\nimport { COLLAB_FIELD } from '../collab'\nimport { HttpError } from '../errors'\nimport { authenticated, empty, type HandlerContext, type HandlerRequest, type HandlerResponse, json, readBody, text } from './context'\n\n/** Body schema of `settingsPut`: the complete editor settings. */\nexport const settingsPutBodySchema = editorSettingsSchema\n\nconst MAX_USERS = 20\nconst MAX_TAGS = 20\n\n/**\n * The authenticated user's editor settings, normalized with `parseEditorSettings`. `204` when the adapter keeps no\n * settings (the client stays on localStorage); `200` with JSON `null` when the user has none stored yet (the client\n * uploads its local ones).\n */\nexport async function settingsGet(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse> {\n const user = await authenticated(ctx, request)\n if (!ctx.adapter.loadSettings) return empty()\n const stored = await ctx.adapter.loadSettings(user)\n if (stored === null || stored === undefined) return json(null)\n return json(parseEditorSettings(stored))\n}\n\n/** Stores the authenticated user's editor settings (complete, validated: 400 otherwise); `501` when the adapter keeps none. */\nexport async function settingsPut(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse> {\n const user = await authenticated(ctx, request)\n if (!ctx.adapter.storeSettings) throw new HttpError(501, 'Einstellungen werden nicht gespeichert')\n const settings = await readBody(request, settingsPutBodySchema)\n await ctx.adapter.storeSettings(user, settings)\n return empty()\n}\n\n/**\n * All `#` tag names used in any document, deduplicated and sorted. Documents currently open in the collaboration server\n * are read from their live Y.Doc (a tag added in document A shows up in document B before the debounced store); all\n * others from the adapter's stored content.\n */\nexport async function listWorkspaceTags({ adapter, collab }: HandlerContext): Promise<string[]> {\n const names = new Set<string>()\n const open = collab?.hocuspocus.documents\n if (open) for (const doc of open.values()) collectTagNames(yDocToProsemirrorJSON(doc, COLLAB_FIELD), names)\n for (const { id, content } of await adapter.listContents()) {\n if (!open?.has(id)) collectTagNames(content, names)\n }\n return [...names].sort((a, b) => a.localeCompare(b, 'de'))\n}\n\n/**\n * Tag names for the `#` popup: tags used in any document, filtered by the normalised `?q=` (prefix matches first, then\n * substrings). Requires an authenticated user via the adapter.\n */\nexport async function tagsGet(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse> {\n await authenticated(ctx, request)\n const q = normalizeTagName(String(request.query?.q ?? ''))\n const matches = (await listWorkspaceTags(ctx)).filter(tag => tag.includes(q))\n const prefixMatches = matches.filter(tag => tag.startsWith(q))\n return json([...prefixMatches, ...matches.filter(tag => !tag.startsWith(q))].slice(0, MAX_TAGS))\n}\n\n/**\n * Users for the `@` mention popup, filtered case-insensitively by `?q=` (prefix matches first, then substrings).\n * Requires an authenticated user via the adapter.\n */\nexport async function usersGet(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse> {\n await authenticated(ctx, request)\n const q = String(request.query?.q ?? '').trim().toLowerCase()\n // Re-pick the fields so an adapter returning richer user records cannot leak them.\n const matches = (await ctx.adapter.listUsers())\n .map(({ id, username, color }) => ({ id, username, color }))\n .filter(u => u.username.toLowerCase().includes(q))\n .sort((a, b) => a.username.localeCompare(b.username, 'de'))\n const prefixMatches = matches.filter(u => u.username.toLowerCase().startsWith(q))\n return json([...prefixMatches, ...matches.filter(u => !prefixMatches.includes(u))].slice(0, MAX_USERS))\n}\n\n/**\n * Stores a file (multipart field `file`) in the package of document `params.id` (or `scratch` for editors not bound to\n * a stored document); answers `{ url, name }`. Requires an authenticated user via the adapter.\n */\nexport async function assetPost(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse> {\n await authenticated(ctx, request)\n const id = request.params?.id ?? ''\n if (!ASSET_DOCUMENT_ID.test(id)) throw new HttpError(400, 'Ungültige Dokument-ID')\n // A body that is no multipart form at all counts as „no file“.\n const form = await request.readForm?.().catch(() => null)\n const file = form?.get('file')\n if (!(file instanceof File)) throw new HttpError(400, 'Keine Datei übermittelt')\n const mime = mediaMime(file.type) || 'application/octet-stream'\n const maxBytes = MAX_MEDIA_BYTES[mediaKindOf(mime) ?? 'file']\n if (file.size > maxBytes) throw new HttpError(413, `Datei ist größer als ${maxBytes / 1024 / 1024} MB`)\n const nameExt = file.name.includes('.') ? file.name.split('.').pop()?.toLowerCase() : undefined\n const ext = MEDIA_TYPES[mime]?.ext ?? (nameExt && /^[a-z0-9]{1,8}$/.test(nameExt) ? nameExt : 'bin')\n const name = `${globalThis.crypto.randomUUID()}.${ext}`\n await ctx.adapter.storeAsset(id, {\n name,\n filename: file.name.slice(0, 255) || name,\n mimeType: mime,\n size: file.size,\n createdAt: new Date().toISOString(),\n data: Buffer.from(await file.arrayBuffer()),\n })\n return json({ url: assetUrl(id, name), name })\n}\n\n// Answers single byte ranges (`Range: bytes=a-b`, `bytes=a-`, `bytes=-n`): Safari only plays and seeks audio/video\n// served with range support. Other Range forms (several ranges) get the whole file, which RFC 9110 allows.\nconst BYTE_RANGE = /^bytes=(\\d*)-(\\d*)$/\n\n/**\n * The stored file `params.name` of document `params.id`, with `Range` support (media elements send the session cookie\n * like any same-origin request). Requires an authenticated user via the adapter.\n */\nexport async function assetGet(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse> {\n await authenticated(ctx, request)\n const id = request.params?.id ?? ''\n const name = request.params?.name ?? ''\n if (!ASSET_DOCUMENT_ID.test(id) || !ASSET_NAME.test(name)) throw new HttpError(404, 'Datei nicht gefunden')\n const asset = await ctx.adapter.loadAsset(id, name)\n if (!asset) throw new HttpError(404, 'Datei nicht gefunden')\n const { record, data } = asset\n const total = data.length\n const disposition = record.mimeType === 'application/octet-stream' ? 'attachment' : 'inline'\n const headers: Record<string, string> = {\n 'accept-ranges': 'bytes',\n 'cache-control': 'private, max-age=31536000, immutable',\n 'content-type': record.mimeType,\n 'content-disposition': `${disposition}; filename*=UTF-8''${encodeURIComponent(record.filename)}`,\n }\n const range = BYTE_RANGE.exec(request.headers.get('range') ?? '')\n if (!range) return { status: 200, headers: { ...headers, 'content-length': String(total) }, body: data }\n const [, first, last] = range\n const start = first ? Number(first) : Math.max(0, total - Number(last))\n const end = first && last ? Math.min(Number(last), total - 1) : total - 1\n if (start >= total || start > end) return empty(416, { 'content-range': `bytes */${total}` })\n return {\n status: 206,\n headers: { ...headers, 'content-range': `bytes ${start}-${end}/${total}`, 'content-length': String(end - start + 1) },\n body: data.subarray(start, end + 1),\n }\n}\n\nconst themesUnsupported = () => new HttpError(501, 'Themes werden vom Adapter nicht unterstützt')\n\n/** The theme library (builtins and uploads) as `ThemeRecord[]`. `501` when the adapter has no theme support. */\nexport async function themesGet(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse> {\n await authenticated(ctx, request)\n if (!ctx.adapter.listThemes) throw themesUnsupported()\n return json(await ctx.adapter.listThemes())\n}\n\n/** `theme.css` of theme `params.id` as `text/css`. `400` for a malformed id, `404` for an unknown one, `501` when the adapter has no theme support. */\nexport async function themeGet(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse> {\n await authenticated(ctx, request)\n if (!ctx.adapter.loadTheme) throw themesUnsupported()\n const id = request.params?.id ?? ''\n if (!THEME_ID.test(id)) throw new HttpError(400, 'Ungültige Theme-ID')\n const theme = await ctx.adapter.loadTheme(id)\n if (!theme) throw new HttpError(404, 'Theme nicht gefunden')\n const etag = `\"${theme.record.version ?? '0'}-${new TextEncoder().encode(theme.css).length}\"`\n const headers = { 'cache-control': 'private, max-age=0, must-revalidate', 'etag': etag }\n if (request.headers.get('if-none-match') === etag) return empty(304, headers)\n return text(theme.css, 'text/css; charset=utf-8', headers)\n}\n\n/** Deletes the uploaded theme `params.id` (`204`). `400` for a malformed id, `404` for an unknown one, `403` for a builtin, `501` when the adapter has no theme write support. */\nexport async function themeDelete(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse> {\n await authenticated(ctx, request)\n const { adapter } = ctx\n if (!adapter.listThemes || !adapter.removeTheme) throw themesUnsupported()\n const id = request.params?.id ?? ''\n if (!THEME_ID.test(id)) throw new HttpError(400, 'Ungültige Theme-ID')\n // `removeTheme` answers `false` for builtins and unknown ids alike, so the record decides between 403 and 404.\n const record = (await adapter.listThemes()).find(t => t.id === id)\n if (!record) throw new HttpError(404, 'Theme nicht gefunden')\n if (record.builtin) throw new HttpError(403, 'Mitgelieferte Themes können nicht gelöscht werden')\n if (!await adapter.removeTheme(id)) throw new HttpError(404, 'Theme nicht gefunden')\n return empty()\n}\n\nconst MAX_MANIFEST_BYTES = 64 * 1024\nconst MAX_ID_LENGTH = 64\n// Markers of an HTML/XML/SVG document in the head of a „stylesheet“.\nconst MARKUP_HEAD = /<script|<\\?xml/i\n\n/** `[^a-z0-9]+` → `-`, trimmed, at most `max` characters; `theme` when nothing is left. */\nfunction slugOf(name: string, max: number): string {\n const slug = name.normalize('NFKD').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+/, '').slice(0, max).replace(/-+$/, '')\n return slug || 'theme'\n}\n\n/**\n * Uploads an Obsidian theme into the shared library: multipart `css` (File, required), `manifest` (File) and `name`\n * (string) optional. Answers 201 with the new `ThemeRecord`; the id is the slug of the name, made unique with `-2`,\n * `-3` … against the library.\n */\nexport async function themePost(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse> {\n await authenticated(ctx, request)\n const { adapter } = ctx\n if (!adapter.listThemes || !adapter.storeTheme) throw themesUnsupported()\n // A body that is no multipart form counts as „no file“.\n const form = await request.readForm?.().catch(() => null)\n const cssFile = form?.get('css')\n if (!(cssFile instanceof File) || cssFile.size === 0) throw new HttpError(400, 'Keine CSS-Datei übermittelt')\n if (cssFile.size > MAX_THEME_BYTES) throw new HttpError(413, `Theme ist größer als ${MAX_THEME_BYTES / 1024 / 1024} MB`)\n const bytes = new Uint8Array(await cssFile.arrayBuffer())\n if (bytes.includes(0) || MARKUP_HEAD.test(new TextDecoder('latin1').decode(bytes.subarray(0, 512)))) {\n throw new HttpError(400, 'Theme ist keine CSS-Textdatei')\n }\n let css: string\n try {\n css = new TextDecoder('utf-8', { fatal: true }).decode(bytes)\n }\n catch {\n throw new HttpError(400, 'Theme ist keine gültige UTF-8-Textdatei')\n }\n\n let manifest: ThemeManifest | undefined\n const manifestFile = form?.get('manifest')\n if (manifestFile instanceof File && manifestFile.size > 0) {\n try {\n if (manifestFile.size > MAX_MANIFEST_BYTES) throw new Error('manifest too large')\n manifest = themeManifestSchema.parse(JSON.parse(await manifestFile.text()))\n }\n catch {\n throw new HttpError(400, 'Ungültiges manifest.json')\n }\n }\n\n const nameField = form?.get('name')\n const cssBaseName = cssFile.name.replace(/\\.css$/i, '')\n const name = manifest?.name\n ?? [typeof nameField === 'string' ? nameField : '', cssBaseName].map(n => n.trim().slice(0, 120)).find(Boolean)\n ?? 'Theme'\n\n const taken = new Set((await adapter.listThemes()).map(t => t.id))\n const base = slugOf(name, MAX_ID_LENGTH)\n let id = base\n for (let n = 2; taken.has(id); n++) {\n const suffix = `-${n}`\n id = `${slugOf(name, MAX_ID_LENGTH - suffix.length)}${suffix}`\n }\n\n const record: Omit<ThemeRecord, 'builtin'> = { ...manifest, name, id }\n await adapter.storeTheme(record, css)\n return json({ ...record, builtin: false } satisfies ThemeRecord, 201)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"editor.js","names":[],"sources":["../../../src/server/handlers/editor.ts"],"sourcesContent":["import { createHash } from 'node:crypto'\nimport { yDocToProsemirrorJSON } from '@tiptap/y-tiptap'\nimport { ASSET_DOCUMENT_ID, ASSET_NAME, assetUrl, MAX_MEDIA_BYTES, MEDIA_TYPES, mediaKindOf, mediaMime } from '../../features/media/schema'\nimport { collectTagNames, normalizeTagName } from '../../features/mentions/schema'\nimport { MAX_THEME_BYTES, THEME_ID, themeManifestSchema, type ThemeManifest, type ThemeRecord } from '../../features/themes/schema'\nimport { editorSettingsSchema, parseEditorSettings } from '../../settings'\nimport { COLLAB_FIELD } from '../collab'\nimport { HttpError } from '../errors'\nimport { serverCapabilities } from '../ports'\nimport { authenticated, empty, type HandlerContext, type HandlerRequest, type HandlerResponse, json, port, readBody, text } from './context'\n\n/**\n * The capabilities this server serves (`BackendCapability[]`, see `serverCapabilities`): what the client's probe\n * (`createHttpBackend({ probe: true })`) prunes its backend to. Requires an authenticated user through the `identity` port, like the\n * routes whose capabilities it lists.\n */\nexport async function capabilitiesGet(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse> {\n await authenticated(ctx, request)\n return json(serverCapabilities(ctx.ports, ctx.served))\n}\n\n/** Body schema of `settingsPut`: the complete editor settings. */\nexport const settingsPutBodySchema = editorSettingsSchema\n\nconst MAX_USERS = 20\nconst MAX_TAGS = 20\n\n/**\n * The authenticated user's editor settings, normalized with `parseEditorSettings`. `204` without a `settings` port (the\n * client stays on localStorage); `200` with JSON `null` when the user has none stored yet (the client uploads its local\n * ones).\n */\nexport async function settingsGet(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse> {\n const user = await authenticated(ctx, request)\n if (!ctx.ports.settings) return empty()\n const stored = await ctx.ports.settings.loadSettings(user)\n if (stored === null || stored === undefined) return json(null)\n return json(parseEditorSettings(stored))\n}\n\n/** Stores the authenticated user's editor settings (complete, validated: 400 otherwise); `501` without a `settings` port. */\nexport async function settingsPut(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse> {\n const user = await authenticated(ctx, request)\n const store = port(ctx, 'settings')\n const settings = await readBody(request, settingsPutBodySchema)\n await store.storeSettings(user, settings)\n return empty()\n}\n\n/**\n * All `#` tag names used in any document, deduplicated and sorted. Documents currently open in the collaboration server\n * are read from their live Y.Doc (a tag added in document A shows up in document B before the debounced store); all\n * others from the stored content of `ports.documents`.\n */\nexport async function listWorkspaceTags({ ports, collab }: HandlerContext): Promise<string[]> {\n const names = new Set<string>()\n const open = collab?.hocuspocus.documents\n if (open) for (const doc of open.values()) collectTagNames(yDocToProsemirrorJSON(doc, COLLAB_FIELD), names)\n for (const { id, content } of await ports.documents.listContents()) {\n if (!open?.has(id)) collectTagNames(content, names)\n }\n return [...names].sort((a, b) => a.localeCompare(b, 'de'))\n}\n\n/**\n * Tag names for the `#` popup: tags used in any document, filtered by the normalised `?q=` (prefix matches first, then\n * substrings). Requires an authenticated user through the `identity` port.\n */\nexport async function tagsGet(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse> {\n await authenticated(ctx, request)\n const q = normalizeTagName(String(request.query?.q ?? ''))\n const matches = (await listWorkspaceTags(ctx)).filter(tag => tag.includes(q))\n const prefixMatches = matches.filter(tag => tag.startsWith(q))\n return json([...prefixMatches, ...matches.filter(tag => !tag.startsWith(q))].slice(0, MAX_TAGS))\n}\n\n/**\n * Users for the `@` mention popup, filtered case-insensitively by `?q=` (prefix matches first, then substrings).\n * Requires an authenticated user through the `identity` port.\n */\nexport async function usersGet(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse> {\n await authenticated(ctx, request)\n const q = String(request.query?.q ?? '').trim().toLowerCase()\n // Re-pick the fields so a directory returning richer user records cannot leak them.\n const matches = (await port(ctx, 'directory').listUsers())\n .map(({ id, username, color }) => ({ id, username, color }))\n .filter(u => u.username.toLowerCase().includes(q))\n .sort((a, b) => a.username.localeCompare(b.username, 'de'))\n const prefixMatches = matches.filter(u => u.username.toLowerCase().startsWith(q))\n return json([...prefixMatches, ...matches.filter(u => !prefixMatches.includes(u))].slice(0, MAX_USERS))\n}\n\n/**\n * Stores a file (multipart field `file`) in the package of document `params.id` (or `scratch` for editors not bound to\n * a stored document); answers `{ url, name, sha256 }`. Requires an authenticated user through the `identity` port.\n */\nexport async function assetPost(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse> {\n await authenticated(ctx, request)\n const id = request.params?.id ?? ''\n if (!ASSET_DOCUMENT_ID.test(id)) throw new HttpError(400, 'Ungültige Dokument-ID')\n // A body that is no multipart form at all counts as „no file“.\n const form = await request.readForm?.().catch(() => null)\n const file = form?.get('file')\n if (!(file instanceof File)) throw new HttpError(400, 'Keine Datei übermittelt')\n const mime = mediaMime(file.type) || 'application/octet-stream'\n const maxBytes = MAX_MEDIA_BYTES[mediaKindOf(mime) ?? 'file']\n if (file.size > maxBytes) throw new HttpError(413, `Datei ist größer als ${maxBytes / 1024 / 1024} MB`)\n const nameExt = file.name.includes('.') ? file.name.split('.').pop()?.toLowerCase() : undefined\n const ext = MEDIA_TYPES[mime]?.ext ?? (nameExt && /^[a-z0-9]{1,8}$/.test(nameExt) ? nameExt : 'bin')\n const name = `${globalThis.crypto.randomUUID()}.${ext}`\n const data = Buffer.from(await file.arrayBuffer())\n const sha256 = createHash('sha256').update(data).digest('hex')\n await port(ctx, 'assets').storeAsset(id, {\n name,\n filename: file.name.slice(0, 255) || name,\n mimeType: mime,\n size: file.size,\n createdAt: new Date().toISOString(),\n sha256,\n data,\n })\n return json({ url: assetUrl(id, name), name, sha256 })\n}\n\n// Answers single byte ranges (`Range: bytes=a-b`, `bytes=a-`, `bytes=-n`): Safari only plays and seeks audio/video\n// served with range support. Other Range forms (several ranges) get the whole file, which RFC 9110 allows.\nconst BYTE_RANGE = /^bytes=(\\d*)-(\\d*)$/\n\n/**\n * The stored file `params.name` of document `params.id`, with `Range` support (media elements send the session cookie\n * like any same-origin request). Requires an authenticated user through the `identity` port.\n */\nexport async function assetGet(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse> {\n await authenticated(ctx, request)\n const id = request.params?.id ?? ''\n const name = request.params?.name ?? ''\n if (!ASSET_DOCUMENT_ID.test(id) || !ASSET_NAME.test(name)) throw new HttpError(404, 'Datei nicht gefunden')\n const asset = await port(ctx, 'assets').loadAsset(id, name)\n if (!asset) throw new HttpError(404, 'Datei nicht gefunden')\n const { record, data } = asset\n const total = data.length\n const disposition = record.mimeType === 'application/octet-stream' ? 'attachment' : 'inline'\n const headers: Record<string, string> = {\n 'accept-ranges': 'bytes',\n 'cache-control': 'private, max-age=31536000, immutable',\n 'content-type': record.mimeType,\n 'content-disposition': `${disposition}; filename*=UTF-8''${encodeURIComponent(record.filename)}`,\n }\n const range = BYTE_RANGE.exec(request.headers.get('range') ?? '')\n if (!range) return { status: 200, headers: { ...headers, 'content-length': String(total) }, body: data }\n const [, first, last] = range\n const start = first ? Number(first) : Math.max(0, total - Number(last))\n const end = first && last ? Math.min(Number(last), total - 1) : total - 1\n if (start >= total || start > end) return empty(416, { 'content-range': `bytes */${total}` })\n return {\n status: 206,\n headers: { ...headers, 'content-range': `bytes ${start}-${end}/${total}`, 'content-length': String(end - start + 1) },\n body: data.subarray(start, end + 1),\n }\n}\n\n/** The theme library (builtins and uploads) as `ThemeRecord[]`. `501` without a `themes` port. */\nexport async function themesGet(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse> {\n await authenticated(ctx, request)\n return json(await port(ctx, 'themes').listThemes())\n}\n\n/** `theme.css` of theme `params.id` as `text/css`. `400` for a malformed id, `404` for an unknown one, `501` without a `themes` port. */\nexport async function themeGet(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse> {\n await authenticated(ctx, request)\n const themes = port(ctx, 'themes')\n const id = request.params?.id ?? ''\n if (!THEME_ID.test(id)) throw new HttpError(400, 'Ungültige Theme-ID')\n const theme = await themes.loadTheme(id)\n if (!theme) throw new HttpError(404, 'Theme nicht gefunden')\n const etag = `\"${theme.record.version ?? '0'}-${new TextEncoder().encode(theme.css).length}\"`\n const headers = { 'cache-control': 'private, max-age=0, must-revalidate', 'etag': etag }\n if (request.headers.get('if-none-match') === etag) return empty(304, headers)\n return text(theme.css, 'text/css; charset=utf-8', headers)\n}\n\n/** Deletes the uploaded theme `params.id` (`204`). `400` for a malformed id, `404` for an unknown one, `403` for a builtin, `501` without a `themes` port. */\nexport async function themeDelete(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse> {\n await authenticated(ctx, request)\n const themes = port(ctx, 'themes')\n const id = request.params?.id ?? ''\n if (!THEME_ID.test(id)) throw new HttpError(400, 'Ungültige Theme-ID')\n // `removeTheme` answers `false` for builtins and unknown ids alike, so the record decides between 403 and 404.\n const record = (await themes.listThemes()).find(t => t.id === id)\n if (!record) throw new HttpError(404, 'Theme nicht gefunden')\n if (record.builtin) throw new HttpError(403, 'Mitgelieferte Themes können nicht gelöscht werden')\n if (!await themes.removeTheme(id)) throw new HttpError(404, 'Theme nicht gefunden')\n return empty()\n}\n\nconst MAX_MANIFEST_BYTES = 64 * 1024\nconst MAX_ID_LENGTH = 64\n// Markers of an HTML/XML/SVG document in the head of a „stylesheet“.\nconst MARKUP_HEAD = /<script|<\\?xml/i\n\n/** `[^a-z0-9]+` → `-`, trimmed, at most `max` characters; `theme` when nothing is left. */\nfunction slugOf(name: string, max: number): string {\n const slug = name.normalize('NFKD').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+/, '').slice(0, max).replace(/-+$/, '')\n return slug || 'theme'\n}\n\n/**\n * Uploads an Obsidian theme into the shared library: multipart `css` (File, required), `manifest` (File) and `name`\n * (string) optional. Answers 201 with the new `ThemeRecord`; the id is the slug of the name, made unique with `-2`,\n * `-3` … against the library.\n */\nexport async function themePost(ctx: HandlerContext, request: HandlerRequest): Promise<HandlerResponse> {\n await authenticated(ctx, request)\n const themes = port(ctx, 'themes')\n // A body that is no multipart form counts as „no file“.\n const form = await request.readForm?.().catch(() => null)\n const cssFile = form?.get('css')\n if (!(cssFile instanceof File) || cssFile.size === 0) throw new HttpError(400, 'Keine CSS-Datei übermittelt')\n if (cssFile.size > MAX_THEME_BYTES) throw new HttpError(413, `Theme ist größer als ${MAX_THEME_BYTES / 1024 / 1024} MB`)\n const bytes = new Uint8Array(await cssFile.arrayBuffer())\n if (bytes.includes(0) || MARKUP_HEAD.test(new TextDecoder('latin1').decode(bytes.subarray(0, 512)))) {\n throw new HttpError(400, 'Theme ist keine CSS-Textdatei')\n }\n let css: string\n try {\n css = new TextDecoder('utf-8', { fatal: true }).decode(bytes)\n }\n catch {\n throw new HttpError(400, 'Theme ist keine gültige UTF-8-Textdatei')\n }\n\n let manifest: ThemeManifest | undefined\n const manifestFile = form?.get('manifest')\n if (manifestFile instanceof File && manifestFile.size > 0) {\n try {\n if (manifestFile.size > MAX_MANIFEST_BYTES) throw new Error('manifest too large')\n manifest = themeManifestSchema.parse(JSON.parse(await manifestFile.text()))\n }\n catch {\n throw new HttpError(400, 'Ungültiges manifest.json')\n }\n }\n\n const nameField = form?.get('name')\n const cssBaseName = cssFile.name.replace(/\\.css$/i, '')\n const name = manifest?.name\n ?? [typeof nameField === 'string' ? nameField : '', cssBaseName].map(n => n.trim().slice(0, 120)).find(Boolean)\n ?? 'Theme'\n\n const taken = new Set((await themes.listThemes()).map(t => t.id))\n const base = slugOf(name, MAX_ID_LENGTH)\n let id = base\n for (let n = 2; taken.has(id); n++) {\n const suffix = `-${n}`\n id = `${slugOf(name, MAX_ID_LENGTH - suffix.length)}${suffix}`\n }\n\n const record: Omit<ThemeRecord, 'builtin'> = { ...manifest, name, id }\n await themes.storeTheme(record, css)\n return json({ ...record, builtin: false } satisfies ThemeRecord, 201)\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { AiHandlerContext, HandlerContext, HandlerRequest, HandlerResponse, authenticated, empty, enforceRateLimit, eventStream, json, readBody, text } from "./context.js";
2
- import { chatBodySchema, chatPost, completeBodySchema, completePost, generateBodySchema, generatePost, modelsGet, transcribeBodySchema, transcribePost, transcriptCleanupBodySchema, transcriptCleanupPost } from "./ai.js";
3
- import { assetGet, assetPost, listWorkspaceTags, settingsGet, settingsPut, settingsPutBodySchema, tagsGet, themeDelete, themeGet, themePost, themesGet, usersGet } from "./editor.js";
4
- export { type AiHandlerContext, type HandlerContext, type HandlerRequest, type HandlerResponse, assetGet, assetPost, authenticated, chatBodySchema, chatPost, completeBodySchema, completePost, empty, enforceRateLimit, eventStream, generateBodySchema, generatePost, json, listWorkspaceTags, modelsGet, readBody, settingsGet, settingsPut, settingsPutBodySchema, tagsGet, text, themeDelete, themeGet, themePost, themesGet, transcribeBodySchema, transcribePost, transcriptCleanupBodySchema, transcriptCleanupPost, usersGet };
1
+ import { AiHandlerContext, HandlerContext, HandlerRequest, HandlerResponse, authenticated, empty, enforceRateLimit, eventStream, json, port, readBody, text } from "./context.js";
2
+ import { chatBodySchema, chatPost, completeBodySchema, completePost, extractBodySchema, extractPost, generateBodySchema, generatePost, modelsGet, transcriptCleanupBodySchema, transcriptCleanupPost } from "./ai.js";
3
+ import { assetGet, assetPost, capabilitiesGet, listWorkspaceTags, settingsGet, settingsPut, settingsPutBodySchema, tagsGet, themeDelete, themeGet, themePost, themesGet, usersGet } from "./editor.js";
4
+ export { type AiHandlerContext, type HandlerContext, type HandlerRequest, type HandlerResponse, assetGet, assetPost, authenticated, capabilitiesGet, chatBodySchema, chatPost, completeBodySchema, completePost, empty, enforceRateLimit, eventStream, extractBodySchema, extractPost, generateBodySchema, generatePost, json, listWorkspaceTags, modelsGet, port, readBody, settingsGet, settingsPut, settingsPutBodySchema, tagsGet, text, themeDelete, themeGet, themePost, themesGet, transcriptCleanupBodySchema, transcriptCleanupPost, usersGet };
@@ -1,4 +1,4 @@
1
- import { authenticated, empty, enforceRateLimit, eventStream, json, readBody, text } from "./context.js";
2
- import { chatBodySchema, chatPost, completeBodySchema, completePost, generateBodySchema, generatePost, modelsGet, transcribeBodySchema, transcribePost, transcriptCleanupBodySchema, transcriptCleanupPost } from "./ai.js";
3
- import { assetGet, assetPost, listWorkspaceTags, settingsGet, settingsPut, settingsPutBodySchema, tagsGet, themeDelete, themeGet, themePost, themesGet, usersGet } from "./editor.js";
4
- export { assetGet, assetPost, authenticated, chatBodySchema, chatPost, completeBodySchema, completePost, empty, enforceRateLimit, eventStream, generateBodySchema, generatePost, json, listWorkspaceTags, modelsGet, readBody, settingsGet, settingsPut, settingsPutBodySchema, tagsGet, text, themeDelete, themeGet, themePost, themesGet, transcribeBodySchema, transcribePost, transcriptCleanupBodySchema, transcriptCleanupPost, usersGet };
1
+ import { authenticated, empty, enforceRateLimit, eventStream, json, port, readBody, text } from "./context.js";
2
+ import { chatBodySchema, chatPost, completeBodySchema, completePost, extractBodySchema, extractPost, generateBodySchema, generatePost, modelsGet, transcriptCleanupBodySchema, transcriptCleanupPost } from "./ai.js";
3
+ import { assetGet, assetPost, capabilitiesGet, listWorkspaceTags, settingsGet, settingsPut, settingsPutBodySchema, tagsGet, themeDelete, themeGet, themePost, themesGet, usersGet } from "./editor.js";
4
+ export { assetGet, assetPost, authenticated, capabilitiesGet, chatBodySchema, chatPost, completeBodySchema, completePost, empty, enforceRateLimit, eventStream, extractBodySchema, extractPost, generateBodySchema, generatePost, json, listWorkspaceTags, modelsGet, port, readBody, settingsGet, settingsPut, settingsPutBodySchema, tagsGet, text, themeDelete, themeGet, themePost, themesGet, transcriptCleanupBodySchema, transcriptCleanupPost, usersGet };
@@ -1,35 +1,26 @@
1
- import { ModelProfile, ModelRef } from "../features/ai/protocol/models.js";
1
+ import { ModelProfile, ModelRef } from "../core/backend-types.js";
2
2
  import "../features/ai/protocol/index.js";
3
- import { EditorAdapter } from "./adapter.js";
4
- import { AiModels, AiModelsConfig } from "./ai.js";
3
+ import { AiModels } from "./ai.js";
4
+ import { EditorPorts } from "./ports.js";
5
5
  import { CollabServer } from "./collab.js";
6
- import { JSONContent } from "@tiptap/core";
6
+ import { AnyExtension, JSONContent } from "@tiptap/core";
7
7
  import { LanguageModel } from "ai";
8
8
  //#region src/server/host.d.ts
9
- export interface EditorServerConfig {
10
- /**
11
- * The AI models: presets, shared key, transcription, slots. `languageModel`/`listModels` default to the adapter's
12
- * methods of the same names.
13
- */
14
- ai?: Partial<AiModelsConfig>;
15
- /** Per-user limit shared by the AI endpoints. Default 30 requests per minute. */
16
- rateLimit?: {
17
- max: number;
18
- windowMs: number;
19
- };
20
- }
21
- /** 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. */
22
- export declare function setEditorAdapter(next: EditorAdapter): void;
23
- export declare function useEditorAdapter(): EditorAdapter;
24
- /** Sets the AI configuration and the rate limit of the process-wide server. Call before the first request. */
25
- export declare function configureEditorServer(next: EditorServerConfig): void;
26
- /** The process-wide collaboration server, created from the registered adapter on first use. */
9
+ /**
10
+ * Registers the host's ports for installers that read them later (the Nuxt module's server plugin installs on the first
11
+ * request, after every Nitro plugin has run). `options.schema`: the collaboration schema, see `CollabServerOptions.schema`.
12
+ */
13
+ export declare function setEditorPorts(next: EditorPorts, options?: {
14
+ schema?: () => AnyExtension[];
15
+ }): void;
16
+ export declare function useEditorPorts(): EditorPorts;
17
+ /** The process-wide collaboration server of the installed server. Throws when none is installed or `collab: false`. */
27
18
  export declare function useCollabServer(): CollabServer;
28
- /** The process-wide AI models: the configured presets, with the adapter's `languageModel`/`listModels` hooks. */
19
+ /** 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`. */
29
20
  export declare function useAiModels(): AiModels;
30
21
  /** Closes the process-wide collaboration server (pending stores are written first) and forgets it. */
31
22
  export declare function closeEditorServer(): Promise<void>;
32
- /** Open collaboration connections and loaded documents of this process (zeros before the first connection). */
23
+ /** Open collaboration connections and loaded documents of this process (zeros when collaboration is off). */
33
24
  export declare function collabStats(): {
34
25
  connections: number;
35
26
  documents: number;
@@ -46,7 +37,7 @@ export declare function resolveModel(ref: ModelRef, user: object | null): Promis
46
37
  export declare function listAiModels(user: object | null): Promise<ModelProfile[]>;
47
38
  /**
48
39
  * Per-user limit for host-defined AI routes: the same limiter as the editor's own AI endpoints. Call first in the route.
49
- * Throws 401 (`HttpError`) without a user, 429 when exceeded; returns the user the adapter authenticated, for `resolveModel`.
40
+ * Throws 401 (`HttpError`) without a user, 429 when exceeded; returns the user the identity port authenticated, for `resolveModel`.
50
41
  * With a Node-backed request (`event.node.res`, as h3 events have) the 429's `Retry-After` header is set on the response too.
51
42
  */
52
43
  export declare function enforceAiRateLimit(request: {