@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.
- package/dist/lib/browser/ChannelContainer-4PYFOIDK.mjs +16 -0
- package/dist/lib/browser/ChatContainer-EXNNREYB.mjs +15 -0
- package/dist/lib/browser/{app-graph-builder-OY7R7EJP.mjs → app-graph-builder-FHAOPO57.mjs} +8 -8
- package/dist/lib/browser/app-graph-builder-FHAOPO57.mjs.map +7 -0
- package/dist/lib/browser/{call-manager-APQAZWHT.mjs → call-manager-RMPTWSTF.mjs} +6 -5
- package/dist/lib/browser/call-manager-RMPTWSTF.mjs.map +7 -0
- package/dist/lib/browser/{chunk-R5MDLUPC.mjs → chunk-4APCDRSH.mjs} +3 -3
- package/dist/lib/browser/{chunk-R5MDLUPC.mjs.map → chunk-4APCDRSH.mjs.map} +1 -1
- package/dist/lib/browser/{chunk-XZKBN3NS.mjs → chunk-7W7QK5ZP.mjs} +253 -250
- package/dist/lib/browser/chunk-7W7QK5ZP.mjs.map +7 -0
- package/dist/lib/browser/{chunk-IIUTBDVB.mjs → chunk-EV4JWI7L.mjs} +2 -2
- package/dist/lib/browser/chunk-G4CNILRR.mjs +23 -0
- package/dist/lib/browser/{chunk-6NBVNXTM.mjs.map → chunk-G4CNILRR.mjs.map} +3 -3
- package/dist/lib/browser/{chunk-JKQUJOTX.mjs → chunk-GERVMFQW.mjs} +2 -2
- package/dist/lib/browser/{chunk-AEXWNS6Z.mjs → chunk-KTWYVC5X.mjs} +34 -15
- package/dist/lib/browser/chunk-KTWYVC5X.mjs.map +7 -0
- package/dist/lib/browser/{chunk-TAFSCSUR.mjs → chunk-PBMNFG3B.mjs} +97 -72
- package/dist/lib/browser/chunk-PBMNFG3B.mjs.map +7 -0
- package/dist/lib/browser/chunk-RI3Z6MK3.mjs +181 -0
- package/dist/lib/browser/chunk-RI3Z6MK3.mjs.map +7 -0
- package/dist/lib/browser/chunk-XYUJXHYV.mjs +106 -0
- package/dist/lib/browser/chunk-XYUJXHYV.mjs.map +7 -0
- package/dist/lib/browser/{chunk-4H4A264L.mjs → chunk-ZCEU5K23.mjs} +490 -308
- package/dist/lib/browser/chunk-ZCEU5K23.mjs.map +7 -0
- package/dist/lib/browser/{chunk-PG5CTFKK.mjs → chunk-ZH2WPTNP.mjs} +226 -158
- package/dist/lib/browser/chunk-ZH2WPTNP.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +49 -44
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/{intent-resolver-FK2MDVDT.mjs → intent-resolver-J7OCP2P6.mjs} +90 -16
- package/dist/lib/browser/intent-resolver-J7OCP2P6.mjs.map +7 -0
- package/dist/lib/browser/{markdown-TE5SWWNJ.mjs → markdown-Z677YORA.mjs} +8 -8
- package/dist/lib/browser/markdown-Z677YORA.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/react-root-XKOD4KRB.mjs +28 -0
- package/dist/lib/browser/{react-surface-VXUJKSOG.mjs → react-surface-GVGZRBDK.mjs} +12 -11
- package/dist/lib/browser/react-surface-GVGZRBDK.mjs.map +7 -0
- package/dist/lib/browser/{settings-RB2RSLXV.mjs → settings-GRKEID73.mjs} +4 -4
- package/dist/lib/browser/{state-RKL5MSDP.mjs → state-2T4KDWBX.mjs} +4 -4
- package/dist/lib/browser/{state-RKL5MSDP.mjs.map → state-2T4KDWBX.mjs.map} +2 -2
- package/dist/lib/browser/toolkit-KUPIIFC6.mjs +80 -0
- package/dist/lib/browser/toolkit-KUPIIFC6.mjs.map +7 -0
- package/dist/lib/browser/types/index.mjs +2 -2
- package/dist/lib/node-esm/ChannelContainer-KQQEZWUN.mjs +17 -0
- package/dist/lib/node-esm/{ChatContainer-F6CSADV7.mjs → ChatContainer-QVQKFBWA.mjs} +6 -5
- package/dist/lib/node-esm/{app-graph-builder-BAHBHYWI.mjs → app-graph-builder-XEYWX5FC.mjs} +8 -8
- package/dist/lib/node-esm/app-graph-builder-XEYWX5FC.mjs.map +7 -0
- package/dist/lib/node-esm/{call-manager-UUYXLF4T.mjs → call-manager-QAREJFVX.mjs} +6 -5
- package/dist/lib/node-esm/call-manager-QAREJFVX.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-2V3WSLUZ.mjs +108 -0
- package/dist/lib/node-esm/chunk-2V3WSLUZ.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-4T45PCKP.mjs +25 -0
- package/dist/lib/node-esm/{chunk-O63QJPQX.mjs.map → chunk-4T45PCKP.mjs.map} +3 -3
- package/dist/lib/node-esm/{chunk-PGRP3O4O.mjs → chunk-57XR3LEF.mjs} +2 -2
- package/dist/lib/node-esm/{chunk-P6RLFCNT.mjs → chunk-DKCQCENK.mjs} +97 -72
- package/dist/lib/node-esm/chunk-DKCQCENK.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-ESQC6SYE.mjs → chunk-GRLRWTRU.mjs} +2 -2
- package/dist/lib/node-esm/chunk-JNPKMT7O.mjs +182 -0
- package/dist/lib/node-esm/chunk-JNPKMT7O.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-UZWVVFT3.mjs → chunk-LE2LIYGX.mjs} +226 -158
- package/dist/lib/node-esm/chunk-LE2LIYGX.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-UJMPYKT3.mjs → chunk-P6E247RF.mjs} +34 -15
- package/dist/lib/node-esm/chunk-P6E247RF.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-K4KAUOKT.mjs → chunk-PYTVBN5J.mjs} +3 -3
- package/dist/lib/node-esm/{chunk-K4KAUOKT.mjs.map → chunk-PYTVBN5J.mjs.map} +1 -1
- package/dist/lib/node-esm/{chunk-2RNIPFDA.mjs → chunk-SNKFZQST.mjs} +253 -250
- package/dist/lib/node-esm/chunk-SNKFZQST.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-WXNPD542.mjs → chunk-TIPIOH2J.mjs} +489 -308
- package/dist/lib/node-esm/chunk-TIPIOH2J.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +49 -44
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/{intent-resolver-BU73VYW3.mjs → intent-resolver-SR2LW4HF.mjs} +90 -16
- package/dist/lib/node-esm/intent-resolver-SR2LW4HF.mjs.map +7 -0
- package/dist/lib/node-esm/{markdown-HJUWNBLS.mjs → markdown-FL4IXLRP.mjs} +8 -8
- package/dist/lib/node-esm/markdown-FL4IXLRP.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/{react-root-RUXOAQNW.mjs → react-root-4JWDRIQB.mjs} +12 -11
- package/dist/lib/{browser/react-root-NK3A4VG7.mjs.map → node-esm/react-root-4JWDRIQB.mjs.map} +1 -1
- package/dist/lib/node-esm/{react-surface-ELXFYKP6.mjs → react-surface-WLQUVRAX.mjs} +12 -11
- package/dist/lib/node-esm/react-surface-WLQUVRAX.mjs.map +7 -0
- package/dist/lib/node-esm/{settings-EA7DFSM6.mjs → settings-F2ODVNNW.mjs} +4 -4
- package/dist/lib/node-esm/{state-6AUTNROZ.mjs → state-62TQKQVB.mjs} +4 -4
- package/dist/lib/node-esm/{state-6AUTNROZ.mjs.map → state-62TQKQVB.mjs.map} +2 -2
- package/dist/lib/node-esm/toolkit-KZIS7G36.mjs +81 -0
- package/dist/lib/node-esm/toolkit-KZIS7G36.mjs.map +7 -0
- package/dist/lib/node-esm/types/index.mjs +2 -2
- package/dist/types/src/ThreadPlugin.d.ts.map +1 -1
- package/dist/types/src/calls/call-manager.d.ts +1 -1
- package/dist/types/src/calls/call-manager.d.ts.map +1 -1
- package/dist/types/src/calls/call-swarm-synchronizer.d.ts.map +1 -1
- package/dist/types/src/calls/media-manager.d.ts +1 -1
- package/dist/types/src/calls/media-manager.d.ts.map +1 -1
- package/dist/types/src/calls/types.d.ts +1 -1
- package/dist/types/src/calls/types.d.ts.map +1 -1
- package/dist/types/src/calls/util/calls-service.d.ts +8 -3
- package/dist/types/src/calls/util/calls-service.d.ts.map +1 -1
- package/dist/types/src/calls/util/stub-media-streams.d.ts.map +1 -1
- package/dist/types/src/calls-service.stories.d.ts +24 -0
- package/dist/types/src/calls-service.stories.d.ts.map +1 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/capabilities/call-manager.d.ts +1 -1
- package/dist/types/src/capabilities/call-manager.d.ts.map +1 -1
- package/dist/types/src/capabilities/capabilities.d.ts +2 -2
- package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +11 -10
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts +1 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
- package/dist/types/src/capabilities/markdown.d.ts +1 -1
- package/dist/types/src/capabilities/markdown.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-root.d.ts +2 -2
- package/dist/types/src/capabilities/react-surface.d.ts +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/capabilities/settings.d.ts +1 -1
- package/dist/types/src/capabilities/state.d.ts +2 -2
- package/dist/types/src/capabilities/state.d.ts.map +1 -1
- package/dist/types/src/capabilities/toolkit.d.ts +5 -0
- package/dist/types/src/capabilities/toolkit.d.ts.map +1 -0
- package/dist/types/src/components/Call/Call.d.ts.map +1 -1
- package/dist/types/src/components/Call/Toolbar.d.ts.map +1 -1
- package/dist/types/src/components/CallDebugPanel.d.ts +7 -0
- package/dist/types/src/components/CallDebugPanel.d.ts.map +1 -1
- package/dist/types/src/components/CallSidebar.d.ts.map +1 -1
- package/dist/types/src/components/ChannelContainer.d.ts.map +1 -1
- package/dist/types/src/components/ChannelContainer.stories.d.ts +89 -4
- package/dist/types/src/components/ChannelContainer.stories.d.ts.map +1 -1
- package/dist/types/src/components/Chat.stories.d.ts +90 -3
- package/dist/types/src/components/Chat.stories.d.ts.map +1 -1
- package/dist/types/src/components/ChatContainer.d.ts +2 -2
- package/dist/types/src/components/ChatContainer.d.ts.map +1 -1
- package/dist/types/src/components/Comments.stories.d.ts +156 -3
- package/dist/types/src/components/Comments.stories.d.ts.map +1 -1
- package/dist/types/src/components/CommentsContainer.d.ts +4 -4
- package/dist/types/src/components/CommentsContainer.d.ts.map +1 -1
- package/dist/types/src/components/CommentsThreadContainer.d.ts +14 -0
- package/dist/types/src/components/CommentsThreadContainer.d.ts.map +1 -0
- package/dist/types/src/components/Lobby/Lobby.d.ts.map +1 -1
- package/dist/types/src/components/Media/VideoObject.d.ts +1 -1
- package/dist/types/src/components/Media/VideoObject.stories.d.ts +15 -3
- package/dist/types/src/components/Media/VideoObject.stories.d.ts.map +1 -1
- package/dist/types/src/components/MessageContainer.d.ts +4 -1
- package/dist/types/src/components/MessageContainer.d.ts.map +1 -1
- package/dist/types/src/components/Participant/Participant.d.ts.map +1 -1
- package/dist/types/src/components/Participant/ParticipantGrid.d.ts.map +1 -1
- package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts +154 -2
- package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts.map +1 -1
- package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts +156 -3
- package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts.map +1 -1
- package/dist/types/src/components/ResponsiveGrid/ResponsiveGridItem.d.ts.map +1 -1
- package/dist/types/src/components/ThreadComplementary.d.ts.map +1 -1
- package/dist/types/src/components/command-extension.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +1 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts +1 -0
- package/dist/types/src/components/testing.d.ts.map +1 -1
- package/dist/types/src/extensions/threads.d.ts +2 -2
- package/dist/types/src/extensions/threads.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +3 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useBlackCanvasStreamTrack.d.ts +2 -0
- package/dist/types/src/hooks/useBlackCanvasStreamTrack.d.ts.map +1 -0
- package/dist/types/src/hooks/useInaudibleAudioStreamTrack.d.ts +2 -0
- package/dist/types/src/hooks/useInaudibleAudioStreamTrack.d.ts.map +1 -0
- package/dist/types/src/hooks/useVideoStreamTrack.d.ts +3 -0
- package/dist/types/src/hooks/useVideoStreamTrack.d.ts.map +1 -0
- package/dist/types/src/testing/stories.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +76 -194
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/schema.d.ts +125 -81
- package/dist/types/src/types/schema.d.ts.map +1 -1
- package/dist/types/src/types/types.d.ts +270 -139
- package/dist/types/src/types/types.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +17 -2
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +56 -53
- package/src/ThreadPlugin.tsx +16 -24
- package/src/calls/call-manager.ts +8 -4
- package/src/calls/call-swarm-synchronizer.ts +1 -1
- package/src/calls/media-manager.ts +70 -37
- package/src/calls/types.ts +8 -4
- package/src/calls/util/calls-service.ts +72 -18
- package/src/calls/util/stub-media-streams.ts +62 -8
- package/src/calls-service.stories.tsx +232 -0
- package/src/capabilities/app-graph-builder.ts +8 -5
- package/src/capabilities/call-manager.ts +3 -2
- package/src/capabilities/capabilities.ts +2 -2
- package/src/capabilities/index.ts +1 -0
- package/src/capabilities/intent-resolver.ts +60 -8
- package/src/capabilities/markdown.ts +4 -3
- package/src/capabilities/react-surface.tsx +5 -4
- package/src/capabilities/state.ts +2 -1
- package/src/capabilities/toolkit.ts +78 -0
- package/src/components/Call/Call.tsx +4 -3
- package/src/components/Call/Toolbar.tsx +8 -8
- package/src/components/CallDebugPanel.tsx +110 -51
- package/src/components/CallSidebar.tsx +2 -1
- package/src/components/ChannelContainer.stories.tsx +11 -10
- package/src/components/ChannelContainer.tsx +13 -11
- package/src/components/Chat.stories.tsx +29 -27
- package/src/components/ChatContainer.tsx +20 -15
- package/src/components/Comments.stories.tsx +52 -41
- package/src/components/CommentsContainer.tsx +17 -11
- package/src/components/{CommentContainer.tsx → CommentsThreadContainer.tsx} +53 -82
- package/src/components/Lobby/Lobby.tsx +1 -1
- package/src/components/Media/VideoObject.stories.tsx +30 -27
- package/src/components/MessageContainer.tsx +65 -47
- package/src/components/Participant/Participant.tsx +13 -7
- package/src/components/Participant/ParticipantGrid.tsx +2 -1
- package/src/components/ResponsiveGrid/ResponsiveContainer.stories.tsx +7 -6
- package/src/components/ResponsiveGrid/ResponsiveGrid.stories.tsx +42 -39
- package/src/components/ResponsiveGrid/ResponsiveGrid.tsx +1 -1
- package/src/components/ResponsiveGrid/ResponsiveGridItem.tsx +4 -4
- package/src/components/ThreadComplementary.tsx +40 -10
- package/src/components/ThreadSettings.tsx +4 -4
- package/src/components/command-extension.ts +5 -2
- package/src/components/index.ts +1 -1
- package/src/components/testing.ts +24 -2
- package/src/extensions/threads.ts +6 -6
- package/src/hooks/index.ts +3 -0
- package/src/hooks/useBlackCanvasStreamTrack.tsx +27 -0
- package/src/hooks/useDebugMode.ts +1 -1
- package/src/hooks/useInaudibleAudioStreamTrack.tsx +27 -0
- package/src/hooks/useVideoStreamTrack.tsx +36 -0
- package/src/testing/stories.ts +7 -3
- package/src/translations.ts +14 -9
- package/src/types/types.ts +28 -11
- package/src/typings/peermetrics-webrtc-stats.d.ts +17 -1
- package/src/typings.d.ts +8 -0
- package/dist/lib/browser/ChannelContainer-PKFBVENP.mjs +0 -15
- package/dist/lib/browser/ChatContainer-RSOKYAMK.mjs +0 -14
- package/dist/lib/browser/app-graph-builder-OY7R7EJP.mjs.map +0 -7
- package/dist/lib/browser/call-manager-APQAZWHT.mjs.map +0 -7
- package/dist/lib/browser/chunk-4H4A264L.mjs.map +0 -7
- package/dist/lib/browser/chunk-5P5BH5GE.mjs +0 -88
- package/dist/lib/browser/chunk-5P5BH5GE.mjs.map +0 -7
- package/dist/lib/browser/chunk-6NBVNXTM.mjs +0 -21
- package/dist/lib/browser/chunk-AEXWNS6Z.mjs.map +0 -7
- package/dist/lib/browser/chunk-PG5CTFKK.mjs.map +0 -7
- package/dist/lib/browser/chunk-TAFSCSUR.mjs.map +0 -7
- package/dist/lib/browser/chunk-XZKBN3NS.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-FK2MDVDT.mjs.map +0 -7
- package/dist/lib/browser/markdown-TE5SWWNJ.mjs.map +0 -7
- package/dist/lib/browser/react-root-NK3A4VG7.mjs +0 -27
- package/dist/lib/browser/react-surface-VXUJKSOG.mjs.map +0 -7
- package/dist/lib/node/ChannelContainer-YS5YT2ML.cjs +0 -36
- package/dist/lib/node/ChannelContainer-YS5YT2ML.cjs.map +0 -7
- package/dist/lib/node/ChatContainer-GCOM3M56.cjs +0 -35
- package/dist/lib/node/ChatContainer-GCOM3M56.cjs.map +0 -7
- package/dist/lib/node/app-graph-builder-PBHJNDQY.cjs +0 -179
- package/dist/lib/node/app-graph-builder-PBHJNDQY.cjs.map +0 -7
- package/dist/lib/node/call-manager-HV2XJW5O.cjs +0 -37
- package/dist/lib/node/call-manager-HV2XJW5O.cjs.map +0 -7
- package/dist/lib/node/chunk-44I33JDT.cjs +0 -1731
- package/dist/lib/node/chunk-44I33JDT.cjs.map +0 -7
- package/dist/lib/node/chunk-4YSNVPWU.cjs +0 -37
- package/dist/lib/node/chunk-4YSNVPWU.cjs.map +0 -7
- package/dist/lib/node/chunk-E3WBZTTI.cjs +0 -371
- package/dist/lib/node/chunk-E3WBZTTI.cjs.map +0 -7
- package/dist/lib/node/chunk-ERG7G6FF.cjs +0 -59
- package/dist/lib/node/chunk-ERG7G6FF.cjs.map +0 -7
- package/dist/lib/node/chunk-FUXJAVFZ.cjs +0 -108
- package/dist/lib/node/chunk-FUXJAVFZ.cjs.map +0 -7
- package/dist/lib/node/chunk-HLMCEE5K.cjs +0 -41
- package/dist/lib/node/chunk-HLMCEE5K.cjs.map +0 -7
- package/dist/lib/node/chunk-IP533AMV.cjs +0 -554
- package/dist/lib/node/chunk-IP533AMV.cjs.map +0 -7
- package/dist/lib/node/chunk-LR5NENBE.cjs +0 -54
- package/dist/lib/node/chunk-LR5NENBE.cjs.map +0 -7
- package/dist/lib/node/chunk-UM36TPCT.cjs +0 -984
- package/dist/lib/node/chunk-UM36TPCT.cjs.map +0 -7
- package/dist/lib/node/chunk-ZGDN3XBR.cjs +0 -149
- package/dist/lib/node/chunk-ZGDN3XBR.cjs.map +0 -7
- package/dist/lib/node/index.cjs +0 -310
- package/dist/lib/node/index.cjs.map +0 -7
- package/dist/lib/node/intent-resolver-SYSJ5SJG.cjs +0 -363
- package/dist/lib/node/intent-resolver-SYSJ5SJG.cjs.map +0 -7
- package/dist/lib/node/markdown-GQIPJS2F.cjs +0 -178
- package/dist/lib/node/markdown-GQIPJS2F.cjs.map +0 -7
- package/dist/lib/node/meta.json +0 -1
- package/dist/lib/node/react-root-6HHDMULJ.cjs +0 -51
- package/dist/lib/node/react-root-6HHDMULJ.cjs.map +0 -7
- package/dist/lib/node/react-surface-NBH42NN2.cjs +0 -122
- package/dist/lib/node/react-surface-NBH42NN2.cjs.map +0 -7
- package/dist/lib/node/settings-4LQSFEDK.cjs +0 -36
- package/dist/lib/node/settings-4LQSFEDK.cjs.map +0 -7
- package/dist/lib/node/state-IY5XX3H2.cjs +0 -50
- package/dist/lib/node/state-IY5XX3H2.cjs.map +0 -7
- package/dist/lib/node/types/index.cjs +0 -38
- package/dist/lib/node/types/index.cjs.map +0 -7
- package/dist/lib/node-esm/ChannelContainer-O4QJII2P.mjs +0 -16
- package/dist/lib/node-esm/app-graph-builder-BAHBHYWI.mjs.map +0 -7
- package/dist/lib/node-esm/call-manager-UUYXLF4T.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-2RNIPFDA.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-O3V45YJP.mjs +0 -90
- package/dist/lib/node-esm/chunk-O3V45YJP.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-O63QJPQX.mjs +0 -23
- package/dist/lib/node-esm/chunk-P6RLFCNT.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-UJMPYKT3.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-UZWVVFT3.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-WXNPD542.mjs.map +0 -7
- package/dist/lib/node-esm/intent-resolver-BU73VYW3.mjs.map +0 -7
- package/dist/lib/node-esm/markdown-HJUWNBLS.mjs.map +0 -7
- package/dist/lib/node-esm/react-surface-ELXFYKP6.mjs.map +0 -7
- package/dist/types/src/components/CommentContainer.d.ts +0 -13
- package/dist/types/src/components/CommentContainer.d.ts.map +0 -1
- package/dist/types/src/peers.stories.d.ts +0 -11
- package/dist/types/src/peers.stories.d.ts.map +0 -1
- package/src/peers.stories.tsx +0 -189
- /package/dist/lib/browser/{ChannelContainer-PKFBVENP.mjs.map → ChannelContainer-4PYFOIDK.mjs.map} +0 -0
- /package/dist/lib/browser/{ChatContainer-RSOKYAMK.mjs.map → ChatContainer-EXNNREYB.mjs.map} +0 -0
- /package/dist/lib/browser/{chunk-IIUTBDVB.mjs.map → chunk-EV4JWI7L.mjs.map} +0 -0
- /package/dist/lib/browser/{chunk-JKQUJOTX.mjs.map → chunk-GERVMFQW.mjs.map} +0 -0
- /package/dist/lib/{node-esm/react-root-RUXOAQNW.mjs.map → browser/react-root-XKOD4KRB.mjs.map} +0 -0
- /package/dist/lib/browser/{settings-RB2RSLXV.mjs.map → settings-GRKEID73.mjs.map} +0 -0
- /package/dist/lib/node-esm/{ChannelContainer-O4QJII2P.mjs.map → ChannelContainer-KQQEZWUN.mjs.map} +0 -0
- /package/dist/lib/node-esm/{ChatContainer-F6CSADV7.mjs.map → ChatContainer-QVQKFBWA.mjs.map} +0 -0
- /package/dist/lib/node-esm/{chunk-PGRP3O4O.mjs.map → chunk-57XR3LEF.mjs.map} +0 -0
- /package/dist/lib/node-esm/{chunk-ESQC6SYE.mjs.map → chunk-GRLRWTRU.mjs.map} +0 -0
- /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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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<
|
|
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.
|
|
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 {
|
|
7
|
-
import {
|
|
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(),
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 {
|
|
12
|
-
import {
|
|
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 {
|
|
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 {
|
|
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
|
|
8
|
+
import { type CallManager, type CallState, type MediaState } from '../calls';
|
|
9
9
|
import { THREAD_PLUGIN } from '../meta';
|
|
10
|
-
import { type
|
|
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';
|