@dxos/plugin-thread 0.8.4-main.f5c0578 → 0.8.4-main.fcc0d83b33

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 (488) hide show
  1. package/dist/lib/browser/add-message-OC4QB4I2.mjs +89 -0
  2. package/dist/lib/browser/add-message-OC4QB4I2.mjs.map +7 -0
  3. package/dist/lib/browser/blueprints/index.mjs +37 -0
  4. package/dist/lib/browser/blueprints/index.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
  6. package/dist/lib/browser/chunk-J67QAUIW.mjs +61 -0
  7. package/dist/lib/browser/chunk-J67QAUIW.mjs.map +7 -0
  8. package/dist/lib/browser/chunk-KCMJ7H7F.mjs +259 -0
  9. package/dist/lib/browser/chunk-KCMJ7H7F.mjs.map +7 -0
  10. package/dist/lib/browser/create-IUWQEW74.mjs +55 -0
  11. package/dist/lib/browser/create-IUWQEW74.mjs.map +7 -0
  12. package/dist/lib/browser/create-channel-CBC5WEFG.mjs +21 -0
  13. package/dist/lib/browser/create-channel-CBC5WEFG.mjs.map +7 -0
  14. package/dist/lib/browser/create-channel-thread-JJ5LQ3OZ.mjs +28 -0
  15. package/dist/lib/browser/create-channel-thread-JJ5LQ3OZ.mjs.map +7 -0
  16. package/dist/lib/browser/create-proposals-RHLVRJZ4.mjs +57 -0
  17. package/dist/lib/browser/create-proposals-RHLVRJZ4.mjs.map +7 -0
  18. package/dist/lib/browser/delete-PVIEGTTY.mjs +59 -0
  19. package/dist/lib/browser/delete-PVIEGTTY.mjs.map +7 -0
  20. package/dist/lib/browser/delete-message-TLVRPLJF.mjs +56 -0
  21. package/dist/lib/browser/delete-message-TLVRPLJF.mjs.map +7 -0
  22. package/dist/lib/browser/index.mjs +1875 -229
  23. package/dist/lib/browser/index.mjs.map +4 -4
  24. package/dist/lib/browser/meta.json +1 -1
  25. package/dist/lib/browser/on-create-space-KRTKYRFU.mjs +25 -0
  26. package/dist/lib/browser/on-create-space-KRTKYRFU.mjs.map +7 -0
  27. package/dist/lib/browser/operations/index.mjs +14 -0
  28. package/dist/lib/browser/operations/index.mjs.map +7 -0
  29. package/dist/lib/browser/restore-AVE55SJF.mjs +33 -0
  30. package/dist/lib/browser/restore-AVE55SJF.mjs.map +7 -0
  31. package/dist/lib/browser/restore-message-F57RMGDJ.mjs +34 -0
  32. package/dist/lib/browser/restore-message-F57RMGDJ.mjs.map +7 -0
  33. package/dist/lib/browser/select-BJDZJI64.mjs +26 -0
  34. package/dist/lib/browser/select-BJDZJI64.mjs.map +7 -0
  35. package/dist/lib/browser/toggle-resolved-HQE5P7BV.mjs +37 -0
  36. package/dist/lib/browser/toggle-resolved-HQE5P7BV.mjs.map +7 -0
  37. package/dist/lib/browser/translations.mjs +90 -0
  38. package/dist/lib/browser/translations.mjs.map +7 -0
  39. package/dist/lib/browser/types/index.mjs +8 -12
  40. package/dist/lib/node-esm/add-message-HJXNAILW.mjs +90 -0
  41. package/dist/lib/node-esm/add-message-HJXNAILW.mjs.map +7 -0
  42. package/dist/lib/node-esm/blueprints/index.mjs +38 -0
  43. package/dist/lib/node-esm/blueprints/index.mjs.map +7 -0
  44. package/dist/lib/node-esm/chunk-2Q6V7NGK.mjs +62 -0
  45. package/dist/lib/node-esm/chunk-2Q6V7NGK.mjs.map +7 -0
  46. package/dist/lib/node-esm/chunk-4KRVIOPC.mjs +260 -0
  47. package/dist/lib/node-esm/chunk-4KRVIOPC.mjs.map +7 -0
  48. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
  49. package/dist/lib/node-esm/create-NALJT67D.mjs +56 -0
  50. package/dist/lib/node-esm/create-NALJT67D.mjs.map +7 -0
  51. package/dist/lib/node-esm/create-channel-CS2EAYJF.mjs +22 -0
  52. package/dist/lib/node-esm/create-channel-CS2EAYJF.mjs.map +7 -0
  53. package/dist/lib/node-esm/create-channel-thread-KZZFZDTU.mjs +29 -0
  54. package/dist/lib/node-esm/create-channel-thread-KZZFZDTU.mjs.map +7 -0
  55. package/dist/lib/node-esm/create-proposals-AFAYZQBI.mjs +58 -0
  56. package/dist/lib/node-esm/create-proposals-AFAYZQBI.mjs.map +7 -0
  57. package/dist/lib/node-esm/delete-HQJVZY7Q.mjs +60 -0
  58. package/dist/lib/node-esm/delete-HQJVZY7Q.mjs.map +7 -0
  59. package/dist/lib/node-esm/delete-message-VVPEYLV4.mjs +57 -0
  60. package/dist/lib/node-esm/delete-message-VVPEYLV4.mjs.map +7 -0
  61. package/dist/lib/node-esm/index.mjs +1875 -229
  62. package/dist/lib/node-esm/index.mjs.map +4 -4
  63. package/dist/lib/node-esm/meta.json +1 -1
  64. package/dist/lib/node-esm/on-create-space-2UX7Z5EQ.mjs +26 -0
  65. package/dist/lib/node-esm/on-create-space-2UX7Z5EQ.mjs.map +7 -0
  66. package/dist/lib/node-esm/operations/index.mjs +15 -0
  67. package/dist/lib/node-esm/operations/index.mjs.map +7 -0
  68. package/dist/lib/node-esm/restore-FMIWJR5T.mjs +34 -0
  69. package/dist/lib/node-esm/restore-FMIWJR5T.mjs.map +7 -0
  70. package/dist/lib/node-esm/restore-message-3L7AMQMG.mjs +35 -0
  71. package/dist/lib/node-esm/restore-message-3L7AMQMG.mjs.map +7 -0
  72. package/dist/lib/node-esm/select-VCAFISBK.mjs +27 -0
  73. package/dist/lib/node-esm/select-VCAFISBK.mjs.map +7 -0
  74. package/dist/lib/node-esm/toggle-resolved-JDZZ257P.mjs +38 -0
  75. package/dist/lib/node-esm/toggle-resolved-JDZZ257P.mjs.map +7 -0
  76. package/dist/lib/node-esm/translations.mjs +91 -0
  77. package/dist/lib/node-esm/translations.mjs.map +7 -0
  78. package/dist/lib/node-esm/types/index.mjs +8 -12
  79. package/dist/types/src/ThreadPlugin.d.ts +2 -1
  80. package/dist/types/src/ThreadPlugin.d.ts.map +1 -1
  81. package/dist/types/src/blueprints/index.d.ts +2 -0
  82. package/dist/types/src/blueprints/index.d.ts.map +1 -0
  83. package/dist/types/src/blueprints/thread-blueprint.d.ts +4 -0
  84. package/dist/types/src/blueprints/thread-blueprint.d.ts.map +1 -0
  85. package/dist/types/src/calls/call-manager.d.ts +40 -30
  86. package/dist/types/src/calls/call-manager.d.ts.map +1 -1
  87. package/dist/types/src/calls/call-swarm-synchronizer.d.ts +2 -2
  88. package/dist/types/src/calls/call-swarm-synchronizer.d.ts.map +1 -1
  89. package/dist/types/src/calls/media-manager.d.ts +2 -2
  90. package/dist/types/src/calls/media-manager.d.ts.map +1 -1
  91. package/dist/types/src/calls/speaking-monitor.d.ts +0 -3
  92. package/dist/types/src/calls/speaking-monitor.d.ts.map +1 -1
  93. package/dist/types/src/calls/types.d.ts.map +1 -1
  94. package/dist/types/src/calls/util/audio.d.ts.map +1 -1
  95. package/dist/types/src/calls/util/calls-service.d.ts +6 -4
  96. package/dist/types/src/calls/util/calls-service.d.ts.map +1 -1
  97. package/dist/types/src/calls/util/history-cache.d.ts.map +1 -1
  98. package/dist/types/src/calls/util/media.d.ts.map +1 -1
  99. package/dist/types/src/calls/util/stub-media-streams.d.ts.map +1 -1
  100. package/dist/types/src/calls/util/task-scheduling.d.ts +2 -2
  101. package/dist/types/src/calls/util/task-scheduling.d.ts.map +1 -1
  102. package/dist/types/src/calls-service.stories.d.ts +10 -9
  103. package/dist/types/src/calls-service.stories.d.ts.map +1 -1
  104. package/dist/types/src/capabilities/app-graph-builder.d.ts +4 -2
  105. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  106. package/dist/types/src/capabilities/blueprint-definition.d.ts +5 -0
  107. package/dist/types/src/capabilities/blueprint-definition.d.ts.map +1 -0
  108. package/dist/types/src/capabilities/call-manager.d.ts +3 -2
  109. package/dist/types/src/capabilities/call-manager.d.ts.map +1 -1
  110. package/dist/types/src/capabilities/index.d.ts +13 -13
  111. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  112. package/dist/types/src/capabilities/markdown.d.ts +3 -2
  113. package/dist/types/src/capabilities/markdown.d.ts.map +1 -1
  114. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  115. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  116. package/dist/types/src/capabilities/react-root.d.ts +4 -2
  117. package/dist/types/src/capabilities/react-root.d.ts.map +1 -1
  118. package/dist/types/src/capabilities/react-surface.d.ts +3 -2
  119. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  120. package/dist/types/src/capabilities/settings.d.ts +5 -2
  121. package/dist/types/src/capabilities/settings.d.ts.map +1 -1
  122. package/dist/types/src/capabilities/state.d.ts +5 -5
  123. package/dist/types/src/capabilities/state.d.ts.map +1 -1
  124. package/dist/types/src/capabilities/undo-mappings.d.ts +5 -0
  125. package/dist/types/src/capabilities/undo-mappings.d.ts.map +1 -0
  126. package/dist/types/src/components/Call/Call.d.ts +32 -4
  127. package/dist/types/src/components/Call/Call.d.ts.map +1 -1
  128. package/dist/types/src/components/Call/Toolbar.d.ts +6 -6
  129. package/dist/types/src/components/Call/Toolbar.d.ts.map +1 -1
  130. package/dist/types/src/components/CommentsPanel/CommentsPanel.d.ts +13 -0
  131. package/dist/types/src/components/CommentsPanel/CommentsPanel.d.ts.map +1 -0
  132. package/dist/types/src/components/CommentsPanel/CommentsPanel.stories.d.ts +160 -0
  133. package/dist/types/src/components/CommentsPanel/CommentsPanel.stories.d.ts.map +1 -0
  134. package/dist/types/src/components/CommentsPanel/CommentsThread.d.ts +14 -0
  135. package/dist/types/src/components/CommentsPanel/CommentsThread.d.ts.map +1 -0
  136. package/dist/types/src/components/CommentsPanel/index.d.ts +3 -0
  137. package/dist/types/src/components/CommentsPanel/index.d.ts.map +1 -0
  138. package/dist/types/src/components/Lobby/Lobby.d.ts +24 -3
  139. package/dist/types/src/components/Lobby/Lobby.d.ts.map +1 -1
  140. package/dist/types/src/components/Media/VideoObject.d.ts +3 -3
  141. package/dist/types/src/components/Media/VideoObject.d.ts.map +1 -1
  142. package/dist/types/src/components/Media/VideoObject.stories.d.ts +18 -4
  143. package/dist/types/src/components/Media/VideoObject.stories.d.ts.map +1 -1
  144. package/dist/types/src/components/MessagePanel/MessagePanel.d.ts +15 -0
  145. package/dist/types/src/components/MessagePanel/MessagePanel.d.ts.map +1 -0
  146. package/dist/types/src/components/MessagePanel/index.d.ts +2 -0
  147. package/dist/types/src/components/MessagePanel/index.d.ts.map +1 -0
  148. package/dist/types/src/components/Participant/Participant.d.ts.map +1 -1
  149. package/dist/types/src/components/Participant/ParticipantGrid.d.ts.map +1 -1
  150. package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.d.ts.map +1 -1
  151. package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts +160 -5
  152. package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts.map +1 -1
  153. package/dist/types/src/components/ResponsiveGrid/ResponsiveGridItem.d.ts.map +1 -1
  154. package/dist/types/src/components/ResponsiveGrid/{ResponsiveContainer.d.ts → ResponsivePanel.d.ts} +4 -4
  155. package/dist/types/src/components/ResponsiveGrid/ResponsivePanel.d.ts.map +1 -0
  156. package/dist/types/src/components/ResponsiveGrid/ResponsivePanel.stories.d.ts +164 -0
  157. package/dist/types/src/components/ResponsiveGrid/ResponsivePanel.stories.d.ts.map +1 -0
  158. package/dist/types/src/components/ResponsiveGrid/index.d.ts +1 -1
  159. package/dist/types/src/components/ResponsiveGrid/index.d.ts.map +1 -1
  160. package/dist/types/src/components/ThreadSettings/ThreadSettings.d.ts +6 -0
  161. package/dist/types/src/components/ThreadSettings/ThreadSettings.d.ts.map +1 -0
  162. package/dist/types/src/components/ThreadSettings/ThreadSettings.stories.d.ts +161 -0
  163. package/dist/types/src/components/ThreadSettings/ThreadSettings.stories.d.ts.map +1 -0
  164. package/dist/types/src/components/ThreadSettings/index.d.ts +2 -0
  165. package/dist/types/src/components/ThreadSettings/index.d.ts.map +1 -0
  166. package/dist/types/src/components/index.d.ts +4 -9
  167. package/dist/types/src/components/index.d.ts.map +1 -1
  168. package/dist/types/src/containers/CallDebugPanel/CallDebugPanel.d.ts +15 -0
  169. package/dist/types/src/containers/CallDebugPanel/CallDebugPanel.d.ts.map +1 -0
  170. package/dist/types/src/containers/CallDebugPanel/index.d.ts +2 -0
  171. package/dist/types/src/containers/CallDebugPanel/index.d.ts.map +1 -0
  172. package/dist/types/src/{components → containers/CallSidebar}/CallSidebar.d.ts +0 -1
  173. package/dist/types/src/containers/CallSidebar/CallSidebar.d.ts.map +1 -0
  174. package/dist/types/src/containers/CallSidebar/index.d.ts +2 -0
  175. package/dist/types/src/containers/CallSidebar/index.d.ts.map +1 -0
  176. package/dist/types/src/containers/ChannelContainer/ChannelContainer.d.ts +12 -0
  177. package/dist/types/src/containers/ChannelContainer/ChannelContainer.d.ts.map +1 -0
  178. package/dist/types/src/containers/ChannelContainer/ChannelContainer.stories.d.ts +162 -0
  179. package/dist/types/src/containers/ChannelContainer/ChannelContainer.stories.d.ts.map +1 -0
  180. package/dist/types/src/containers/ChannelContainer/index.d.ts +2 -0
  181. package/dist/types/src/containers/ChannelContainer/index.d.ts.map +1 -0
  182. package/dist/types/src/containers/ChatContainer/ChatContainer.d.ts +16 -0
  183. package/dist/types/src/containers/ChatContainer/ChatContainer.d.ts.map +1 -0
  184. package/dist/types/src/containers/ChatContainer/ChatContainer.stories.d.ts +162 -0
  185. package/dist/types/src/containers/ChatContainer/ChatContainer.stories.d.ts.map +1 -0
  186. package/dist/types/src/containers/ChatContainer/index.d.ts +4 -0
  187. package/dist/types/src/containers/ChatContainer/index.d.ts.map +1 -0
  188. package/dist/types/src/containers/ThreadCompanion/ThreadCompanion.d.ts +8 -0
  189. package/dist/types/src/containers/ThreadCompanion/ThreadCompanion.d.ts.map +1 -0
  190. package/dist/types/src/containers/ThreadCompanion/index.d.ts +2 -0
  191. package/dist/types/src/containers/ThreadCompanion/index.d.ts.map +1 -0
  192. package/dist/types/src/containers/index.d.ts +7 -0
  193. package/dist/types/src/containers/index.d.ts.map +1 -0
  194. package/dist/types/src/{components/command-extension.d.ts → extensions/command.d.ts} +1 -1
  195. package/dist/types/src/extensions/command.d.ts.map +1 -0
  196. package/dist/types/src/extensions/index.d.ts +1 -0
  197. package/dist/types/src/extensions/index.d.ts.map +1 -1
  198. package/dist/types/src/extensions/threads.d.ts +8 -3
  199. package/dist/types/src/extensions/threads.d.ts.map +1 -1
  200. package/dist/types/src/hooks/analytics.d.ts +2 -3
  201. package/dist/types/src/hooks/analytics.d.ts.map +1 -1
  202. package/dist/types/src/hooks/index.d.ts +2 -1
  203. package/dist/types/src/hooks/index.d.ts.map +1 -1
  204. package/dist/types/src/hooks/useBlackCanvasStreamTrack.d.ts +2 -0
  205. package/dist/types/src/hooks/useBlackCanvasStreamTrack.d.ts.map +1 -0
  206. package/dist/types/src/hooks/useStatus.d.ts.map +1 -1
  207. package/dist/types/src/hooks/useVideoStreamTrack.d.ts +1 -1
  208. package/dist/types/src/hooks/useVideoStreamTrack.d.ts.map +1 -1
  209. package/dist/types/src/index.d.ts +1 -1
  210. package/dist/types/src/index.d.ts.map +1 -1
  211. package/dist/types/src/meta.d.ts +3 -4
  212. package/dist/types/src/meta.d.ts.map +1 -1
  213. package/dist/types/src/operations/add-message.d.ts +5 -0
  214. package/dist/types/src/operations/add-message.d.ts.map +1 -0
  215. package/dist/types/src/operations/create-channel-thread.d.ts +5 -0
  216. package/dist/types/src/operations/create-channel-thread.d.ts.map +1 -0
  217. package/dist/types/src/operations/create-channel.d.ts +5 -0
  218. package/dist/types/src/operations/create-channel.d.ts.map +1 -0
  219. package/dist/types/src/operations/create-proposals.d.ts +5 -0
  220. package/dist/types/src/operations/create-proposals.d.ts.map +1 -0
  221. package/dist/types/src/operations/create.d.ts +5 -0
  222. package/dist/types/src/operations/create.d.ts.map +1 -0
  223. package/dist/types/src/operations/definitions.d.ts +2804 -0
  224. package/dist/types/src/operations/definitions.d.ts.map +1 -0
  225. package/dist/types/src/operations/delete-message.d.ts +5 -0
  226. package/dist/types/src/operations/delete-message.d.ts.map +1 -0
  227. package/dist/types/src/operations/delete.d.ts +5 -0
  228. package/dist/types/src/operations/delete.d.ts.map +1 -0
  229. package/dist/types/src/operations/index.d.ts +4 -0
  230. package/dist/types/src/operations/index.d.ts.map +1 -0
  231. package/dist/types/src/operations/on-create-space.d.ts +5 -0
  232. package/dist/types/src/operations/on-create-space.d.ts.map +1 -0
  233. package/dist/types/src/operations/restore-message.d.ts +5 -0
  234. package/dist/types/src/operations/restore-message.d.ts.map +1 -0
  235. package/dist/types/src/operations/restore.d.ts +5 -0
  236. package/dist/types/src/operations/restore.d.ts.map +1 -0
  237. package/dist/types/src/operations/select.d.ts +5 -0
  238. package/dist/types/src/operations/select.d.ts.map +1 -0
  239. package/dist/types/src/operations/toggle-resolved.d.ts +5 -0
  240. package/dist/types/src/operations/toggle-resolved.d.ts.map +1 -0
  241. package/dist/types/src/testing/data.d.ts +5 -0
  242. package/dist/types/src/testing/data.d.ts.map +1 -0
  243. package/dist/types/src/testing/index.d.ts +1 -1
  244. package/dist/types/src/testing/index.d.ts.map +1 -1
  245. package/dist/types/src/translations.d.ts +142 -72
  246. package/dist/types/src/translations.d.ts.map +1 -1
  247. package/dist/types/src/types/Channel.d.ts +715 -0
  248. package/dist/types/src/types/Channel.d.ts.map +1 -0
  249. package/dist/types/src/types/Settings.d.ts +5 -0
  250. package/dist/types/src/types/Settings.d.ts.map +1 -0
  251. package/dist/types/src/types/capabilities.d.ts +24 -0
  252. package/dist/types/src/types/capabilities.d.ts.map +1 -0
  253. package/dist/types/src/types/index.d.ts +2 -1
  254. package/dist/types/src/types/index.d.ts.map +1 -1
  255. package/dist/types/src/types/types.d.ts +4 -374
  256. package/dist/types/src/types/types.d.ts.map +1 -1
  257. package/dist/types/src/util.d.ts +2 -2
  258. package/dist/types/src/util.d.ts.map +1 -1
  259. package/dist/types/tsconfig.tsbuildinfo +1 -1
  260. package/package.json +111 -74
  261. package/src/ThreadPlugin.tsx +110 -135
  262. package/src/blueprints/index.ts +5 -0
  263. package/src/blueprints/thread-blueprint.ts +36 -0
  264. package/src/calls/call-manager.ts +77 -53
  265. package/src/calls/call-swarm-synchronizer.ts +2 -2
  266. package/src/calls/media-manager.ts +65 -36
  267. package/src/calls/types.ts +7 -3
  268. package/src/calls/util/calls-service.ts +64 -13
  269. package/src/calls/util/stub-media-streams.ts +64 -5
  270. package/src/calls/util/task-scheduling.ts +4 -4
  271. package/src/calls-service.stories.tsx +80 -66
  272. package/src/capabilities/app-graph-builder.ts +175 -163
  273. package/src/capabilities/blueprint-definition.ts +17 -0
  274. package/src/capabilities/call-manager.ts +19 -12
  275. package/src/capabilities/index.ts +15 -11
  276. package/src/capabilities/markdown.ts +54 -37
  277. package/src/capabilities/operation-handler.ts +16 -0
  278. package/src/capabilities/react-root.tsx +12 -9
  279. package/src/capabilities/react-surface.tsx +80 -78
  280. package/src/capabilities/settings.ts +28 -12
  281. package/src/capabilities/state.ts +14 -18
  282. package/src/capabilities/undo-mappings.ts +46 -0
  283. package/src/components/Call/Call.tsx +16 -12
  284. package/src/components/Call/Toolbar.tsx +61 -44
  285. package/src/components/CommentsPanel/CommentsPanel.stories.tsx +95 -0
  286. package/src/components/CommentsPanel/CommentsPanel.tsx +71 -0
  287. package/src/components/{CommentsThreadContainer.tsx → CommentsPanel/CommentsThread.tsx} +66 -62
  288. package/src/components/CommentsPanel/index.ts +6 -0
  289. package/src/components/Lobby/Lobby.tsx +20 -16
  290. package/src/components/Media/AudioStream.tsx +2 -2
  291. package/src/components/Media/VideoObject.stories.tsx +37 -31
  292. package/src/components/Media/VideoObject.tsx +1 -1
  293. package/src/components/MessagePanel/MessagePanel.tsx +222 -0
  294. package/src/components/MessagePanel/index.ts +5 -0
  295. package/src/components/Participant/Participant.tsx +35 -15
  296. package/src/components/Participant/ParticipantGrid.tsx +0 -1
  297. package/src/components/ResponsiveGrid/ResponsiveGrid.stories.tsx +49 -48
  298. package/src/components/ResponsiveGrid/ResponsiveGrid.tsx +5 -5
  299. package/src/components/ResponsiveGrid/ResponsiveGridItem.tsx +12 -9
  300. package/src/components/ResponsiveGrid/{ResponsiveContainer.stories.tsx → ResponsivePanel.stories.tsx} +11 -12
  301. package/src/components/ResponsiveGrid/{ResponsiveContainer.tsx → ResponsivePanel.tsx} +5 -5
  302. package/src/components/ResponsiveGrid/index.ts +1 -1
  303. package/src/components/ThreadSettings/ThreadSettings.stories.tsx +32 -0
  304. package/src/components/ThreadSettings/ThreadSettings.tsx +20 -0
  305. package/src/components/ThreadSettings/index.ts +5 -0
  306. package/src/components/index.ts +5 -12
  307. package/src/containers/CallDebugPanel/CallDebugPanel.tsx +173 -0
  308. package/src/containers/CallDebugPanel/index.ts +5 -0
  309. package/src/containers/CallSidebar/CallSidebar.tsx +18 -0
  310. package/src/containers/CallSidebar/index.ts +5 -0
  311. package/src/containers/ChannelContainer/ChannelContainer.stories.tsx +93 -0
  312. package/src/{components → containers/ChannelContainer}/ChannelContainer.tsx +93 -71
  313. package/src/containers/ChannelContainer/index.ts +5 -0
  314. package/src/containers/ChatContainer/ChatContainer.stories.tsx +87 -0
  315. package/src/containers/ChatContainer/ChatContainer.tsx +126 -0
  316. package/src/containers/ChatContainer/index.ts +8 -0
  317. package/src/containers/ThreadCompanion/ThreadCompanion.tsx +217 -0
  318. package/src/containers/ThreadCompanion/index.ts +5 -0
  319. package/src/containers/index.ts +11 -0
  320. package/src/{components/command-extension.ts → extensions/command.ts} +6 -3
  321. package/src/extensions/index.ts +1 -0
  322. package/src/extensions/threads.ts +87 -42
  323. package/src/hooks/analytics.ts +22 -21
  324. package/src/hooks/index.ts +3 -1
  325. package/src/hooks/useBlackCanvasStreamTrack.tsx +27 -0
  326. package/src/hooks/useVideoStreamTrack.tsx +6 -3
  327. package/src/index.ts +1 -1
  328. package/src/meta.ts +11 -7
  329. package/src/operations/add-message.ts +81 -0
  330. package/src/operations/create-channel-thread.ts +26 -0
  331. package/src/operations/create-channel.ts +20 -0
  332. package/src/operations/create-proposals.ts +49 -0
  333. package/src/operations/create.ts +48 -0
  334. package/src/operations/definitions.ts +177 -0
  335. package/src/operations/delete-message.ts +53 -0
  336. package/src/operations/delete.ts +63 -0
  337. package/src/operations/index.ts +22 -0
  338. package/src/operations/on-create-space.ts +27 -0
  339. package/src/operations/restore-message.ts +38 -0
  340. package/src/operations/restore.ts +38 -0
  341. package/src/operations/select.ts +24 -0
  342. package/src/operations/toggle-resolved.ts +41 -0
  343. package/src/testing/data.ts +49 -0
  344. package/src/testing/index.ts +1 -1
  345. package/src/translations.ts +74 -73
  346. package/src/types/Channel.ts +37 -0
  347. package/src/types/Settings.ts +10 -0
  348. package/src/types/capabilities.ts +36 -0
  349. package/src/types/index.ts +2 -1
  350. package/src/types/types.ts +5 -100
  351. package/src/typings/peermetrics-webrtc-stats.d.ts +17 -1
  352. package/src/util.ts +2 -2
  353. package/dist/lib/browser/ChannelContainer-O2SFQJU7.mjs +0 -16
  354. package/dist/lib/browser/ChatContainer-PVT3DUZJ.mjs +0 -15
  355. package/dist/lib/browser/app-graph-builder-AF3M7UWN.mjs +0 -171
  356. package/dist/lib/browser/app-graph-builder-AF3M7UWN.mjs.map +0 -7
  357. package/dist/lib/browser/call-manager-XRRCAVLI.mjs +0 -24
  358. package/dist/lib/browser/call-manager-XRRCAVLI.mjs.map +0 -7
  359. package/dist/lib/browser/chunk-2CWJBXBH.mjs +0 -21
  360. package/dist/lib/browser/chunk-2CWJBXBH.mjs.map +0 -7
  361. package/dist/lib/browser/chunk-4APCDRSH.mjs +0 -18
  362. package/dist/lib/browser/chunk-4APCDRSH.mjs.map +0 -7
  363. package/dist/lib/browser/chunk-DW7JD64V.mjs +0 -137
  364. package/dist/lib/browser/chunk-DW7JD64V.mjs.map +0 -7
  365. package/dist/lib/browser/chunk-EV4JWI7L.mjs +0 -17
  366. package/dist/lib/browser/chunk-EV4JWI7L.mjs.map +0 -7
  367. package/dist/lib/browser/chunk-FY4ZRD5X.mjs +0 -367
  368. package/dist/lib/browser/chunk-FY4ZRD5X.mjs.map +0 -7
  369. package/dist/lib/browser/chunk-GERVMFQW.mjs +0 -31
  370. package/dist/lib/browser/chunk-GERVMFQW.mjs.map +0 -7
  371. package/dist/lib/browser/chunk-J3JO5NWO.mjs +0 -477
  372. package/dist/lib/browser/chunk-J3JO5NWO.mjs.map +0 -7
  373. package/dist/lib/browser/chunk-JGKMMI65.mjs +0 -56
  374. package/dist/lib/browser/chunk-JGKMMI65.mjs.map +0 -7
  375. package/dist/lib/browser/chunk-TUFWPOVS.mjs +0 -1698
  376. package/dist/lib/browser/chunk-TUFWPOVS.mjs.map +0 -7
  377. package/dist/lib/browser/chunk-X5PIP5YR.mjs +0 -149
  378. package/dist/lib/browser/chunk-X5PIP5YR.mjs.map +0 -7
  379. package/dist/lib/browser/chunk-ZJ7QBXK6.mjs +0 -984
  380. package/dist/lib/browser/chunk-ZJ7QBXK6.mjs.map +0 -7
  381. package/dist/lib/browser/intent-resolver-DCY4P4OX.mjs +0 -369
  382. package/dist/lib/browser/intent-resolver-DCY4P4OX.mjs.map +0 -7
  383. package/dist/lib/browser/markdown-WZSXCEZJ.mjs +0 -169
  384. package/dist/lib/browser/markdown-WZSXCEZJ.mjs.map +0 -7
  385. package/dist/lib/browser/react-root-QXPALOUQ.mjs +0 -28
  386. package/dist/lib/browser/react-root-QXPALOUQ.mjs.map +0 -7
  387. package/dist/lib/browser/react-surface-PYAMIADB.mjs +0 -109
  388. package/dist/lib/browser/react-surface-PYAMIADB.mjs.map +0 -7
  389. package/dist/lib/browser/settings-AC6YSASL.mjs +0 -22
  390. package/dist/lib/browser/settings-AC6YSASL.mjs.map +0 -7
  391. package/dist/lib/browser/state-2T4KDWBX.mjs +0 -34
  392. package/dist/lib/browser/state-2T4KDWBX.mjs.map +0 -7
  393. package/dist/lib/node-esm/ChannelContainer-B2ZGAE4P.mjs +0 -17
  394. package/dist/lib/node-esm/ChannelContainer-B2ZGAE4P.mjs.map +0 -7
  395. package/dist/lib/node-esm/ChatContainer-2CT4PJ7I.mjs +0 -16
  396. package/dist/lib/node-esm/ChatContainer-2CT4PJ7I.mjs.map +0 -7
  397. package/dist/lib/node-esm/app-graph-builder-OLSJVCWY.mjs +0 -172
  398. package/dist/lib/node-esm/app-graph-builder-OLSJVCWY.mjs.map +0 -7
  399. package/dist/lib/node-esm/call-manager-EI7FXRAU.mjs +0 -25
  400. package/dist/lib/node-esm/call-manager-EI7FXRAU.mjs.map +0 -7
  401. package/dist/lib/node-esm/chunk-4TME3BR4.mjs +0 -1699
  402. package/dist/lib/node-esm/chunk-4TME3BR4.mjs.map +0 -7
  403. package/dist/lib/node-esm/chunk-57XR3LEF.mjs +0 -33
  404. package/dist/lib/node-esm/chunk-57XR3LEF.mjs.map +0 -7
  405. package/dist/lib/node-esm/chunk-6CRHHOST.mjs +0 -23
  406. package/dist/lib/node-esm/chunk-6CRHHOST.mjs.map +0 -7
  407. package/dist/lib/node-esm/chunk-BF4UKS55.mjs +0 -368
  408. package/dist/lib/node-esm/chunk-BF4UKS55.mjs.map +0 -7
  409. package/dist/lib/node-esm/chunk-GRLRWTRU.mjs +0 -19
  410. package/dist/lib/node-esm/chunk-GRLRWTRU.mjs.map +0 -7
  411. package/dist/lib/node-esm/chunk-PYTVBN5J.mjs +0 -19
  412. package/dist/lib/node-esm/chunk-PYTVBN5J.mjs.map +0 -7
  413. package/dist/lib/node-esm/chunk-QBHKLWGR.mjs +0 -58
  414. package/dist/lib/node-esm/chunk-QBHKLWGR.mjs.map +0 -7
  415. package/dist/lib/node-esm/chunk-SED3O2XO.mjs +0 -150
  416. package/dist/lib/node-esm/chunk-SED3O2XO.mjs.map +0 -7
  417. package/dist/lib/node-esm/chunk-VNG6M2IY.mjs +0 -478
  418. package/dist/lib/node-esm/chunk-VNG6M2IY.mjs.map +0 -7
  419. package/dist/lib/node-esm/chunk-XVKWHTH4.mjs +0 -138
  420. package/dist/lib/node-esm/chunk-XVKWHTH4.mjs.map +0 -7
  421. package/dist/lib/node-esm/chunk-YIDU3DXK.mjs +0 -985
  422. package/dist/lib/node-esm/chunk-YIDU3DXK.mjs.map +0 -7
  423. package/dist/lib/node-esm/intent-resolver-QGTPU6QB.mjs +0 -370
  424. package/dist/lib/node-esm/intent-resolver-QGTPU6QB.mjs.map +0 -7
  425. package/dist/lib/node-esm/markdown-3MZXUGUA.mjs +0 -170
  426. package/dist/lib/node-esm/markdown-3MZXUGUA.mjs.map +0 -7
  427. package/dist/lib/node-esm/react-root-7ZFJYVUZ.mjs +0 -29
  428. package/dist/lib/node-esm/react-root-7ZFJYVUZ.mjs.map +0 -7
  429. package/dist/lib/node-esm/react-surface-UJFCSFNO.mjs +0 -110
  430. package/dist/lib/node-esm/react-surface-UJFCSFNO.mjs.map +0 -7
  431. package/dist/lib/node-esm/settings-N52O7MLS.mjs +0 -23
  432. package/dist/lib/node-esm/settings-N52O7MLS.mjs.map +0 -7
  433. package/dist/lib/node-esm/state-62TQKQVB.mjs +0 -35
  434. package/dist/lib/node-esm/state-62TQKQVB.mjs.map +0 -7
  435. package/dist/types/src/capabilities/capabilities.d.ts +0 -27
  436. package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
  437. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  438. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  439. package/dist/types/src/components/CallDebugPanel.d.ts +0 -8
  440. package/dist/types/src/components/CallDebugPanel.d.ts.map +0 -1
  441. package/dist/types/src/components/CallSidebar.d.ts.map +0 -1
  442. package/dist/types/src/components/ChannelContainer.d.ts +0 -14
  443. package/dist/types/src/components/ChannelContainer.d.ts.map +0 -1
  444. package/dist/types/src/components/ChannelContainer.stories.d.ts +0 -10
  445. package/dist/types/src/components/ChannelContainer.stories.d.ts.map +0 -1
  446. package/dist/types/src/components/Chat.stories.d.ts +0 -7
  447. package/dist/types/src/components/Chat.stories.d.ts.map +0 -1
  448. package/dist/types/src/components/ChatContainer.d.ts +0 -17
  449. package/dist/types/src/components/ChatContainer.d.ts.map +0 -1
  450. package/dist/types/src/components/Comments.stories.d.ts +0 -6
  451. package/dist/types/src/components/Comments.stories.d.ts.map +0 -1
  452. package/dist/types/src/components/CommentsContainer.d.ts +0 -13
  453. package/dist/types/src/components/CommentsContainer.d.ts.map +0 -1
  454. package/dist/types/src/components/CommentsThreadContainer.d.ts +0 -14
  455. package/dist/types/src/components/CommentsThreadContainer.d.ts.map +0 -1
  456. package/dist/types/src/components/MessageContainer.d.ts +0 -11
  457. package/dist/types/src/components/MessageContainer.d.ts.map +0 -1
  458. package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.d.ts.map +0 -1
  459. package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts +0 -10
  460. package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts.map +0 -1
  461. package/dist/types/src/components/ThreadComplementary.d.ts +0 -5
  462. package/dist/types/src/components/ThreadComplementary.d.ts.map +0 -1
  463. package/dist/types/src/components/ThreadSettings.d.ts +0 -6
  464. package/dist/types/src/components/ThreadSettings.d.ts.map +0 -1
  465. package/dist/types/src/components/command-extension.d.ts.map +0 -1
  466. package/dist/types/src/components/testing.d.ts +0 -4
  467. package/dist/types/src/components/testing.d.ts.map +0 -1
  468. package/dist/types/src/testing/stories.d.ts +0 -2
  469. package/dist/types/src/testing/stories.d.ts.map +0 -1
  470. package/dist/types/src/types/schema.d.ts +0 -164
  471. package/dist/types/src/types/schema.d.ts.map +0 -1
  472. package/src/capabilities/capabilities.ts +0 -33
  473. package/src/capabilities/intent-resolver.ts +0 -315
  474. package/src/components/CallDebugPanel.tsx +0 -115
  475. package/src/components/CallSidebar.tsx +0 -18
  476. package/src/components/ChannelContainer.stories.tsx +0 -59
  477. package/src/components/Chat.stories.tsx +0 -89
  478. package/src/components/ChatContainer.tsx +0 -142
  479. package/src/components/Comments.stories.tsx +0 -93
  480. package/src/components/CommentsContainer.tsx +0 -72
  481. package/src/components/MessageContainer.tsx +0 -152
  482. package/src/components/ThreadComplementary.tsx +0 -151
  483. package/src/components/ThreadSettings.tsx +0 -17
  484. package/src/components/testing.ts +0 -29
  485. package/src/testing/stories.ts +0 -54
  486. package/src/types/schema.ts +0 -33
  487. /package/dist/lib/browser/{ChannelContainer-O2SFQJU7.mjs.map → chunk-J5LGTIGS.mjs.map} +0 -0
  488. /package/dist/lib/{browser/ChatContainer-PVT3DUZJ.mjs.map → node-esm/chunk-HSLMI22Q.mjs.map} +0 -0
@@ -2,13 +2,12 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { computed } from '@preact/signals-core';
5
+ import { Atom, type Registry } from '@effect-atom/atom-react';
6
6
 
7
7
  import { Event, synchronized } from '@dxos/async';
8
8
  import { type Client } from '@dxos/client';
9
9
  import { Resource } from '@dxos/context';
10
10
  import { invariant } from '@dxos/invariant';
11
- import { live } from '@dxos/live-object';
12
11
  import { type Tracks } from '@dxos/protocols/proto/dxos/edge/calls';
13
12
  import { isNonNullable } from '@dxos/util';
14
13
 
@@ -31,84 +30,103 @@ export class CallManager extends Resource {
31
30
  public readonly left = new Event<string>();
32
31
 
33
32
  /**
34
- * Live object state. Is changed on internal events.
33
+ * Atom-based state. Updated via `_updateState()`.
35
34
  * CAUTION: Do not change directly.
36
35
  */
37
- private readonly _state = live<GlobalState>({
36
+ private readonly _stateAtom = Atom.make<GlobalState>({
38
37
  call: {},
39
38
  media: { pulledAudioTracks: {}, pulledVideoStreams: {} },
40
39
  });
41
40
 
42
- // TODO(wittjosiah): This shouldn't be necessary, live-object's signals should be granular.
43
- private readonly _raisedHandSignal = computed(() => this._state.call.raisedHand ?? false);
44
- private readonly _speakingSignal = computed(() => this._state.call.speaking ?? false);
45
- private readonly _joinedSignal = computed(() => this._state.call.joined ?? false);
41
+ // Derived atoms for reactive subscriptions.
42
+ private readonly _roomIdAtom = Atom.make((get) => get(this._stateAtom).call.roomId);
43
+ private readonly _raisedHandAtom = Atom.make((get) => get(this._stateAtom).call.raisedHand ?? false);
44
+ private readonly _speakingAtom = Atom.make((get) => get(this._stateAtom).call.speaking ?? false);
45
+ private readonly _joinedAtom = Atom.make((get) => get(this._stateAtom).call.joined ?? false);
46
+ private readonly _selfAtom = Atom.make((get) => get(this._stateAtom).call.self ?? {});
47
+ private readonly _tracksAtom = Atom.make((get) => get(this._stateAtom).call.tracks ?? {});
48
+ private readonly _usersAtom = Atom.make((get) => get(this._stateAtom).call.users ?? []);
49
+ private readonly _mediaAtom = Atom.make((get) => get(this._stateAtom).media);
50
+ private readonly _audioTracksToPlayAtom = Atom.make((get) => {
51
+ const state = get(this._stateAtom);
52
+ return (state.call.users ?? [])
53
+ .map((user: UserState) => (user.tracks?.audioEnabled ? user.tracks?.audio : undefined))
54
+ .filter(isNonNullable)
55
+ .map((track: string) => state.media.pulledAudioTracks[track as EncodedTrackName]?.track)
56
+ .filter(isNonNullable);
57
+ });
58
+ private readonly _videoStreamAtomFamily = Atom.family<EncodedTrackName, Atom.Atom<MediaStream | undefined>>((name) =>
59
+ Atom.make((get) => get(this._stateAtom).media.pulledVideoStreams[name]?.stream),
60
+ );
61
+ private readonly _activityAtomFamily = Atom.family<string, Atom.Atom<ActivityState | undefined>>((key) =>
62
+ Atom.make((get) => get(this._stateAtom).call.activities?.[key]),
63
+ );
46
64
 
47
65
  private readonly _swarmSynchronizer: CallSwarmSynchronizer;
48
66
  private readonly _mediaManager: MediaManager;
49
67
 
50
- /** @reactive */
51
- get roomId(): string | undefined {
52
- return this._state.call.roomId;
68
+ //
69
+ // Derived atoms for reactive UI subscriptions.
70
+ //
71
+
72
+ /** Derived atom for roomId. */
73
+ get roomIdAtom(): Atom.Atom<string | undefined> {
74
+ return this._roomIdAtom;
53
75
  }
54
76
 
55
- /** @reactive */
56
- get raisedHand(): boolean {
57
- return this._raisedHandSignal.value;
77
+ /** Derived atom for raisedHand. */
78
+ get raisedHandAtom(): Atom.Atom<boolean> {
79
+ return this._raisedHandAtom;
58
80
  }
59
81
 
60
- /** @reactive */
61
- get speaking(): boolean {
62
- return this._speakingSignal.value;
82
+ /** Derived atom for speaking. */
83
+ get speakingAtom(): Atom.Atom<boolean> {
84
+ return this._speakingAtom;
63
85
  }
64
86
 
65
- /** @reactive */
66
- get joined(): boolean {
67
- return this._joinedSignal.value;
87
+ /** Derived atom for joined. */
88
+ get joinedAtom(): Atom.Atom<boolean> {
89
+ return this._joinedAtom;
68
90
  }
69
91
 
70
- /** @reactive */
71
- get self(): UserState {
72
- return this._state.call.self ?? {};
92
+ /** Derived atom for self. */
93
+ get selfAtom(): Atom.Atom<UserState> {
94
+ return this._selfAtom;
73
95
  }
74
96
 
75
- /** @reactive */
76
- get tracks(): Tracks {
77
- return this._state.call.tracks ?? {};
97
+ /** Derived atom for tracks. */
98
+ get tracksAtom(): Atom.Atom<Tracks> {
99
+ return this._tracksAtom;
78
100
  }
79
101
 
80
- /** @reactive */
81
- get users(): UserState[] {
82
- return this._state.call.users ?? [];
102
+ /** Derived atom for users. */
103
+ get usersAtom(): Atom.Atom<UserState[]> {
104
+ return this._usersAtom;
83
105
  }
84
106
 
85
- /** @reactive */
86
- get media() {
87
- return this._state.media;
107
+ /** Derived atom for media. */
108
+ get mediaAtom(): Atom.Atom<MediaState> {
109
+ return this._mediaAtom;
88
110
  }
89
111
 
90
- /** @reactive */
91
- get audioTracksToPlay(): MediaStreamTrack[] {
92
- return (this._state.call.users ?? [])
93
- .map((user) => (user.tracks?.audioEnabled ? user.tracks?.audio : undefined))
94
- .filter(isNonNullable)
95
- .map((track) => this._state.media.pulledAudioTracks[track as EncodedTrackName]?.track)
96
- .filter(isNonNullable);
112
+ /** Derived atom for audioTracksToPlay. */
113
+ get audioTracksToPlayAtom(): Atom.Atom<MediaStreamTrack[]> {
114
+ return this._audioTracksToPlayAtom;
97
115
  }
98
116
 
99
- /** @reactive */
100
- get state() {
101
- return this._state;
117
+ /** Returns the full state atom for reactive subscriptions. */
118
+ get stateAtom(): Atom.Atom<GlobalState> {
119
+ return this._stateAtom;
102
120
  }
103
121
 
104
- /** @reactive */
105
- getVideoStream(name?: EncodedTrackName): MediaStream | undefined {
106
- return name ? this._state.media.pulledVideoStreams[name]?.stream : undefined;
122
+ /** Returns a derived atom for a video stream by name. */
123
+ videoStreamAtom(name: EncodedTrackName): Atom.Atom<MediaStream | undefined> {
124
+ return this._videoStreamAtomFamily(name);
107
125
  }
108
126
 
109
- /** @reactive */
110
- getActivity(key: string): ActivityState | undefined {
111
- return this._state.call.activities?.[key];
127
+ /** Returns a derived atom for an activity by key. */
128
+ activityAtom(key: string): Atom.Atom<ActivityState | undefined> {
129
+ return this._activityAtomFamily(key);
112
130
  }
113
131
 
114
132
  setRoomId(roomId: string): void {
@@ -152,7 +170,10 @@ export class CallManager extends Resource {
152
170
  }
153
171
 
154
172
  // TODO(burdon): Can this be mocked?
155
- constructor(private readonly _client: Client) {
173
+ constructor(
174
+ private readonly _client: Client,
175
+ private readonly _registry: Registry.Registry,
176
+ ) {
156
177
  super();
157
178
  this._client.config.getOrThrow('runtime.services.edge.url');
158
179
  const networkService = this._client.services.services.NetworkService;
@@ -205,12 +226,13 @@ export class CallManager extends Resource {
205
226
  this._swarmSynchronizer.setJoined(false);
206
227
  await this._swarmSynchronizer.leave();
207
228
  await this._mediaManager.leave();
208
- this.roomId && this.left.emit(this.roomId);
229
+ const roomId = this._registry.get(this._roomIdAtom);
230
+ roomId && this.left.emit(roomId);
209
231
  }
210
232
 
211
233
  private _onCallStateUpdated(state: CallState): void {
212
234
  const tracksToPull = state.users
213
- ?.filter((user) => user.joined && user.id !== state.self?.id)
235
+ ?.filter((user) => user.joined && user.id !== state.self!.id)
214
236
  ?.flatMap((user) => [user.tracks?.video, user.tracks?.audio, user.tracks?.screenshare])
215
237
  .filter(isNonNullable);
216
238
  this._mediaManager._schedulePullTracks(tracksToPull as EncodedTrackName[]);
@@ -240,7 +262,9 @@ export class CallManager extends Resource {
240
262
  * Only this method is allowed to change state.
241
263
  */
242
264
  private _updateState(): void {
243
- this._state.call = this._swarmSynchronizer._getState();
244
- this._state.media = this._mediaManager._getState();
265
+ this._registry.set(this._stateAtom, {
266
+ call: this._swarmSynchronizer._getState(),
267
+ media: this._mediaManager._getState(),
268
+ });
245
269
  }
246
270
  }
@@ -50,7 +50,7 @@ export type CallState = {
50
50
  tracks?: UserState['tracks'];
51
51
  };
52
52
 
53
- export type CallSwarmSynchronizerParams = { networkService: NetworkService };
53
+ export type CallSwarmSynchronizerProps = { networkService: NetworkService };
54
54
 
55
55
  /**
56
56
  * Period for peer to reconnect to the call swarm gracefully if connection was lost abruptly.
@@ -76,7 +76,7 @@ export class CallSwarmSynchronizer extends Resource {
76
76
 
77
77
  private _sendStateTask?: DeferredTask = undefined;
78
78
 
79
- constructor({ networkService }: CallSwarmSynchronizerParams) {
79
+ constructor({ networkService }: CallSwarmSynchronizerProps) {
80
80
  super();
81
81
  this._networkService = networkService;
82
82
  }
@@ -4,6 +4,7 @@
4
4
 
5
5
  import { DeferredTask, Event, sleep, synchronized } from '@dxos/async';
6
6
  import { type Context, Resource, cancelWithContext } from '@dxos/context';
7
+ import { invariant } from '@dxos/invariant';
7
8
  import { log } from '@dxos/log';
8
9
 
9
10
  import { SpeakingMonitor } from './speaking-monitor';
@@ -48,19 +49,23 @@ const VIDEO_WIDTH = 1280;
48
49
  const VIDEO_HEIGHT = 720;
49
50
  const MAX_WEB_CAM_FRAMERATE = 24;
50
51
  const MAX_WEB_CAM_BITRATE = 120_0000;
51
- const RETRY_INTERVAL = 500;
52
+ const RETRY_INTERVAL = 100;
52
53
 
53
- export type MediaManagerParams = {
54
+ export type MediaManagerProps = {
54
55
  serviceConfig: CallsServiceConfig;
55
56
  };
56
57
 
57
- const USE_INAUDIBLE_AUDIO = false;
58
+ const USE_INAUDIBLE_AUDIO = true;
58
59
 
59
60
  export class MediaManager extends Resource {
60
61
  public readonly stateUpdated = new Event<MediaState>();
61
- private readonly _state: MediaState = { pulledVideoStreams: {}, pulledAudioTracks: {} };
62
- private _speakingMonitor?: SpeakingMonitor = undefined;
63
62
 
63
+ private readonly _state: MediaState = {
64
+ pulledVideoStreams: {},
65
+ pulledAudioTracks: {},
66
+ };
67
+
68
+ private _speakingMonitor?: SpeakingMonitor = undefined;
64
69
  private _trackToReconcile: EncodedTrackName[] = [];
65
70
  private _blackCanvasStreamTrack?: MediaStreamTrack = undefined;
66
71
  private _inaudibleAudioStreamTrack?: MediaStreamTrack = undefined;
@@ -84,6 +89,7 @@ export class MediaManager extends Resource {
84
89
  width: VIDEO_WIDTH,
85
90
  height: VIDEO_HEIGHT,
86
91
  });
92
+
87
93
  this._state.videoTrack = this._blackCanvasStreamTrack;
88
94
  this._state.videoStream = new MediaStream();
89
95
  this._state.videoStream.addTrack(this._state.videoTrack);
@@ -136,6 +142,7 @@ export class MediaManager extends Resource {
136
142
  this._state.videoStream!.removeTrack(this._state.videoTrack!);
137
143
  this._state.videoTrack = await getUserMediaTrack('videoinput', { width: VIDEO_WIDTH, height: VIDEO_HEIGHT });
138
144
  this._state.videoStream!.addTrack(this._state.videoTrack);
145
+
139
146
  this._state.videoEnabled = true;
140
147
  this.stateUpdated.emit(this._state);
141
148
  this._pushTracksTask!.schedule();
@@ -225,7 +232,6 @@ export class MediaManager extends Resource {
225
232
  // Wait for cloudflare to process the track.
226
233
  await cancelWithContext(this._ctx, sleep(800));
227
234
  const trackNames = this._trackToReconcile;
228
-
229
235
  const tracksToPull = trackNames.filter(
230
236
  (name) => !this._state.pulledAudioTracks[name] && !this._state.pulledVideoStreams[name],
231
237
  );
@@ -248,7 +254,7 @@ export class MediaManager extends Resource {
248
254
  });
249
255
 
250
256
  // Pull new tracks.
251
- await Promise.all(tracksToPull.map((name) => this._pullTrack(name)));
257
+ const pullResults = await Promise.all(tracksToPull.map((name) => this._pullTrack(name)));
252
258
 
253
259
  // Close old tracks.
254
260
  await Promise.all([...audioTracksToClose, ...videoStreamsToClose].map(([_, { ctx }]) => ctx.dispose()));
@@ -257,7 +263,14 @@ export class MediaManager extends Resource {
257
263
  currentAudioTracks: Object.keys(this._state.pulledAudioTracks),
258
264
  currentVideoStreams: Object.keys(this._state.pulledVideoStreams),
259
265
  });
266
+
260
267
  this.stateUpdated.emit(this._state);
268
+ if (pullResults.some(({ shouldRetry }) => shouldRetry)) {
269
+ await cancelWithContext(this._ctx, sleep(RETRY_INTERVAL));
270
+ log.info('retrying pull tracks', { tracksToPull });
271
+ invariant(this._pullTracksTask);
272
+ this._pullTracksTask.schedule();
273
+ }
261
274
  }
262
275
 
263
276
  private async _pushTracks(): Promise<void> {
@@ -266,38 +279,46 @@ export class MediaManager extends Resource {
266
279
  }
267
280
 
268
281
  let updated = false;
269
- const [pushedVideoTrack, pushedAudioTrack, pushedScreenshareTrack] = await Promise.all([
270
- this._pushTrack(this._state.videoTrack, this._state.pushedVideoTrack, [
282
+ const [pushVideoResult, pushAudioResult, pushScreenshareResult] = await Promise.all([
283
+ this._maybePushTrack(this._state.videoTrack, this._state.pushedVideoTrack, [
271
284
  { maxFramerate: MAX_WEB_CAM_FRAMERATE, maxBitrate: MAX_WEB_CAM_BITRATE },
272
285
  ]),
273
- this._pushTrack(this._state.audioTrack, this._state.pushedAudioTrack, [{ networkPriority: 'high' }]),
274
- this._pushTrack(this._state.screenshareTrack, this._state.pushedScreenshareTrack),
286
+ this._maybePushTrack(this._state.audioTrack, this._state.pushedAudioTrack, [{ networkPriority: 'high' }]),
287
+ this._maybePushTrack(this._state.screenshareTrack, this._state.pushedScreenshareTrack),
275
288
  ]);
276
289
 
277
- if (pushedVideoTrack !== this._state.pushedVideoTrack) {
278
- this._state.pushedVideoTrack = pushedVideoTrack;
290
+ if (pushVideoResult.track !== this._state.pushedVideoTrack) {
291
+ this._state.pushedVideoTrack = pushVideoResult.track;
279
292
  updated = true;
280
293
  }
281
- if (pushedAudioTrack !== this._state.pushedAudioTrack) {
282
- this._state.pushedAudioTrack = pushedAudioTrack;
294
+ if (pushAudioResult.track !== this._state.pushedAudioTrack) {
295
+ this._state.pushedAudioTrack = pushAudioResult.track;
283
296
  updated = true;
284
297
  }
285
- if (pushedScreenshareTrack !== this._state.pushedScreenshareTrack) {
286
- this._state.pushedScreenshareTrack = pushedScreenshareTrack;
298
+ if (pushScreenshareResult.track !== this._state.pushedScreenshareTrack) {
299
+ this._state.pushedScreenshareTrack = pushScreenshareResult.track;
287
300
  updated = true;
288
301
  }
289
- if (!updated) {
290
- return;
302
+
303
+ const shouldRetry = pushVideoResult.shouldRetry || pushAudioResult.shouldRetry || pushScreenshareResult.shouldRetry;
304
+ if (updated) {
305
+ this.stateUpdated.emit(this._state);
291
306
  }
292
307
 
293
- this.stateUpdated.emit(this._state);
308
+ if (shouldRetry) {
309
+ await cancelWithContext(this._ctx, sleep(RETRY_INTERVAL));
310
+ log.info('retrying push tracks', { pushVideoResult, pushAudioResult, pushScreenshareResult });
311
+ invariant(this._pushTracksTask);
312
+ this._pushTracksTask.schedule();
313
+ }
294
314
  }
295
315
 
296
- private async _pullTrack(name: EncodedTrackName): Promise<void> {
316
+ private async _pullTrack(name: EncodedTrackName): Promise<{ shouldRetry: boolean }> {
297
317
  const ctx = this._ctx.derive();
298
318
  try {
299
319
  const trackData = TrackNameCodec.decode(name);
300
- const track = await this._state.peer!.pullTrack({ trackData, ctx });
320
+ // We need to set mid here to `undefined`, because mid is peer specific.
321
+ const track = await this._state.peer!.pullTrack({ trackData: { ...trackData, mid: undefined }, ctx });
301
322
  if (track?.readyState === 'ended') {
302
323
  throw new Error('Pulled track ended immediately');
303
324
  }
@@ -306,7 +327,7 @@ export class MediaManager extends Resource {
306
327
  case 'audio': {
307
328
  this._state.pulledAudioTracks[name] = { track, ctx };
308
329
  ctx.onDispose(() => delete this._state.pulledAudioTracks[name]);
309
- break;
330
+ return { shouldRetry: false };
310
331
  }
311
332
  case 'video': {
312
333
  const mediaStream = new MediaStream();
@@ -317,33 +338,41 @@ export class MediaManager extends Resource {
317
338
  track.stop();
318
339
  delete this._state.pulledVideoStreams[name];
319
340
  });
320
- break;
341
+ return { shouldRetry: false };
321
342
  }
322
343
  default:
323
344
  throw new Error(`Invalid track kind: ${track?.kind}`);
324
345
  }
325
346
  } catch (err) {
326
- log.verbose('failed to pull track', { err, name });
347
+ log.info('failed to pull track', { err, name });
327
348
  void ctx.dispose();
328
- await cancelWithContext(this._ctx, sleep(RETRY_INTERVAL));
329
- log.verbose('retrying pull track', { name });
330
- this._pullTracksTask!.schedule();
349
+ return { shouldRetry: true };
331
350
  }
332
351
  }
333
352
 
334
- private async _pushTrack(
353
+ private async _maybePushTrack(
335
354
  track?: MediaStreamTrack,
336
355
  previousTrack?: TrackObject,
337
356
  encodings?: RTCRtpEncodingParameters[],
338
- ): Promise<TrackObject | undefined> {
357
+ ): Promise<{ track?: TrackObject; shouldRetry?: boolean }> {
339
358
  if (!track && !previousTrack) {
340
- return;
359
+ return { track: undefined };
341
360
  }
342
361
 
343
- return this._state.peer!.pushTrack({
344
- track: track ?? null,
345
- previousTrack,
346
- encodings,
347
- });
362
+ const ctx = this._ctx.derive();
363
+ try {
364
+ return {
365
+ track: await this._state.peer!.pushTrack({
366
+ ctx,
367
+ track: track ?? null,
368
+ previousTrack,
369
+ encodings,
370
+ }),
371
+ };
372
+ } catch (err) {
373
+ log.info('failed to push track', { err, track, previousTrack, encodings });
374
+ void ctx.dispose();
375
+ return { shouldRetry: true };
376
+ }
348
377
  }
349
378
  }
@@ -2,6 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
+ import { invariant } from '@dxos/invariant';
5
6
  import { buf } from '@dxos/protocols/buf';
6
7
  import {
7
8
  type ActivitySchema,
@@ -61,10 +62,13 @@ export type EncodedTrackName = string & { __brand: 'EncodedTrackName' };
61
62
 
62
63
  export const TrackNameCodec = {
63
64
  encode: (trackData: TrackObject): EncodedTrackName => {
64
- return (trackData.sessionId + '/' + trackData.trackName) as EncodedTrackName;
65
+ invariant(trackData.sessionId);
66
+ invariant(trackData.trackName);
67
+ invariant(trackData.mid);
68
+ return (trackData.sessionId + '/' + trackData.trackName + '/' + trackData.mid) as EncodedTrackName;
65
69
  },
66
70
  decode: (name: EncodedTrackName): TrackObject => {
67
- const [sessionId, trackName] = name.split('/');
68
- return { sessionId, trackName, location: 'remote' };
71
+ const [sessionId, trackName, mid] = name.split('/');
72
+ return { sessionId, trackName, location: 'remote', mid };
69
73
  },
70
74
  };
@@ -2,7 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { PersistentLifecycle } from '@dxos/async';
5
+ import { PersistentLifecycle, Trigger, scheduleTask } from '@dxos/async';
6
6
  import { type Context, Resource } from '@dxos/context';
7
7
  import { invariant } from '@dxos/invariant';
8
8
  import { log } from '@dxos/log';
@@ -14,7 +14,6 @@ import {
14
14
  type TrackObject,
15
15
  type TracksResponse,
16
16
  } from '../types';
17
-
18
17
  import { HistoryCache } from './history-cache';
19
18
  import { BulkRequestDispatcher, FIFOScheduler } from './task-scheduling';
20
19
 
@@ -27,18 +26,20 @@ export type Session = {
27
26
 
28
27
  export type CallsServiceConfig = {
29
28
  apiBase: string;
30
- apiExtraParams?: string;
29
+ apiExtraProps?: string;
31
30
  iceServers?: RTCIceServer[];
32
31
  };
33
32
 
34
33
  export type HistoryRecord =
35
34
  | {
35
+ endpoint: string;
36
36
  type: 'request';
37
37
  time: string;
38
38
  method: string;
39
39
  body: any;
40
40
  }
41
41
  | {
42
+ endpoint: string;
42
43
  type: 'response';
43
44
  time: string;
44
45
  status: number;
@@ -116,7 +117,7 @@ export class CallsServicePeer extends Resource {
116
117
  });
117
118
  peerConnection.addEventListener('connectionstatechange', () => {
118
119
  if (peerConnection.connectionState === 'failed' || peerConnection.connectionState === 'closed') {
119
- log.warn('calls connection failed', { state: peerConnection.connectionState });
120
+ log.info('calls connection failed', { state: peerConnection.connectionState });
120
121
  void this._persistentLifecycle.scheduleRestart();
121
122
  }
122
123
  });
@@ -125,7 +126,7 @@ export class CallsServicePeer extends Resource {
125
126
  peerConnection.addEventListener('iceconnectionstatechange', () => {
126
127
  clearTimeout(iceTimeout);
127
128
  if (peerConnection.iceConnectionState === 'failed' || peerConnection.iceConnectionState === 'closed') {
128
- log.warn('calls connection to ICEs failed', { state: peerConnection.iceConnectionState });
129
+ log.info('calls connection to ICEs failed', { state: peerConnection.iceConnectionState });
129
130
  void this._persistentLifecycle.scheduleRestart();
130
131
  } else if (peerConnection.iceConnectionState === 'disconnected') {
131
132
  // TODO(mykola): we should start to inspect the connection stats from here on for
@@ -138,7 +139,7 @@ export class CallsServicePeer extends Resource {
138
139
  return;
139
140
  }
140
141
 
141
- log.warn('calls iceConnectionState timed out', { state: peerConnection.iceConnectionState, timeoutSeconds });
142
+ log.info('calls iceConnectionState timed out', { state: peerConnection.iceConnectionState, timeoutSeconds });
142
143
  void this._persistentLifecycle.scheduleRestart();
143
144
  }, timeoutSeconds * 1_000);
144
145
  }
@@ -155,6 +156,7 @@ export class CallsServicePeer extends Resource {
155
156
 
156
157
  private async _fetch<T extends ErrorResponse>(relativePath: string, requestInit?: RequestInit): Promise<T> {
157
158
  this.history.push({
159
+ endpoint: relativePath,
158
160
  type: 'request',
159
161
  time: new Date().toISOString(),
160
162
  method: requestInit?.method ?? 'GET',
@@ -170,6 +172,7 @@ export class CallsServicePeer extends Resource {
170
172
  try {
171
173
  const data = (await response.clone().json()) as T;
172
174
  this.history.push({
175
+ endpoint: relativePath,
173
176
  type: 'response',
174
177
  time: new Date().toISOString(),
175
178
  status: response.status,
@@ -183,6 +186,7 @@ export class CallsServicePeer extends Resource {
183
186
  } catch (error) {
184
187
  const text = await response.text();
185
188
  this.history.push({
189
+ endpoint: relativePath,
186
190
  type: 'response',
187
191
  time: new Date().toISOString(),
188
192
  status: response.status,
@@ -204,11 +208,11 @@ export class CallsServicePeer extends Resource {
204
208
  sessionId,
205
209
  trackName,
206
210
  }: {
211
+ ctx: Context;
207
212
  peerConnection: RTCPeerConnection;
208
213
  transceiver: RTCRtpTransceiver;
209
214
  sessionId: string;
210
215
  trackName: string;
211
- ctx?: Context;
212
216
  }): Promise<TrackObject | void> {
213
217
  log.verbose('pushing track ', trackName);
214
218
  const pushedTrackPromise = this.pushTrackDispatcher
@@ -246,9 +250,13 @@ export class CallsServicePeer extends Resource {
246
250
  };
247
251
  }),
248
252
  )
249
- .then(({ tracks }) => {
253
+ .then(async ({ tracks }) => {
250
254
  const trackData = tracks.find((t) => t.mid === transceiver.mid);
251
255
  if (trackData) {
256
+ // we wait for the transceiver to start sending data before we emit
257
+ // the track metadata to ensure that the track will be able to be
258
+ // pulled before making the metadata available to anyone else.
259
+ // await waitForTransceiverToSendData(ctx, transceiver);
252
260
  return {
253
261
  ...trackData,
254
262
  sessionId,
@@ -257,9 +265,6 @@ export class CallsServicePeer extends Resource {
257
265
  } else {
258
266
  log.error('missing track data');
259
267
  }
260
- })
261
- .catch((err) => {
262
- log.catch(err);
263
268
  });
264
269
 
265
270
  const onDispose = async () => {
@@ -281,8 +286,8 @@ export class CallsServicePeer extends Resource {
281
286
  previousTrack,
282
287
  }: {
283
288
  track: MediaStreamTrack | null;
289
+ ctx: Context;
284
290
  encodings?: RTCRtpEncodingParameters[];
285
- ctx?: Context;
286
291
  previousTrack?: TrackObject;
287
292
  }): Promise<TrackObject | undefined> {
288
293
  await this.waitUntilOpen();
@@ -405,7 +410,7 @@ export class CallsServicePeer extends Resource {
405
410
  })
406
411
  .catch((err) => log.catch(err));
407
412
  } else {
408
- log.warn('missing track info', { trackData, availableTracks: Array.from(trackMap.keys()) });
413
+ log.info('missing track info', { trackData, availableTracks: Array.from(trackMap.keys()) });
409
414
  }
410
415
  });
411
416
 
@@ -529,3 +534,49 @@ const peerConnectionIsConnected = async (peerConnection: RTCPeerConnection) => {
529
534
  await connected;
530
535
  }
531
536
  };
537
+
538
+ const INITIAL_DELAY = 50;
539
+ const MAX_DELAY = 500;
540
+ const MAX_RETRIES = 20;
541
+ const WAIT_FOR_DATA_TIMEOUT = 10_000;
542
+
543
+ const waitForTransceiverToSendData = async (ctx: Context, transceiver: RTCRtpTransceiver): Promise<void> => {
544
+ let delay = INITIAL_DELAY;
545
+ let checks = 0;
546
+ const waitForData = new Trigger();
547
+ ctx.onDispose(() => waitForData.throw(new Error('Transceiver was closed')));
548
+
549
+ const checkStats = async () => {
550
+ if (ctx.disposed) {
551
+ return;
552
+ }
553
+
554
+ try {
555
+ const stats = await transceiver.sender.getStats();
556
+ let dataFound = false;
557
+ stats.forEach((stat) => {
558
+ if (stat.type === 'outbound-rtp' && stat.bytesSent > 0) {
559
+ dataFound = true;
560
+ }
561
+ });
562
+
563
+ if (dataFound) {
564
+ waitForData.wake();
565
+ return;
566
+ }
567
+ } catch {
568
+ // Stats might not be available yet, continue checking
569
+ }
570
+ checks++;
571
+ if (checks > MAX_RETRIES) {
572
+ waitForData.throw(new Error('Transceiver did not send data'));
573
+ return;
574
+ }
575
+
576
+ delay = Math.min(delay * 2, MAX_DELAY); // Exponential backoff with max cap
577
+ scheduleTask(ctx, checkStats, delay);
578
+ };
579
+
580
+ void checkStats();
581
+ return waitForData.wait({ timeout: WAIT_FOR_DATA_TIMEOUT });
582
+ };