@dxos/plugin-thread 0.8.2-main.f11618f → 0.8.2-staging.42af850

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 (400) hide show
  1. package/dist/lib/browser/ChannelContainer-LGYSQMC7.mjs +15 -0
  2. package/dist/lib/browser/ChatContainer-JWRI73OG.mjs +14 -0
  3. package/dist/lib/browser/app-graph-builder-K3CFBN7V.mjs +171 -0
  4. package/dist/lib/browser/app-graph-builder-K3CFBN7V.mjs.map +7 -0
  5. package/dist/lib/browser/call-manager-APQAZWHT.mjs +23 -0
  6. package/dist/lib/browser/call-manager-APQAZWHT.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-4H4A264L.mjs +1708 -0
  8. package/dist/lib/browser/chunk-4H4A264L.mjs.map +7 -0
  9. package/dist/lib/browser/{chunk-AYNXYEKP.mjs → chunk-5P5BH5GE.mjs} +57 -35
  10. package/dist/lib/browser/chunk-5P5BH5GE.mjs.map +7 -0
  11. package/dist/lib/browser/chunk-5PGLGDIP.mjs +983 -0
  12. package/dist/lib/browser/chunk-5PGLGDIP.mjs.map +7 -0
  13. package/dist/lib/browser/chunk-CF2MXRCH.mjs +21 -0
  14. package/dist/lib/browser/chunk-CF2MXRCH.mjs.map +7 -0
  15. package/dist/lib/browser/chunk-G3TS64FP.mjs +351 -0
  16. package/dist/lib/browser/chunk-G3TS64FP.mjs.map +7 -0
  17. package/dist/lib/browser/{chunk-WBJLUUOK.mjs → chunk-IIUTBDVB.mjs} +4 -4
  18. package/dist/lib/browser/chunk-IIUTBDVB.mjs.map +7 -0
  19. package/dist/lib/browser/chunk-JKQUJOTX.mjs +31 -0
  20. package/dist/lib/browser/chunk-JKQUJOTX.mjs.map +7 -0
  21. package/dist/lib/browser/chunk-KMVGJG23.mjs +545 -0
  22. package/dist/lib/browser/chunk-KMVGJG23.mjs.map +7 -0
  23. package/dist/lib/browser/{chunk-EP6MRLY7.mjs → chunk-R5MDLUPC.mjs} +5 -3
  24. package/dist/lib/browser/chunk-R5MDLUPC.mjs.map +7 -0
  25. package/dist/lib/browser/chunk-WDOQXTI2.mjs +126 -0
  26. package/dist/lib/browser/chunk-WDOQXTI2.mjs.map +7 -0
  27. package/dist/lib/browser/index.mjs +107 -41
  28. package/dist/lib/browser/index.mjs.map +4 -4
  29. package/dist/lib/browser/{intent-resolver-3UW6ROYT.mjs → intent-resolver-YUYZCTLF.mjs} +100 -72
  30. package/dist/lib/browser/intent-resolver-YUYZCTLF.mjs.map +7 -0
  31. package/dist/lib/browser/markdown-4EC3OCF2.mjs +169 -0
  32. package/dist/lib/browser/markdown-4EC3OCF2.mjs.map +7 -0
  33. package/dist/lib/browser/meta.json +1 -1
  34. package/dist/lib/browser/react-root-EECCWHCW.mjs +27 -0
  35. package/dist/lib/browser/react-root-EECCWHCW.mjs.map +7 -0
  36. package/dist/lib/browser/react-surface-5QLZAFDL.mjs +108 -0
  37. package/dist/lib/browser/react-surface-5QLZAFDL.mjs.map +7 -0
  38. package/dist/lib/browser/{settings-2VZ7S4SK.mjs → settings-KVBQQSO5.mjs} +3 -3
  39. package/dist/lib/browser/{state-KBGI3QTR.mjs → state-RKL5MSDP.mjs} +4 -4
  40. package/dist/lib/browser/{state-KBGI3QTR.mjs.map → state-RKL5MSDP.mjs.map} +3 -3
  41. package/dist/lib/browser/types/index.mjs +16 -0
  42. package/dist/lib/browser/types/index.mjs.map +7 -0
  43. package/dist/lib/node/ChannelContainer-5EKNEH56.cjs +36 -0
  44. package/dist/lib/node/ChannelContainer-5EKNEH56.cjs.map +7 -0
  45. package/dist/lib/node/ChatContainer-EE3FPSYO.cjs +35 -0
  46. package/dist/lib/node/ChatContainer-EE3FPSYO.cjs.map +7 -0
  47. package/dist/lib/node/app-graph-builder-IRE3GYKE.cjs +179 -0
  48. package/dist/lib/node/app-graph-builder-IRE3GYKE.cjs.map +7 -0
  49. package/dist/lib/node/call-manager-HV2XJW5O.cjs +37 -0
  50. package/dist/lib/node/call-manager-HV2XJW5O.cjs.map +7 -0
  51. package/dist/lib/node/chunk-44I33JDT.cjs +1731 -0
  52. package/dist/lib/node/chunk-44I33JDT.cjs.map +7 -0
  53. package/dist/lib/node/chunk-4B3PPXA6.cjs +371 -0
  54. package/dist/lib/node/chunk-4B3PPXA6.cjs.map +7 -0
  55. package/dist/lib/node/{chunk-NQ5DTPOY.cjs → chunk-4YSNVPWU.cjs} +10 -8
  56. package/dist/lib/node/chunk-4YSNVPWU.cjs.map +7 -0
  57. package/dist/lib/node/chunk-6B3M6XRE.cjs +984 -0
  58. package/dist/lib/node/chunk-6B3M6XRE.cjs.map +7 -0
  59. package/dist/lib/node/{chunk-W25MBII2.cjs → chunk-FUXJAVFZ.cjs} +50 -29
  60. package/dist/lib/node/chunk-FUXJAVFZ.cjs.map +7 -0
  61. package/dist/lib/node/{chunk-ONLWOUYZ.cjs → chunk-HLMCEE5K.cjs} +7 -7
  62. package/dist/lib/node/{chunk-ONLWOUYZ.cjs.map → chunk-HLMCEE5K.cjs.map} +2 -2
  63. package/dist/lib/node/chunk-JLHENFGK.cjs +549 -0
  64. package/dist/lib/node/chunk-JLHENFGK.cjs.map +7 -0
  65. package/dist/lib/node/chunk-LR5NENBE.cjs +54 -0
  66. package/dist/lib/node/chunk-LR5NENBE.cjs.map +7 -0
  67. package/dist/lib/node/chunk-TKHJVC2C.cjs +147 -0
  68. package/dist/lib/node/chunk-TKHJVC2C.cjs.map +7 -0
  69. package/dist/lib/node/{chunk-IX63EKGL.cjs → chunk-U7NOIXN6.cjs} +16 -10
  70. package/dist/lib/node/chunk-U7NOIXN6.cjs.map +7 -0
  71. package/dist/lib/node/index.cjs +142 -80
  72. package/dist/lib/node/index.cjs.map +4 -4
  73. package/dist/lib/node/{intent-resolver-DC6HDNTX.cjs → intent-resolver-MZ3HADNY.cjs} +108 -82
  74. package/dist/lib/node/intent-resolver-MZ3HADNY.cjs.map +7 -0
  75. package/dist/lib/node/markdown-NJDPXIKD.cjs +178 -0
  76. package/dist/lib/node/markdown-NJDPXIKD.cjs.map +7 -0
  77. package/dist/lib/node/meta.json +1 -1
  78. package/dist/lib/node/react-root-IAYQ2DBO.cjs +51 -0
  79. package/dist/lib/node/react-root-IAYQ2DBO.cjs.map +7 -0
  80. package/dist/lib/node/react-surface-AVC5VVIS.cjs +122 -0
  81. package/dist/lib/node/react-surface-AVC5VVIS.cjs.map +7 -0
  82. package/dist/lib/node/{settings-7MGTJ46L.cjs → settings-H45P5YO2.cjs} +8 -8
  83. package/dist/lib/node/{state-FOHMAVSU.cjs → state-IY5XX3H2.cjs} +8 -8
  84. package/dist/lib/node/{state-FOHMAVSU.cjs.map → state-IY5XX3H2.cjs.map} +3 -3
  85. package/dist/lib/node/{types.cjs → types/index.cjs} +12 -6
  86. package/dist/lib/node/types/index.cjs.map +7 -0
  87. package/dist/lib/node-esm/ChannelContainer-KFS2RWWW.mjs +16 -0
  88. package/dist/lib/node-esm/ChannelContainer-KFS2RWWW.mjs.map +7 -0
  89. package/dist/lib/node-esm/ChatContainer-UJYPQMLV.mjs +15 -0
  90. package/dist/lib/node-esm/ChatContainer-UJYPQMLV.mjs.map +7 -0
  91. package/dist/lib/node-esm/app-graph-builder-I5VMPLE4.mjs +172 -0
  92. package/dist/lib/node-esm/app-graph-builder-I5VMPLE4.mjs.map +7 -0
  93. package/dist/lib/node-esm/call-manager-UUYXLF4T.mjs +24 -0
  94. package/dist/lib/node-esm/call-manager-UUYXLF4T.mjs.map +7 -0
  95. package/dist/lib/node-esm/{chunk-42F2DTMM.mjs → chunk-ESQC6SYE.mjs} +4 -4
  96. package/dist/lib/node-esm/chunk-ESQC6SYE.mjs.map +7 -0
  97. package/dist/lib/node-esm/chunk-J323VQ4P.mjs +127 -0
  98. package/dist/lib/node-esm/chunk-J323VQ4P.mjs.map +7 -0
  99. package/dist/lib/node-esm/{chunk-WLY2HMDB.mjs → chunk-K4KAUOKT.mjs} +5 -3
  100. package/dist/lib/node-esm/chunk-K4KAUOKT.mjs.map +7 -0
  101. package/dist/lib/node-esm/chunk-MNJ3V4XM.mjs +546 -0
  102. package/dist/lib/node-esm/chunk-MNJ3V4XM.mjs.map +7 -0
  103. package/dist/lib/node-esm/{chunk-T6E5EY7Z.mjs → chunk-O3V45YJP.mjs} +57 -35
  104. package/dist/lib/node-esm/chunk-O3V45YJP.mjs.map +7 -0
  105. package/dist/lib/node-esm/chunk-ODUB4GAB.mjs +23 -0
  106. package/dist/lib/node-esm/chunk-ODUB4GAB.mjs.map +7 -0
  107. package/dist/lib/node-esm/chunk-PGRP3O4O.mjs +33 -0
  108. package/dist/lib/node-esm/chunk-PGRP3O4O.mjs.map +7 -0
  109. package/dist/lib/node-esm/chunk-POKXRTII.mjs +352 -0
  110. package/dist/lib/node-esm/chunk-POKXRTII.mjs.map +7 -0
  111. package/dist/lib/node-esm/chunk-WXNPD542.mjs +1710 -0
  112. package/dist/lib/node-esm/chunk-WXNPD542.mjs.map +7 -0
  113. package/dist/lib/node-esm/chunk-X6AUQDTE.mjs +984 -0
  114. package/dist/lib/node-esm/chunk-X6AUQDTE.mjs.map +7 -0
  115. package/dist/lib/node-esm/index.mjs +107 -41
  116. package/dist/lib/node-esm/index.mjs.map +4 -4
  117. package/dist/lib/node-esm/{intent-resolver-OAMDKGAA.mjs → intent-resolver-CU22OPAH.mjs} +100 -72
  118. package/dist/lib/node-esm/intent-resolver-CU22OPAH.mjs.map +7 -0
  119. package/dist/lib/node-esm/markdown-HRGGO7IA.mjs +170 -0
  120. package/dist/lib/node-esm/markdown-HRGGO7IA.mjs.map +7 -0
  121. package/dist/lib/node-esm/meta.json +1 -1
  122. package/dist/lib/node-esm/react-root-NQMUEI6Z.mjs +28 -0
  123. package/dist/lib/node-esm/react-root-NQMUEI6Z.mjs.map +7 -0
  124. package/dist/lib/node-esm/react-surface-Z4X5VLMY.mjs +109 -0
  125. package/dist/lib/node-esm/react-surface-Z4X5VLMY.mjs.map +7 -0
  126. package/dist/lib/node-esm/{settings-AJAZ3O47.mjs → settings-IJGUOU3F.mjs} +3 -3
  127. package/dist/lib/node-esm/{state-IRLEO2SB.mjs → state-6AUTNROZ.mjs} +4 -4
  128. package/dist/lib/node-esm/{state-IRLEO2SB.mjs.map → state-6AUTNROZ.mjs.map} +3 -3
  129. package/dist/lib/node-esm/types/index.mjs +17 -0
  130. package/dist/lib/node-esm/types/index.mjs.map +7 -0
  131. package/dist/types/src/ThreadPlugin.d.ts.map +1 -1
  132. package/dist/types/src/calls/call-manager.d.ts +77 -0
  133. package/dist/types/src/calls/call-manager.d.ts.map +1 -0
  134. package/dist/types/src/calls/call-swarm-synchronizer.d.ts +66 -0
  135. package/dist/types/src/calls/call-swarm-synchronizer.d.ts.map +1 -0
  136. package/dist/types/src/calls/index.d.ts +7 -0
  137. package/dist/types/src/calls/index.d.ts.map +1 -0
  138. package/dist/types/src/calls/media-manager.d.ts +60 -0
  139. package/dist/types/src/calls/media-manager.d.ts.map +1 -0
  140. package/dist/types/src/calls/speaking-monitor.d.ts +24 -0
  141. package/dist/types/src/calls/speaking-monitor.d.ts.map +1 -0
  142. package/dist/types/src/calls/types.d.ts +45 -0
  143. package/dist/types/src/calls/types.d.ts.map +1 -0
  144. package/dist/types/src/calls/util/audio.d.ts +6 -0
  145. package/dist/types/src/calls/util/audio.d.ts.map +1 -0
  146. package/dist/types/src/calls/util/calls-service.d.ts +72 -0
  147. package/dist/types/src/calls/util/calls-service.d.ts.map +1 -0
  148. package/dist/types/src/calls/util/history-cache.d.ts +11 -0
  149. package/dist/types/src/calls/util/history-cache.d.ts.map +1 -0
  150. package/dist/types/src/calls/util/index.d.ts +5 -0
  151. package/dist/types/src/calls/util/index.d.ts.map +1 -0
  152. package/dist/types/src/calls/util/media.d.ts +6 -0
  153. package/dist/types/src/calls/util/media.d.ts.map +1 -0
  154. package/dist/types/src/calls/util/stub-media-streams.d.ts +18 -0
  155. package/dist/types/src/calls/util/stub-media-streams.d.ts.map +1 -0
  156. package/dist/types/src/calls/util/task-scheduling.d.ts +17 -0
  157. package/dist/types/src/calls/util/task-scheduling.d.ts.map +1 -0
  158. package/dist/types/src/capabilities/app-graph-builder.d.ts +2 -179
  159. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  160. package/dist/types/src/capabilities/call-manager.d.ts +5 -0
  161. package/dist/types/src/capabilities/call-manager.d.ts.map +1 -0
  162. package/dist/types/src/capabilities/capabilities.d.ts +13 -1
  163. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  164. package/dist/types/src/capabilities/index.d.ts +8 -179
  165. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  166. package/dist/types/src/capabilities/intent-resolver.d.ts +2 -2
  167. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  168. package/dist/types/src/capabilities/markdown.d.ts +2 -2
  169. package/dist/types/src/capabilities/markdown.d.ts.map +1 -1
  170. package/dist/types/src/capabilities/react-root.d.ts +7 -0
  171. package/dist/types/src/capabilities/react-root.d.ts.map +1 -0
  172. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  173. package/dist/types/src/components/Call/Call.d.ts +17 -0
  174. package/dist/types/src/components/Call/Call.d.ts.map +1 -0
  175. package/dist/types/src/components/Call/Toolbar.d.ts +16 -0
  176. package/dist/types/src/components/Call/Toolbar.d.ts.map +1 -0
  177. package/dist/types/src/components/Call/index.d.ts +3 -0
  178. package/dist/types/src/components/Call/index.d.ts.map +1 -0
  179. package/dist/types/src/components/CallDebugPanel.d.ts +8 -0
  180. package/dist/types/src/components/CallDebugPanel.d.ts.map +1 -0
  181. package/dist/types/src/components/CallSidebar.d.ts +4 -0
  182. package/dist/types/src/components/CallSidebar.d.ts.map +1 -0
  183. package/dist/types/src/components/ChannelContainer.d.ts +14 -0
  184. package/dist/types/src/components/ChannelContainer.d.ts.map +1 -0
  185. package/dist/types/src/components/ChannelContainer.stories.d.ts +10 -0
  186. package/dist/types/src/components/ChannelContainer.stories.d.ts.map +1 -0
  187. package/dist/types/src/components/Chat.stories.d.ts.map +1 -1
  188. package/dist/types/src/components/ChatContainer.d.ts +9 -7
  189. package/dist/types/src/components/ChatContainer.d.ts.map +1 -1
  190. package/dist/types/src/components/CommentContainer.d.ts +11 -2
  191. package/dist/types/src/components/CommentContainer.d.ts.map +1 -1
  192. package/dist/types/src/components/Comments.stories.d.ts +1 -1
  193. package/dist/types/src/components/Comments.stories.d.ts.map +1 -1
  194. package/dist/types/src/components/CommentsContainer.d.ts +5 -9
  195. package/dist/types/src/components/CommentsContainer.d.ts.map +1 -1
  196. package/dist/types/src/components/Lobby/Lobby.d.ts +15 -0
  197. package/dist/types/src/components/Lobby/Lobby.d.ts.map +1 -0
  198. package/dist/types/src/components/Lobby/index.d.ts +2 -0
  199. package/dist/types/src/components/Lobby/index.d.ts.map +1 -0
  200. package/dist/types/src/components/Media/AudioStream.d.ts +6 -0
  201. package/dist/types/src/components/Media/AudioStream.d.ts.map +1 -0
  202. package/dist/types/src/components/Media/VideoObject.d.ts +15 -0
  203. package/dist/types/src/components/Media/VideoObject.d.ts.map +1 -0
  204. package/dist/types/src/components/Media/VideoObject.stories.d.ts +8 -0
  205. package/dist/types/src/components/Media/VideoObject.stories.d.ts.map +1 -0
  206. package/dist/types/src/components/Media/index.d.ts +3 -0
  207. package/dist/types/src/components/Media/index.d.ts.map +1 -0
  208. package/dist/types/src/components/MessageContainer.d.ts +5 -4
  209. package/dist/types/src/components/MessageContainer.d.ts.map +1 -1
  210. package/dist/types/src/components/Participant/Participant.d.ts +6 -0
  211. package/dist/types/src/components/Participant/Participant.d.ts.map +1 -0
  212. package/dist/types/src/components/Participant/ParticipantGrid.d.ts +11 -0
  213. package/dist/types/src/components/Participant/ParticipantGrid.d.ts.map +1 -0
  214. package/dist/types/src/components/Participant/index.d.ts +3 -0
  215. package/dist/types/src/components/Participant/index.d.ts.map +1 -0
  216. package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.d.ts +12 -0
  217. package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.d.ts.map +1 -0
  218. package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts +10 -0
  219. package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts.map +1 -0
  220. package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.d.ts +32 -0
  221. package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.d.ts.map +1 -0
  222. package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts +23 -0
  223. package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts.map +1 -0
  224. package/dist/types/src/components/ResponsiveGrid/ResponsiveGridItem.d.ts +21 -0
  225. package/dist/types/src/components/ResponsiveGrid/ResponsiveGridItem.d.ts.map +1 -0
  226. package/dist/types/src/components/ResponsiveGrid/index.d.ts +4 -0
  227. package/dist/types/src/components/ResponsiveGrid/index.d.ts.map +1 -0
  228. package/dist/types/src/components/ThreadComplementary.d.ts.map +1 -1
  229. package/dist/types/src/components/ThreadSettings.d.ts.map +1 -1
  230. package/dist/types/src/components/index.d.ts +5 -1
  231. package/dist/types/src/components/index.d.ts.map +1 -1
  232. package/dist/types/src/components/testing.d.ts +54 -119
  233. package/dist/types/src/components/testing.d.ts.map +1 -1
  234. package/dist/types/src/extensions/threads.d.ts.map +1 -1
  235. package/dist/types/src/hooks/analytics.d.ts +2 -2
  236. package/dist/types/src/hooks/analytics.d.ts.map +1 -1
  237. package/dist/types/src/hooks/index.d.ts +2 -1
  238. package/dist/types/src/hooks/index.d.ts.map +1 -1
  239. package/dist/types/src/hooks/useDebugMode.d.ts +2 -0
  240. package/dist/types/src/hooks/useDebugMode.d.ts.map +1 -0
  241. package/dist/types/src/hooks/useStatus.d.ts.map +1 -1
  242. package/dist/types/src/index.d.ts +1 -1
  243. package/dist/types/src/index.d.ts.map +1 -1
  244. package/dist/types/src/meta.d.ts.map +1 -1
  245. package/dist/types/src/peers.stories.d.ts +11 -0
  246. package/dist/types/src/peers.stories.d.ts.map +1 -0
  247. package/dist/types/src/testing/index.d.ts +2 -0
  248. package/dist/types/src/testing/index.d.ts.map +1 -0
  249. package/dist/types/src/testing/stories.d.ts +2 -0
  250. package/dist/types/src/testing/stories.d.ts.map +1 -0
  251. package/dist/types/src/translations.d.ts +35 -56
  252. package/dist/types/src/translations.d.ts.map +1 -1
  253. package/dist/types/src/types/index.d.ts +3 -0
  254. package/dist/types/src/types/index.d.ts.map +1 -0
  255. package/dist/types/src/types/schema.d.ts +317 -0
  256. package/dist/types/src/types/schema.d.ts.map +1 -0
  257. package/dist/types/src/types/types.d.ts +1015 -0
  258. package/dist/types/src/types/types.d.ts.map +1 -0
  259. package/dist/types/src/util.d.ts +2 -0
  260. package/dist/types/src/util.d.ts.map +1 -1
  261. package/dist/types/tsconfig.tsbuildinfo +1 -1
  262. package/package.json +60 -40
  263. package/src/ThreadPlugin.tsx +33 -14
  264. package/src/calls/call-manager.ts +242 -0
  265. package/src/calls/call-swarm-synchronizer.ts +350 -0
  266. package/src/calls/index.ts +10 -0
  267. package/src/calls/media-manager.ts +342 -0
  268. package/src/calls/speaking-monitor.ts +85 -0
  269. package/src/calls/types.ts +70 -0
  270. package/src/calls/util/audio.ts +58 -0
  271. package/src/calls/util/calls-service.ts +527 -0
  272. package/src/calls/util/history-cache.ts +27 -0
  273. package/src/calls/util/index.ts +8 -0
  274. package/src/calls/util/media.ts +52 -0
  275. package/src/calls/util/stub-media-streams.ts +73 -0
  276. package/src/calls/util/task-scheduling.ts +92 -0
  277. package/src/capabilities/app-graph-builder.ts +171 -25
  278. package/src/capabilities/call-manager.ts +19 -0
  279. package/src/capabilities/capabilities.ts +15 -1
  280. package/src/capabilities/index.ts +2 -0
  281. package/src/capabilities/intent-resolver.ts +76 -55
  282. package/src/capabilities/markdown.ts +54 -4
  283. package/src/capabilities/react-root.tsx +17 -0
  284. package/src/capabilities/react-surface.tsx +52 -27
  285. package/src/capabilities/state.ts +1 -1
  286. package/src/components/Call/Call.tsx +88 -0
  287. package/src/components/Call/Toolbar.tsx +182 -0
  288. package/src/components/Call/index.ts +6 -0
  289. package/src/components/CallDebugPanel.tsx +115 -0
  290. package/src/components/CallSidebar.tsx +17 -0
  291. package/src/components/ChannelContainer.stories.tsx +58 -0
  292. package/src/components/ChannelContainer.tsx +203 -0
  293. package/src/components/Chat.stories.tsx +9 -10
  294. package/src/components/ChatContainer.tsx +37 -25
  295. package/src/components/CommentContainer.tsx +56 -61
  296. package/src/components/Comments.stories.tsx +20 -16
  297. package/src/components/CommentsContainer.tsx +18 -28
  298. package/src/components/Lobby/Lobby.tsx +119 -0
  299. package/src/components/Lobby/index.ts +5 -0
  300. package/src/components/Media/AudioStream.tsx +67 -0
  301. package/src/components/Media/VideoObject.stories.tsx +52 -0
  302. package/src/components/Media/VideoObject.tsx +58 -0
  303. package/src/components/Media/index.ts +6 -0
  304. package/src/components/MessageContainer.tsx +31 -50
  305. package/src/components/Participant/Participant.tsx +57 -0
  306. package/src/components/Participant/ParticipantGrid.tsx +88 -0
  307. package/src/components/Participant/index.ts +6 -0
  308. package/src/components/ResponsiveGrid/ResponsiveContainer.stories.tsx +54 -0
  309. package/src/components/ResponsiveGrid/ResponsiveContainer.tsx +31 -0
  310. package/src/components/ResponsiveGrid/ResponsiveGrid.stories.tsx +156 -0
  311. package/src/components/ResponsiveGrid/ResponsiveGrid.tsx +341 -0
  312. package/src/components/ResponsiveGrid/ResponsiveGridItem.tsx +131 -0
  313. package/src/components/ResponsiveGrid/index.ts +7 -0
  314. package/src/components/ThreadComplementary.tsx +37 -42
  315. package/src/components/index.ts +4 -0
  316. package/src/components/testing.ts +4 -3
  317. package/src/extensions/threads.ts +42 -24
  318. package/src/hooks/analytics.ts +6 -2
  319. package/src/hooks/index.ts +2 -1
  320. package/src/hooks/useDebugMode.ts +25 -0
  321. package/src/index.ts +1 -1
  322. package/src/meta.ts +4 -3
  323. package/src/peers.stories.tsx +189 -0
  324. package/src/testing/index.ts +5 -0
  325. package/src/testing/stories.ts +50 -0
  326. package/src/translations.ts +46 -5
  327. package/src/types/index.ts +6 -0
  328. package/src/types/schema.ts +29 -0
  329. package/src/types/types.ts +110 -0
  330. package/src/typings/peermetrics-webrtc-stats.d.ts +30 -0
  331. package/src/util.ts +12 -0
  332. package/dist/lib/browser/ChatContainer-WC6KQDDU.mjs +0 -138
  333. package/dist/lib/browser/ChatContainer-WC6KQDDU.mjs.map +0 -7
  334. package/dist/lib/browser/app-graph-builder-6W4UKJDI.mjs +0 -41
  335. package/dist/lib/browser/app-graph-builder-6W4UKJDI.mjs.map +0 -7
  336. package/dist/lib/browser/chunk-AYNXYEKP.mjs.map +0 -7
  337. package/dist/lib/browser/chunk-EP6MRLY7.mjs.map +0 -7
  338. package/dist/lib/browser/chunk-FY5OCUP6.mjs +0 -207
  339. package/dist/lib/browser/chunk-FY5OCUP6.mjs.map +0 -7
  340. package/dist/lib/browser/chunk-Q66FBBJD.mjs +0 -17
  341. package/dist/lib/browser/chunk-Q66FBBJD.mjs.map +0 -7
  342. package/dist/lib/browser/chunk-WBJLUUOK.mjs.map +0 -7
  343. package/dist/lib/browser/chunk-WOG72DWE.mjs +0 -93
  344. package/dist/lib/browser/chunk-WOG72DWE.mjs.map +0 -7
  345. package/dist/lib/browser/intent-resolver-3UW6ROYT.mjs.map +0 -7
  346. package/dist/lib/browser/markdown-7KXBXCUS.mjs +0 -111
  347. package/dist/lib/browser/markdown-7KXBXCUS.mjs.map +0 -7
  348. package/dist/lib/browser/react-surface-F2AIYIUH.mjs +0 -437
  349. package/dist/lib/browser/react-surface-F2AIYIUH.mjs.map +0 -7
  350. package/dist/lib/browser/types.mjs +0 -10
  351. package/dist/lib/node/ChatContainer-LVYQ67PJ.cjs +0 -163
  352. package/dist/lib/node/ChatContainer-LVYQ67PJ.cjs.map +0 -7
  353. package/dist/lib/node/app-graph-builder-HZNWT4QU.cjs +0 -57
  354. package/dist/lib/node/app-graph-builder-HZNWT4QU.cjs.map +0 -7
  355. package/dist/lib/node/chunk-46BSFPBV.cjs +0 -113
  356. package/dist/lib/node/chunk-46BSFPBV.cjs.map +0 -7
  357. package/dist/lib/node/chunk-IX63EKGL.cjs.map +0 -7
  358. package/dist/lib/node/chunk-NQ5DTPOY.cjs.map +0 -7
  359. package/dist/lib/node/chunk-RIYLEDQ7.cjs +0 -232
  360. package/dist/lib/node/chunk-RIYLEDQ7.cjs.map +0 -7
  361. package/dist/lib/node/chunk-W25MBII2.cjs.map +0 -7
  362. package/dist/lib/node/intent-resolver-DC6HDNTX.cjs.map +0 -7
  363. package/dist/lib/node/markdown-L2WMCQKM.cjs +0 -121
  364. package/dist/lib/node/markdown-L2WMCQKM.cjs.map +0 -7
  365. package/dist/lib/node/react-surface-GP5IH5LN.cjs +0 -439
  366. package/dist/lib/node/react-surface-GP5IH5LN.cjs.map +0 -7
  367. package/dist/lib/node/types.cjs.map +0 -7
  368. package/dist/lib/node-esm/ChatContainer-WMOPMK5H.mjs +0 -139
  369. package/dist/lib/node-esm/ChatContainer-WMOPMK5H.mjs.map +0 -7
  370. package/dist/lib/node-esm/app-graph-builder-M3KK5QJH.mjs +0 -42
  371. package/dist/lib/node-esm/app-graph-builder-M3KK5QJH.mjs.map +0 -7
  372. package/dist/lib/node-esm/chunk-42F2DTMM.mjs.map +0 -7
  373. package/dist/lib/node-esm/chunk-7DOPZH6Y.mjs +0 -208
  374. package/dist/lib/node-esm/chunk-7DOPZH6Y.mjs.map +0 -7
  375. package/dist/lib/node-esm/chunk-E446MGLP.mjs +0 -94
  376. package/dist/lib/node-esm/chunk-E446MGLP.mjs.map +0 -7
  377. package/dist/lib/node-esm/chunk-QUTIMZJ4.mjs +0 -19
  378. package/dist/lib/node-esm/chunk-QUTIMZJ4.mjs.map +0 -7
  379. package/dist/lib/node-esm/chunk-T6E5EY7Z.mjs.map +0 -7
  380. package/dist/lib/node-esm/chunk-WLY2HMDB.mjs.map +0 -7
  381. package/dist/lib/node-esm/intent-resolver-OAMDKGAA.mjs.map +0 -7
  382. package/dist/lib/node-esm/markdown-ZKU23UVD.mjs +0 -112
  383. package/dist/lib/node-esm/markdown-ZKU23UVD.mjs.map +0 -7
  384. package/dist/lib/node-esm/react-surface-45GRKLWG.mjs +0 -438
  385. package/dist/lib/node-esm/react-surface-45GRKLWG.mjs.map +0 -7
  386. package/dist/lib/node-esm/types.mjs +0 -11
  387. package/dist/types/src/components/types.d.ts +0 -28
  388. package/dist/types/src/components/types.d.ts.map +0 -1
  389. package/dist/types/src/events.d.ts +0 -4
  390. package/dist/types/src/events.d.ts.map +0 -1
  391. package/dist/types/src/types.d.ts +0 -231
  392. package/dist/types/src/types.d.ts.map +0 -1
  393. package/src/components/types.ts +0 -32
  394. package/src/events.ts +0 -11
  395. package/src/types.ts +0 -100
  396. /package/dist/lib/browser/{types.mjs.map → ChannelContainer-LGYSQMC7.mjs.map} +0 -0
  397. /package/dist/lib/{node-esm/types.mjs.map → browser/ChatContainer-JWRI73OG.mjs.map} +0 -0
  398. /package/dist/lib/browser/{settings-2VZ7S4SK.mjs.map → settings-KVBQQSO5.mjs.map} +0 -0
  399. /package/dist/lib/node/{settings-7MGTJ46L.cjs.map → settings-H45P5YO2.cjs.map} +0 -0
  400. /package/dist/lib/node-esm/{settings-AJAZ3O47.mjs.map → settings-IJGUOU3F.mjs.map} +0 -0
@@ -0,0 +1,92 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ const DefaultBatchSizeLimit = 64;
6
+
7
+ type Task<Value = unknown> = () => Promise<Value>;
8
+
9
+ export class FIFOScheduler {
10
+ #schedulerChain: Promise<void>;
11
+
12
+ constructor() {
13
+ this.#schedulerChain = Promise.resolve();
14
+ }
15
+
16
+ schedule<T>(task: Task<T>): Promise<T> {
17
+ return new Promise((resolve, reject) => {
18
+ this.#schedulerChain = this.#schedulerChain.then(async () => {
19
+ try {
20
+ resolve(await task());
21
+ } catch (error: any) {
22
+ reject(error);
23
+ }
24
+ });
25
+ });
26
+ }
27
+ }
28
+
29
+ // TODO(mykola): Reconcile with @dxos/async task scheduling.
30
+ export class BulkRequestDispatcher<RequestEntryParams, BulkResponse> {
31
+ #currentBatch: RequestEntryParams[];
32
+ #currentBulkResponse: Promise<BulkResponse> | null;
33
+ #batchSizeLimit: number;
34
+
35
+ constructor(batchSizeLimit: number = DefaultBatchSizeLimit) {
36
+ this.#currentBatch = [];
37
+ this.#currentBulkResponse = null;
38
+ this.#batchSizeLimit = batchSizeLimit;
39
+ }
40
+
41
+ /**
42
+ * Returns a bulk response promise.
43
+ * At the event loop iteration end, the accumulated entries will be dispatched as a bulk request.
44
+ */
45
+ doBulkRequest(
46
+ params: RequestEntryParams,
47
+ bulkRequestFunc: (bulkCopy: RequestEntryParams[]) => Promise<BulkResponse>,
48
+ ): Promise<BulkResponse> {
49
+ if (this.#currentBatch.length >= this.#batchSizeLimit) {
50
+ // If it reaches the batch size limit, we make another bulk request.
51
+ this.#currentBatch = [];
52
+ this.#currentBulkResponse = null;
53
+ }
54
+ this.#currentBatch.push(params);
55
+ if (this.#currentBulkResponse != null) {
56
+ return this.#currentBulkResponse;
57
+ }
58
+
59
+ // Save the current batch list reference in the function scope because this.#currentBatch could be reset
60
+ // if the batch limit is reached.
61
+ const batch = this.#currentBatch;
62
+ this.#currentBulkResponse = new Promise((resolve, reject) => {
63
+ // script
64
+ // |
65
+ // V
66
+ // microtasks (Promise)
67
+ // |
68
+ // V
69
+ // macrotasks (setTimeout)
70
+ //
71
+ // macrotasks are run in the event loop iteration end, so we use that moment to make the bulkRequestFunc call.
72
+ setTimeout(() => {
73
+ // When the bulk request happens, the batch list and the response is reset to start another batch.
74
+ // Coming callers will wait for a new response promise.
75
+ this.#currentBulkResponse = null;
76
+
77
+ // We cut here to make the bulk request.
78
+ const batchCopy = batch.splice(0, batch.length);
79
+ bulkRequestFunc(batchCopy)
80
+ .then((result) => {
81
+ resolve(result);
82
+ })
83
+ .catch((err) => {
84
+ reject(err);
85
+ });
86
+ }, 0);
87
+ });
88
+
89
+ // This bulk response needs to be processed to extract the the result for the entry.
90
+ return this.#currentBulkResponse;
91
+ }
92
+ }
@@ -2,33 +2,179 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Capabilities, contributes, type PluginsContext } from '@dxos/app-framework';
6
- import { type ReactiveEchoObject } from '@dxos/client/echo';
7
- import { PLANK_COMPANION_TYPE, ATTENDABLE_PATH_SEPARATOR } from '@dxos/plugin-deck/types';
8
- import { createExtension, type Node } from '@dxos/plugin-graph';
5
+ import { Rx } from '@effect-rx/rx-react';
6
+ import { Option, pipe } from 'effect';
9
7
 
10
- import { meta } from '../meta';
8
+ import { Capabilities, contributes, createIntent, type PluginContext } from '@dxos/app-framework';
9
+ import { getTypename, isInstanceOf } from '@dxos/echo-schema';
10
+ import { AttentionCapabilities } from '@dxos/plugin-attention';
11
+ import { PLANK_COMPANION_TYPE, ATTENDABLE_PATH_SEPARATOR, DECK_COMPANION_TYPE } from '@dxos/plugin-deck/types';
12
+ import { createExtension, ROOT_ID, rxFromSignal } from '@dxos/plugin-graph';
13
+ import { fullyQualifiedId, isEchoObject } from '@dxos/react-client/echo';
11
14
 
12
- export default (context: PluginsContext) =>
13
- contributes(Capabilities.AppGraphBuilder, [
15
+ import { ThreadCapabilities } from './capabilities';
16
+ import { meta, THREAD_PLUGIN } from '../meta';
17
+ import { ChannelType, ThreadAction } from '../types';
18
+ import { getAnchor } from '../util';
19
+
20
+ export default (context: PluginContext) => {
21
+ const resolve = (typename: string) =>
22
+ context.getCapabilities(Capabilities.Metadata).find(({ id }) => id === typename)?.metadata ?? {};
23
+
24
+ return contributes(Capabilities.AppGraphBuilder, [
25
+ createExtension({
26
+ id: `${THREAD_PLUGIN}/active-call`,
27
+ connector: (node) =>
28
+ Rx.make((get) =>
29
+ pipe(
30
+ get(node),
31
+ Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),
32
+ Option.map((node) => {
33
+ const [call] = get(context.capabilities(ThreadCapabilities.CallManager));
34
+ return get(
35
+ rxFromSignal(() =>
36
+ call?.joined
37
+ ? [
38
+ {
39
+ id: `${node.id}${ATTENDABLE_PATH_SEPARATOR}active-call`,
40
+ type: DECK_COMPANION_TYPE,
41
+ data: null,
42
+ properties: {
43
+ label: ['call panel label', { ns: THREAD_PLUGIN }],
44
+ icon: 'ph--video-conference--regular',
45
+ position: 'hoist',
46
+ disposition: 'hidden',
47
+ },
48
+ },
49
+ ]
50
+ : [],
51
+ ),
52
+ );
53
+ }),
54
+ Option.getOrElse(() => []),
55
+ ),
56
+ ),
57
+ }),
58
+ // TODO(wittjosiah): The channel shouldn't become the companion during a call.
59
+ // Alternative: the call/meeting/thread should be a child node of the channel and that should be opened.
60
+ createExtension({
61
+ id: `${THREAD_PLUGIN}/channel-chat-companion`,
62
+ connector: (node) => {
63
+ return Rx.make((get) => {
64
+ return pipe(
65
+ get(node),
66
+ Option.flatMap((node) => (isInstanceOf(ChannelType, node.data) ? Option.some(node.data) : Option.none())),
67
+ Option.map((channel) => {
68
+ const callManager = context.getCapability(ThreadCapabilities.CallManager);
69
+ const joined = get(
70
+ rxFromSignal(() => callManager.joined && callManager.roomId === fullyQualifiedId(channel)),
71
+ );
72
+ if (!joined) {
73
+ return [];
74
+ }
75
+
76
+ return [
77
+ {
78
+ id: `${fullyQualifiedId(channel)}${ATTENDABLE_PATH_SEPARATOR}chat`,
79
+ type: PLANK_COMPANION_TYPE,
80
+ data: 'chat',
81
+ properties: {
82
+ label: ['channel companion label', { ns: THREAD_PLUGIN }],
83
+ icon: 'ph--hash--regular',
84
+ position: 'hoist',
85
+ disposition: 'hidden',
86
+ },
87
+ },
88
+ ];
89
+ }),
90
+ Option.getOrElse(() => []),
91
+ );
92
+ });
93
+ },
94
+ }),
14
95
  createExtension({
15
- id: `${meta.id}/comments`,
16
- // TODO(wittjosiah): Support comments on any object.
17
- // filter: (node): node is Node<ReactiveEchoObject<any>> => isEchoObject(node.data),
18
- filter: (node): node is Node<ReactiveEchoObject<any>> =>
19
- !!node.data && typeof node.data === 'object' && 'threads' in node.data && Array.isArray(node.data.threads),
20
- connector: ({ node }) => [
21
- {
22
- id: [node.id, 'comments'].join(ATTENDABLE_PATH_SEPARATOR),
23
- type: PLANK_COMPANION_TYPE,
24
- data: 'comments',
25
- properties: {
26
- label: ['comments label', { ns: meta.id }],
27
- icon: 'ph--chat-text--regular',
28
- disposition: 'hidden',
29
- position: 'hoist',
30
- },
31
- },
32
- ],
96
+ id: `${meta.id}/comments-companion`,
97
+ connector: (node) =>
98
+ Rx.make((get) =>
99
+ pipe(
100
+ get(node),
101
+ Option.flatMap((node) => {
102
+ if (!isEchoObject(node.data) || isInstanceOf(ChannelType, node.data)) {
103
+ return Option.none();
104
+ }
105
+ const metadata = resolve(getTypename(node.data)!);
106
+ return typeof metadata.comments === 'string' ? Option.some(node) : Option.none();
107
+ }),
108
+ Option.map((node) => [
109
+ {
110
+ id: [node.id, 'comments'].join(ATTENDABLE_PATH_SEPARATOR),
111
+ type: PLANK_COMPANION_TYPE,
112
+ data: 'comments',
113
+ properties: {
114
+ label: ['comments label', { ns: meta.id }],
115
+ icon: 'ph--chat-text--regular',
116
+ disposition: 'hidden',
117
+ position: 'hoist',
118
+ },
119
+ },
120
+ ]),
121
+ Option.getOrElse(() => []),
122
+ ),
123
+ ),
124
+ }),
125
+ createExtension({
126
+ id: `${meta.id}/comment-toolbar`,
127
+ actions: (node) =>
128
+ Rx.make((get) =>
129
+ pipe(
130
+ get(node),
131
+ Option.flatMap((node) => {
132
+ if (!isEchoObject(node.data) || isInstanceOf(ChannelType, node.data)) {
133
+ return Option.none();
134
+ }
135
+ const metadata = resolve(getTypename(node.data)!);
136
+ return typeof metadata.comments === 'string' ? Option.some(node.data) : Option.none();
137
+ }),
138
+ Option.map((object) => {
139
+ const selectionManager = context.getCapability(AttentionCapabilities.Selection);
140
+ const toolbar = get(context.capabilities(ThreadCapabilities.State))[0]?.state.toolbar ?? {};
141
+ const disabled = get(
142
+ rxFromSignal(() => {
143
+ const metadata = resolve(getTypename(object)!);
144
+ const selection = selectionManager.getSelection(fullyQualifiedId(object), metadata.selectionMode);
145
+ const anchor = getAnchor(selection);
146
+ const invalidSelection = !anchor;
147
+ const overlappingComment = toolbar[fullyQualifiedId(object)];
148
+ return (metadata.comments === 'anchored' && invalidSelection) || overlappingComment;
149
+ }),
150
+ );
151
+
152
+ return [
153
+ {
154
+ id: `${fullyQualifiedId(object)}/comment`,
155
+ data: () => {
156
+ const { dispatchPromise: dispatch } = context.getCapability(Capabilities.IntentDispatcher);
157
+ const metadata = resolve(getTypename(object)!);
158
+ const selection = selectionManager.getSelection(fullyQualifiedId(object));
159
+ // TODO(wittjosiah): Use presence of selection to determine if the comment should be anchored.
160
+ // Requires all components which support selection (e.g. table/kanban) to support anchored comments.
161
+ const anchor = metadata.comments === 'anchored' ? getAnchor(selection) : Date.now().toString();
162
+ const name = metadata.getAnchorLabel?.(object, anchor);
163
+ void dispatch(createIntent(ThreadAction.Create, { anchor, name, subject: object }));
164
+ },
165
+ properties: {
166
+ label: ['add comment label', { ns: meta.id }],
167
+ icon: 'ph--chat-text--regular',
168
+ disposition: 'toolbar',
169
+ disabled,
170
+ testId: 'thread.comment.add',
171
+ },
172
+ },
173
+ ];
174
+ }),
175
+ Option.getOrElse(() => []),
176
+ ),
177
+ ),
33
178
  }),
34
179
  ]);
180
+ };
@@ -0,0 +1,19 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { contributes, type PluginContext } from '@dxos/app-framework';
6
+ import { ClientCapabilities } from '@dxos/plugin-client';
7
+
8
+ import { ThreadCapabilities } from './capabilities';
9
+ import { CallManager } from '../calls';
10
+
11
+ export default async (context: PluginContext) => {
12
+ const client = context.getCapability(ClientCapabilities.Client);
13
+ const callManager = new CallManager(client);
14
+ await callManager.open();
15
+
16
+ return contributes(ThreadCapabilities.CallManager, callManager, () => {
17
+ void callManager.close();
18
+ });
19
+ };
@@ -5,10 +5,24 @@
5
5
  import { defineCapability } from '@dxos/app-framework';
6
6
  import { type DeepReadonly } from '@dxos/util';
7
7
 
8
+ import { type CallState, type MediaState, type CallManager } from '../calls';
8
9
  import { THREAD_PLUGIN } from '../meta';
9
- import { type ViewState, type ThreadState } from '../types';
10
+ import { type ViewState, type ThreadState, type ChannelType } from '../types';
10
11
 
11
12
  export namespace ThreadCapabilities {
13
+ export const CallManager = defineCapability<CallManager>(`${THREAD_PLUGIN}/capability/call-manager`);
14
+
15
+ // TODO(burdon): Better way to define specific extensions for meeting companions.
16
+ // TODO(burdon): This brings in deps from ../calls; how should we manage/minimize explicit type exposure to other plugins?
17
+ // TODO(wittjosiah): These callbacks could be intents once we support broadcast.
18
+ export type CallProperties = {
19
+ onJoin: (state: { channel?: ChannelType; roomId?: string }) => Promise<void>;
20
+ onLeave: (roomId?: string) => Promise<void>;
21
+ onCallStateUpdated: (callState: CallState) => Promise<void>;
22
+ onMediaStateUpdated: ([mediaState, isSpeaking]: [MediaState, boolean]) => Promise<void>;
23
+ };
24
+ export const CallExtension = defineCapability<CallProperties>(`${THREAD_PLUGIN}/capability/call-extension`);
25
+
12
26
  type GetViewState = (subjectId: string) => ViewState;
13
27
  export const State = defineCapability<{ state: DeepReadonly<ThreadState>; getViewState: GetViewState }>(
14
28
  `${THREAD_PLUGIN}/capability/state`,
@@ -5,8 +5,10 @@
5
5
  import { lazy } from '@dxos/app-framework';
6
6
 
7
7
  export const AppGraphBuilder = lazy(() => import('./app-graph-builder'));
8
+ export const CallManager = lazy(() => import('./call-manager'));
8
9
  export const IntentResolver = lazy(() => import('./intent-resolver'));
9
10
  export const Markdown = lazy(() => import('./markdown'));
11
+ export const ReactRoot = lazy(() => import('./react-root'));
10
12
  export const ReactSurface = lazy(() => import('./react-surface'));
11
13
  export const ThreadSettings = lazy(() => import('./settings'));
12
14
  export const ThreadState = lazy(() => import('./state'));
@@ -2,61 +2,70 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Capabilities, contributes, createIntent, createResolver, type PluginsContext } from '@dxos/app-framework';
6
- import { ObjectId, Ref } from '@dxos/echo-schema';
5
+ import { batch } from '@preact/signals-core';
6
+
7
+ import { Capabilities, contributes, createIntent, createResolver, type PluginContext } from '@dxos/app-framework';
8
+ import { RelationSourceId, RelationTargetId } from '@dxos/echo-schema';
7
9
  import { invariant } from '@dxos/invariant';
8
- import { DXN, QueueSubspaceTags } from '@dxos/keys';
9
- import { refFromDXN } from '@dxos/live-object';
10
- import { log } from '@dxos/log';
11
10
  import { ATTENDABLE_PATH_SEPARATOR, DeckAction } from '@dxos/plugin-deck/types';
12
11
  import { ObservabilityAction } from '@dxos/plugin-observability/types';
13
- import { ChannelType, ThreadType } from '@dxos/plugin-space/types';
14
- import { live, fullyQualifiedId, getSpace, makeRef } from '@dxos/react-client/echo';
15
- import { MessageType } from '@dxos/schema';
12
+ import { SpaceAction } from '@dxos/plugin-space/types';
13
+ import { live, fullyQualifiedId, getSpace, Ref } from '@dxos/react-client/echo';
14
+ import { AnchoredTo, DataType } from '@dxos/schema';
16
15
 
17
16
  import { ThreadCapabilities } from './capabilities';
18
17
  import { THREAD_PLUGIN } from '../meta';
19
- import { ThreadAction } from '../types';
18
+ import { ChannelType, ThreadAction, ThreadType } from '../types';
20
19
 
21
- export default (context: PluginsContext) =>
20
+ export default (context: PluginContext) =>
22
21
  contributes(Capabilities.IntentResolver, [
23
22
  createResolver({
24
23
  intent: ThreadAction.CreateChannel,
25
- resolve: ({ spaceId, name }) => ({
24
+ resolve: ({ name }) => ({
26
25
  data: {
27
26
  object: live(ChannelType, {
28
27
  name,
29
- queue: refFromDXN(new DXN(DXN.kind.QUEUE, [QueueSubspaceTags.DATA, spaceId, ObjectId.random()])),
28
+ defaultThread: Ref.make(live(ThreadType, { messages: [], status: 'active' })),
29
+ threads: [],
30
30
  }),
31
31
  },
32
32
  }),
33
33
  }),
34
+ createResolver({
35
+ intent: ThreadAction.CreateChannelThread,
36
+ resolve: ({ channel }) => {
37
+ const thread = live(ThreadType, { messages: [], status: 'active' });
38
+ channel.threads.push(Ref.make(thread));
39
+ return {
40
+ data: {
41
+ object: thread,
42
+ },
43
+ };
44
+ },
45
+ }),
46
+ // TODO(wittjosiah): Break this up into more composable pieces.
34
47
  createResolver({
35
48
  intent: ThreadAction.Create,
36
- resolve: ({ name, cursor, subject }) => {
37
- // Seed the threads array if it does not exist.
38
- if (subject?.threads === undefined) {
39
- try {
40
- // Static schema will throw an error if subject does not support threads array property.
41
- subject.threads = [];
42
- } catch (err) {
43
- log.error('Subject does not support threads array', { typename: subject?.typename });
44
- return;
45
- }
46
- }
49
+ resolve: ({ name, anchor: _anchor, subject }) => {
50
+ const space = getSpace(subject);
51
+ invariant(space, 'Space not found');
47
52
 
48
- const { state } = context.requestCapability(ThreadCapabilities.MutableState);
53
+ const { state } = context.getCapability(ThreadCapabilities.MutableState);
49
54
  const subjectId = fullyQualifiedId(subject);
50
- const thread = live(ThreadType, { name, anchor: cursor, messages: [], status: 'staged' });
55
+ const thread = live(ThreadType, { name, messages: [], status: 'staged' });
56
+ const anchor = live(AnchoredTo, {
57
+ [RelationSourceId]: thread,
58
+ [RelationTargetId]: subject,
59
+ anchor: _anchor,
60
+ });
51
61
  const draft = state.drafts[subjectId];
52
62
  if (draft) {
53
- draft.push(thread);
63
+ draft.push(anchor);
54
64
  } else {
55
- state.drafts[subjectId] = [thread];
65
+ state.drafts[subjectId] = [anchor];
56
66
  }
57
67
 
58
68
  return {
59
- data: { object: thread },
60
69
  intents: [
61
70
  createIntent(ThreadAction.Select, { current: fullyQualifiedId(thread) }),
62
71
  createIntent(DeckAction.ChangeCompanion, {
@@ -70,7 +79,7 @@ export default (context: PluginsContext) =>
70
79
  createResolver({
71
80
  intent: ThreadAction.Select,
72
81
  resolve: ({ current }) => {
73
- const { state } = context.requestCapability(ThreadCapabilities.MutableState);
82
+ const { state } = context.getCapability(ThreadCapabilities.MutableState);
74
83
  state.current = current;
75
84
  },
76
85
  }),
@@ -102,37 +111,35 @@ export default (context: PluginsContext) =>
102
111
  }),
103
112
  createResolver({
104
113
  intent: ThreadAction.Delete,
105
- resolve: ({ subject, thread }, undo) => {
106
- const { state } = context.requestCapability(ThreadCapabilities.MutableState);
114
+ resolve: ({ subject, anchor, thread: _thread }, undo) => {
115
+ const thread = _thread ?? (anchor[RelationSourceId] as ThreadType);
116
+ const { state } = context.getCapability(ThreadCapabilities.MutableState);
107
117
  const subjectId = fullyQualifiedId(subject);
108
118
  const draft = state.drafts[subjectId];
109
119
  if (draft) {
110
120
  // Check if we're deleting a draft; if so, remove it.
111
- const index = draft.findIndex((t) => t.id === thread.id);
121
+ const index = draft.findIndex((a) => a.id === anchor.id);
112
122
  if (index !== -1) {
113
123
  draft.splice(index, 1);
114
124
  return;
115
125
  }
116
126
  }
117
127
 
118
- const space = getSpace(thread);
119
- if (!space || !subject.threads) {
128
+ const space = getSpace(anchor);
129
+ if (!space) {
120
130
  return;
121
131
  }
122
132
 
123
133
  if (!undo) {
124
- const index = subject.threads.findIndex((t: any) => t?.id === thread.id);
125
- const cursor = subject.threads[index]?.anchor;
126
- if (index !== -1) {
127
- subject.threads?.splice(index, 1);
128
- }
129
-
130
- space.db.remove(thread);
134
+ batch(() => {
135
+ space.db.remove(thread);
136
+ space.db.remove(anchor);
137
+ });
131
138
 
132
139
  return {
133
140
  undoable: {
134
141
  message: ['thread deleted label', { ns: THREAD_PLUGIN }],
135
- data: { cursor },
142
+ data: { thread, anchor },
136
143
  },
137
144
  intents: [
138
145
  createIntent(ObservabilityAction.SendEvent, {
@@ -145,9 +152,10 @@ export default (context: PluginsContext) =>
145
152
  ],
146
153
  };
147
154
  } else {
148
- // TODO(wittjosiah): SDK should do this automatically.
149
- const savedThread = space.db.add(thread);
150
- subject.threads.push(savedThread);
155
+ batch(() => {
156
+ space.db.add(thread);
157
+ space.db.add(anchor);
158
+ });
151
159
 
152
160
  return {
153
161
  intents: [
@@ -165,27 +173,39 @@ export default (context: PluginsContext) =>
165
173
  }),
166
174
  createResolver({
167
175
  intent: ThreadAction.AddMessage,
168
- resolve: ({ thread, subject, sender, text }) => {
169
- const { state } = context.requestCapability(ThreadCapabilities.MutableState);
176
+ resolve: ({ anchor, subject, sender, text }) => {
177
+ const thread = anchor[RelationSourceId] as ThreadType;
178
+ const { state } = context.getCapability(ThreadCapabilities.MutableState);
170
179
  const subjectId = fullyQualifiedId(subject);
171
180
  const space = getSpace(subject);
172
181
  invariant(space, 'Space not found');
173
182
  const intents = [];
174
183
 
175
- const message = live(MessageType, {
184
+ const message = live(DataType.Message, {
176
185
  sender,
177
186
  created: new Date().toISOString(),
178
187
  blocks: [{ type: 'text', text }],
179
188
  // TODO(wittjosiah): Context based on attention.
180
189
  // context: context ? makeRef(context) : undefined,
181
190
  });
182
- thread.messages.push(makeRef(message));
191
+ thread.messages.push(Ref.make(message));
183
192
 
184
- if (state.drafts[subjectId]?.find((t) => t === thread)) {
193
+ const draft = state.drafts[subjectId]?.find((a) => a.id === anchor.id);
194
+ if (draft) {
185
195
  // Move draft to document.
186
196
  thread.status = 'active';
187
- subject.threads ? subject.threads.push(makeRef(thread)) : (subject.threads = [makeRef(thread)]);
188
- state.drafts[subjectId] = state.drafts[subjectId]?.filter(({ id }) => id !== thread.id);
197
+ // TODO(wittjosiah): This causes the thread to flash as it transitions from draft to db.
198
+ state.drafts[subjectId] = state.drafts[subjectId]?.filter((a) => a.id !== anchor.id);
199
+ intents.push(createIntent(SpaceAction.AddObject, { object: thread, target: space, hidden: true }));
200
+ intents.push(
201
+ createIntent(SpaceAction.AddRelation, {
202
+ space,
203
+ schema: AnchoredTo,
204
+ source: thread,
205
+ target: subject,
206
+ fields: { anchor: draft.anchor },
207
+ }),
208
+ );
189
209
  intents.push(
190
210
  createIntent(ObservabilityAction.SendEvent, {
191
211
  name: 'threads.create',
@@ -215,7 +235,8 @@ export default (context: PluginsContext) =>
215
235
  }),
216
236
  createResolver({
217
237
  intent: ThreadAction.DeleteMessage,
218
- resolve: ({ subject, thread, messageId, message, messageIndex }, undo) => {
238
+ resolve: ({ subject, anchor, messageId, message, messageIndex }, undo) => {
239
+ const thread = anchor[RelationSourceId] as ThreadType;
219
240
  const space = getSpace(subject);
220
241
  invariant(space, 'Space not found');
221
242
 
@@ -229,7 +250,7 @@ export default (context: PluginsContext) =>
229
250
  if (messageIndex === 0 && thread.messages.length === 1) {
230
251
  // If the message is the only message in the thread, delete the thread.
231
252
  return {
232
- intents: [createIntent(ThreadAction.Delete, { subject, thread })],
253
+ intents: [createIntent(ThreadAction.Delete, { subject, anchor })],
233
254
  };
234
255
  } else {
235
256
  thread.messages.splice(messageIndex, 1);
@@ -256,7 +277,7 @@ export default (context: PluginsContext) =>
256
277
  return;
257
278
  }
258
279
 
259
- thread.messages.splice(messageIndex, 0, makeRef(message));
280
+ thread.messages.splice(messageIndex, 0, Ref.make(message));
260
281
  return {
261
282
  intents: [
262
283
  createIntent(ObservabilityAction.SendEvent, {
@@ -2,17 +2,67 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Capabilities, contributes, type PluginsContext } from '@dxos/app-framework';
5
+ import { EditorView } from '@codemirror/view';
6
+
7
+ import { Capabilities, contributes, createIntent, type PluginContext } from '@dxos/app-framework';
8
+ import { ATTENDABLE_PATH_SEPARATOR, DeckAction } from '@dxos/plugin-deck/types';
6
9
  import { MarkdownCapabilities } from '@dxos/plugin-markdown';
10
+ import { fullyQualifiedId } from '@dxos/react-client/echo';
11
+ import { commentClickedEffect, commentsState, type EditorState, overlap } from '@dxos/react-ui-editor';
7
12
 
8
13
  import { ThreadCapabilities } from './capabilities';
9
14
  import { threads } from '../extensions';
10
15
 
11
- export default (context: PluginsContext) =>
16
+ export default (context: PluginContext) =>
12
17
  contributes(MarkdownCapabilities.Extensions, [
13
18
  ({ document: doc }) => {
14
- const { dispatchPromise: dispatch } = context.requestCapability(Capabilities.IntentDispatcher);
15
- const { state } = context.requestCapability(ThreadCapabilities.MutableState);
19
+ const { dispatchPromise: dispatch } = context.getCapability(Capabilities.IntentDispatcher);
20
+ const { state } = context.getCapability(ThreadCapabilities.MutableState);
16
21
  return threads(state, doc, dispatch);
17
22
  },
23
+ ({ document: doc }) => {
24
+ const { state } = context.getCapability(ThreadCapabilities.MutableState);
25
+
26
+ return EditorView.updateListener.of((update) => {
27
+ if (update.docChanged || update.selectionSet) {
28
+ state.toolbar[fullyQualifiedId(doc)] = selectionOverlapsComment(update.state);
29
+ }
30
+ });
31
+ },
32
+ ({ document: doc }) => {
33
+ const { dispatchPromise: dispatch } = context.getCapability(Capabilities.IntentDispatcher);
34
+ const id = fullyQualifiedId(doc);
35
+
36
+ return EditorView.updateListener.of((update) => {
37
+ update.transactions.forEach((transaction) => {
38
+ transaction.effects.forEach(async (effect) => {
39
+ if (effect.is(commentClickedEffect)) {
40
+ void dispatch(
41
+ createIntent(DeckAction.ChangeCompanion, {
42
+ primary: id,
43
+ companion: `${id}${ATTENDABLE_PATH_SEPARATOR}comments`,
44
+ }),
45
+ );
46
+ }
47
+ });
48
+ });
49
+ });
50
+ },
18
51
  ]);
52
+
53
+ const selectionOverlapsComment = (state: EditorState): boolean => {
54
+ // May not be defined if thread plugin not installed.
55
+ const commentState = state.field(commentsState, false);
56
+ if (commentState === undefined) {
57
+ return false;
58
+ }
59
+
60
+ const { selection } = state;
61
+ for (const range of selection.ranges) {
62
+ if (commentState.comments.some(({ range: commentRange }) => overlap(commentRange, range))) {
63
+ return true;
64
+ }
65
+ }
66
+
67
+ return false;
68
+ };