@ecsplico/editor 1.0.0 → 2.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 (363) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +7 -7
  3. package/dist/adapters/anchors.d.ts +80 -0
  4. package/dist/adapters/anchors.js +270 -0
  5. package/dist/adapters/anchors.js.map +1 -0
  6. package/dist/adapters/comments/client.d.ts +64 -0
  7. package/dist/adapters/comments/client.js +536 -0
  8. package/dist/adapters/comments/client.js.map +1 -0
  9. package/dist/adapters/comments/drizzle.d.ts +430 -0
  10. package/dist/adapters/comments/drizzle.js +236 -0
  11. package/dist/adapters/comments/drizzle.js.map +1 -0
  12. package/dist/adapters/comments/errors.d.ts +9 -0
  13. package/dist/adapters/comments/errors.js +19 -0
  14. package/dist/adapters/comments/errors.js.map +1 -0
  15. package/dist/adapters/comments/json.d.ts +19 -0
  16. package/dist/adapters/comments/json.js +94 -0
  17. package/dist/adapters/comments/json.js.map +1 -0
  18. package/dist/adapters/comments/record.js +78 -0
  19. package/dist/adapters/comments/record.js.map +1 -0
  20. package/dist/adapters/comments/server.d.ts +23 -0
  21. package/dist/adapters/comments/server.js +102 -0
  22. package/dist/adapters/comments/server.js.map +1 -0
  23. package/dist/adapters/comments/types.d.ts +109 -0
  24. package/dist/adapters/documents.js +108 -0
  25. package/dist/adapters/documents.js.map +1 -0
  26. package/dist/adapters/drizzle.d.ts +293 -0
  27. package/dist/adapters/drizzle.js +157 -0
  28. package/dist/adapters/drizzle.js.map +1 -0
  29. package/dist/adapters/files.js +30 -0
  30. package/dist/adapters/files.js.map +1 -0
  31. package/dist/adapters/forge.d.ts +58 -0
  32. package/dist/adapters/forge.js +91 -0
  33. package/dist/adapters/forge.js.map +1 -0
  34. package/dist/adapters/index.d.ts +13 -0
  35. package/dist/adapters/index.js +0 -0
  36. package/dist/adapters/json.d.ts +24 -0
  37. package/dist/adapters/json.js +128 -0
  38. package/dist/adapters/json.js.map +1 -0
  39. package/dist/adapters/nitro.d.ts +61 -0
  40. package/dist/adapters/nitro.js +212 -0
  41. package/dist/adapters/nitro.js.map +1 -0
  42. package/dist/adapters/routes.js +16 -0
  43. package/dist/adapters/routes.js.map +1 -0
  44. package/dist/adapters/shared.d.ts +37 -0
  45. package/dist/adapters/shared.js +32 -0
  46. package/dist/adapters/shared.js.map +1 -0
  47. package/dist/adapters/vue.d.ts +67 -0
  48. package/dist/adapters/vue.js +187 -0
  49. package/dist/adapters/vue.js.map +1 -0
  50. package/dist/code/CodeSurface.vue.d.ts +3 -3
  51. package/dist/core/doc-anchors.d.ts +5 -0
  52. package/dist/core/doc-anchors.js +4 -3
  53. package/dist/core/doc-anchors.js.map +1 -1
  54. package/dist/core/editor-ui.js +57 -1
  55. package/dist/core/editor-ui.js.map +1 -1
  56. package/dist/core/notify.d.ts +1 -1
  57. package/dist/core/notify.js.map +1 -1
  58. package/dist/core/surface-session.js +139 -0
  59. package/dist/core/surface-session.js.map +1 -0
  60. package/dist/document/DocumentSurface.d.ts +1 -1
  61. package/dist/document/DocumentSurface.vue.d.ts +3 -3
  62. package/dist/features/ai/agent-op-review.d.ts +2 -2
  63. package/dist/features/ai/agent-op-review.js.map +1 -1
  64. package/dist/features/ai/agent-ops.d.ts +1 -1
  65. package/dist/features/ai/agent-ops.js +9 -6
  66. package/dist/features/ai/agent-ops.js.map +1 -1
  67. package/dist/features/ai/ai-apply.d.ts +1 -1
  68. package/dist/features/ai/ai-review.js +10 -1
  69. package/dist/features/ai/ai-review.js.map +1 -1
  70. package/dist/features/ai/components/AiSelectionMenu.js +78 -252
  71. package/dist/features/ai/components/AiSelectionMenu.js.map +1 -1
  72. package/dist/features/ai/components/AiSelectionMenu.vue.d.ts +2 -1
  73. package/dist/features/ai/components/AiSidebar.js +2 -2
  74. package/dist/features/ai/components/DocumentChatAnswer.js +1 -1
  75. package/dist/features/ai/components/DocumentChatOps.js +1 -0
  76. package/dist/features/ai/components/DocumentChatOps.js.map +1 -1
  77. package/dist/features/ai/components/ModelQuickSwitch.js +1 -1
  78. package/dist/features/ai/components/SettingsAiTab.js +1 -1
  79. package/dist/features/ai/components/SettingsModelProfiles.js +1 -1
  80. package/dist/features/ai/document-chat.d.ts +3 -2
  81. package/dist/features/ai/document-chat.js +16 -19
  82. package/dist/features/ai/document-chat.js.map +1 -1
  83. package/dist/features/ai/index.d.ts +5 -3
  84. package/dist/features/ai/index.js +4 -2
  85. package/dist/features/ai/protocol/agent-ops.d.ts +22 -17
  86. package/dist/features/ai/protocol/agent-ops.js +65 -39
  87. package/dist/features/ai/protocol/agent-ops.js.map +1 -1
  88. package/dist/features/ai/protocol/block-lines.d.ts +89 -0
  89. package/dist/features/ai/protocol/block-lines.js +177 -0
  90. package/dist/features/ai/protocol/block-lines.js.map +1 -0
  91. package/dist/features/ai/protocol/chat.js +10 -10
  92. package/dist/features/ai/protocol/chat.js.map +1 -1
  93. package/dist/features/ai/protocol/index.d.ts +3 -2
  94. package/dist/features/ai/protocol/index.js +3 -2
  95. package/dist/features/ai/react/AiSelectionMenu.d.ts +3 -2
  96. package/dist/features/ai/react/AiSelectionMenu.js +64 -255
  97. package/dist/features/ai/react/AiSelectionMenu.js.map +1 -1
  98. package/dist/features/ai/react/AiSidebar.js +2 -2
  99. package/dist/features/ai/react/DocumentChatAnswer.js +1 -1
  100. package/dist/features/ai/react/DocumentChatOps.js +1 -0
  101. package/dist/features/ai/react/DocumentChatOps.js.map +1 -1
  102. package/dist/features/ai/react/ModelQuickSwitch.js +1 -1
  103. package/dist/features/ai/react/SettingsAiTab.js +1 -1
  104. package/dist/features/ai/react/SettingsModelProfiles.js +1 -1
  105. package/dist/features/ai/react/use-ai-selection-flow.js +34 -0
  106. package/dist/features/ai/react/use-ai-selection-flow.js.map +1 -0
  107. package/dist/features/ai/selection-flow.d.ts +133 -0
  108. package/dist/features/ai/selection-flow.js +283 -0
  109. package/dist/features/ai/selection-flow.js.map +1 -0
  110. package/dist/features/ai/use-ai-assistant.d.ts +1 -1
  111. package/dist/features/ai/use-document-chat.d.ts +1 -1
  112. package/dist/features/authors/components/AuthorColorsPanel.js +1 -1
  113. package/dist/features/authors/feature.js +1 -1
  114. package/dist/features/authors/index.js +1 -1
  115. package/dist/features/authors/react/AuthorColorsPanel.js +1 -1
  116. package/dist/features/comments/components/CommentBubble.js +1 -1
  117. package/dist/features/comments/components/CommentComposer.js +1 -1
  118. package/dist/features/comments/components/CommentThreadView.js +5 -2
  119. package/dist/features/comments/components/CommentThreadView.js.map +1 -1
  120. package/dist/features/comments/components/CommentsMargin.js +108 -230
  121. package/dist/features/comments/components/CommentsMargin.js.map +1 -1
  122. package/dist/features/comments/components/CommentsOverlay.js +1 -1
  123. package/dist/features/comments/feature.js +1 -1
  124. package/dist/features/comments/index.d.ts +4 -2
  125. package/dist/features/comments/index.js +4 -2
  126. package/dist/features/comments/margin-controller.d.ts +44 -0
  127. package/dist/features/comments/margin-controller.js +132 -0
  128. package/dist/features/comments/margin-controller.js.map +1 -0
  129. package/dist/features/comments/margin-layout.d.ts +55 -0
  130. package/dist/features/comments/margin-layout.js +79 -0
  131. package/dist/features/comments/margin-layout.js.map +1 -0
  132. package/dist/features/comments/model.d.ts +8 -0
  133. package/dist/features/comments/model.js +60 -34
  134. package/dist/features/comments/model.js.map +1 -1
  135. package/dist/features/comments/react/CommentBubble.js +1 -1
  136. package/dist/features/comments/react/CommentComposer.js +1 -1
  137. package/dist/features/comments/react/CommentThreadView.js +2 -2
  138. package/dist/features/comments/react/CommentThreadView.js.map +1 -1
  139. package/dist/features/comments/react/CommentsMargin.d.ts +0 -5
  140. package/dist/features/comments/react/CommentsMargin.js +85 -251
  141. package/dist/features/comments/react/CommentsMargin.js.map +1 -1
  142. package/dist/features/comments/react/CommentsOverlay.js +1 -1
  143. package/dist/features/comments/react/use-comments.js +1 -1
  144. package/dist/features/comments/react/use-margin-layout.js +45 -0
  145. package/dist/features/comments/react/use-margin-layout.js.map +1 -0
  146. package/dist/features/comments/react.d.ts +1 -1
  147. package/dist/features/comments/schema.d.ts +23 -0
  148. package/dist/features/comments/schema.js.map +1 -1
  149. package/dist/features/comments/snapshot-equality.js +40 -0
  150. package/dist/features/comments/snapshot-equality.js.map +1 -0
  151. package/dist/features/comments/thread-anchor.js +33 -0
  152. package/dist/features/comments/thread-anchor.js.map +1 -0
  153. package/dist/features/comments/use-comments.d.ts +3 -1
  154. package/dist/features/comments/use-comments.js +1 -0
  155. package/dist/features/comments/use-comments.js.map +1 -1
  156. package/dist/features/comments/use-margin-layout.js +29 -0
  157. package/dist/features/comments/use-margin-layout.js.map +1 -0
  158. package/dist/features/comments/vue.d.ts +1 -1
  159. package/dist/features/composites/accepted-children.d.ts +21 -0
  160. package/dist/features/composites/accepted-children.js +126 -0
  161. package/dist/features/composites/accepted-children.js.map +1 -0
  162. package/dist/features/composites/components/CompositeDetails.js +1 -1
  163. package/dist/features/composites/components/CompositeInspector.js +38 -164
  164. package/dist/features/composites/components/CompositeInspector.js.map +1 -1
  165. package/dist/features/composites/feature.d.ts +2 -1
  166. package/dist/features/composites/feature.js +8 -2
  167. package/dist/features/composites/feature.js.map +1 -1
  168. package/dist/features/composites/index.d.ts +5 -3
  169. package/dist/features/composites/index.js +8 -6
  170. package/dist/features/composites/inspector-model.d.ts +97 -0
  171. package/dist/features/composites/inspector-model.js +255 -0
  172. package/dist/features/composites/inspector-model.js.map +1 -0
  173. package/dist/features/composites/kinds.d.ts +11 -0
  174. package/dist/features/composites/kinds.js +17 -2
  175. package/dist/features/composites/kinds.js.map +1 -1
  176. package/dist/features/composites/outline.d.ts +18 -5
  177. package/dist/features/composites/outline.js +44 -12
  178. package/dist/features/composites/outline.js.map +1 -1
  179. package/dist/features/composites/react/CompositeDetails.js +1 -1
  180. package/dist/features/composites/react/CompositeInspector.d.ts +1 -1
  181. package/dist/features/composites/react/CompositeInspector.js +21 -180
  182. package/dist/features/composites/react/CompositeInspector.js.map +1 -1
  183. package/dist/features/composites/react/CompositeStatusMenu.d.ts +1 -1
  184. package/dist/features/composites/react/CompositeView.js +1 -1
  185. package/dist/features/composites/react/use-composite-inspector.js +29 -0
  186. package/dist/features/composites/react/use-composite-inspector.js.map +1 -0
  187. package/dist/features/composites/schema.d.ts +2 -2
  188. package/dist/features/composites/schema.js +2 -2
  189. package/dist/features/composites/schema.js.map +1 -1
  190. package/dist/features/composites/use-composite-anchors.d.ts +1 -1
  191. package/dist/features/composites/use-composite-inspector.js +41 -0
  192. package/dist/features/composites/use-composite-inspector.js.map +1 -0
  193. package/dist/features/composites/use-composite-rows.d.ts +1 -1
  194. package/dist/features/media/index.d.ts +1 -1
  195. package/dist/features/media/vue.d.ts +1 -1
  196. package/dist/features/mentions/index.d.ts +3 -3
  197. package/dist/features/mentions/index.js +3 -3
  198. package/dist/features/mentions/schema.d.ts +1 -1
  199. package/dist/features/mentions/schema.js +1 -1
  200. package/dist/features/themes/index.d.ts +1 -1
  201. package/dist/features/themes/index.js +1 -1
  202. package/dist/features/transcript/feature.js +1 -1
  203. package/dist/features/transcript/index.js +2 -2
  204. package/dist/i18n/de/ai.js +2 -0
  205. package/dist/i18n/de/ai.js.map +1 -1
  206. package/dist/i18n/de/common.js +1 -2
  207. package/dist/i18n/de/common.js.map +1 -1
  208. package/dist/i18n/de/composites.js +8 -1
  209. package/dist/i18n/de/composites.js.map +1 -1
  210. package/dist/i18n/de/tree.js +14 -1
  211. package/dist/i18n/de/tree.js.map +1 -1
  212. package/dist/i18n/de.d.ts +22 -1
  213. package/dist/i18n/en/ai.js +2 -0
  214. package/dist/i18n/en/ai.js.map +1 -1
  215. package/dist/i18n/en/common.js +1 -2
  216. package/dist/i18n/en/common.js.map +1 -1
  217. package/dist/i18n/en/composites.js +8 -1
  218. package/dist/i18n/en/composites.js.map +1 -1
  219. package/dist/i18n/en/tree.js +14 -1
  220. package/dist/i18n/en/tree.js.map +1 -1
  221. package/dist/integrations/composite-ai/composite-fill.js +2 -2
  222. package/dist/integrations/composite-ai/composite-summary.js +2 -2
  223. package/dist/integrations/composite-ai/index.js +2 -2
  224. package/dist/integrations/transcript-ai/transcript-cleanup.js +1 -1
  225. package/dist/markdown/MarkdownSurface.d.ts +1 -1
  226. package/dist/markdown/MarkdownSurface.js +2 -2
  227. package/dist/markdown/MarkdownSurface.vue.d.ts +7 -7
  228. package/dist/markdown/index.d.ts +2 -2
  229. package/dist/nuxt/module.d.ts +0 -6
  230. package/dist/nuxt/module.js +3 -5
  231. package/dist/nuxt/module.js.map +1 -1
  232. package/dist/nuxt/runtime/install-context.d.ts +2 -3
  233. package/dist/nuxt/runtime/install-context.js +2 -3
  234. package/dist/nuxt/runtime/install-context.js.map +1 -1
  235. package/dist/nuxt/runtime/plugins/editor-context-nuxt-ui.client.ts +1 -1
  236. package/dist/nuxt/runtime/server/routes/collab/[id].js +1 -1
  237. package/dist/react/EditorSurface.d.ts +1 -1
  238. package/dist/react/EditorSurface.js +43 -149
  239. package/dist/react/EditorSurface.js.map +1 -1
  240. package/dist/react/EditorToolbar.js +3 -40
  241. package/dist/react/EditorToolbar.js.map +1 -1
  242. package/dist/react/styles/ui-vars.css +2 -2
  243. package/dist/schema/advanced.js +2 -2
  244. package/dist/server/adapter.d.ts +2 -2
  245. package/dist/server/collab.js +1 -1
  246. package/dist/server/handlers/ai.d.ts +4 -2
  247. package/dist/server/handlers/ai.js +11 -9
  248. package/dist/server/handlers/ai.js.map +1 -1
  249. package/dist/server/handlers/context.d.ts +1 -1
  250. package/dist/server/handlers/editor.d.ts +1 -1
  251. package/dist/server/handlers/editor.js +2 -2
  252. package/dist/server/host.d.ts +1 -1
  253. package/dist/server/index.d.ts +2 -2
  254. package/dist/settings/index.d.ts +1 -1
  255. package/dist/styles/ai.css +1 -1
  256. package/dist/styles/authors.css +1 -1
  257. package/dist/styles/block-ui.css +1 -1
  258. package/dist/styles/collab.css +1 -1
  259. package/dist/styles/comments.css +1 -1
  260. package/dist/styles/core.css +2 -2
  261. package/dist/styles/media.css +1 -1
  262. package/dist/styles/mentions.css +1 -1
  263. package/dist/styles/themes.css +1 -1
  264. package/dist/styles/tokens.css +1 -1
  265. package/dist/styles/transcript.css +1 -1
  266. package/dist/tree/DocumentTree.js +159 -387
  267. package/dist/tree/DocumentTree.js.map +1 -1
  268. package/dist/tree/drop-rules.js +37 -0
  269. package/dist/tree/drop-rules.js.map +1 -0
  270. package/dist/tree/react/DocumentTree.d.ts +2 -2
  271. package/dist/tree/react/DocumentTree.js +135 -397
  272. package/dist/tree/react/DocumentTree.js.map +1 -1
  273. package/dist/tree/react/use-tree-model.js +129 -0
  274. package/dist/tree/react/use-tree-model.js.map +1 -0
  275. package/dist/tree/react.js +1 -1
  276. package/dist/tree/tree-host.js +100 -0
  277. package/dist/tree/tree-host.js.map +1 -0
  278. package/dist/tree/tree-items.js +22 -43
  279. package/dist/tree/tree-items.js.map +1 -1
  280. package/dist/tree/tree-model.js +580 -0
  281. package/dist/tree/tree-model.js.map +1 -0
  282. package/dist/tree/tree-rows.js +77 -0
  283. package/dist/tree/tree-rows.js.map +1 -0
  284. package/dist/tree/use-tree-model.js +94 -0
  285. package/dist/tree/use-tree-model.js.map +1 -0
  286. package/dist/tree/vue.js +1 -1
  287. package/dist/vue/AdvancedEditor.vue.d.ts +4 -4
  288. package/dist/vue/SimpleEditor.vue.d.ts +2 -2
  289. package/dist/vue/components/EditorSurface.js +27 -87
  290. package/dist/vue/components/EditorSurface.js.map +1 -1
  291. package/dist/vue/components/EditorSurface.vue.d.ts +4 -4
  292. package/dist/vue/components/EditorToolbar.js +7 -44
  293. package/dist/vue/components/EditorToolbar.js.map +1 -1
  294. package/dist/vue/context.d.ts +4 -4
  295. package/dist/vue/context.js +3 -2
  296. package/dist/vue/context.js.map +1 -1
  297. package/dist/vue/kit/types.d.ts +1 -1
  298. package/dist/vue/kit/use-ui-kit.d.ts +2 -2
  299. package/dist/vue/kit/use-ui-kit.js +3 -3
  300. package/dist/vue/kit/use-ui-kit.js.map +1 -1
  301. package/dist/vue/use-editor-ui.d.ts +1 -1
  302. package/dist/vue/use-notifier.d.ts +1 -1
  303. package/docs/integration.md +98 -5
  304. package/docs/llms.md +10 -2
  305. package/docs/usage.md +10 -5
  306. package/package.json +70 -23
  307. package/dist/nuxt/runtime/plugins/editor-context-primevue.client.ts +0 -8
  308. package/dist/vue/kit/primevue/Alert.js +0 -49
  309. package/dist/vue/kit/primevue/Alert.js.map +0 -1
  310. package/dist/vue/kit/primevue/Avatar.js +0 -54
  311. package/dist/vue/kit/primevue/Avatar.js.map +0 -1
  312. package/dist/vue/kit/primevue/Badge.js +0 -41
  313. package/dist/vue/kit/primevue/Badge.js.map +0 -1
  314. package/dist/vue/kit/primevue/Button.js +0 -112
  315. package/dist/vue/kit/primevue/Button.js.map +0 -1
  316. package/dist/vue/kit/primevue/Chip.js +0 -38
  317. package/dist/vue/kit/primevue/Chip.js.map +0 -1
  318. package/dist/vue/kit/primevue/DropdownMenu.js +0 -98
  319. package/dist/vue/kit/primevue/DropdownMenu.js.map +0 -1
  320. package/dist/vue/kit/primevue/FieldGroup.js +0 -22
  321. package/dist/vue/kit/primevue/FieldGroup.js.map +0 -1
  322. package/dist/vue/kit/primevue/FormField.js +0 -56
  323. package/dist/vue/kit/primevue/FormField.js.map +0 -1
  324. package/dist/vue/kit/primevue/Icon.js +0 -23
  325. package/dist/vue/kit/primevue/Icon.js.map +0 -1
  326. package/dist/vue/kit/primevue/Input.js +0 -96
  327. package/dist/vue/kit/primevue/Input.js.map +0 -1
  328. package/dist/vue/kit/primevue/InputMenu.js +0 -122
  329. package/dist/vue/kit/primevue/InputMenu.js.map +0 -1
  330. package/dist/vue/kit/primevue/Modal.js +0 -59
  331. package/dist/vue/kit/primevue/Modal.js.map +0 -1
  332. package/dist/vue/kit/primevue/Popover.js +0 -135
  333. package/dist/vue/kit/primevue/Popover.js.map +0 -1
  334. package/dist/vue/kit/primevue/RadioGroup.js +0 -58
  335. package/dist/vue/kit/primevue/RadioGroup.js.map +0 -1
  336. package/dist/vue/kit/primevue/Select.js +0 -68
  337. package/dist/vue/kit/primevue/Select.js.map +0 -1
  338. package/dist/vue/kit/primevue/SelectMenu.js +0 -94
  339. package/dist/vue/kit/primevue/SelectMenu.js.map +0 -1
  340. package/dist/vue/kit/primevue/Separator.js +0 -16
  341. package/dist/vue/kit/primevue/Separator.js.map +0 -1
  342. package/dist/vue/kit/primevue/Switch.js +0 -46
  343. package/dist/vue/kit/primevue/Switch.js.map +0 -1
  344. package/dist/vue/kit/primevue/Table.js +0 -54
  345. package/dist/vue/kit/primevue/Table.js.map +0 -1
  346. package/dist/vue/kit/primevue/Tabs.js +0 -49
  347. package/dist/vue/kit/primevue/Tabs.js.map +0 -1
  348. package/dist/vue/kit/primevue/Textarea.js +0 -55
  349. package/dist/vue/kit/primevue/Textarea.js.map +0 -1
  350. package/dist/vue/kit/primevue/Tooltip.js +0 -43
  351. package/dist/vue/kit/primevue/Tooltip.js.map +0 -1
  352. package/dist/vue/kit/primevue/Tree.js +0 -75
  353. package/dist/vue/kit/primevue/Tree.js.map +0 -1
  354. package/dist/vue/kit/primevue/select-options.js +0 -55
  355. package/dist/vue/kit/primevue/select-options.js.map +0 -1
  356. package/dist/vue/kit/primevue/shared.js +0 -49
  357. package/dist/vue/kit/primevue/shared.js.map +0 -1
  358. package/dist/vue/kit/primevue/trigger.js +0 -25
  359. package/dist/vue/kit/primevue/trigger.js.map +0 -1
  360. package/dist/vue/kit/primevue.css +0 -86
  361. package/dist/vue/kit/primevue.d.ts +0 -33
  362. package/dist/vue/kit/primevue.js +0 -96
  363. package/dist/vue/kit/primevue.js.map +0 -1
@@ -0,0 +1,536 @@
1
+ import { captureAnchor, capturePoint, mapAnchor, resolveAnchor } from "../anchors.js";
2
+ import { createStore } from "../../core/store.js";
3
+ import { releaseRanges, resolveRange } from "../../core/doc-anchors.js";
4
+ import { COMMENT_LIMITS } from "../../features/comments/schema.js";
5
+ import { cancelCommentDraft, commentsKey, setActiveComment, startCommentDraft } from "../../features/comments/comments-plugin.js";
6
+ import { EMPTY_SNAPSHOT, NO_POSITIONS, NO_RANGES, sameOrphanAt, sameRange, sameRanges, sameUser } from "../../features/comments/snapshot-equality.js";
7
+ //#region src/adapters/comments/client.ts
8
+ /** Neutral colour of authors that stored no colour. */
9
+ const FALLBACK_COLOR = "#6b7280";
10
+ /** Characters of context that must agree for an orphan to be re-attached on load. */
11
+ const REATTACH_CONTEXT = 24;
12
+ const newId = (prefix) => `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
13
+ /** The `error` message of a refused request's JSON body. */
14
+ function errorOf(body) {
15
+ return typeof body === "object" && body !== null && "error" in body ? body.error : void 0;
16
+ }
17
+ function isDiscussion(value) {
18
+ return typeof value === "object" && value !== null && "annotations" in value && Array.isArray(value.annotations) && "threads" in value && Array.isArray(value.threads);
19
+ }
20
+ const sameJson = (a, b) => JSON.stringify(a) === JSON.stringify(b);
21
+ const authorOf = (comment) => ({
22
+ id: comment.authorId,
23
+ name: comment.authorName ?? comment.authorId,
24
+ color: comment.authorColor ?? FALLBACK_COLOR
25
+ });
26
+ function quoteOf(anchor) {
27
+ if (!anchor) return "";
28
+ if (anchor.kind === "range") return anchor.quote;
29
+ if (anchor.kind === "orphan") return anchor.quote ?? (anchor.previous.kind === "range" ? anchor.previous.quote : "");
30
+ return "";
31
+ }
32
+ function viewOf(thread, anchor) {
33
+ const [first, ...replies] = thread.comments;
34
+ return {
35
+ id: thread.id,
36
+ author: first ? authorOf(first) : {
37
+ id: "",
38
+ name: "",
39
+ color: FALLBACK_COLOR
40
+ },
41
+ text: first?.body ?? "",
42
+ createdAt: first?.createdAt ?? "",
43
+ ...first?.editedAt !== void 0 && { editedAt: first.editedAt },
44
+ quote: quoteOf(anchor),
45
+ resolved: thread.status === "resolved",
46
+ replies: replies.map((reply) => ({
47
+ id: reply.id,
48
+ author: authorOf(reply),
49
+ text: reply.body,
50
+ createdAt: reply.createdAt,
51
+ ...reply.editedAt !== void 0 && { editedAt: reply.editedAt }
52
+ }))
53
+ };
54
+ }
55
+ function rangeOf(anchor) {
56
+ if (!anchor || anchor.kind === "orphan") return null;
57
+ return anchor.kind === "range" ? {
58
+ from: anchor.from,
59
+ to: anchor.to
60
+ } : {
61
+ from: anchor.position,
62
+ to: anchor.position
63
+ };
64
+ }
65
+ /** A document is "empty" while the host has not put its content in yet: nothing to resolve anchors against. */
66
+ const isBlank = (doc) => doc.textContent === "";
67
+ /** Whether the text at `candidate` still reads like the context `previous` was written in (one side suffices). */
68
+ function contextAgrees(candidate, previous) {
69
+ if (candidate.kind === "orphan" || previous.kind === "orphan") return false;
70
+ const before = previous.contextBefore?.slice(-24);
71
+ const after = previous.contextAfter?.slice(0, REATTACH_CONTEXT);
72
+ if (!before && !after) return true;
73
+ return !!before && !!candidate.contextBefore?.endsWith(before) || !!after && !!candidate.contextAfter?.startsWith(after);
74
+ }
75
+ /**
76
+ * The comments of one editor over a REST endpoint, as a `CommentsModel` (the host passes `() => model` as the
77
+ * `model` factory of `commentsFeature`/`commentsFeatureCore`; one instance serves the plugin and every hook).
78
+ *
79
+ * - **Load.** `refresh()` (called by the feature once the editor exists) fetches `GET endpoint`; each annotation's
80
+ * anchor is resolved against the document (exact offsets, else quote and context search). An anchor that moved is
81
+ * re-captured and written back; an anchor whose text is gone becomes an `orphan` (the thread stays, without a range)
82
+ * and an orphan whose text is back with the same surroundings is re-attached. While the document is still empty the
83
+ * resolving waits for its content.
84
+ * - **Edits.** Every transaction carries all anchors with it (`mapAnchor`), so ranges, quotes and contexts follow the
85
+ * text; changed anchors are written back after `persistDelay`. Text deleted under an anchor orphans it for good (it is
86
+ * never silently re-attached to other text during editing; `reload()` re-attaches it when its text and context
87
+ * are found again, e.g. after the content was replaced).
88
+ * - **Writes** are applied locally at once and sent in order; a failed request is reported to `onError` and the threads
89
+ * are reloaded. Without a `user` or while `canComment` is false nothing is written. Only the author may edit or
90
+ * delete a comment.
91
+ * - **Lifecycle.** The model follows the editor `getEditor` names until that editor is destroyed; `dispose()` writes
92
+ * pending anchor changes and does not stop it (the feature and its hooks share the instance and dispose it on their
93
+ * own schedule).
94
+ */
95
+ function createRestCommentsModel(options) {
96
+ const { fetch, documentId, getEditor, onError } = options;
97
+ const endpoint = options.endpoint ?? `/comments/${encodeURIComponent(documentId)}`;
98
+ const persistDelay = options.persistDelay ?? 500;
99
+ const store = createStore(EMPTY_SNAPSHOT);
100
+ const userNow = () => typeof options.user === "function" ? options.user() : options.user;
101
+ const canCommentNow = () => typeof options.canComment === "function" ? options.canComment() : options.canComment;
102
+ /** Editors that announced their destruction: their view is still alive while `destroy` is emitted. */
103
+ const gone = /* @__PURE__ */ new WeakSet();
104
+ const current = () => {
105
+ const instance = getEditor();
106
+ return instance && !instance.isDestroyed && !gone.has(instance) ? instance : void 0;
107
+ };
108
+ let threads = [];
109
+ let anchors = /* @__PURE__ */ new Map();
110
+ /** The anchor each annotation has on the server, serialised. */
111
+ const persisted = /* @__PURE__ */ new Map();
112
+ const dirty = /* @__PURE__ */ new Set();
113
+ /**
114
+ * Where the text of an annotation that became an orphan during this session was: the deletion point, mapped through
115
+ * every later edit. Keyed by annotation id (`orphanAt` in the snapshot is keyed by thread id; `orphanPositions` translates).
116
+ * Deletion points are session-local: `load()` clears them, and an anchor that arrives already orphaned has none, because
117
+ * the server stores no deletion point. Such threads get no `orphanAt` entry and sit after the placed ones in the margin.
118
+ */
119
+ const deletedAt = /* @__PURE__ */ new Map();
120
+ /** Anchors wait for the document content (resolve on load) before they get a range. */
121
+ let unresolved = false;
122
+ /** A load was requested / the first one succeeded: writes wait for it, so a load never overwrites a newer local change. */
123
+ let loaded = false;
124
+ let ready = false;
125
+ let chain = Promise.resolve();
126
+ let timer;
127
+ function enqueue(task, reloadOnError = true) {
128
+ chain = chain.then(task).catch((error) => {
129
+ onError?.(error instanceof Error ? error : new Error(String(error)));
130
+ if (reloadOnError) enqueue(load, false);
131
+ });
132
+ }
133
+ async function request(init) {
134
+ const response = await fetch(endpoint, init && {
135
+ method: init.method,
136
+ headers: { "content-type": "application/json" },
137
+ body: JSON.stringify(init.body)
138
+ });
139
+ if (!response.ok) {
140
+ const detail = await response.json().then(errorOf, () => void 0);
141
+ throw new Error(`Comments request ${init?.method ?? "GET"} ${endpoint} failed: ${response.status}${typeof detail === "string" ? ` ${detail}` : ""}`);
142
+ }
143
+ return response.json();
144
+ }
145
+ const send = (body) => enqueue(async () => void await request({
146
+ method: "POST",
147
+ body
148
+ }));
149
+ function writeAnchors() {
150
+ timer = void 0;
151
+ if (!userNow() || !ready || !canCommentNow()) {
152
+ dirty.clear();
153
+ return;
154
+ }
155
+ for (const id of dirty) {
156
+ const anchor = anchors.get(id);
157
+ const threadId = threads.find((thread) => thread.annotationId === id)?.id;
158
+ if (!anchor || !threadId || persisted.get(id) === JSON.stringify(anchor)) continue;
159
+ persisted.set(id, JSON.stringify(anchor));
160
+ send({
161
+ action: "update-annotation",
162
+ annotation: {
163
+ id,
164
+ threadId,
165
+ anchor
166
+ }
167
+ });
168
+ }
169
+ dirty.clear();
170
+ }
171
+ function markDirty(id) {
172
+ dirty.add(id);
173
+ if (timer === void 0) timer = setTimeout(writeAnchors, persistDelay);
174
+ }
175
+ function flush() {
176
+ clearTimeout(timer);
177
+ writeAnchors();
178
+ }
179
+ /** `anchor` read against `editor`'s document: the moved/re-captured anchor, an orphan, or the same object. */
180
+ function resolveOne(editor, anchor) {
181
+ const live = anchor.kind === "orphan" ? anchor.previous : anchor;
182
+ const found = resolveAnchor(editor.state.doc, live);
183
+ if (!found) return anchor.kind === "orphan" ? anchor : {
184
+ kind: "orphan",
185
+ previous: anchor,
186
+ quote: quoteOf(anchor) || void 0,
187
+ contextBefore: anchor.contextBefore,
188
+ contextAfter: anchor.contextAfter,
189
+ reason: "unresolvable"
190
+ };
191
+ const next = live.kind === "range" ? captureAnchor(editor, found) : capturePoint(editor, found.from);
192
+ if (anchor.kind === "orphan" && !contextAgrees(next, live)) return anchor;
193
+ return sameJson(next, anchor) ? anchor : next;
194
+ }
195
+ function resolveAll(editor) {
196
+ if (isBlank(editor.state.doc)) {
197
+ unresolved = anchors.size > 0;
198
+ return;
199
+ }
200
+ unresolved = false;
201
+ for (const [id, anchor] of anchors) {
202
+ const next = resolveOne(editor, anchor);
203
+ if (next !== anchor) {
204
+ anchors.set(id, next);
205
+ if (next.kind !== "orphan") deletedAt.delete(id);
206
+ markDirty(id);
207
+ }
208
+ }
209
+ }
210
+ function carry(transactions) {
211
+ for (const transaction of transactions) {
212
+ if (!transaction.docChanged) continue;
213
+ for (const [id, position] of deletedAt) deletedAt.set(id, transaction.mapping.map(position, 1));
214
+ for (const [id, anchor] of anchors) {
215
+ const next = mapAnchor(anchor, transaction);
216
+ if (next !== anchor) {
217
+ anchors.set(id, next);
218
+ if (next.kind === "orphan" && anchor.kind !== "orphan") deletedAt.set(id, transaction.mapping.map(anchor.kind === "range" ? anchor.from : anchor.position, 1));
219
+ markDirty(id);
220
+ }
221
+ }
222
+ }
223
+ }
224
+ function rangesOf(editor) {
225
+ if (!editor || unresolved) return NO_RANGES;
226
+ const size = editor.state.doc.content.size;
227
+ const ranges = /* @__PURE__ */ new Map();
228
+ for (const thread of threads) {
229
+ const range = rangeOf(anchors.get(thread.annotationId));
230
+ if (range && range.from <= size) ranges.set(thread.id, {
231
+ from: range.from,
232
+ to: Math.min(range.to, size)
233
+ });
234
+ }
235
+ return ranges;
236
+ }
237
+ /**
238
+ * The snapshot's `orphanAt`, keyed by thread id: where each open thread without a text range was, read from `deletedAt`
239
+ * (keyed by annotation id). Empty when there is no tracked deletion point; threads loaded already orphaned never have one
240
+ * (the server stores none) and are left out, so they sit after the placed ones in the margin.
241
+ */
242
+ function orphanPositions(editor, ranges) {
243
+ if (!editor || unresolved || deletedAt.size === 0) return NO_POSITIONS;
244
+ const size = editor.state.doc.content.size;
245
+ let found;
246
+ for (const thread of threads) {
247
+ if (thread.status === "resolved" || ranges.has(thread.id)) continue;
248
+ const position = deletedAt.get(thread.annotationId);
249
+ if (position !== void 0 && position <= size) (found ??= /* @__PURE__ */ new Map()).set(thread.id, position);
250
+ }
251
+ return found ?? NO_POSITIONS;
252
+ }
253
+ function recompute() {
254
+ const editor = current();
255
+ const previous = store.get();
256
+ const user = userNow();
257
+ const available = user !== null;
258
+ const canComment = available && ready && canCommentNow();
259
+ const views = threads.map((thread) => viewOf(thread, anchors.get(thread.annotationId)));
260
+ const nextRanges = rangesOf(editor);
261
+ const ranges = sameRanges(nextRanges, previous.ranges) ? previous.ranges : nextRanges;
262
+ const nextOrphanAt = orphanPositions(editor, ranges);
263
+ const orphanAt = sameOrphanAt(nextOrphanAt, previous.orphanAt) ? previous.orphanAt : nextOrphanAt;
264
+ const plugin = editor && commentsKey.getState(editor.state);
265
+ const active = plugin?.active ?? null;
266
+ const anchor = plugin?.draft;
267
+ const draft = editor && anchor ? resolveRange(editor.state, anchor) : null;
268
+ const draftQuote = editor && draft ? editor.state.doc.textBetween(draft.from, draft.to, " ").slice(0, COMMENT_LIMITS.quote) : "";
269
+ const threadsOut = views.length === previous.threads.length && views.every((view, index) => sameJson(view, previous.threads[index])) ? previous.threads : views;
270
+ if (available === previous.available && canComment === previous.canComment && sameUser(user, previous.user) && threadsOut === previous.threads && ranges === previous.ranges && orphanAt === previous.orphanAt && active === previous.active && sameRange(draft, previous.draft) && draftQuote === previous.draftQuote) return;
271
+ const kept = threadsOut === previous.threads && ranges === previous.ranges;
272
+ store.set({
273
+ available,
274
+ canComment,
275
+ user,
276
+ threads: threadsOut,
277
+ ranges,
278
+ orphanAt,
279
+ active,
280
+ draft: sameRange(draft, previous.draft) ? previous.draft : draft,
281
+ draftQuote,
282
+ open: kept ? previous.open : threadsOut.filter((thread) => !thread.resolved).sort((a, b) => (ranges.get(a.id)?.from ?? Infinity) - (ranges.get(b.id)?.from ?? Infinity) || a.createdAt.localeCompare(b.createdAt)),
283
+ resolved: threadsOut === previous.threads ? previous.resolved : threadsOut.filter((thread) => thread.resolved).sort((a, b) => b.createdAt.localeCompare(a.createdAt))
284
+ });
285
+ }
286
+ let bound;
287
+ function onTransaction({ transaction, appendedTransactions }) {
288
+ const editor = bound;
289
+ if (editor && anchors.size) {
290
+ const all = [transaction, ...appendedTransactions ?? []];
291
+ if (all.some((tr) => tr.docChanged)) {
292
+ if (isBlank(editor.state.doc)) unresolved = true;
293
+ else if (unresolved) resolveAll(editor);
294
+ else carry(all);
295
+ }
296
+ }
297
+ recompute();
298
+ }
299
+ function onDestroy() {
300
+ if (bound) gone.add(bound);
301
+ unbind();
302
+ recompute();
303
+ }
304
+ function unbind() {
305
+ bound?.off("transaction", onTransaction);
306
+ bound?.off("update", recompute);
307
+ bound?.off("destroy", onDestroy);
308
+ bound = void 0;
309
+ }
310
+ function refresh() {
311
+ const editor = current();
312
+ if (editor !== bound) {
313
+ unbind();
314
+ bound = editor;
315
+ editor?.on("transaction", onTransaction);
316
+ editor?.on("update", recompute);
317
+ editor?.on("destroy", onDestroy);
318
+ if (editor && loaded) resolveAll(editor);
319
+ }
320
+ if (!loaded) {
321
+ loaded = true;
322
+ enqueue(load, false);
323
+ }
324
+ recompute();
325
+ }
326
+ function dispose() {
327
+ flush();
328
+ }
329
+ async function load() {
330
+ const discussion = await request();
331
+ if (!isDiscussion(discussion)) throw new Error(`Comments request GET ${endpoint} did not answer a discussion.`);
332
+ threads = discussion.threads;
333
+ anchors = new Map(discussion.annotations.map((annotation) => [annotation.id, annotation.anchor]));
334
+ persisted.clear();
335
+ for (const [id, anchor] of anchors) persisted.set(id, JSON.stringify(anchor));
336
+ dirty.clear();
337
+ deletedAt.clear();
338
+ ready = true;
339
+ const editor = current();
340
+ unresolved = anchors.size > 0;
341
+ if (editor) resolveAll(editor);
342
+ recompute();
343
+ }
344
+ function reload() {
345
+ flush();
346
+ loaded = true;
347
+ enqueue(load, false);
348
+ return idle();
349
+ }
350
+ async function idle() {
351
+ flush();
352
+ const seen = chain;
353
+ await seen;
354
+ if (chain !== seen || timer !== void 0 || dirty.size > 0) await idle();
355
+ }
356
+ /** Trimmed and cut to the limit; '' when nothing is left. */
357
+ const clean = (text) => text.trim().slice(0, COMMENT_LIMITS.text);
358
+ function writer() {
359
+ const user = userNow();
360
+ return user && ready && canCommentNow() ? user : null;
361
+ }
362
+ const commentOf = (user, body) => ({
363
+ id: newId("cm"),
364
+ body,
365
+ authorId: user.id,
366
+ authorName: user.name,
367
+ authorColor: user.color,
368
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
369
+ });
370
+ function setThreads(next) {
371
+ threads = next;
372
+ recompute();
373
+ }
374
+ const threadById = (id) => threads.find((thread) => thread.id === id);
375
+ function replaceThread(id, change) {
376
+ setThreads(threads.map((thread) => thread.id === id ? change(thread) : thread));
377
+ }
378
+ function add(text) {
379
+ const editor = current();
380
+ const user = writer();
381
+ const body = clean(text);
382
+ const draft = editor && commentsKey.getState(editor.state)?.draft;
383
+ const range = editor && draft ? resolveRange(editor.state, draft) : null;
384
+ if (!editor || !user || !draft || !range || range.from >= range.to || !body) return null;
385
+ const threadId = newId("ct");
386
+ const annotation = {
387
+ id: newId("ca"),
388
+ threadId,
389
+ anchor: captureAnchor(editor, range)
390
+ };
391
+ const comment = commentOf(user, body);
392
+ editor.view.dispatch(editor.state.tr.setMeta(commentsKey, {
393
+ draft: null,
394
+ active: threadId
395
+ }).setMeta("addToHistory", false));
396
+ releaseRanges(editor, [draft]);
397
+ anchors.set(annotation.id, annotation.anchor);
398
+ persisted.set(annotation.id, JSON.stringify(annotation.anchor));
399
+ threads = [...threads, {
400
+ id: threadId,
401
+ annotationId: annotation.id,
402
+ status: "open",
403
+ comments: [comment]
404
+ }];
405
+ recompute();
406
+ send({
407
+ action: "create",
408
+ annotation,
409
+ thread: {
410
+ id: threadId,
411
+ annotationId: annotation.id,
412
+ initialComment: comment
413
+ }
414
+ });
415
+ return threadId;
416
+ }
417
+ function reply(threadId, text) {
418
+ const user = writer();
419
+ const body = clean(text);
420
+ if (!user || !body || !threadById(threadId)) return;
421
+ const comment = commentOf(user, body);
422
+ replaceThread(threadId, (thread) => ({
423
+ ...thread,
424
+ comments: [...thread.comments, comment]
425
+ }));
426
+ send({
427
+ action: "reply",
428
+ threadId,
429
+ comment
430
+ });
431
+ }
432
+ function edit(threadId, replyId, text) {
433
+ const user = writer();
434
+ const body = clean(text);
435
+ const thread = threadById(threadId);
436
+ const target = thread && (replyId === null ? thread.comments[0] : thread.comments.find((comment) => comment.id === replyId));
437
+ if (!user || !body || !thread || !target || target.authorId !== user.id || target.body === body) return;
438
+ const editedAt = (/* @__PURE__ */ new Date()).toISOString();
439
+ replaceThread(threadId, (item) => ({
440
+ ...item,
441
+ comments: item.comments.map((comment) => comment.id === target.id ? {
442
+ ...comment,
443
+ body,
444
+ editedAt
445
+ } : comment)
446
+ }));
447
+ send({
448
+ action: "edit",
449
+ threadId,
450
+ commentId: target.id,
451
+ body,
452
+ editedAt
453
+ });
454
+ }
455
+ const activeThread = () => {
456
+ const editor = current();
457
+ return editor ? commentsKey.getState(editor.state)?.active ?? null : null;
458
+ };
459
+ function setResolved(threadId, resolved) {
460
+ const thread = threadById(threadId);
461
+ if (!writer() || !thread || thread.status === "resolved" === resolved) return;
462
+ const status = resolved ? "resolved" : "open";
463
+ replaceThread(threadId, (item) => ({
464
+ ...item,
465
+ status
466
+ }));
467
+ if (resolved && activeThread() === threadId) activate(null);
468
+ send({
469
+ action: "status",
470
+ threadId,
471
+ status
472
+ });
473
+ }
474
+ function remove(threadId) {
475
+ const user = writer();
476
+ const thread = threadById(threadId);
477
+ if (!user || !thread || thread.comments[0]?.authorId !== user.id) return;
478
+ if (activeThread() === threadId) activate(null);
479
+ anchors.delete(thread.annotationId);
480
+ persisted.delete(thread.annotationId);
481
+ dirty.delete(thread.annotationId);
482
+ deletedAt.delete(thread.annotationId);
483
+ setThreads(threads.filter((item) => item.id !== threadId));
484
+ send({
485
+ action: "remove",
486
+ threadId
487
+ });
488
+ }
489
+ function removeReply(threadId, replyId) {
490
+ const user = writer();
491
+ const thread = threadById(threadId);
492
+ const target = thread?.comments.slice(1).find((comment) => comment.id === replyId);
493
+ if (!user || !thread || !target || target.authorId !== user.id) return;
494
+ replaceThread(threadId, (item) => ({
495
+ ...item,
496
+ comments: item.comments.filter((comment) => comment.id !== replyId)
497
+ }));
498
+ send({
499
+ action: "remove-comment",
500
+ threadId,
501
+ commentId: replyId
502
+ });
503
+ }
504
+ function activate(id, activateOptions = {}) {
505
+ const editor = current();
506
+ if (editor) setActiveComment(editor, id, activateOptions);
507
+ }
508
+ function startDraft() {
509
+ const editor = current();
510
+ if (editor && writer()) startCommentDraft(editor);
511
+ }
512
+ function cancelDraft() {
513
+ const editor = current();
514
+ if (editor) cancelCommentDraft(editor);
515
+ }
516
+ return {
517
+ state: store,
518
+ refresh,
519
+ dispose,
520
+ add,
521
+ reply,
522
+ edit,
523
+ setResolved,
524
+ remove,
525
+ removeReply,
526
+ activate,
527
+ startDraft,
528
+ cancelDraft,
529
+ reload,
530
+ idle
531
+ };
532
+ }
533
+ //#endregion
534
+ export { createRestCommentsModel };
535
+
536
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","names":["EMPTY"],"sources":["../../../src/adapters/comments/client.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { Transaction } from '@tiptap/pm/state'\nimport { type AuthorIdentity, createStore, releaseRanges, resolveRange } from '../../core'\nimport { cancelCommentDraft, COMMENT_LIMITS, type CommentReply, type CommentsModel, type CommentsSnapshot, type CommentThread as EditorThread, commentsKey, type DocRange, setActiveComment, startCommentDraft } from '../../features/comments'\nimport { EMPTY_SNAPSHOT as EMPTY, NO_POSITIONS, NO_RANGES, NO_THREADS, sameOrphanAt, sameRange, sameRanges, sameUser } from '../../features/comments/snapshot-equality'\nimport { captureAnchor, capturePoint, type PortableAnchor, resolveAnchor, mapAnchor } from '../anchors'\nimport type { Annotation, Comment, CommentAction, CommentThread, Discussion } from './types'\n\n// A `CommentsModel` for the editor's comments feature (`commentsFeature({ model })`) whose threads live behind a REST\n// endpoint (`handleCommentsRequest` serves it) instead of the document's Y.Doc. The text a thread hangs on is a\n// portable anchor (`../anchors`), not a `comment` mark: anchors are resolved against the document when the threads\n// load, follow every edit of the editor, and are written back to the endpoint when they moved.\n\n/** The part of a `Response` the model reads; `globalThis.fetch` fits. */\nexport interface CommentsFetchResponse {\n ok: boolean\n status: number\n json(): Promise<unknown>\n}\n\nexport type CommentsFetch = (url: string, init?: { method?: string, headers?: Record<string, string>, body?: string }) => Promise<CommentsFetchResponse>\n\nexport interface RestCommentsModelOptions {\n /** How requests are sent: `globalThis.fetch`, or a wrapper that adds the base URL and credentials. */\n fetch: CommentsFetch\n /** The document the threads belong to. */\n documentId: string\n /** The document's comments endpoint (`GET` → `Discussion`, `POST` → `CommentAction`); default `/comments/<encoded documentId>`. */\n endpoint?: string\n /** Who writes: the author of new comments and the only one who may edit or delete them; `null` while nobody is signed in (no comments then). */\n user: AuthorIdentity | null | (() => AuthorIdentity | null)\n /** Whether the user may compose and change comments now; readers of a read-only document may be allowed. */\n canComment: boolean | (() => boolean)\n /** The editor the threads belong to; may return no editor yet or a destroyed one. */\n getEditor: () => Editor | undefined\n /** Milliseconds a changed anchor waits before it is written back (typing moves many); default 500. `idle()` writes at once. */\n persistDelay?: number\n /** Called with every failed request; the model reloads the threads afterwards, so the local state falls back to the server's. */\n onError?: (error: Error) => void\n}\n\nexport interface RestCommentsModel extends CommentsModel {\n /** Fetches the threads again and resolves their anchors against the current document. */\n reload(): Promise<void>\n /** Resolves once every change made so far has been sent (and the threads loaded, if a load was requested). */\n idle(): Promise<void>\n}\n\n/** Neutral colour of authors that stored no colour. */\nconst FALLBACK_COLOR = '#6b7280'\n/** Characters of context that must agree for an orphan to be re-attached on load. */\nconst REATTACH_CONTEXT = 24\n\nconst newId = (prefix: string) => `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`\n/** The `error` message of a refused request's JSON body. */\nfunction errorOf(body: unknown): unknown {\n return typeof body === 'object' && body !== null && 'error' in body ? body.error : undefined\n}\n\nfunction isDiscussion(value: unknown): value is Discussion {\n return typeof value === 'object' && value !== null && 'annotations' in value && Array.isArray(value.annotations) && 'threads' in value && Array.isArray(value.threads)\n}\n\nconst sameJson = (a: unknown, b: unknown) => JSON.stringify(a) === JSON.stringify(b)\n\nconst authorOf = (comment: Comment): EditorThread['author'] => ({ id: comment.authorId, name: comment.authorName ?? comment.authorId, color: comment.authorColor ?? FALLBACK_COLOR })\n\nfunction quoteOf(anchor: PortableAnchor | undefined): string {\n if (!anchor) return ''\n if (anchor.kind === 'range') return anchor.quote\n if (anchor.kind === 'orphan') return anchor.quote ?? (anchor.previous.kind === 'range' ? anchor.previous.quote : '')\n return ''\n}\n\nfunction viewOf(thread: CommentThread, anchor: PortableAnchor | undefined): EditorThread {\n const [first, ...replies] = thread.comments\n return {\n id: thread.id,\n author: first ? authorOf(first) : { id: '', name: '', color: FALLBACK_COLOR },\n text: first?.body ?? '',\n createdAt: first?.createdAt ?? '',\n ...(first?.editedAt !== undefined && { editedAt: first.editedAt }),\n quote: quoteOf(anchor),\n resolved: thread.status === 'resolved',\n replies: replies.map((reply): CommentReply => ({\n id: reply.id,\n author: authorOf(reply),\n text: reply.body,\n createdAt: reply.createdAt,\n ...(reply.editedAt !== undefined && { editedAt: reply.editedAt }),\n })),\n }\n}\n\nfunction rangeOf(anchor: PortableAnchor | undefined): DocRange | null {\n if (!anchor || anchor.kind === 'orphan') return null\n return anchor.kind === 'range' ? { from: anchor.from, to: anchor.to } : { from: anchor.position, to: anchor.position }\n}\n\n/** A document is \"empty\" while the host has not put its content in yet: nothing to resolve anchors against. */\nconst isBlank = (doc: { textContent: string }) => doc.textContent === ''\n\n/** Whether the text at `candidate` still reads like the context `previous` was written in (one side suffices). */\nfunction contextAgrees(candidate: PortableAnchor, previous: PortableAnchor): boolean {\n if (candidate.kind === 'orphan' || previous.kind === 'orphan') return false\n const before = previous.contextBefore?.slice(-REATTACH_CONTEXT)\n const after = previous.contextAfter?.slice(0, REATTACH_CONTEXT)\n if (!before && !after) return true\n return (!!before && !!candidate.contextBefore?.endsWith(before)) || (!!after && !!candidate.contextAfter?.startsWith(after))\n}\n\n/**\n * The comments of one editor over a REST endpoint, as a `CommentsModel` (the host passes `() => model` as the\n * `model` factory of `commentsFeature`/`commentsFeatureCore`; one instance serves the plugin and every hook).\n *\n * - **Load.** `refresh()` (called by the feature once the editor exists) fetches `GET endpoint`; each annotation's\n * anchor is resolved against the document (exact offsets, else quote and context search). An anchor that moved is\n * re-captured and written back; an anchor whose text is gone becomes an `orphan` (the thread stays, without a range)\n * and an orphan whose text is back with the same surroundings is re-attached. While the document is still empty the\n * resolving waits for its content.\n * - **Edits.** Every transaction carries all anchors with it (`mapAnchor`), so ranges, quotes and contexts follow the\n * text; changed anchors are written back after `persistDelay`. Text deleted under an anchor orphans it for good (it is\n * never silently re-attached to other text during editing; `reload()` re-attaches it when its text and context\n * are found again, e.g. after the content was replaced).\n * - **Writes** are applied locally at once and sent in order; a failed request is reported to `onError` and the threads\n * are reloaded. Without a `user` or while `canComment` is false nothing is written. Only the author may edit or\n * delete a comment.\n * - **Lifecycle.** The model follows the editor `getEditor` names until that editor is destroyed; `dispose()` writes\n * pending anchor changes and does not stop it (the feature and its hooks share the instance and dispose it on their\n * own schedule).\n */\nexport function createRestCommentsModel(options: RestCommentsModelOptions): RestCommentsModel {\n const { fetch, documentId, getEditor, onError } = options\n const endpoint = options.endpoint ?? `/comments/${encodeURIComponent(documentId)}`\n const persistDelay = options.persistDelay ?? 500\n const store = createStore<CommentsSnapshot>(EMPTY)\n\n const userNow = () => (typeof options.user === 'function' ? options.user() : options.user)\n const canCommentNow = () => (typeof options.canComment === 'function' ? options.canComment() : options.canComment)\n /** Editors that announced their destruction: their view is still alive while `destroy` is emitted. */\n const gone = new WeakSet<Editor>()\n const current = () => {\n const instance = getEditor()\n return instance && !instance.isDestroyed && !gone.has(instance) ? instance : undefined\n }\n\n // -- Data: what the endpoint holds (annotation anchors are the local truth until written back) -----------------------\n let threads: readonly CommentThread[] = []\n let anchors = new Map<string, PortableAnchor>()\n /** The anchor each annotation has on the server, serialised. */\n const persisted = new Map<string, string>()\n const dirty = new Set<string>()\n /**\n * Where the text of an annotation that became an orphan during this session was: the deletion point, mapped through\n * every later edit. Keyed by annotation id (`orphanAt` in the snapshot is keyed by thread id; `orphanPositions` translates).\n * Deletion points are session-local: `load()` clears them, and an anchor that arrives already orphaned has none, because\n * the server stores no deletion point. Such threads get no `orphanAt` entry and sit after the placed ones in the margin.\n */\n const deletedAt = new Map<string, number>()\n /** Anchors wait for the document content (resolve on load) before they get a range. */\n let unresolved = false\n /** A load was requested / the first one succeeded: writes wait for it, so a load never overwrites a newer local change. */\n let loaded = false\n let ready = false\n\n // -- Requests: one queue, so a reply never overtakes its thread's creation ---------------------------------------------\n let chain: Promise<void> = Promise.resolve()\n let timer: ReturnType<typeof setTimeout> | undefined\n\n function enqueue(task: () => Promise<void>, reloadOnError = true): void {\n chain = chain.then(task).catch((error: unknown) => {\n onError?.(error instanceof Error ? error : new Error(String(error)))\n if (reloadOnError) enqueue(load, false)\n })\n }\n\n async function request(init?: { method: string, body: CommentAction }): Promise<unknown> {\n const response = await fetch(endpoint, init && { method: init.method, headers: { 'content-type': 'application/json' }, body: JSON.stringify(init.body) })\n if (!response.ok) {\n const detail = await response.json().then(errorOf, () => undefined)\n throw new Error(`Comments request ${init?.method ?? 'GET'} ${endpoint} failed: ${response.status}${typeof detail === 'string' ? ` ${detail}` : ''}`)\n }\n return response.json()\n }\n\n const send = (body: CommentAction) => enqueue(async () => void await request({ method: 'POST', body }))\n\n function writeAnchors(): void {\n timer = undefined\n if (!userNow() || !ready || !canCommentNow()) {\n dirty.clear()\n return\n }\n for (const id of dirty) {\n const anchor = anchors.get(id)\n const threadId = threads.find(thread => thread.annotationId === id)?.id\n if (!anchor || !threadId || persisted.get(id) === JSON.stringify(anchor)) continue\n persisted.set(id, JSON.stringify(anchor))\n send({ action: 'update-annotation', annotation: { id, threadId, anchor } })\n }\n dirty.clear()\n }\n\n function markDirty(id: string): void {\n dirty.add(id)\n if (timer === undefined) timer = setTimeout(writeAnchors, persistDelay)\n }\n\n function flush(): void {\n clearTimeout(timer)\n writeAnchors()\n }\n\n // -- Anchors ------------------------------------------------------------------------------------------------------------\n\n /** `anchor` read against `editor`'s document: the moved/re-captured anchor, an orphan, or the same object. */\n function resolveOne(editor: Editor, anchor: PortableAnchor): PortableAnchor {\n const live = anchor.kind === 'orphan' ? anchor.previous : anchor\n const found = resolveAnchor(editor.state.doc, live)\n if (!found) {\n return anchor.kind === 'orphan'\n ? anchor\n : { kind: 'orphan', previous: anchor, quote: quoteOf(anchor) || undefined, contextBefore: anchor.contextBefore, contextAfter: anchor.contextAfter, reason: 'unresolvable' }\n }\n const next = live.kind === 'range' ? captureAnchor(editor, found) : capturePoint(editor, found.from)\n if (anchor.kind === 'orphan' && !contextAgrees(next, live)) return anchor\n return sameJson(next, anchor) ? anchor : next\n }\n\n function resolveAll(editor: Editor): void {\n if (isBlank(editor.state.doc)) {\n unresolved = anchors.size > 0\n return\n }\n unresolved = false\n for (const [id, anchor] of anchors) {\n const next = resolveOne(editor, anchor)\n if (next !== anchor) {\n anchors.set(id, next)\n if (next.kind !== 'orphan') deletedAt.delete(id)\n markDirty(id)\n }\n }\n }\n\n function carry(transactions: readonly Transaction[]): void {\n for (const transaction of transactions) {\n if (!transaction.docChanged) continue\n for (const [id, position] of deletedAt) deletedAt.set(id, transaction.mapping.map(position, 1))\n for (const [id, anchor] of anchors) {\n const next = mapAnchor(anchor, transaction)\n if (next !== anchor) {\n anchors.set(id, next)\n if (next.kind === 'orphan' && anchor.kind !== 'orphan') {\n deletedAt.set(id, transaction.mapping.map(anchor.kind === 'range' ? anchor.from : anchor.position, 1))\n }\n markDirty(id)\n }\n }\n }\n }\n\n // -- Snapshot -----------------------------------------------------------------------------------------------------------\n\n function rangesOf(editor: Editor | undefined): ReadonlyMap<string, DocRange> {\n if (!editor || unresolved) return NO_RANGES\n const size = editor.state.doc.content.size\n const ranges = new Map<string, DocRange>()\n for (const thread of threads) {\n const range = rangeOf(anchors.get(thread.annotationId))\n if (range && range.from <= size) ranges.set(thread.id, { from: range.from, to: Math.min(range.to, size) })\n }\n return ranges\n }\n\n /**\n * The snapshot's `orphanAt`, keyed by thread id: where each open thread without a text range was, read from `deletedAt`\n * (keyed by annotation id). Empty when there is no tracked deletion point; threads loaded already orphaned never have one\n * (the server stores none) and are left out, so they sit after the placed ones in the margin.\n */\n function orphanPositions(editor: Editor | undefined, ranges: ReadonlyMap<string, DocRange>): ReadonlyMap<string, number> {\n if (!editor || unresolved || deletedAt.size === 0) return NO_POSITIONS\n const size = editor.state.doc.content.size\n let found: Map<string, number> | undefined\n for (const thread of threads) {\n if (thread.status === 'resolved' || ranges.has(thread.id)) continue\n const position = deletedAt.get(thread.annotationId)\n if (position !== undefined && position <= size) (found ??= new Map()).set(thread.id, position)\n }\n return found ?? NO_POSITIONS\n }\n\n function recompute(): void {\n const editor = current()\n const previous = store.get()\n const user = userNow()\n const available = user !== null\n const canComment = available && ready && canCommentNow()\n const views = threads.map(thread => viewOf(thread, anchors.get(thread.annotationId)))\n const nextRanges = rangesOf(editor)\n const ranges = sameRanges(nextRanges, previous.ranges) ? previous.ranges : nextRanges\n const nextOrphanAt = orphanPositions(editor, ranges)\n const orphanAt = sameOrphanAt(nextOrphanAt, previous.orphanAt) ? previous.orphanAt : nextOrphanAt\n const plugin = editor && commentsKey.getState(editor.state)\n const active = plugin?.active ?? null\n const anchor = plugin?.draft\n const draft = editor && anchor ? resolveRange(editor.state, anchor) : null\n const draftQuote = editor && draft ? editor.state.doc.textBetween(draft.from, draft.to, ' ').slice(0, COMMENT_LIMITS.quote) : ''\n const sameViews = (views.length === previous.threads.length && views.every((view, index) => sameJson(view, previous.threads[index])))\n const threadsOut = sameViews ? previous.threads : views\n\n if (\n available === previous.available && canComment === previous.canComment && sameUser(user, previous.user) && threadsOut === previous.threads\n && ranges === previous.ranges && orphanAt === previous.orphanAt && active === previous.active && sameRange(draft, previous.draft) && draftQuote === previous.draftQuote\n ) return\n\n const kept = threadsOut === previous.threads && ranges === previous.ranges\n store.set({\n available,\n canComment,\n user,\n threads: threadsOut,\n ranges,\n orphanAt,\n active,\n draft: sameRange(draft, previous.draft) ? previous.draft : draft,\n draftQuote,\n open: kept\n ? previous.open\n : threadsOut\n .filter(thread => !thread.resolved)\n .sort((a, b) => (ranges.get(a.id)?.from ?? Infinity) - (ranges.get(b.id)?.from ?? Infinity) || a.createdAt.localeCompare(b.createdAt)),\n resolved: threadsOut === previous.threads ? previous.resolved : threadsOut.filter(thread => thread.resolved).sort((a, b) => b.createdAt.localeCompare(a.createdAt)),\n })\n }\n\n // -- Editor binding -----------------------------------------------------------------------------------------------------\n\n let bound: Editor | undefined\n\n function onTransaction({ transaction, appendedTransactions }: { transaction: Transaction, appendedTransactions?: readonly Transaction[] }): void {\n const editor = bound\n if (editor && anchors.size) {\n const all = [transaction, ...(appendedTransactions ?? [])]\n if (all.some(tr => tr.docChanged)) {\n if (isBlank(editor.state.doc)) unresolved = true\n else if (unresolved) resolveAll(editor)\n else carry(all)\n }\n }\n recompute()\n }\n\n function onDestroy(): void {\n if (bound) gone.add(bound)\n unbind()\n recompute()\n }\n\n function unbind(): void {\n bound?.off('transaction', onTransaction)\n bound?.off('update', recompute)\n bound?.off('destroy', onDestroy)\n bound = undefined\n }\n\n function refresh(): void {\n const editor = current()\n if (editor !== bound) {\n unbind()\n bound = editor\n editor?.on('transaction', onTransaction)\n // `setEditable` emits `update` only, and `canComment` may follow it.\n editor?.on('update', recompute)\n editor?.on('destroy', onDestroy)\n if (editor && loaded) resolveAll(editor)\n }\n if (!loaded) {\n loaded = true\n enqueue(load, false)\n }\n recompute()\n }\n\n function dispose(): void {\n flush()\n }\n\n async function load(): Promise<void> {\n const discussion = await request()\n if (!isDiscussion(discussion)) throw new Error(`Comments request GET ${endpoint} did not answer a discussion.`)\n threads = discussion.threads\n anchors = new Map(discussion.annotations.map((annotation: Annotation) => [annotation.id, annotation.anchor]))\n persisted.clear()\n for (const [id, anchor] of anchors) persisted.set(id, JSON.stringify(anchor))\n dirty.clear()\n deletedAt.clear()\n ready = true\n const editor = current()\n unresolved = anchors.size > 0\n if (editor) resolveAll(editor)\n recompute()\n }\n\n function reload(): Promise<void> {\n flush()\n loaded = true\n enqueue(load, false)\n return idle()\n }\n\n async function idle(): Promise<void> {\n flush()\n const seen = chain\n await seen\n // A request that failed queued a reload, a finished one may have moved anchors.\n if (chain !== seen || timer !== undefined || dirty.size > 0) await idle()\n }\n\n // -- Mutations ----------------------------------------------------------------------------------------------------------\n\n /** Trimmed and cut to the limit; '' when nothing is left. */\n const clean = (text: string) => text.trim().slice(0, COMMENT_LIMITS.text)\n\n function writer(): AuthorIdentity | null {\n const user = userNow()\n return user && ready && canCommentNow() ? user : null\n }\n\n const commentOf = (user: AuthorIdentity, body: string): Comment => ({ id: newId('cm'), body, authorId: user.id, authorName: user.name, authorColor: user.color, createdAt: new Date().toISOString() })\n\n function setThreads(next: readonly CommentThread[]): void {\n threads = next\n recompute()\n }\n\n const threadById = (id: string) => threads.find(thread => thread.id === id)\n\n function replaceThread(id: string, change: (thread: CommentThread) => CommentThread): void {\n setThreads(threads.map(thread => (thread.id === id ? change(thread) : thread)))\n }\n\n function add(text: string): string | null {\n const editor = current()\n const user = writer()\n const body = clean(text)\n const draft = editor && commentsKey.getState(editor.state)?.draft\n const range = editor && draft ? resolveRange(editor.state, draft) : null\n if (!editor || !user || !draft || !range || range.from >= range.to || !body) return null\n const threadId = newId('ct')\n const annotation: Annotation = { id: newId('ca'), threadId, anchor: captureAnchor(editor, range) }\n const comment = commentOf(user, body)\n editor.view.dispatch(editor.state.tr.setMeta(commentsKey, { draft: null, active: threadId }).setMeta('addToHistory', false))\n releaseRanges(editor, [draft])\n anchors.set(annotation.id, annotation.anchor)\n persisted.set(annotation.id, JSON.stringify(annotation.anchor))\n threads = [...threads, { id: threadId, annotationId: annotation.id, status: 'open', comments: [comment] }]\n recompute()\n send({ action: 'create', annotation, thread: { id: threadId, annotationId: annotation.id, initialComment: comment } })\n return threadId\n }\n\n function reply(threadId: string, text: string): void {\n const user = writer()\n const body = clean(text)\n if (!user || !body || !threadById(threadId)) return\n const comment = commentOf(user, body)\n replaceThread(threadId, thread => ({ ...thread, comments: [...thread.comments, comment] }))\n send({ action: 'reply', threadId, comment })\n }\n\n function edit(threadId: string, replyId: string | null, text: string): void {\n const user = writer()\n const body = clean(text)\n const thread = threadById(threadId)\n const target = thread && (replyId === null ? thread.comments[0] : thread.comments.find(comment => comment.id === replyId))\n if (!user || !body || !thread || !target || target.authorId !== user.id || target.body === body) return\n const editedAt = new Date().toISOString()\n replaceThread(threadId, item => ({ ...item, comments: item.comments.map(comment => (comment.id === target.id ? { ...comment, body, editedAt } : comment)) }))\n send({ action: 'edit', threadId, commentId: target.id, body, editedAt })\n }\n\n const activeThread = () => {\n const editor = current()\n return editor ? commentsKey.getState(editor.state)?.active ?? null : null\n }\n\n function setResolved(threadId: string, resolved: boolean): void {\n const thread = threadById(threadId)\n if (!writer() || !thread || (thread.status === 'resolved') === resolved) return\n const status = resolved ? 'resolved' : 'open'\n replaceThread(threadId, item => ({ ...item, status }))\n if (resolved && activeThread() === threadId) activate(null)\n send({ action: 'status', threadId, status })\n }\n\n function remove(threadId: string): void {\n const user = writer()\n const thread = threadById(threadId)\n if (!user || !thread || thread.comments[0]?.authorId !== user.id) return\n if (activeThread() === threadId) activate(null)\n anchors.delete(thread.annotationId)\n persisted.delete(thread.annotationId)\n dirty.delete(thread.annotationId)\n deletedAt.delete(thread.annotationId)\n setThreads(threads.filter(item => item.id !== threadId))\n send({ action: 'remove', threadId })\n }\n\n function removeReply(threadId: string, replyId: string): void {\n const user = writer()\n const thread = threadById(threadId)\n const target = thread?.comments.slice(1).find(comment => comment.id === replyId)\n if (!user || !thread || !target || target.authorId !== user.id) return\n replaceThread(threadId, item => ({ ...item, comments: item.comments.filter(comment => comment.id !== replyId) }))\n send({ action: 'remove-comment', threadId, commentId: replyId })\n }\n\n function activate(id: string | null, activateOptions: { reveal?: boolean } = {}): void {\n const editor = current()\n if (editor) setActiveComment(editor, id, activateOptions)\n }\n\n function startDraft(): void {\n const editor = current()\n if (editor && writer()) startCommentDraft(editor)\n }\n\n function cancelDraft(): void {\n const editor = current()\n if (editor) cancelCommentDraft(editor)\n }\n\n return { state: store, refresh, dispose, add, reply, edit, setResolved, remove, removeReply, activate, startDraft, cancelDraft, reload, idle }\n}\n"],"mappings":"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"}