@dxos/plugin-thread 0.8.3 → 0.8.4-main.1f223c7

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 (320) hide show
  1. package/dist/lib/browser/ChannelContainer-4PYFOIDK.mjs +16 -0
  2. package/dist/lib/browser/ChatContainer-EXNNREYB.mjs +15 -0
  3. package/dist/lib/browser/{app-graph-builder-OY7R7EJP.mjs → app-graph-builder-FHAOPO57.mjs} +8 -8
  4. package/dist/lib/browser/app-graph-builder-FHAOPO57.mjs.map +7 -0
  5. package/dist/lib/browser/{call-manager-APQAZWHT.mjs → call-manager-RMPTWSTF.mjs} +6 -5
  6. package/dist/lib/browser/call-manager-RMPTWSTF.mjs.map +7 -0
  7. package/dist/lib/browser/{chunk-R5MDLUPC.mjs → chunk-4APCDRSH.mjs} +3 -3
  8. package/dist/lib/browser/{chunk-R5MDLUPC.mjs.map → chunk-4APCDRSH.mjs.map} +1 -1
  9. package/dist/lib/browser/{chunk-XZKBN3NS.mjs → chunk-7W7QK5ZP.mjs} +253 -250
  10. package/dist/lib/browser/chunk-7W7QK5ZP.mjs.map +7 -0
  11. package/dist/lib/browser/{chunk-IIUTBDVB.mjs → chunk-EV4JWI7L.mjs} +2 -2
  12. package/dist/lib/browser/chunk-G4CNILRR.mjs +23 -0
  13. package/dist/lib/browser/{chunk-6NBVNXTM.mjs.map → chunk-G4CNILRR.mjs.map} +3 -3
  14. package/dist/lib/browser/{chunk-JKQUJOTX.mjs → chunk-GERVMFQW.mjs} +2 -2
  15. package/dist/lib/browser/{chunk-AEXWNS6Z.mjs → chunk-KTWYVC5X.mjs} +34 -15
  16. package/dist/lib/browser/chunk-KTWYVC5X.mjs.map +7 -0
  17. package/dist/lib/browser/{chunk-TAFSCSUR.mjs → chunk-PBMNFG3B.mjs} +97 -72
  18. package/dist/lib/browser/chunk-PBMNFG3B.mjs.map +7 -0
  19. package/dist/lib/browser/chunk-RI3Z6MK3.mjs +181 -0
  20. package/dist/lib/browser/chunk-RI3Z6MK3.mjs.map +7 -0
  21. package/dist/lib/browser/chunk-XYUJXHYV.mjs +106 -0
  22. package/dist/lib/browser/chunk-XYUJXHYV.mjs.map +7 -0
  23. package/dist/lib/browser/{chunk-4H4A264L.mjs → chunk-ZCEU5K23.mjs} +490 -308
  24. package/dist/lib/browser/chunk-ZCEU5K23.mjs.map +7 -0
  25. package/dist/lib/browser/{chunk-PG5CTFKK.mjs → chunk-ZH2WPTNP.mjs} +226 -158
  26. package/dist/lib/browser/chunk-ZH2WPTNP.mjs.map +7 -0
  27. package/dist/lib/browser/index.mjs +49 -44
  28. package/dist/lib/browser/index.mjs.map +3 -3
  29. package/dist/lib/browser/{intent-resolver-FK2MDVDT.mjs → intent-resolver-J7OCP2P6.mjs} +90 -16
  30. package/dist/lib/browser/intent-resolver-J7OCP2P6.mjs.map +7 -0
  31. package/dist/lib/browser/{markdown-TE5SWWNJ.mjs → markdown-Z677YORA.mjs} +8 -8
  32. package/dist/lib/browser/markdown-Z677YORA.mjs.map +7 -0
  33. package/dist/lib/browser/meta.json +1 -1
  34. package/dist/lib/browser/react-root-XKOD4KRB.mjs +28 -0
  35. package/dist/lib/browser/{react-surface-VXUJKSOG.mjs → react-surface-GVGZRBDK.mjs} +12 -11
  36. package/dist/lib/browser/react-surface-GVGZRBDK.mjs.map +7 -0
  37. package/dist/lib/browser/{settings-RB2RSLXV.mjs → settings-GRKEID73.mjs} +4 -4
  38. package/dist/lib/browser/{state-RKL5MSDP.mjs → state-2T4KDWBX.mjs} +4 -4
  39. package/dist/lib/browser/{state-RKL5MSDP.mjs.map → state-2T4KDWBX.mjs.map} +2 -2
  40. package/dist/lib/browser/toolkit-KUPIIFC6.mjs +80 -0
  41. package/dist/lib/browser/toolkit-KUPIIFC6.mjs.map +7 -0
  42. package/dist/lib/browser/types/index.mjs +2 -2
  43. package/dist/lib/node-esm/ChannelContainer-KQQEZWUN.mjs +17 -0
  44. package/dist/lib/node-esm/{ChatContainer-F6CSADV7.mjs → ChatContainer-QVQKFBWA.mjs} +6 -5
  45. package/dist/lib/node-esm/{app-graph-builder-BAHBHYWI.mjs → app-graph-builder-XEYWX5FC.mjs} +8 -8
  46. package/dist/lib/node-esm/app-graph-builder-XEYWX5FC.mjs.map +7 -0
  47. package/dist/lib/node-esm/{call-manager-UUYXLF4T.mjs → call-manager-QAREJFVX.mjs} +6 -5
  48. package/dist/lib/node-esm/call-manager-QAREJFVX.mjs.map +7 -0
  49. package/dist/lib/node-esm/chunk-2V3WSLUZ.mjs +108 -0
  50. package/dist/lib/node-esm/chunk-2V3WSLUZ.mjs.map +7 -0
  51. package/dist/lib/node-esm/chunk-4T45PCKP.mjs +25 -0
  52. package/dist/lib/node-esm/{chunk-O63QJPQX.mjs.map → chunk-4T45PCKP.mjs.map} +3 -3
  53. package/dist/lib/node-esm/{chunk-PGRP3O4O.mjs → chunk-57XR3LEF.mjs} +2 -2
  54. package/dist/lib/node-esm/{chunk-P6RLFCNT.mjs → chunk-DKCQCENK.mjs} +97 -72
  55. package/dist/lib/node-esm/chunk-DKCQCENK.mjs.map +7 -0
  56. package/dist/lib/node-esm/{chunk-ESQC6SYE.mjs → chunk-GRLRWTRU.mjs} +2 -2
  57. package/dist/lib/node-esm/chunk-JNPKMT7O.mjs +182 -0
  58. package/dist/lib/node-esm/chunk-JNPKMT7O.mjs.map +7 -0
  59. package/dist/lib/node-esm/{chunk-UZWVVFT3.mjs → chunk-LE2LIYGX.mjs} +226 -158
  60. package/dist/lib/node-esm/chunk-LE2LIYGX.mjs.map +7 -0
  61. package/dist/lib/node-esm/{chunk-UJMPYKT3.mjs → chunk-P6E247RF.mjs} +34 -15
  62. package/dist/lib/node-esm/chunk-P6E247RF.mjs.map +7 -0
  63. package/dist/lib/node-esm/{chunk-K4KAUOKT.mjs → chunk-PYTVBN5J.mjs} +3 -3
  64. package/dist/lib/node-esm/{chunk-K4KAUOKT.mjs.map → chunk-PYTVBN5J.mjs.map} +1 -1
  65. package/dist/lib/node-esm/{chunk-2RNIPFDA.mjs → chunk-SNKFZQST.mjs} +253 -250
  66. package/dist/lib/node-esm/chunk-SNKFZQST.mjs.map +7 -0
  67. package/dist/lib/node-esm/{chunk-WXNPD542.mjs → chunk-TIPIOH2J.mjs} +489 -308
  68. package/dist/lib/node-esm/chunk-TIPIOH2J.mjs.map +7 -0
  69. package/dist/lib/node-esm/index.mjs +49 -44
  70. package/dist/lib/node-esm/index.mjs.map +3 -3
  71. package/dist/lib/node-esm/{intent-resolver-BU73VYW3.mjs → intent-resolver-SR2LW4HF.mjs} +90 -16
  72. package/dist/lib/node-esm/intent-resolver-SR2LW4HF.mjs.map +7 -0
  73. package/dist/lib/node-esm/{markdown-HJUWNBLS.mjs → markdown-FL4IXLRP.mjs} +8 -8
  74. package/dist/lib/node-esm/markdown-FL4IXLRP.mjs.map +7 -0
  75. package/dist/lib/node-esm/meta.json +1 -1
  76. package/dist/lib/node-esm/{react-root-RUXOAQNW.mjs → react-root-4JWDRIQB.mjs} +12 -11
  77. package/dist/lib/{browser/react-root-NK3A4VG7.mjs.map → node-esm/react-root-4JWDRIQB.mjs.map} +1 -1
  78. package/dist/lib/node-esm/{react-surface-ELXFYKP6.mjs → react-surface-WLQUVRAX.mjs} +12 -11
  79. package/dist/lib/node-esm/react-surface-WLQUVRAX.mjs.map +7 -0
  80. package/dist/lib/node-esm/{settings-EA7DFSM6.mjs → settings-F2ODVNNW.mjs} +4 -4
  81. package/dist/lib/node-esm/{state-6AUTNROZ.mjs → state-62TQKQVB.mjs} +4 -4
  82. package/dist/lib/node-esm/{state-6AUTNROZ.mjs.map → state-62TQKQVB.mjs.map} +2 -2
  83. package/dist/lib/node-esm/toolkit-KZIS7G36.mjs +81 -0
  84. package/dist/lib/node-esm/toolkit-KZIS7G36.mjs.map +7 -0
  85. package/dist/lib/node-esm/types/index.mjs +2 -2
  86. package/dist/types/src/ThreadPlugin.d.ts.map +1 -1
  87. package/dist/types/src/calls/call-manager.d.ts +1 -1
  88. package/dist/types/src/calls/call-manager.d.ts.map +1 -1
  89. package/dist/types/src/calls/call-swarm-synchronizer.d.ts.map +1 -1
  90. package/dist/types/src/calls/media-manager.d.ts +1 -1
  91. package/dist/types/src/calls/media-manager.d.ts.map +1 -1
  92. package/dist/types/src/calls/types.d.ts +1 -1
  93. package/dist/types/src/calls/types.d.ts.map +1 -1
  94. package/dist/types/src/calls/util/calls-service.d.ts +8 -3
  95. package/dist/types/src/calls/util/calls-service.d.ts.map +1 -1
  96. package/dist/types/src/calls/util/stub-media-streams.d.ts.map +1 -1
  97. package/dist/types/src/calls-service.stories.d.ts +24 -0
  98. package/dist/types/src/calls-service.stories.d.ts.map +1 -0
  99. package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -1
  100. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  101. package/dist/types/src/capabilities/call-manager.d.ts +1 -1
  102. package/dist/types/src/capabilities/call-manager.d.ts.map +1 -1
  103. package/dist/types/src/capabilities/capabilities.d.ts +2 -2
  104. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  105. package/dist/types/src/capabilities/index.d.ts +11 -10
  106. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  107. package/dist/types/src/capabilities/intent-resolver.d.ts +1 -1
  108. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  109. package/dist/types/src/capabilities/markdown.d.ts +1 -1
  110. package/dist/types/src/capabilities/markdown.d.ts.map +1 -1
  111. package/dist/types/src/capabilities/react-root.d.ts +2 -2
  112. package/dist/types/src/capabilities/react-surface.d.ts +1 -1
  113. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  114. package/dist/types/src/capabilities/settings.d.ts +1 -1
  115. package/dist/types/src/capabilities/state.d.ts +2 -2
  116. package/dist/types/src/capabilities/state.d.ts.map +1 -1
  117. package/dist/types/src/capabilities/toolkit.d.ts +5 -0
  118. package/dist/types/src/capabilities/toolkit.d.ts.map +1 -0
  119. package/dist/types/src/components/Call/Call.d.ts.map +1 -1
  120. package/dist/types/src/components/Call/Toolbar.d.ts.map +1 -1
  121. package/dist/types/src/components/CallDebugPanel.d.ts +7 -0
  122. package/dist/types/src/components/CallDebugPanel.d.ts.map +1 -1
  123. package/dist/types/src/components/CallSidebar.d.ts.map +1 -1
  124. package/dist/types/src/components/ChannelContainer.d.ts.map +1 -1
  125. package/dist/types/src/components/ChannelContainer.stories.d.ts +89 -4
  126. package/dist/types/src/components/ChannelContainer.stories.d.ts.map +1 -1
  127. package/dist/types/src/components/Chat.stories.d.ts +90 -3
  128. package/dist/types/src/components/Chat.stories.d.ts.map +1 -1
  129. package/dist/types/src/components/ChatContainer.d.ts +2 -2
  130. package/dist/types/src/components/ChatContainer.d.ts.map +1 -1
  131. package/dist/types/src/components/Comments.stories.d.ts +156 -3
  132. package/dist/types/src/components/Comments.stories.d.ts.map +1 -1
  133. package/dist/types/src/components/CommentsContainer.d.ts +4 -4
  134. package/dist/types/src/components/CommentsContainer.d.ts.map +1 -1
  135. package/dist/types/src/components/CommentsThreadContainer.d.ts +14 -0
  136. package/dist/types/src/components/CommentsThreadContainer.d.ts.map +1 -0
  137. package/dist/types/src/components/Lobby/Lobby.d.ts.map +1 -1
  138. package/dist/types/src/components/Media/VideoObject.d.ts +1 -1
  139. package/dist/types/src/components/Media/VideoObject.stories.d.ts +15 -3
  140. package/dist/types/src/components/Media/VideoObject.stories.d.ts.map +1 -1
  141. package/dist/types/src/components/MessageContainer.d.ts +4 -1
  142. package/dist/types/src/components/MessageContainer.d.ts.map +1 -1
  143. package/dist/types/src/components/Participant/Participant.d.ts.map +1 -1
  144. package/dist/types/src/components/Participant/ParticipantGrid.d.ts.map +1 -1
  145. package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts +154 -2
  146. package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts.map +1 -1
  147. package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts +156 -3
  148. package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts.map +1 -1
  149. package/dist/types/src/components/ResponsiveGrid/ResponsiveGridItem.d.ts.map +1 -1
  150. package/dist/types/src/components/ThreadComplementary.d.ts.map +1 -1
  151. package/dist/types/src/components/command-extension.d.ts.map +1 -1
  152. package/dist/types/src/components/index.d.ts +1 -1
  153. package/dist/types/src/components/index.d.ts.map +1 -1
  154. package/dist/types/src/components/testing.d.ts +1 -0
  155. package/dist/types/src/components/testing.d.ts.map +1 -1
  156. package/dist/types/src/extensions/threads.d.ts +2 -2
  157. package/dist/types/src/extensions/threads.d.ts.map +1 -1
  158. package/dist/types/src/hooks/index.d.ts +3 -0
  159. package/dist/types/src/hooks/index.d.ts.map +1 -1
  160. package/dist/types/src/hooks/useBlackCanvasStreamTrack.d.ts +2 -0
  161. package/dist/types/src/hooks/useBlackCanvasStreamTrack.d.ts.map +1 -0
  162. package/dist/types/src/hooks/useInaudibleAudioStreamTrack.d.ts +2 -0
  163. package/dist/types/src/hooks/useInaudibleAudioStreamTrack.d.ts.map +1 -0
  164. package/dist/types/src/hooks/useVideoStreamTrack.d.ts +3 -0
  165. package/dist/types/src/hooks/useVideoStreamTrack.d.ts.map +1 -0
  166. package/dist/types/src/testing/stories.d.ts.map +1 -1
  167. package/dist/types/src/translations.d.ts +76 -194
  168. package/dist/types/src/translations.d.ts.map +1 -1
  169. package/dist/types/src/types/schema.d.ts +125 -81
  170. package/dist/types/src/types/schema.d.ts.map +1 -1
  171. package/dist/types/src/types/types.d.ts +270 -139
  172. package/dist/types/src/types/types.d.ts.map +1 -1
  173. package/dist/types/src/util.d.ts +17 -2
  174. package/dist/types/src/util.d.ts.map +1 -1
  175. package/dist/types/tsconfig.tsbuildinfo +1 -1
  176. package/package.json +56 -53
  177. package/src/ThreadPlugin.tsx +16 -24
  178. package/src/calls/call-manager.ts +8 -4
  179. package/src/calls/call-swarm-synchronizer.ts +1 -1
  180. package/src/calls/media-manager.ts +70 -37
  181. package/src/calls/types.ts +8 -4
  182. package/src/calls/util/calls-service.ts +72 -18
  183. package/src/calls/util/stub-media-streams.ts +62 -8
  184. package/src/calls-service.stories.tsx +232 -0
  185. package/src/capabilities/app-graph-builder.ts +8 -5
  186. package/src/capabilities/call-manager.ts +3 -2
  187. package/src/capabilities/capabilities.ts +2 -2
  188. package/src/capabilities/index.ts +1 -0
  189. package/src/capabilities/intent-resolver.ts +60 -8
  190. package/src/capabilities/markdown.ts +4 -3
  191. package/src/capabilities/react-surface.tsx +5 -4
  192. package/src/capabilities/state.ts +2 -1
  193. package/src/capabilities/toolkit.ts +78 -0
  194. package/src/components/Call/Call.tsx +4 -3
  195. package/src/components/Call/Toolbar.tsx +8 -8
  196. package/src/components/CallDebugPanel.tsx +110 -51
  197. package/src/components/CallSidebar.tsx +2 -1
  198. package/src/components/ChannelContainer.stories.tsx +11 -10
  199. package/src/components/ChannelContainer.tsx +13 -11
  200. package/src/components/Chat.stories.tsx +29 -27
  201. package/src/components/ChatContainer.tsx +20 -15
  202. package/src/components/Comments.stories.tsx +52 -41
  203. package/src/components/CommentsContainer.tsx +17 -11
  204. package/src/components/{CommentContainer.tsx → CommentsThreadContainer.tsx} +53 -82
  205. package/src/components/Lobby/Lobby.tsx +1 -1
  206. package/src/components/Media/VideoObject.stories.tsx +30 -27
  207. package/src/components/MessageContainer.tsx +65 -47
  208. package/src/components/Participant/Participant.tsx +13 -7
  209. package/src/components/Participant/ParticipantGrid.tsx +2 -1
  210. package/src/components/ResponsiveGrid/ResponsiveContainer.stories.tsx +7 -6
  211. package/src/components/ResponsiveGrid/ResponsiveGrid.stories.tsx +42 -39
  212. package/src/components/ResponsiveGrid/ResponsiveGrid.tsx +1 -1
  213. package/src/components/ResponsiveGrid/ResponsiveGridItem.tsx +4 -4
  214. package/src/components/ThreadComplementary.tsx +40 -10
  215. package/src/components/ThreadSettings.tsx +4 -4
  216. package/src/components/command-extension.ts +5 -2
  217. package/src/components/index.ts +1 -1
  218. package/src/components/testing.ts +24 -2
  219. package/src/extensions/threads.ts +6 -6
  220. package/src/hooks/index.ts +3 -0
  221. package/src/hooks/useBlackCanvasStreamTrack.tsx +27 -0
  222. package/src/hooks/useDebugMode.ts +1 -1
  223. package/src/hooks/useInaudibleAudioStreamTrack.tsx +27 -0
  224. package/src/hooks/useVideoStreamTrack.tsx +36 -0
  225. package/src/testing/stories.ts +7 -3
  226. package/src/translations.ts +14 -9
  227. package/src/types/types.ts +28 -11
  228. package/src/typings/peermetrics-webrtc-stats.d.ts +17 -1
  229. package/src/typings.d.ts +8 -0
  230. package/dist/lib/browser/ChannelContainer-PKFBVENP.mjs +0 -15
  231. package/dist/lib/browser/ChatContainer-RSOKYAMK.mjs +0 -14
  232. package/dist/lib/browser/app-graph-builder-OY7R7EJP.mjs.map +0 -7
  233. package/dist/lib/browser/call-manager-APQAZWHT.mjs.map +0 -7
  234. package/dist/lib/browser/chunk-4H4A264L.mjs.map +0 -7
  235. package/dist/lib/browser/chunk-5P5BH5GE.mjs +0 -88
  236. package/dist/lib/browser/chunk-5P5BH5GE.mjs.map +0 -7
  237. package/dist/lib/browser/chunk-6NBVNXTM.mjs +0 -21
  238. package/dist/lib/browser/chunk-AEXWNS6Z.mjs.map +0 -7
  239. package/dist/lib/browser/chunk-PG5CTFKK.mjs.map +0 -7
  240. package/dist/lib/browser/chunk-TAFSCSUR.mjs.map +0 -7
  241. package/dist/lib/browser/chunk-XZKBN3NS.mjs.map +0 -7
  242. package/dist/lib/browser/intent-resolver-FK2MDVDT.mjs.map +0 -7
  243. package/dist/lib/browser/markdown-TE5SWWNJ.mjs.map +0 -7
  244. package/dist/lib/browser/react-root-NK3A4VG7.mjs +0 -27
  245. package/dist/lib/browser/react-surface-VXUJKSOG.mjs.map +0 -7
  246. package/dist/lib/node/ChannelContainer-YS5YT2ML.cjs +0 -36
  247. package/dist/lib/node/ChannelContainer-YS5YT2ML.cjs.map +0 -7
  248. package/dist/lib/node/ChatContainer-GCOM3M56.cjs +0 -35
  249. package/dist/lib/node/ChatContainer-GCOM3M56.cjs.map +0 -7
  250. package/dist/lib/node/app-graph-builder-PBHJNDQY.cjs +0 -179
  251. package/dist/lib/node/app-graph-builder-PBHJNDQY.cjs.map +0 -7
  252. package/dist/lib/node/call-manager-HV2XJW5O.cjs +0 -37
  253. package/dist/lib/node/call-manager-HV2XJW5O.cjs.map +0 -7
  254. package/dist/lib/node/chunk-44I33JDT.cjs +0 -1731
  255. package/dist/lib/node/chunk-44I33JDT.cjs.map +0 -7
  256. package/dist/lib/node/chunk-4YSNVPWU.cjs +0 -37
  257. package/dist/lib/node/chunk-4YSNVPWU.cjs.map +0 -7
  258. package/dist/lib/node/chunk-E3WBZTTI.cjs +0 -371
  259. package/dist/lib/node/chunk-E3WBZTTI.cjs.map +0 -7
  260. package/dist/lib/node/chunk-ERG7G6FF.cjs +0 -59
  261. package/dist/lib/node/chunk-ERG7G6FF.cjs.map +0 -7
  262. package/dist/lib/node/chunk-FUXJAVFZ.cjs +0 -108
  263. package/dist/lib/node/chunk-FUXJAVFZ.cjs.map +0 -7
  264. package/dist/lib/node/chunk-HLMCEE5K.cjs +0 -41
  265. package/dist/lib/node/chunk-HLMCEE5K.cjs.map +0 -7
  266. package/dist/lib/node/chunk-IP533AMV.cjs +0 -554
  267. package/dist/lib/node/chunk-IP533AMV.cjs.map +0 -7
  268. package/dist/lib/node/chunk-LR5NENBE.cjs +0 -54
  269. package/dist/lib/node/chunk-LR5NENBE.cjs.map +0 -7
  270. package/dist/lib/node/chunk-UM36TPCT.cjs +0 -984
  271. package/dist/lib/node/chunk-UM36TPCT.cjs.map +0 -7
  272. package/dist/lib/node/chunk-ZGDN3XBR.cjs +0 -149
  273. package/dist/lib/node/chunk-ZGDN3XBR.cjs.map +0 -7
  274. package/dist/lib/node/index.cjs +0 -310
  275. package/dist/lib/node/index.cjs.map +0 -7
  276. package/dist/lib/node/intent-resolver-SYSJ5SJG.cjs +0 -363
  277. package/dist/lib/node/intent-resolver-SYSJ5SJG.cjs.map +0 -7
  278. package/dist/lib/node/markdown-GQIPJS2F.cjs +0 -178
  279. package/dist/lib/node/markdown-GQIPJS2F.cjs.map +0 -7
  280. package/dist/lib/node/meta.json +0 -1
  281. package/dist/lib/node/react-root-6HHDMULJ.cjs +0 -51
  282. package/dist/lib/node/react-root-6HHDMULJ.cjs.map +0 -7
  283. package/dist/lib/node/react-surface-NBH42NN2.cjs +0 -122
  284. package/dist/lib/node/react-surface-NBH42NN2.cjs.map +0 -7
  285. package/dist/lib/node/settings-4LQSFEDK.cjs +0 -36
  286. package/dist/lib/node/settings-4LQSFEDK.cjs.map +0 -7
  287. package/dist/lib/node/state-IY5XX3H2.cjs +0 -50
  288. package/dist/lib/node/state-IY5XX3H2.cjs.map +0 -7
  289. package/dist/lib/node/types/index.cjs +0 -38
  290. package/dist/lib/node/types/index.cjs.map +0 -7
  291. package/dist/lib/node-esm/ChannelContainer-O4QJII2P.mjs +0 -16
  292. package/dist/lib/node-esm/app-graph-builder-BAHBHYWI.mjs.map +0 -7
  293. package/dist/lib/node-esm/call-manager-UUYXLF4T.mjs.map +0 -7
  294. package/dist/lib/node-esm/chunk-2RNIPFDA.mjs.map +0 -7
  295. package/dist/lib/node-esm/chunk-O3V45YJP.mjs +0 -90
  296. package/dist/lib/node-esm/chunk-O3V45YJP.mjs.map +0 -7
  297. package/dist/lib/node-esm/chunk-O63QJPQX.mjs +0 -23
  298. package/dist/lib/node-esm/chunk-P6RLFCNT.mjs.map +0 -7
  299. package/dist/lib/node-esm/chunk-UJMPYKT3.mjs.map +0 -7
  300. package/dist/lib/node-esm/chunk-UZWVVFT3.mjs.map +0 -7
  301. package/dist/lib/node-esm/chunk-WXNPD542.mjs.map +0 -7
  302. package/dist/lib/node-esm/intent-resolver-BU73VYW3.mjs.map +0 -7
  303. package/dist/lib/node-esm/markdown-HJUWNBLS.mjs.map +0 -7
  304. package/dist/lib/node-esm/react-surface-ELXFYKP6.mjs.map +0 -7
  305. package/dist/types/src/components/CommentContainer.d.ts +0 -13
  306. package/dist/types/src/components/CommentContainer.d.ts.map +0 -1
  307. package/dist/types/src/peers.stories.d.ts +0 -11
  308. package/dist/types/src/peers.stories.d.ts.map +0 -1
  309. package/src/peers.stories.tsx +0 -189
  310. /package/dist/lib/browser/{ChannelContainer-PKFBVENP.mjs.map → ChannelContainer-4PYFOIDK.mjs.map} +0 -0
  311. /package/dist/lib/browser/{ChatContainer-RSOKYAMK.mjs.map → ChatContainer-EXNNREYB.mjs.map} +0 -0
  312. /package/dist/lib/browser/{chunk-IIUTBDVB.mjs.map → chunk-EV4JWI7L.mjs.map} +0 -0
  313. /package/dist/lib/browser/{chunk-JKQUJOTX.mjs.map → chunk-GERVMFQW.mjs.map} +0 -0
  314. /package/dist/lib/{node-esm/react-root-RUXOAQNW.mjs.map → browser/react-root-XKOD4KRB.mjs.map} +0 -0
  315. /package/dist/lib/browser/{settings-RB2RSLXV.mjs.map → settings-GRKEID73.mjs.map} +0 -0
  316. /package/dist/lib/node-esm/{ChannelContainer-O4QJII2P.mjs.map → ChannelContainer-KQQEZWUN.mjs.map} +0 -0
  317. /package/dist/lib/node-esm/{ChatContainer-F6CSADV7.mjs.map → ChatContainer-QVQKFBWA.mjs.map} +0 -0
  318. /package/dist/lib/node-esm/{chunk-PGRP3O4O.mjs.map → chunk-57XR3LEF.mjs.map} +0 -0
  319. /package/dist/lib/node-esm/{chunk-ESQC6SYE.mjs.map → chunk-GRLRWTRU.mjs.map} +0 -0
  320. /package/dist/lib/node-esm/{settings-EA7DFSM6.mjs.map → settings-F2ODVNNW.mjs.map} +0 -0
@@ -2,21 +2,22 @@
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';
9
9
 
10
- import { HistoryCache } from './history-cache';
11
- import { BulkRequestDispatcher, FIFOScheduler } from './task-scheduling';
12
10
  import {
13
- type SessionResponse,
14
11
  type ErrorResponse,
15
12
  type RenegotiationResponse,
13
+ type SessionResponse,
16
14
  type TrackObject,
17
15
  type TracksResponse,
18
16
  } from '../types';
19
17
 
18
+ import { HistoryCache } from './history-cache';
19
+ import { BulkRequestDispatcher, FIFOScheduler } from './task-scheduling';
20
+
20
21
  const NETWORK_TIMEOUT = 5_000;
21
22
 
22
23
  export type Session = {
@@ -32,12 +33,14 @@ export type CallsServiceConfig = {
32
33
 
33
34
  export type HistoryRecord =
34
35
  | {
36
+ endpoint: string;
35
37
  type: 'request';
36
38
  time: string;
37
39
  method: string;
38
40
  body: any;
39
41
  }
40
42
  | {
43
+ endpoint: string;
41
44
  type: 'response';
42
45
  time: string;
43
46
  status: number;
@@ -73,7 +76,10 @@ export class CallsServicePeer extends Resource {
73
76
  pullTrackDispatcher = new BulkRequestDispatcher<
74
77
  TrackObject,
75
78
  {
76
- trackMap: Map<TrackObject, { resolvedTrack: Promise<MediaStreamTrack>; mid: string }>;
79
+ /**
80
+ * trackName -> { resolvedTrack, mid }
81
+ */
82
+ trackMap: Map<string, { resolvedTrack: Promise<MediaStreamTrack>; mid: string }>;
77
83
  }
78
84
  >(32);
79
85
 
@@ -112,7 +118,7 @@ export class CallsServicePeer extends Resource {
112
118
  });
113
119
  peerConnection.addEventListener('connectionstatechange', () => {
114
120
  if (peerConnection.connectionState === 'failed' || peerConnection.connectionState === 'closed') {
115
- log.warn('calls connection failed', { state: peerConnection.connectionState });
121
+ log.info('calls connection failed', { state: peerConnection.connectionState });
116
122
  void this._persistentLifecycle.scheduleRestart();
117
123
  }
118
124
  });
@@ -121,7 +127,7 @@ export class CallsServicePeer extends Resource {
121
127
  peerConnection.addEventListener('iceconnectionstatechange', () => {
122
128
  clearTimeout(iceTimeout);
123
129
  if (peerConnection.iceConnectionState === 'failed' || peerConnection.iceConnectionState === 'closed') {
124
- log.warn('calls connection to ICEs failed', { state: peerConnection.iceConnectionState });
130
+ log.info('calls connection to ICEs failed', { state: peerConnection.iceConnectionState });
125
131
  void this._persistentLifecycle.scheduleRestart();
126
132
  } else if (peerConnection.iceConnectionState === 'disconnected') {
127
133
  // TODO(mykola): we should start to inspect the connection stats from here on for
@@ -134,7 +140,7 @@ export class CallsServicePeer extends Resource {
134
140
  return;
135
141
  }
136
142
 
137
- log.warn('calls iceConnectionState timed out', { state: peerConnection.iceConnectionState, timeoutSeconds });
143
+ log.info('calls iceConnectionState timed out', { state: peerConnection.iceConnectionState, timeoutSeconds });
138
144
  void this._persistentLifecycle.scheduleRestart();
139
145
  }, timeoutSeconds * 1_000);
140
146
  }
@@ -151,6 +157,7 @@ export class CallsServicePeer extends Resource {
151
157
 
152
158
  private async _fetch<T extends ErrorResponse>(relativePath: string, requestInit?: RequestInit): Promise<T> {
153
159
  this.history.push({
160
+ endpoint: relativePath,
154
161
  type: 'request',
155
162
  time: new Date().toISOString(),
156
163
  method: requestInit?.method ?? 'GET',
@@ -166,6 +173,7 @@ export class CallsServicePeer extends Resource {
166
173
  try {
167
174
  const data = (await response.clone().json()) as T;
168
175
  this.history.push({
176
+ endpoint: relativePath,
169
177
  type: 'response',
170
178
  time: new Date().toISOString(),
171
179
  status: response.status,
@@ -179,6 +187,7 @@ export class CallsServicePeer extends Resource {
179
187
  } catch (error) {
180
188
  const text = await response.text();
181
189
  this.history.push({
190
+ endpoint: relativePath,
182
191
  type: 'response',
183
192
  time: new Date().toISOString(),
184
193
  status: response.status,
@@ -200,11 +209,11 @@ export class CallsServicePeer extends Resource {
200
209
  sessionId,
201
210
  trackName,
202
211
  }: {
212
+ ctx: Context;
203
213
  peerConnection: RTCPeerConnection;
204
214
  transceiver: RTCRtpTransceiver;
205
215
  sessionId: string;
206
216
  trackName: string;
207
- ctx?: Context;
208
217
  }): Promise<TrackObject | void> {
209
218
  log.verbose('pushing track ', trackName);
210
219
  const pushedTrackPromise = this.pushTrackDispatcher
@@ -242,9 +251,13 @@ export class CallsServicePeer extends Resource {
242
251
  };
243
252
  }),
244
253
  )
245
- .then(({ tracks }) => {
254
+ .then(async ({ tracks }) => {
246
255
  const trackData = tracks.find((t) => t.mid === transceiver.mid);
247
256
  if (trackData) {
257
+ // we wait for the transceiver to start sending data before we emit
258
+ // the track metadata to ensure that the track will be able to be
259
+ // pulled before making the metadata available to anyone else.
260
+ // await waitForTransceiverToSendData(ctx, transceiver);
248
261
  return {
249
262
  ...trackData,
250
263
  sessionId,
@@ -253,9 +266,6 @@ export class CallsServicePeer extends Resource {
253
266
  } else {
254
267
  log.error('missing track data');
255
268
  }
256
- })
257
- .catch((err) => {
258
- log.catch(err);
259
269
  });
260
270
 
261
271
  const onDispose = async () => {
@@ -277,8 +287,8 @@ export class CallsServicePeer extends Resource {
277
287
  previousTrack,
278
288
  }: {
279
289
  track: MediaStreamTrack | null;
290
+ ctx: Context;
280
291
  encodings?: RTCRtpEncodingParameters[];
281
- ctx?: Context;
282
292
  previousTrack?: TrackObject;
283
293
  }): Promise<TrackObject | undefined> {
284
294
  await this.waitUntilOpen();
@@ -354,14 +364,14 @@ export class CallsServicePeer extends Resource {
354
364
  );
355
365
 
356
366
  if (pulledTrackData && pulledTrackData.mid) {
357
- acc.set(track, {
367
+ acc.set(track.trackName!, {
358
368
  mid: pulledTrackData.mid,
359
369
  resolvedTrack: resolveTrack(peerConnection, (t) => t.mid === pulledTrackData.mid),
360
370
  });
361
371
  }
362
372
 
363
373
  return acc;
364
- }, new Map<TrackObject, { resolvedTrack: Promise<MediaStreamTrack>; mid: string }>());
374
+ }, new Map<string, { resolvedTrack: Promise<MediaStreamTrack>; mid: string }>());
365
375
 
366
376
  if (newTrackResponse.requiresImmediateRenegotiation) {
367
377
  await peerConnection.setRemoteDescription(new RTCSessionDescription(newTrackResponse.sessionDescription));
@@ -392,7 +402,7 @@ export class CallsServicePeer extends Resource {
392
402
  }),
393
403
  )
394
404
  .then(({ trackMap }) => {
395
- const trackInfo = trackMap.get(trackData);
405
+ const trackInfo = trackMap.get(trackData.trackName!);
396
406
  if (trackInfo) {
397
407
  return trackInfo.resolvedTrack
398
408
  .then((track) => {
@@ -401,7 +411,7 @@ export class CallsServicePeer extends Resource {
401
411
  })
402
412
  .catch((err) => log.catch(err));
403
413
  } else {
404
- log.error('missing track info');
414
+ log.info('missing track info', { trackData, availableTracks: Array.from(trackMap.keys()) });
405
415
  }
406
416
  });
407
417
 
@@ -525,3 +535,47 @@ const peerConnectionIsConnected = async (peerConnection: RTCPeerConnection) => {
525
535
  await connected;
526
536
  }
527
537
  };
538
+
539
+ const INITIAL_DELAY = 50;
540
+ const MAX_DELAY = 500;
541
+ const MAX_RETRIES = 20;
542
+ const WAIT_FOR_DATA_TIMEOUT = 10_000;
543
+
544
+ const waitForTransceiverToSendData = async (ctx: Context, transceiver: RTCRtpTransceiver): Promise<void> => {
545
+ let delay = INITIAL_DELAY;
546
+ let checks = 0;
547
+ const waitForData = new Trigger();
548
+ ctx.onDispose(() => waitForData.throw(new Error('Transceiver was closed')));
549
+
550
+ const checkStats = async () => {
551
+ if (ctx.disposed) return;
552
+
553
+ try {
554
+ const stats = await transceiver.sender.getStats();
555
+ let dataFound = false;
556
+ stats.forEach((stat) => {
557
+ if (stat.type === 'outbound-rtp' && stat.bytesSent > 0) {
558
+ dataFound = true;
559
+ }
560
+ });
561
+
562
+ if (dataFound) {
563
+ waitForData.wake();
564
+ return;
565
+ }
566
+ } catch {
567
+ // Stats might not be available yet, continue checking
568
+ }
569
+ checks++;
570
+ if (checks > MAX_RETRIES) {
571
+ waitForData.throw(new Error('Transceiver did not send data'));
572
+ return;
573
+ }
574
+
575
+ delay = Math.min(delay * 2, MAX_DELAY); // Exponential backoff with max cap
576
+ scheduleTask(ctx, checkStats, delay);
577
+ };
578
+
579
+ void checkStats();
580
+ return waitForData.wait({ timeout: WAIT_FOR_DATA_TIMEOUT });
581
+ };
@@ -3,8 +3,8 @@
3
3
  //
4
4
  //
5
5
 
6
- import { waitForCondition, scheduleTaskInterval } from '@dxos/async';
7
- import { cancelWithContext, type Context } from '@dxos/context';
6
+ import { scheduleTaskInterval, waitForCondition } from '@dxos/async';
7
+ import { type Context, cancelWithContext } from '@dxos/context';
8
8
  import { invariant } from '@dxos/invariant';
9
9
 
10
10
  /**
@@ -30,7 +30,7 @@ export const createBlackCanvasStreamTrack = async ({
30
30
  canvasCtx.fillStyle = 'black';
31
31
  canvasCtx.fillRect(0, 0, canvas.width, canvas.height);
32
32
  };
33
- scheduleTaskInterval(ctx, async () => drawFrame(), 1_000);
33
+ scheduleTaskInterval(ctx, async () => drawFrame(), 200);
34
34
 
35
35
  const track = canvas.captureStream().getVideoTracks()[0];
36
36
  drawFrame();
@@ -40,6 +40,20 @@ export const createBlackCanvasStreamTrack = async ({
40
40
  return track;
41
41
  };
42
42
 
43
+ let audioContextStartedPreviously = false;
44
+ const userGestureEvents = [
45
+ 'click',
46
+ 'contextmenu',
47
+ 'auxclick',
48
+ 'dblclick',
49
+ 'mousedown',
50
+ 'mouseup',
51
+ 'pointerup',
52
+ 'touchend',
53
+ 'keydown',
54
+ 'keyup',
55
+ ];
56
+
43
57
  /**
44
58
  * Creates an inaudible audio stream track.
45
59
  * We need this to have audio track available when audio is disabled.
@@ -48,22 +62,62 @@ export const createInaudibleAudioStreamTrack = async ({ ctx }: { ctx: Context })
48
62
  const audioContext = new window.AudioContext();
49
63
  const oscillator = audioContext.createOscillator();
50
64
  oscillator.type = 'triangle';
51
-
52
- // set to 0.1 to make inaudible
53
- oscillator.frequency.setValueAtTime(0.1, audioContext.currentTime);
65
+ // roughly sounds like a box fan
66
+ oscillator.frequency.setValueAtTime(20, audioContext.currentTime);
54
67
 
55
68
  const gainNode = audioContext.createGain();
56
69
  // even w/ gain at 0 some packets are sent
57
70
  gainNode.gain.setValueAtTime(0, audioContext.currentTime);
58
-
59
71
  oscillator.connect(gainNode);
60
72
 
61
73
  const destination = audioContext.createMediaStreamDestination();
62
74
  gainNode.connect(destination);
63
75
 
64
- oscillator.start();
76
+ let oscillatorStarted = false;
77
+ const ensureOscillatorStarted = () => {
78
+ if (oscillatorStarted) return;
79
+ oscillator.start();
80
+ oscillatorStarted = true;
81
+ };
82
+
83
+ const stateChangeHandler = () => {
84
+ if (audioContext.state === 'running') {
85
+ audioContextStartedPreviously = true;
86
+ ensureOscillatorStarted();
87
+ }
88
+ if (audioContext.state === 'suspended' || (audioContext.state as string) === 'interrupted') {
89
+ resumeAudioContext();
90
+ }
91
+ };
92
+
93
+ audioContext.addEventListener('statechange', stateChangeHandler);
94
+
95
+ const resumeAudioContext = () => {
96
+ void audioContext.resume().then(() => {
97
+ cleanUpUserGestureListeners();
98
+ });
99
+ };
100
+
101
+ const cleanUpUserGestureListeners = () => {
102
+ userGestureEvents.forEach((gesture) => {
103
+ document.removeEventListener(gesture, resumeAudioContext, {
104
+ capture: true,
105
+ });
106
+ });
107
+ };
108
+
109
+ if (audioContextStartedPreviously) {
110
+ resumeAudioContext();
111
+ } else {
112
+ userGestureEvents.forEach((gesture) => {
113
+ document.addEventListener(gesture, resumeAudioContext, {
114
+ capture: true,
115
+ });
116
+ });
117
+ }
65
118
 
66
119
  ctx.onDispose(async () => {
120
+ cleanUpUserGestureListeners();
67
121
  oscillator.disconnect();
68
122
  oscillator.stop();
69
123
  await audioContext.close();
@@ -0,0 +1,232 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import '@dxos-theme';
6
+
7
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
8
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
9
+
10
+ import { scheduleTask, sleep } from '@dxos/async';
11
+ import { Context } from '@dxos/context';
12
+ import { invariant } from '@dxos/invariant';
13
+ import { log } from '@dxos/log';
14
+ import { Config, useConfig } from '@dxos/react-client';
15
+ import { withClientProvider } from '@dxos/react-client/testing';
16
+ import { Button } from '@dxos/react-ui';
17
+ import { Json } from '@dxos/react-ui-syntax-highlighter';
18
+ import { withLayout, withTheme } from '@dxos/storybook-utils';
19
+
20
+ const testVideo = new URL('../testing/video.mp4', import.meta.url).href;
21
+
22
+ import { CALLS_URL, CallsServicePeer, type TrackObject } from './calls';
23
+ import { useBlackCanvasStreamTrack, useInaudibleAudioStreamTrack, useVideoStreamTrack } from './hooks';
24
+
25
+ // TODO(burdon): THIS IS TOO COMPLEX FOR A TEST SETUP.
26
+ const pushAndPullTrack = (mediaStreamTrack?: MediaStreamTrack) => {
27
+ const config = useConfig();
28
+ const callsConfig = {
29
+ iceServers: config.get('runtime.services.ice'),
30
+ apiBase: `${CALLS_URL}/api/calls`,
31
+ };
32
+ const peerPush = useMemo(() => new CallsServicePeer(callsConfig), []);
33
+ const peerPull = useMemo(() => new CallsServicePeer(callsConfig), []);
34
+ const [metrics, setMetrics] = useState<Record<string, any>>({});
35
+ const trackInfo = useRef<TrackObject | undefined>(undefined);
36
+ const pullCtx = useRef<Context | undefined>(undefined);
37
+ const [pulledTrack, setPulledTrack] = useState<MediaStreamTrack | undefined>(undefined);
38
+ const hadRun = useRef(false);
39
+
40
+ const deps: any[] = [];
41
+ // Push/pull video stream track to cloudflare.
42
+ useEffect(() => {
43
+ if (hadRun.current || !mediaStreamTrack || !peerPush || !peerPull) {
44
+ return;
45
+ }
46
+ hadRun.current = true;
47
+ const ctx = Context.default();
48
+ log.info('setting up ctx', { ctx, mediaStreamTrack, peerPush, peerPull });
49
+ deps.push([ctx, mediaStreamTrack, peerPush, peerPull]);
50
+ ctx.onDispose(() => {
51
+ log.info('disposing ctx', {});
52
+ });
53
+ scheduleTask(
54
+ ctx,
55
+ async () => {
56
+ log.info('starting push/pull', { mediaStreamTrack });
57
+ await peerPush.open();
58
+ await peerPull.open();
59
+ ctx.onDispose(() => {
60
+ void peerPush.close();
61
+ void peerPull.close();
62
+ });
63
+
64
+ // Push track to cloudflare.
65
+ performance.mark('push:begin');
66
+ log.info('pushing track', { track: mediaStreamTrack });
67
+ trackInfo.current = await peerPush.pushTrack({ track: mediaStreamTrack, ctx: Context.default() });
68
+ performance.mark('push:end');
69
+ const pushTime = performance.measure('push', 'push:begin', 'push:end').duration;
70
+ log.info('successfully pushed track', { pushTime, trackInfo: trackInfo.current });
71
+ setMetrics((prev) => ({ ...prev, 'time to push track [ms]': Math.round(pushTime) }));
72
+
73
+ // Pull track from cloudflare.
74
+ performance.mark('pullTrack:begin');
75
+ pullCtx.current = Context.default();
76
+ let retries = 0;
77
+ let pulledTrack: MediaStreamTrack | undefined;
78
+ while (!pulledTrack && retries < 3) {
79
+ retries++;
80
+ log.info('pulling track', {
81
+ trackData: { ...trackInfo.current!, mid: undefined },
82
+ retries,
83
+ pulledTrack,
84
+ });
85
+ pulledTrack = await peerPull.pullTrack({
86
+ trackData: { ...trackInfo.current!, mid: undefined },
87
+ ctx: pullCtx.current,
88
+ });
89
+ await sleep(200);
90
+ }
91
+ invariant(pulledTrack);
92
+ setPulledTrack(pulledTrack);
93
+ performance.mark('pullTrack:end');
94
+ const pullTime = performance.measure('pullTrack', 'pullTrack:begin', 'pullTrack:end').duration;
95
+ setMetrics((prev) => ({ ...prev, 'time to pull track [ms]': Math.round(pullTime) }));
96
+ log.info('successfully pulled track', { pullTime, pulledTrack });
97
+ },
98
+ 1000,
99
+ );
100
+
101
+ return () => {
102
+ void ctx.dispose();
103
+ };
104
+ }, [mediaStreamTrack, peerPush, peerPull]);
105
+
106
+ const rePullTrack = useCallback(async () => {
107
+ performance.mark('rePullVideo:begin');
108
+ if (!pulledTrack) {
109
+ log.info('no pulled track, skipping re-pull', { pulledTrack });
110
+ return;
111
+ }
112
+ pulledTrack.stop();
113
+ await pullCtx.current!.dispose();
114
+ pullCtx.current = Context.default();
115
+ const newPulledTrack = await peerPull.pullTrack({
116
+ trackData: { ...trackInfo.current!, mid: undefined },
117
+ ctx: pullCtx.current,
118
+ });
119
+ invariant(newPulledTrack);
120
+ setPulledTrack(newPulledTrack);
121
+ performance.mark('rePullVideo:end');
122
+ const rePullTime = performance.measure('rePullVideo', 'rePullVideo:begin', 'rePullVideo:end').duration;
123
+ setMetrics((prev) => ({ ...prev, 'time to re-pull video [ms]': Math.round(rePullTime) }));
124
+ }, [peerPull, trackInfo.current, pullCtx.current, pulledTrack]);
125
+
126
+ return {
127
+ pulledTrack,
128
+ rePullTrack,
129
+ metrics,
130
+ pushService: peerPush,
131
+ pullService: peerPull,
132
+ };
133
+ };
134
+
135
+ type StoryProps = { source: string };
136
+
137
+ const DefaultStory = ({ source }: StoryProps) => {
138
+ const pushVideoElement = useRef<HTMLVideoElement>(null);
139
+ const pullVideoElement = useRef<HTMLVideoElement>(null);
140
+ // Get video stream track.
141
+ const videoStreamTrack = useVideoStreamTrack(pushVideoElement, source);
142
+ const { pulledTrack, rePullTrack, metrics } = pushAndPullTrack(videoStreamTrack);
143
+ const hadRun = useRef(false);
144
+
145
+ // Push/pull video stream track to cloudflare.
146
+ useEffect(() => {
147
+ if (!pulledTrack || hadRun.current) {
148
+ return;
149
+ }
150
+ hadRun.current = true;
151
+ const ctx = Context.default();
152
+ scheduleTask(ctx, async () => {
153
+ pullVideoElement.current!.srcObject = new MediaStream([pulledTrack]);
154
+ await pullVideoElement.current!.play();
155
+ });
156
+
157
+ return () => {
158
+ void ctx.dispose();
159
+ };
160
+ }, [pulledTrack]);
161
+
162
+ return (
163
+ <div className='grid grid-rows-3 gap-4 items-center'>
164
+ <video ref={pushVideoElement} muted autoPlay loop />
165
+ <div className='flex flex-col gap-4'>
166
+ <video ref={pullVideoElement} muted />
167
+ <Button disabled={!pulledTrack} onClick={rePullTrack}>
168
+ Re-pull video
169
+ </Button>
170
+ </div>
171
+ <Json data={metrics} />
172
+ </div>
173
+ );
174
+ };
175
+
176
+ const meta = {
177
+ title: 'plugins/plugin-thread/calls-service',
178
+ render: DefaultStory,
179
+ decorators: [
180
+ withClientProvider({
181
+ config: new Config({
182
+ runtime: {
183
+ services: {
184
+ iceProviders: [{ urls: 'https://edge.dxos.workers.dev/ice' }],
185
+ },
186
+ },
187
+ }),
188
+ }),
189
+ withTheme,
190
+ withLayout(),
191
+ ],
192
+ parameters: {
193
+ layout: 'centered',
194
+ },
195
+ } satisfies Meta<typeof DefaultStory>;
196
+
197
+ export default meta;
198
+
199
+ type Story = StoryObj<typeof meta>;
200
+
201
+ export const Default: Story = {
202
+ args: {
203
+ source: testVideo,
204
+ },
205
+ };
206
+
207
+ export const InaudibleAudioStreamTrack = {
208
+ render: () => {
209
+ const audioStreamTrack = useInaudibleAudioStreamTrack();
210
+ const { rePullTrack, metrics } = pushAndPullTrack(audioStreamTrack);
211
+
212
+ return (
213
+ <div className='flex flex-col gap-4 items-center'>
214
+ <Json data={metrics} />
215
+ <Button onClick={rePullTrack}>Re-pull audio</Button>
216
+ </div>
217
+ );
218
+ },
219
+ };
220
+
221
+ export const BlackVideoStreamTrack = {
222
+ render: () => {
223
+ const videoStreamTrack = useBlackCanvasStreamTrack();
224
+ const { rePullTrack, metrics } = pushAndPullTrack(videoStreamTrack);
225
+ return (
226
+ <div className='flex flex-col gap-4 items-center'>
227
+ <Json data={metrics} />
228
+ <Button onClick={rePullTrack}>Re-pull audio</Button>
229
+ </div>
230
+ );
231
+ },
232
+ };
@@ -5,18 +5,21 @@
5
5
  import { Rx } from '@effect-rx/rx-react';
6
6
  import { Option, pipe } from 'effect';
7
7
 
8
- import { Capabilities, contributes, createIntent, type PluginContext } from '@dxos/app-framework';
8
+ import { Capabilities, type PluginContext, contributes, createIntent } from '@dxos/app-framework';
9
9
  import { Obj } from '@dxos/echo';
10
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';
11
+ import { ATTENDABLE_PATH_SEPARATOR, DECK_COMPANION_TYPE, PLANK_COMPANION_TYPE } from '@dxos/plugin-deck/types';
12
+ import { ROOT_ID, createExtension, rxFromSignal } from '@dxos/plugin-graph';
13
13
  import { fullyQualifiedId } from '@dxos/react-client/echo';
14
14
 
15
- import { ThreadCapabilities } from './capabilities';
16
- import { meta, THREAD_PLUGIN } from '../meta';
15
+ import { THREAD_PLUGIN, meta } from '../meta';
17
16
  import { ChannelType, ThreadAction } from '../types';
18
17
  import { getAnchor } from '../util';
19
18
 
19
+ import { ThreadCapabilities } from './capabilities';
20
+
21
+ // TODO(wittjosiah): Highlight active calls in L1.
22
+ // Track active meetings by subscribing to meetings query and polling the swarms of recent meetings in the space.
20
23
  export default (context: PluginContext) => {
21
24
  const resolve = (typename: string) =>
22
25
  context.getCapabilities(Capabilities.Metadata).find(({ id }) => id === typename)?.metadata ?? {};
@@ -2,12 +2,13 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { contributes, type PluginContext } from '@dxos/app-framework';
5
+ import { type PluginContext, contributes } from '@dxos/app-framework';
6
6
  import { ClientCapabilities } from '@dxos/plugin-client';
7
7
 
8
- import { ThreadCapabilities } from './capabilities';
9
8
  import { CallManager } from '../calls';
10
9
 
10
+ import { ThreadCapabilities } from './capabilities';
11
+
11
12
  export default async (context: PluginContext) => {
12
13
  const client = context.getCapability(ClientCapabilities.Client);
13
14
  const callManager = new CallManager(client);
@@ -5,9 +5,9 @@
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
+ import { type CallManager, type CallState, type MediaState } from '../calls';
9
9
  import { THREAD_PLUGIN } from '../meta';
10
- import { type ViewState, type ThreadState, type ChannelType } from '../types';
10
+ import { type ChannelType, type ThreadState, type ViewState } from '../types';
11
11
 
12
12
  export namespace ThreadCapabilities {
13
13
  export const CallManager = defineCapability<CallManager>(`${THREAD_PLUGIN}/capability/call-manager`);
@@ -12,5 +12,6 @@ export const ReactRoot = lazy(() => import('./react-root'));
12
12
  export const ReactSurface = lazy(() => import('./react-surface'));
13
13
  export const ThreadSettings = lazy(() => import('./settings'));
14
14
  export const ThreadState = lazy(() => import('./state'));
15
+ export const Toolkit = lazy(() => import('./toolkit'));
15
16
 
16
17
  export * from './capabilities';