@dxos/plugin-thread 0.8.4-main.e098934 → 0.8.4-main.e8ec1fe
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-NDIH62Q4.mjs +17 -0
- package/dist/lib/browser/ChatContainer-6FVFME3R.mjs +16 -0
- package/dist/lib/browser/{app-graph-builder-FHAOPO57.mjs → app-graph-builder-URVQHGMR.mjs} +32 -32
- package/dist/lib/browser/app-graph-builder-URVQHGMR.mjs.map +7 -0
- package/dist/lib/browser/blueprint-definition-TQ4JFMZZ.mjs +101 -0
- package/dist/lib/browser/blueprint-definition-TQ4JFMZZ.mjs.map +7 -0
- package/dist/lib/browser/{call-manager-RMPTWSTF.mjs → call-manager-4YFT4XA6.mjs} +8 -7
- package/dist/lib/{node-esm/call-manager-QAREJFVX.mjs.map → browser/call-manager-4YFT4XA6.mjs.map} +1 -1
- package/dist/lib/browser/{chunk-PBMNFG3B.mjs → chunk-6LWKNZUV.mjs} +18 -17
- package/dist/lib/browser/chunk-6LWKNZUV.mjs.map +7 -0
- package/dist/lib/browser/chunk-CFC7LEPD.mjs +18 -0
- package/dist/lib/browser/chunk-CFC7LEPD.mjs.map +7 -0
- package/dist/lib/browser/{chunk-GERVMFQW.mjs → chunk-CP7E2HRE.mjs} +2 -2
- package/dist/lib/browser/chunk-CP7E2HRE.mjs.map +7 -0
- package/dist/lib/browser/{chunk-7W7QK5ZP.mjs → chunk-F36NHPJG.mjs} +37 -34
- package/dist/lib/browser/chunk-F36NHPJG.mjs.map +7 -0
- package/dist/lib/browser/{chunk-ZH2WPTNP.mjs → chunk-HKI7FUMB.mjs} +65 -72
- package/dist/lib/browser/chunk-HKI7FUMB.mjs.map +7 -0
- package/dist/lib/browser/{chunk-XYUJXHYV.mjs → chunk-ISCHODBV.mjs} +1 -1
- package/dist/lib/browser/{chunk-XYUJXHYV.mjs.map → chunk-ISCHODBV.mjs.map} +2 -2
- package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
- package/dist/lib/browser/chunk-JDFDDUTH.mjs +23 -0
- package/dist/lib/browser/chunk-JDFDDUTH.mjs.map +7 -0
- package/dist/lib/browser/{chunk-RI3Z6MK3.mjs → chunk-KOBXMDCI.mjs} +68 -67
- package/dist/lib/browser/chunk-KOBXMDCI.mjs.map +7 -0
- package/dist/lib/browser/chunk-QM34EZQK.mjs +20 -0
- package/dist/lib/browser/chunk-QM34EZQK.mjs.map +7 -0
- package/dist/lib/browser/{chunk-KTWYVC5X.mjs → chunk-R5UOPOO7.mjs} +44 -49
- package/dist/lib/browser/chunk-R5UOPOO7.mjs.map +7 -0
- package/dist/lib/browser/{chunk-ZCEU5K23.mjs → chunk-ZCW3NSDZ.mjs} +139 -236
- package/dist/lib/browser/chunk-ZCW3NSDZ.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +41 -42
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/{intent-resolver-J7OCP2P6.mjs → intent-resolver-S3F7DVFM.mjs} +33 -99
- package/dist/lib/browser/intent-resolver-S3F7DVFM.mjs.map +7 -0
- package/dist/lib/browser/{markdown-Z677YORA.mjs → markdown-454GFKEZ.mjs} +25 -23
- package/dist/lib/browser/markdown-454GFKEZ.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/react-root-ZB5ZA4I6.mjs +29 -0
- package/dist/lib/browser/react-root-ZB5ZA4I6.mjs.map +7 -0
- package/dist/lib/browser/{react-surface-GVGZRBDK.mjs → react-surface-MBLTXSOC.mjs} +38 -36
- package/dist/lib/browser/react-surface-MBLTXSOC.mjs.map +7 -0
- package/dist/lib/browser/{settings-GRKEID73.mjs → settings-JN2HHORY.mjs} +6 -5
- package/dist/lib/{node-esm/settings-F2ODVNNW.mjs.map → browser/settings-JN2HHORY.mjs.map} +1 -1
- package/dist/lib/browser/{state-2T4KDWBX.mjs → state-UYPLBGZJ.mjs} +6 -5
- package/dist/lib/{node-esm/state-62TQKQVB.mjs.map → browser/state-UYPLBGZJ.mjs.map} +1 -1
- package/dist/lib/browser/types/index.mjs +7 -10
- package/dist/lib/node-esm/ChannelContainer-NGSDMNEE.mjs +18 -0
- package/dist/lib/node-esm/ChatContainer-KWNON7EN.mjs +17 -0
- package/dist/lib/node-esm/ChatContainer-KWNON7EN.mjs.map +7 -0
- package/dist/lib/node-esm/{app-graph-builder-XEYWX5FC.mjs → app-graph-builder-2IH5RPR7.mjs} +32 -32
- package/dist/lib/node-esm/app-graph-builder-2IH5RPR7.mjs.map +7 -0
- package/dist/lib/node-esm/blueprint-definition-TSX5HHW7.mjs +102 -0
- package/dist/lib/node-esm/blueprint-definition-TSX5HHW7.mjs.map +7 -0
- package/dist/lib/node-esm/{call-manager-QAREJFVX.mjs → call-manager-UMUXEYH5.mjs} +8 -7
- package/dist/lib/{browser/call-manager-RMPTWSTF.mjs.map → node-esm/call-manager-UMUXEYH5.mjs.map} +1 -1
- package/dist/lib/node-esm/chunk-2AEIN5MI.mjs +22 -0
- package/dist/lib/node-esm/chunk-2AEIN5MI.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-3VRYXHKX.mjs +25 -0
- package/dist/lib/node-esm/chunk-3VRYXHKX.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-TIPIOH2J.mjs → chunk-7KZWZS2U.mjs} +139 -236
- package/dist/lib/node-esm/chunk-7KZWZS2U.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-57XR3LEF.mjs → chunk-ABUFOZVX.mjs} +2 -2
- package/dist/lib/node-esm/chunk-ABUFOZVX.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-P6E247RF.mjs → chunk-MEIWWPR2.mjs} +44 -49
- package/dist/lib/node-esm/chunk-MEIWWPR2.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-LE2LIYGX.mjs → chunk-MM6HOX5W.mjs} +65 -72
- package/dist/lib/node-esm/chunk-MM6HOX5W.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-JNPKMT7O.mjs → chunk-PZH2EDU5.mjs} +68 -67
- package/dist/lib/node-esm/chunk-PZH2EDU5.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-RT6NRL2I.mjs +19 -0
- package/dist/lib/node-esm/chunk-RT6NRL2I.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-2V3WSLUZ.mjs → chunk-VBI32FGI.mjs} +1 -1
- package/dist/lib/node-esm/{chunk-2V3WSLUZ.mjs.map → chunk-VBI32FGI.mjs.map} +2 -2
- package/dist/lib/node-esm/{chunk-SNKFZQST.mjs → chunk-Y3F2SGNH.mjs} +37 -34
- package/dist/lib/node-esm/chunk-Y3F2SGNH.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-DKCQCENK.mjs → chunk-Z4GUSLWL.mjs} +18 -17
- package/dist/lib/node-esm/chunk-Z4GUSLWL.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +41 -42
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/{intent-resolver-SR2LW4HF.mjs → intent-resolver-UES35EMJ.mjs} +33 -99
- package/dist/lib/node-esm/intent-resolver-UES35EMJ.mjs.map +7 -0
- package/dist/lib/node-esm/{markdown-FL4IXLRP.mjs → markdown-7JUG6J7B.mjs} +25 -23
- package/dist/lib/node-esm/markdown-7JUG6J7B.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/react-root-3XXULWUN.mjs +30 -0
- package/dist/lib/node-esm/react-root-3XXULWUN.mjs.map +7 -0
- package/dist/lib/node-esm/{react-surface-WLQUVRAX.mjs → react-surface-DCF4DD7B.mjs} +38 -36
- package/dist/lib/node-esm/react-surface-DCF4DD7B.mjs.map +7 -0
- package/dist/lib/node-esm/{settings-F2ODVNNW.mjs → settings-VSPM3BIM.mjs} +6 -5
- package/dist/lib/{browser/settings-GRKEID73.mjs.map → node-esm/settings-VSPM3BIM.mjs.map} +1 -1
- package/dist/lib/node-esm/{state-62TQKQVB.mjs → state-XNWOLBNE.mjs} +6 -5
- package/dist/lib/{browser/state-2T4KDWBX.mjs.map → node-esm/state-XNWOLBNE.mjs.map} +1 -1
- package/dist/lib/node-esm/types/index.mjs +7 -10
- package/dist/types/src/ThreadPlugin.d.ts +1 -1
- package/dist/types/src/ThreadPlugin.d.ts.map +1 -1
- package/dist/types/src/calls/media-manager.d.ts.map +1 -1
- package/dist/types/src/calls-service.stories.d.ts +0 -1
- package/dist/types/src/calls-service.stories.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/capabilities/blueprint-definition.d.ts +5 -0
- package/dist/types/src/capabilities/blueprint-definition.d.ts.map +1 -0
- 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 +1 -1
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
- package/dist/types/src/capabilities/markdown.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/components/Call/Toolbar.d.ts +2 -2
- package/dist/types/src/components/Call/Toolbar.d.ts.map +1 -1
- package/dist/types/src/components/CallDebugPanel.d.ts.map +1 -1
- package/dist/types/src/components/ChannelContainer.d.ts +2 -2
- package/dist/types/src/components/ChannelContainer.d.ts.map +1 -1
- package/dist/types/src/components/ChannelContainer.stories.d.ts +73 -8
- package/dist/types/src/components/ChannelContainer.stories.d.ts.map +1 -1
- package/dist/types/src/components/Chat.stories.d.ts +73 -6
- package/dist/types/src/components/Chat.stories.d.ts.map +1 -1
- package/dist/types/src/components/ChatContainer.d.ts +6 -5
- package/dist/types/src/components/ChatContainer.d.ts.map +1 -1
- package/dist/types/src/components/Comments.stories.d.ts +1 -2
- package/dist/types/src/components/Comments.stories.d.ts.map +1 -1
- package/dist/types/src/components/CommentsContainer.d.ts +2 -2
- package/dist/types/src/components/CommentsContainer.d.ts.map +1 -1
- package/dist/types/src/components/CommentsThreadContainer.d.ts +8 -8
- package/dist/types/src/components/CommentsThreadContainer.d.ts.map +1 -1
- package/dist/types/src/components/Media/VideoObject.d.ts +2 -2
- package/dist/types/src/components/Media/VideoObject.d.ts.map +1 -1
- package/dist/types/src/components/Media/VideoObject.stories.d.ts +5 -3
- package/dist/types/src/components/Media/VideoObject.stories.d.ts.map +1 -1
- package/dist/types/src/components/MessageContainer.d.ts +2 -2
- package/dist/types/src/components/MessageContainer.d.ts.map +1 -1
- package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts +2 -2
- package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts.map +1 -1
- package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts +2 -2
- 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/ThreadCompanion.d.ts +5 -0
- package/dist/types/src/components/ThreadCompanion.d.ts.map +1 -0
- package/dist/types/src/components/ThreadSettings.d.ts +1 -1
- package/dist/types/src/components/ThreadSettings.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +3 -3
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts +3 -3
- package/dist/types/src/components/testing.d.ts.map +1 -1
- package/dist/types/src/extensions/threads.d.ts.map +1 -1
- package/dist/types/src/functions/create-proposals.d.ts +6 -0
- package/dist/types/src/functions/create-proposals.d.ts.map +1 -0
- package/dist/types/src/functions/index.d.ts +2 -0
- package/dist/types/src/functions/index.d.ts.map +1 -0
- package/dist/types/src/hooks/analytics.d.ts +2 -2
- package/dist/types/src/hooks/analytics.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +2 -2
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useVideoStreamTrack.d.ts +1 -1
- package/dist/types/src/hooks/useVideoStreamTrack.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +1 -2
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/testing/stories.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +72 -6
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/Channel.d.ts +16 -0
- package/dist/types/src/types/Channel.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +1 -1
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/src/types/types.d.ts +30 -117
- package/dist/types/src/types/types.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +62 -58
- package/src/ThreadPlugin.tsx +139 -132
- package/src/calls/media-manager.ts +9 -6
- package/src/calls/util/stub-media-streams.ts +2 -2
- package/src/calls-service.stories.tsx +2 -5
- package/src/capabilities/app-graph-builder.ts +41 -30
- package/src/capabilities/blueprint-definition.ts +38 -0
- package/src/capabilities/capabilities.ts +7 -7
- package/src/capabilities/index.ts +1 -1
- package/src/capabilities/intent-resolver.ts +22 -59
- package/src/capabilities/markdown.ts +5 -3
- package/src/capabilities/react-root.tsx +2 -2
- package/src/capabilities/react-surface.tsx +25 -23
- package/src/components/Call/Call.tsx +1 -1
- package/src/components/Call/Toolbar.tsx +5 -5
- package/src/components/CallDebugPanel.tsx +12 -14
- package/src/components/CallSidebar.tsx +1 -1
- package/src/components/ChannelContainer.stories.tsx +10 -10
- package/src/components/ChannelContainer.tsx +19 -15
- package/src/components/Chat.stories.tsx +14 -19
- package/src/components/ChatContainer.tsx +29 -21
- package/src/components/Comments.stories.tsx +11 -17
- package/src/components/CommentsContainer.tsx +5 -7
- package/src/components/CommentsThreadContainer.tsx +31 -27
- package/src/components/Lobby/Lobby.tsx +1 -1
- package/src/components/Media/VideoObject.stories.tsx +12 -7
- package/src/components/Media/VideoObject.tsx +1 -1
- package/src/components/MessageContainer.tsx +6 -6
- package/src/components/Participant/Participant.tsx +1 -1
- package/src/components/ResponsiveGrid/ResponsiveContainer.stories.tsx +3 -4
- package/src/components/ResponsiveGrid/ResponsiveContainer.tsx +2 -2
- package/src/components/ResponsiveGrid/ResponsiveGrid.stories.tsx +4 -5
- package/src/components/ResponsiveGrid/ResponsiveGrid.tsx +5 -5
- package/src/components/ResponsiveGrid/ResponsiveGridItem.tsx +5 -2
- package/src/components/{ThreadComplementary.tsx → ThreadCompanion.tsx} +41 -34
- package/src/components/ThreadSettings.tsx +4 -5
- package/src/components/index.ts +4 -4
- package/src/components/testing.ts +7 -9
- package/src/extensions/threads.ts +25 -16
- package/src/functions/create-proposals.ts +56 -0
- package/src/functions/index.ts +5 -0
- package/src/hooks/analytics.ts +4 -7
- package/src/hooks/index.ts +3 -2
- package/src/hooks/useVideoStreamTrack.tsx +1 -1
- package/src/meta.ts +9 -5
- package/src/testing/stories.ts +3 -6
- package/src/translations.ts +4 -3
- package/src/types/Channel.ts +26 -0
- package/src/types/index.ts +1 -1
- package/src/types/types.ts +18 -27
- package/src/util.ts +1 -1
- package/dist/lib/browser/ChannelContainer-4PYFOIDK.mjs +0 -16
- package/dist/lib/browser/ChatContainer-EXNNREYB.mjs +0 -15
- package/dist/lib/browser/app-graph-builder-FHAOPO57.mjs.map +0 -7
- package/dist/lib/browser/chunk-4APCDRSH.mjs +0 -18
- package/dist/lib/browser/chunk-4APCDRSH.mjs.map +0 -7
- package/dist/lib/browser/chunk-7W7QK5ZP.mjs.map +0 -7
- package/dist/lib/browser/chunk-EV4JWI7L.mjs +0 -17
- package/dist/lib/browser/chunk-EV4JWI7L.mjs.map +0 -7
- package/dist/lib/browser/chunk-G4CNILRR.mjs +0 -23
- package/dist/lib/browser/chunk-G4CNILRR.mjs.map +0 -7
- package/dist/lib/browser/chunk-GERVMFQW.mjs.map +0 -7
- package/dist/lib/browser/chunk-KTWYVC5X.mjs.map +0 -7
- package/dist/lib/browser/chunk-PBMNFG3B.mjs.map +0 -7
- package/dist/lib/browser/chunk-RI3Z6MK3.mjs.map +0 -7
- package/dist/lib/browser/chunk-ZCEU5K23.mjs.map +0 -7
- package/dist/lib/browser/chunk-ZH2WPTNP.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-J7OCP2P6.mjs.map +0 -7
- package/dist/lib/browser/markdown-Z677YORA.mjs.map +0 -7
- package/dist/lib/browser/react-root-XKOD4KRB.mjs +0 -28
- package/dist/lib/browser/react-root-XKOD4KRB.mjs.map +0 -7
- package/dist/lib/browser/react-surface-GVGZRBDK.mjs.map +0 -7
- package/dist/lib/browser/toolkit-KUPIIFC6.mjs +0 -80
- package/dist/lib/browser/toolkit-KUPIIFC6.mjs.map +0 -7
- package/dist/lib/node-esm/ChannelContainer-KQQEZWUN.mjs +0 -17
- package/dist/lib/node-esm/ChatContainer-QVQKFBWA.mjs +0 -16
- package/dist/lib/node-esm/app-graph-builder-XEYWX5FC.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-4T45PCKP.mjs +0 -25
- package/dist/lib/node-esm/chunk-4T45PCKP.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-57XR3LEF.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-DKCQCENK.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-GRLRWTRU.mjs +0 -19
- package/dist/lib/node-esm/chunk-GRLRWTRU.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-JNPKMT7O.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-LE2LIYGX.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-P6E247RF.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-PYTVBN5J.mjs +0 -19
- package/dist/lib/node-esm/chunk-PYTVBN5J.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-SNKFZQST.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-TIPIOH2J.mjs.map +0 -7
- package/dist/lib/node-esm/intent-resolver-SR2LW4HF.mjs.map +0 -7
- package/dist/lib/node-esm/markdown-FL4IXLRP.mjs.map +0 -7
- package/dist/lib/node-esm/react-root-4JWDRIQB.mjs +0 -29
- package/dist/lib/node-esm/react-root-4JWDRIQB.mjs.map +0 -7
- package/dist/lib/node-esm/react-surface-WLQUVRAX.mjs.map +0 -7
- package/dist/lib/node-esm/toolkit-KZIS7G36.mjs +0 -81
- package/dist/lib/node-esm/toolkit-KZIS7G36.mjs.map +0 -7
- package/dist/types/src/capabilities/toolkit.d.ts +0 -5
- package/dist/types/src/capabilities/toolkit.d.ts.map +0 -1
- package/dist/types/src/components/ThreadComplementary.d.ts +0 -5
- package/dist/types/src/components/ThreadComplementary.d.ts.map +0 -1
- package/dist/types/src/types/schema.d.ts +0 -177
- package/dist/types/src/types/schema.d.ts.map +0 -1
- package/src/capabilities/toolkit.ts +0 -78
- package/src/types/schema.ts +0 -33
- /package/dist/lib/browser/{ChannelContainer-4PYFOIDK.mjs.map → ChannelContainer-NDIH62Q4.mjs.map} +0 -0
- /package/dist/lib/browser/{ChatContainer-EXNNREYB.mjs.map → ChatContainer-6FVFME3R.mjs.map} +0 -0
- /package/dist/lib/{node-esm/ChannelContainer-KQQEZWUN.mjs.map → browser/chunk-J5LGTIGS.mjs.map} +0 -0
- /package/dist/lib/node-esm/{ChatContainer-QVQKFBWA.mjs.map → ChannelContainer-NGSDMNEE.mjs.map} +0 -0
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/components/ChannelContainer.tsx", "../../../src/components/Call/Call.tsx", "../../../src/components/Media/AudioStream.tsx", "../../../src/components/Media/VideoObject.tsx", "../../../src/components/Participant/Participant.tsx", "../../../src/components/ResponsiveGrid/ResponsiveContainer.tsx", "../../../src/components/ResponsiveGrid/ResponsiveGrid.tsx", "../../../src/components/ResponsiveGrid/ResponsiveGridItem.tsx", "../../../src/components/Participant/ParticipantGrid.tsx", "../../../src/components/Call/Toolbar.tsx"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { Rx } from '@effect-rx/rx-react';\nimport React, { type ChangeEvent, useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { useCapabilities, useCapability } from '@dxos/app-framework';\nimport { Context } from '@dxos/context';\nimport { failUndefined } from '@dxos/debug';\nimport { log } from '@dxos/log';\nimport { useClient } from '@dxos/react-client';\nimport { fullyQualifiedId, getSpace } from '@dxos/react-client/echo';\nimport { useIdentity } from '@dxos/react-client/halo';\nimport { ElevationProvider, Input, type ThemedClassName, useTranslation } from '@dxos/react-ui';\nimport { ControlGroup, ControlGroupButton, ControlItemInput } from '@dxos/react-ui-form';\nimport { MenuProvider, ToolbarMenu, createMenuAction, createMenuItemGroup, useMenuActions } from '@dxos/react-ui-menu';\nimport { useSoundEffect } from '@dxos/react-ui-sfx';\nimport { StackItem } from '@dxos/react-ui-stack';\n\nimport { ThreadCapabilities } from '../capabilities';\nimport { meta } from '../meta';\nimport { type ChannelType } from '../types';\n\nimport { Call } from './Call';\nimport ChatContainer from './ChatContainer';\n\nexport type ChannelContainerProps = {\n channel?: ChannelType;\n roomId?: string;\n role?: string;\n fullscreen?: boolean;\n};\n\n/**\n * Renders a call when active, otherwise renders the channel chat.\n */\nexport const ChannelContainer = ({ channel, roomId: _roomId, role, fullscreen }: ChannelContainerProps) => {\n const space = getSpace(channel);\n const callManager = useCapability(ThreadCapabilities.CallManager);\n const roomId = _roomId ?? (channel ? fullyQualifiedId(channel) : failUndefined());\n const identity = useIdentity();\n const isNamed = !!identity?.profile?.displayName;\n const joinSound = useSoundEffect('JoinCall');\n const leaveSound = useSoundEffect('LeaveCall');\n\n const extensions = useCapabilities(ThreadCapabilities.CallExtension);\n useEffect(() => {\n const ctx = new Context();\n callManager.left.on(ctx, (roomId) => {\n extensions.forEach((extension) => {\n void extension.onLeave?.(roomId);\n });\n });\n\n callManager.callStateUpdated.on(ctx, (state) => {\n extensions.forEach((extension) => {\n void extension.onCallStateUpdated?.(state);\n });\n });\n\n callManager.mediaStateUpdated.on(ctx, (state) => {\n extensions.forEach((extension) => {\n void extension.onMediaStateUpdated?.(state);\n });\n });\n\n return () => {\n void ctx.dispose();\n };\n }, [callManager, extensions]);\n\n /**\n * Join the call.\n */\n // TODO(wittjosiah): Show preview before joining?\n const handleJoin = useCallback(async () => {\n if (!roomId || !channel) {\n return;\n }\n\n if (callManager.joined) {\n await callManager.leave();\n }\n\n try {\n void joinSound.play();\n callManager.setRoomId(roomId);\n await callManager.join();\n await Promise.all(extensions.map((extension) => extension.onJoin?.({ channel, roomId })));\n } catch (err) {\n // TODO(burdon): Error sound.\n log.catch(err);\n }\n }, [extensions, channel, roomId]);\n\n /**\n * Leave the call.\n */\n const handleLeave = useCallback(async () => {\n try {\n void leaveSound.play();\n } catch (err) {\n // TODO(burdon): Error sound.\n log.catch(err);\n } finally {\n void callManager.turnAudioOff();\n void callManager.turnVideoOff();\n void callManager.turnScreenshareOff();\n void callManager.leave();\n }\n }, [extensions, roomId]);\n\n const isJoined = callManager.joined && callManager.roomId === roomId;\n\n return (\n <StackItem.Content toolbar={!isJoined} classNames={isJoined && 'h-full'}>\n {isJoined && !isNamed && <DisplayNameMissing />}\n {isJoined && isNamed && (\n <Call.Root>\n <Call.Grid fullscreen={fullscreen} />\n <Call.Toolbar channel={channel} onLeave={handleLeave} />\n </Call.Root>\n )}\n {!isJoined && channel && channel.defaultThread.target && space && (\n <>\n <ChannelToolbar attendableId={fullyQualifiedId(channel)} role={role} onJoinCall={handleJoin} />\n <ChatContainer space={space} thread={channel.defaultThread.target} />\n </>\n )}\n </StackItem.Content>\n );\n};\n\nexport default ChannelContainer;\n\nconst DisplayNameMissing = () => {\n const { t } = useTranslation(meta.id);\n const client = useClient();\n const [displayName, setDisplayName] = useState('');\n const handleChange = useCallback((event: ChangeEvent<HTMLInputElement>) => setDisplayName(event.target.value), []);\n const handleSave = useCallback(() => client.halo.updateProfile({ displayName }), [client, displayName]);\n\n return (\n <ControlGroup classNames='p-4 place-content-center'>\n <ControlItemInput title={t('display name label')} description={t('display name description')}>\n <Input.TextInput\n value={displayName}\n onChange={handleChange}\n placeholder={t('display name input placeholder')}\n classNames='md:min-is-64'\n />\n </ControlItemInput>\n <ControlGroupButton disabled={!displayName} onClick={handleSave}>\n {t('set display name label')}\n </ControlGroupButton>\n </ControlGroup>\n );\n};\n\nconst useChannelToolbarActions = (onJoinCall?: () => void) => {\n const creator = useMemo(\n () =>\n Rx.make(() => {\n return {\n nodes: [\n createMenuItemGroup('root', {\n label: ['channel toolbar title', { ns: meta.id }],\n }),\n createMenuAction('video-call', () => onJoinCall?.(), {\n label: ['start video call label', { ns: meta.id }],\n icon: 'ph--video-camera--regular',\n type: 'video-call',\n }),\n ],\n edges: [{ source: 'root', target: 'video-call' }],\n };\n }),\n [],\n );\n\n return useMenuActions(creator);\n};\n\ntype ChannelToolbarProps = ThemedClassName<{\n attendableId?: string;\n role?: string;\n onJoinCall?: () => void;\n}>;\n\nconst ChannelToolbar = ({ attendableId, role, onJoinCall, classNames }: ChannelToolbarProps) => {\n const menuProps = useChannelToolbarActions(onJoinCall);\n\n return (\n <ElevationProvider elevation={role === 'section' ? 'positioned' : 'base'}>\n <MenuProvider {...menuProps} attendableId={attendableId}>\n <ToolbarMenu classNames={classNames} />\n </MenuProvider>\n </ElevationProvider>\n );\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { type FC, type PropsWithChildren } from 'react';\n\nimport { useCapability } from '@dxos/app-framework';\nimport { type ThemedClassName } from '@dxos/react-ui';\n\nimport { ThreadCapabilities } from '../../capabilities';\nimport { useDebugMode } from '../../hooks';\nimport { AudioStream } from '../Media';\nimport { ParticipantGrid } from '../Participant';\n\nimport { Toolbar, type ToolbarProps } from './Toolbar';\n\n//\n// Root\n//\n\ntype CallRootProps = PropsWithChildren<ThemedClassName>;\n\nconst CallRoot: FC<CallRootProps> = ({ children }) => {\n return <div className='relative flex flex-col grow overflow-hidden'>{children}</div>;\n};\n\nCallRoot.displayName = 'CallRoot';\n\n//\n// Audio\n//\n\ntype CallAudioProps = {};\n\nconst CallAudio: FC<CallAudioProps> = () => {\n const call = useCapability(ThreadCapabilities.CallManager);\n\n return <AudioStream tracks={call.audioTracksToPlay} />;\n};\n\nCallAudio.displayName = 'CallAudio';\n\n//\n// Room\n//\n\ntype CallGridProps = {\n fullscreen?: boolean;\n};\n\nconst CallGrid: FC<CallGridProps> = ({ fullscreen }) => {\n const debug = useDebugMode();\n const call = useCapability(ThreadCapabilities.CallManager);\n\n return (\n <div className='grid grow p-4 dark:bg-neutral-900'>\n <ParticipantGrid self={call.self} users={call.users} debug={debug} fullscreen={fullscreen} />\n </div>\n );\n};\n\nCallGrid.displayName = 'CallGrid';\n\n//\n// Toolbar\n//\n\ntype CallToolbarProps = Pick<ToolbarProps, 'channel' | 'onLeave'>;\n\nconst CallToolbar: FC<CallToolbarProps> = (props) => {\n return (\n <div className='absolute bottom-0 left-0 right-0 flex justify-center'>\n <Toolbar isInRoom {...props} />\n </div>\n );\n};\n\nCallToolbar.displayName = 'CallToolbar';\n\n//\n// Export\n//\n\nexport const Call = {\n Root: CallRoot,\n Grid: CallGrid,\n Audio: CallAudio,\n Toolbar: CallToolbar,\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport React, { type FC, useEffect, useRef } from 'react';\n\nexport type AudioStreamProps = {\n tracks: MediaStreamTrack[];\n};\n\nexport const AudioStream: FC<AudioStreamProps> = ({ tracks }) => {\n const mediaStreamRef = useRef(new MediaStream());\n const ref = useRef<HTMLAudioElement>(null);\n\n useEffect(() => {\n const audio = ref.current;\n if (!audio) {\n return;\n }\n\n const mediaStream = mediaStreamRef.current;\n audio.srcObject = mediaStream;\n }, []);\n\n const resetSrcObject = () => {\n const audio = ref.current;\n const mediaStream = mediaStreamRef.current;\n if (!audio || !mediaStream) {\n return;\n }\n\n // Need to set srcObject again in Chrome and call play() again for Safari\n // https://www.youtube.com/live/Tkx3OGrwVk8?si=K--P_AzNnAGrjraV&t=2533\n // Calling play() this way to make Chrome happy otherwise it throws an error.\n audio.addEventListener('canplay', () => audio.play(), { once: true });\n audio.srcObject = mediaStream;\n };\n\n return (\n <>\n <audio ref={ref} autoPlay />\n {tracks.map((track) => (\n <AudioTrack key={track.id} track={track} mediaStream={mediaStreamRef.current} resetSrcObject={resetSrcObject} />\n ))}\n </>\n );\n};\n\ntype AudioTrackProps = {\n track: MediaStreamTrack;\n mediaStream: MediaStream;\n resetSrcObject: () => void;\n};\n\nconst AudioTrack = ({ track, mediaStream, resetSrcObject }: AudioTrackProps) => {\n useEffect(() => {\n const currentTrack = track;\n mediaStream.addTrack(currentTrack);\n resetSrcObject();\n return () => {\n mediaStream.removeTrack(currentTrack);\n resetSrcObject();\n };\n }, [track, mediaStream]);\n\n return null;\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport React, { type JSX, forwardRef, memo, useEffect, useRef } from 'react';\n\nimport { type ThemedClassName } from '@dxos/react-ui';\nimport { mx } from '@dxos/react-ui-theme';\n\nexport type VideoObjectProps = Omit<JSX.IntrinsicElements['video'], 'className' | 'ref'> &\n ThemedClassName<{\n videoStream?: MediaStream;\n flip?: boolean;\n // TODO(burdon): If screenshare then contain.\n contain?: boolean;\n }>;\n\nexport const VideoObject = memo(\n forwardRef<HTMLVideoElement, VideoObjectProps>(({ videoStream, classNames, flip, contain, ...rest }, ref) => {\n const internalRef = useRef<HTMLVideoElement | null>(null);\n\n useEffect(() => {\n const video = internalRef.current;\n if (video && videoStream) {\n video.srcObject = videoStream;\n video.setAttribute('autoplay', 'true');\n video.setAttribute('playsinline', 'true');\n }\n }, [videoStream, internalRef.current]);\n\n // NOTE: The video element typically has a max size of 1280x720.\n return (\n <video\n className={mx(\n 'w-full aspect-video',\n flip && 'scale-x-[-1]',\n contain ? 'object-contain' : 'object-cover',\n classNames,\n )}\n ref={(v) => {\n internalRef.current = v;\n if (ref === null) {\n return;\n }\n\n if (typeof ref === 'function') {\n ref(v);\n } else {\n ref.current = v;\n }\n }}\n {...rest}\n />\n );\n }),\n);\n\nVideoObject.displayName = 'VideoObject';\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport React, { memo, useMemo } from 'react';\n\nimport { useCapability } from '@dxos/app-framework';\n\nimport { type EncodedTrackName, type UserState } from '../../calls';\nimport { ThreadCapabilities } from '../../capabilities';\nimport { VideoObject } from '../Media';\nimport { ResponsiveGridItem, type ResponsiveGridItemProps } from '../ResponsiveGrid';\n\nexport const SCREENSHARE_SUFFIX = '_screenshare';\n\nexport const Participant = memo(({ item: user, debug, ...props }: ResponsiveGridItemProps<UserState>) => {\n const call = useCapability(ThreadCapabilities.CallManager);\n const isSelf: boolean = call.self.id !== undefined && user.id !== undefined && user.id.startsWith(call.self.id);\n const isScreenshare = user.id?.endsWith(SCREENSHARE_SUFFIX);\n\n const pulledVideoStream =\n !isSelf && isScreenshare && user.tracks?.screenshareEnabled\n ? call.getVideoStream(user.tracks?.screenshare as EncodedTrackName)\n : !isSelf && !isScreenshare && user.tracks?.videoEnabled\n ? call.getVideoStream(user.tracks?.video as EncodedTrackName)\n : undefined;\n\n const videoStream = useMemo<MediaStream | undefined>(() => {\n if (isSelf) {\n if (isScreenshare) {\n return call.media.screenshareVideoStream;\n } else if (!isScreenshare) {\n return call.media.videoStream;\n }\n } else if (!isSelf) {\n return pulledVideoStream;\n }\n }, [isSelf, isScreenshare, call.media.videoStream, call.media.screenshareVideoStream, pulledVideoStream]);\n\n return (\n <ResponsiveGridItem\n {...props}\n item={user}\n name={user.name}\n self={isSelf}\n screenshare={!!call.media.screenshareVideoStream}\n video={call.media.videoEnabled}\n mute={user ? !user.tracks?.audioEnabled : false}\n wave={user.raisedHand}\n speaking={user.speaking}\n debug={debug}\n >\n <VideoObject\n videoStream={videoStream}\n flip={isSelf && !isScreenshare}\n contain={!!isScreenshare}\n classNames='rounded-md'\n />\n </ResponsiveGridItem>\n );\n});\n\nParticipant.displayName = 'Participant';\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { type PropsWithChildren } from 'react';\n\nimport { mx } from '@dxos/react-ui-theme';\n\n/**\n * A container component that maintains the child's aspect ratio while centering its content.\n * The container will scale to fit within its parent's bounds while preserving the aspect ratio.\n *\n * @example\n * <ResponsiveContainer>\n * <VideoObject />\n * </ResponsiveContainer>\n */\nexport const ResponsiveContainer = ({ children }: PropsWithChildren) => {\n return (\n // Outer container that takes full size of parent.\n <div role='none' className='relative flex w-full h-full'>\n {/* Absolute positioning layer for centering content. */}\n <div role='none' className='absolute inset-0 flex justify-center items-center'>\n {/* Content container that maintains given aspect ratio and proper scaling. */}\n <div role='none' className={mx('max-h-full max-w-full w-auto h-auto aspect-video')}>\n {children}\n </div>\n </div>\n </div>\n );\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { type ComponentType, type FC, useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react';\nimport { useResizeDetector } from 'react-resize-detector';\n\nimport { invariant } from '@dxos/invariant';\nimport { type ThemedClassName } from '@dxos/react-ui';\nimport { type Size } from '@dxos/react-ui-dnd';\nimport { mx } from '@dxos/react-ui-theme';\n\nimport { ResponsiveContainer } from './ResponsiveContainer';\nimport { type ResponsiveGridItemProps } from './ResponsiveGridItem';\n\nconst ASPECT_RATIO = 16 / 9;\nconst MIN_GALLERY_HEIGHT = 250;\n\nconst DEFAULT_GAP = 8;\n\nconst maxImageSize = 'w-[2560px] h-[1440px]';\n\n/**\n * Props for the ResponsiveGrid component.\n */\nexport type ResponsiveGridProps<T extends object = any> = ThemedClassName<{\n /** Cell component. */\n Cell: ComponentType<ResponsiveGridItemProps<T>>;\n\n /** Space between grid items in pixels. */\n gap?: number;\n\n /** Function to get the ID of an item. */\n getId?: (item: T) => string;\n\n /** Array of items to display in the grid. */\n items: T[];\n\n /** ID of the pinned item. */\n pinned?: string;\n\n /** Whether to hide the gallery (unpinned items) when an item is pinned. */\n autoHideGallery?: boolean;\n\n /** Whether the divider is resizable. */\n resizable?: boolean;\n\n /** Debug mode. */\n debug?: boolean;\n\n /** Callback when the pinned item changes. */\n onPinnedChange?: (pinned: string | undefined) => void;\n}>;\n\nconst defaultGetId: ResponsiveGridProps<any>['getId'] = (item: any) => item.id;\n\n/**\n * A responsive grid component that automatically adjusts its layout to optimize space usage.\n * Maintains aspect ratio of items while ensuring uniform gaps between them.\n */\nexport const ResponsiveGrid = <T extends object = any>({\n classNames,\n Cell,\n gap = DEFAULT_GAP,\n getId = defaultGetId,\n items,\n pinned,\n autoHideGallery = false,\n debug,\n onPinnedChange,\n}: ResponsiveGridProps<T>) => {\n const {\n width: containerWidth = 0,\n height: containerHeight = 0,\n ref: containerRef,\n } = useResizeDetector<HTMLDivElement>({ refreshRate: 100 });\n const [dividerHeight, setDividerHeight] = useState<Size>(0);\n useEffect(() => {\n if (containerWidth && containerHeight) {\n const { height } = fitAspectRatio(containerWidth, containerHeight, ASPECT_RATIO);\n setDividerHeight(Math.min(height, containerHeight - MIN_GALLERY_HEIGHT));\n }\n }, [containerWidth, containerHeight]);\n\n const pinnedItem = useMemo(() => items.find((item) => getId(item) === pinned), [items, pinned]);\n const mainItems = useMemo(() => items.filter((item) => getId(item) !== pinned), [items, pinned]);\n const hideGallery = autoHideGallery && pinnedItem !== undefined;\n\n //\n // Recalculate optimal layout when container size or items change.\n //\n const [{ time, columns, cellWidth }, setLayout] = useState<Layout>({ time: 0, columns: 0, cellWidth: 0 });\n const { width = 0, height = 0, ref: gridContainerRef } = useResizeDetector<HTMLDivElement>({ refreshRate: 200 });\n useEffect(() => {\n if (containerHeight && width && height) {\n const layout = calculateLayout(width, height, mainItems.length, gap);\n setLayout({ time: Date.now(), ...layout });\n }\n }, [containerHeight, width, height, mainItems.length, gap, pinned]);\n\n //\n // We use the browser to layout invisible divs and then calculate the absolute position of these items,\n // which are animated into position.\n //\n const [bounds, setBounds] = useState<[T, DOMRectBounds][]>([]);\n useLayoutEffect(() => {\n if ((!hideGallery && !gridContainerRef.current) || !containerHeight) {\n return;\n }\n\n // TODO(burdon): Consider directly setting bounds on DOM elementsinstead of state update?\n const t = setTimeout(() => {\n setBounds(\n items\n .filter((item) => !hideGallery || item === pinnedItem)\n .map((item) => {\n invariant(containerRef.current);\n const el = containerRef.current.querySelector(`[data-grid-item=\"${getId(item)}\"]`);\n if (!el) {\n return null;\n }\n\n const bounds = getRelativeBounds(containerRef.current, el as HTMLElement);\n return [item, bounds];\n })\n .filter((item): item is [T, DOMRectBounds] => item !== null),\n );\n });\n\n return () => clearTimeout(t);\n }, [containerHeight, items, pinnedItem, hideGallery, time]);\n\n const handleClick = useCallback(\n (item: T) => onPinnedChange?.(getId(item) === pinned ? undefined : getId(item)),\n [pinned, onPinnedChange],\n );\n\n return (\n <div ref={containerRef} className={mx('relative w-full h-full', classNames)}>\n {/* Placeholder elements to calculate layout. */}\n <div className='absolute inset-0 flex flex-col grow gap-2'>\n {/* Pinned item. */}\n {pinnedItem && (\n <div\n className={mx('flex grow-[2] shrink overflow-hidden justify-center items-center', hideGallery && 'h-full')}\n style={hideGallery ? {} : { height: dividerHeight }}\n >\n <SoloItem id={getId(pinnedItem)} debug={debug} />\n </div>\n )}\n\n {/* Gallery. */}\n {!hideGallery && (\n <div\n ref={gridContainerRef}\n className='flex grow-[1] overflow-hidden justify-center items-center'\n style={hideGallery ? {} : { minHeight: MIN_GALLERY_HEIGHT }}\n >\n {mainItems.length === 1 && (\n <div style={{ width: cellWidth }} className='flex h-full'>\n <SoloItem id={getId(mainItems[0])} debug={debug} />\n </div>\n )}\n\n {mainItems.length > 1 && columns > 0 && (\n <div\n role='grid'\n style={{\n display: 'grid',\n gridTemplateColumns: `repeat(${columns}, ${cellWidth}px)`,\n gap: `${gap}px`,\n }}\n >\n {mainItems.map((item) => (\n <div\n key={getId(item)}\n {...{ 'data-grid-item': getId(item) }}\n className={mx(\n 'aspect-video max-h-full max-w-full w-auto h-auto',\n debug && 'border border-primary-500',\n )}\n />\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n\n {/* Absolutely positioned items. */}\n <div className={mx(debug && 'opacity-10')}>\n {bounds.map(([item, bounds]) => (\n <Cell\n key={getId(item)}\n classNames='absolute transition-all duration-500'\n item={item}\n style={bounds}\n pinned={getId(item) === pinned}\n onClick={items.length > 1 ? handleClick : undefined}\n />\n ))}\n </div>\n </div>\n );\n};\n\nconst SoloItem: FC<Pick<ResponsiveGridProps, 'debug'> & { id: string }> = ({ debug, id }) => {\n return (\n <ResponsiveContainer>\n <div\n {...{ 'data-grid-item': id }}\n className={mx('aspect-video overflow-hidden', debug && 'z-20 border-2 border-primary-500')}\n >\n {/* Maximum size placeholder image forces aspect ratio. */}\n <img alt='placeholder video' className={mx('opacity-0', maxImageSize)} />\n </div>\n </ResponsiveContainer>\n );\n};\n\ntype DOMRectBounds = Pick<DOMRect, 'top' | 'left' | 'width' | 'height'>;\n\n// TODO(burdon): Reconcile with react-ui-gameboard.\nconst getRelativeBounds = (container: HTMLElement, el: HTMLElement): DOMRectBounds => {\n const containerRect = container.getBoundingClientRect();\n const elementRect = el.getBoundingClientRect();\n return {\n top: elementRect.top - containerRect.top,\n left: elementRect.left - containerRect.left,\n width: elementRect.width,\n height: elementRect.height,\n };\n};\n\ntype Layout = {\n time?: number;\n columns: number;\n cellWidth: number;\n};\n\n/**\n * Calculates the optimal number of columns for a grid layout that minimizes wasted space.\n * @param containerWidth - Width of the container in pixels.\n * @param containerHeight - Height of the container in pixels.\n * @param count - Total number of items to display.\n * @param gap - Space between items in pixels.\n * @param aspectRatio - Desired aspect ratio of items (width/height).\n * @returns The optimal number of columns.\n */\nconst calculateLayout = (\n containerWidth: number,\n containerHeight: number,\n count: number,\n gap: number,\n aspectRatio = ASPECT_RATIO,\n): Layout => {\n if (count === 0) {\n return { columns: 1, cellWidth: 1 };\n }\n\n let minWastedSpace = Infinity;\n let bestColumns = 1;\n let cellWidth = 0;\n\n // Try different rows counts to find the optimal layout that minimizes wasted space.\n for (let rows = 1; rows <= count; rows++) {\n const cols = Math.ceil(count / rows);\n\n // Calculate available space accounting for gaps.\n const { width: itemWidth, height: itemHeight } = fitItemsToGrid(\n containerWidth,\n containerHeight,\n cols,\n rows,\n aspectRatio,\n gap,\n );\n\n // Calculate total wasted space for this configuration.\n const usedWidth = itemWidth * cols + gap * cols - 1;\n const usedHeight = itemHeight * rows + gap * rows - 1;\n\n // Determine if optimal.\n const wastedSpace = containerWidth * containerHeight - usedWidth * usedHeight;\n if (wastedSpace < minWastedSpace) {\n minWastedSpace = wastedSpace;\n bestColumns = cols;\n cellWidth = itemWidth;\n }\n }\n\n return { columns: bestColumns, cellWidth };\n};\n\n/**\n * Returns the size of the largest rectangle with the given aspect ration that fits within the grid.\n */\nconst fitItemsToGrid = (\n outerWidth: number,\n outerHeight: number,\n numCols: number,\n numRows: number,\n aspectRatio: number,\n gap: number,\n): { width: number; height: number } => {\n // Calculate available space accounting for gaps.\n const availableWidth = outerWidth - gap * (numCols - 1);\n const availableHeight = outerHeight - gap * (numRows - 1);\n\n // Calculate max dimensions.\n const maxCellWidth = availableWidth / numCols;\n const maxCellHeight = availableHeight / numRows;\n\n // Use fitAspectRatio to get dimensions that fit within max cell size while maintaining the desired aspect ratio\n return fitAspectRatio(maxCellWidth, maxCellHeight, aspectRatio);\n};\n\n/**\n * Returns the size of the largest rectangle the given aspect ratio that fits within the outer rectangle.\n */\nconst fitAspectRatio = (\n outerWidth: number,\n outerHeight: number,\n aspectRatio: number,\n): { width: number; height: number } => {\n if (outerWidth <= 0 || outerHeight <= 0 || aspectRatio <= 0) {\n return { width: 0, height: 0 };\n }\n\n // First try fitting to width.\n let width = outerWidth;\n let height = width / aspectRatio;\n\n // If too tall, fit to height instead.\n if (height > outerHeight) {\n height = outerHeight;\n width = height * aspectRatio;\n }\n\n return { width, height };\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { type CSSProperties, type PropsWithChildren, useEffect, useState } from 'react';\n\nimport { Icon, IconButton, type ThemedClassName, useTranslation } from '@dxos/react-ui';\nimport { Waveform } from '@dxos/react-ui-sfx';\nimport { groupHoverControlItemWithTransition, mx } from '@dxos/react-ui-theme';\n\nimport { meta } from '../../meta';\n\nexport type ResponsiveGridItemProps<T extends object = any> = PropsWithChildren<\n ThemedClassName<{\n item: T;\n style?: CSSProperties;\n pinned?: boolean;\n name?: string;\n self?: boolean;\n screenshare?: boolean;\n video?: boolean;\n mute?: boolean;\n wave?: boolean;\n speaking?: boolean;\n debug?: boolean;\n onClick?: (item: T) => void;\n }>\n>;\n\n/**\n * Cell container.\n */\nexport const ResponsiveGridItem = <T extends object = any>({\n children,\n classNames,\n item,\n style,\n name,\n self,\n pinned,\n screenshare,\n video,\n mute,\n wave,\n speaking,\n onClick,\n}: ResponsiveGridItemProps<T>) => {\n const { t } = useTranslation(meta.id);\n const iconProps: Record<string, { icon: string; label: string; classNames?: string }> = {\n wave: {\n icon: 'ph--hand-waving--duotone',\n label: t('icon wave'),\n classNames: 'animate-pulse bg-orange-500',\n },\n mute: {\n icon: 'ph--microphone-slash--regular',\n label: t('icon muted'),\n },\n };\n\n const props = wave && !pinned ? iconProps.wave : mute ? iconProps.mute : speaking ? iconProps.speaking : undefined;\n\n // Debounce speaking indicator.\n const [speakingIndicator, setSpeakingIndicator] = useState(speaking);\n useEffect(() => {\n if (speaking) {\n setSpeakingIndicator(true);\n } else {\n const timeout = setTimeout(() => {\n setSpeakingIndicator(false);\n }, 1_000);\n return () => clearTimeout(timeout);\n }\n }, [speaking]);\n\n return (\n <div\n className={mx(\n 'relative w-full h-full group',\n 'rounded-md outline outline-2 outline-neutral-900 transition-[outline-color] duration-500',\n speakingIndicator ? 'outline-green-500' : !video && 'outline-separator',\n classNames,\n )}\n style={style}\n >\n {children}\n\n {/* Action. */}\n {onClick && (\n <div className='z-10 absolute top-1 right-1 flex'>\n <IconButton\n classNames={mx('p-1 min-bs-1 rounded', groupHoverControlItemWithTransition)}\n iconOnly\n icon={pinned ? 'ph--x--regular' : 'ph--arrows-out--regular'}\n size={pinned ? 5 : 4}\n label={pinned ? t('icon unpin') : t('icon pin')}\n onClick={() => onClick?.(item)}\n />\n </div>\n )}\n\n {/* Name. */}\n {name && (\n <div className='z-10 absolute bottom-1 left-8 right-1 flex justify-end gap-1 items-center'>\n {/* TODO(burdon): Replace with avatar for everyone. */}\n {/* {self && <Icon icon='ph--asterisk--regular' size={pinned ? 5 : 4} />} */}\n {screenshare && <Icon icon='ph--broadcast--regular' size={pinned ? 5 : 4} />}\n <div\n className={mx('bg-neutral-800 text-neutral-100 py-0.5 truncate rounded', pinned ? 'px-2' : 'px-1 text-xs')}\n >\n {name}\n </div>\n </div>\n )}\n\n {/* Activity. */}\n <div className='z-10 absolute bottom-1 left-1 flex'>\n {(speaking && <Waveform active size={pinned ? 5 : 4} />) ||\n (props && (\n <IconButton\n classNames={mx('p-1 min-bs-1 rounded', props?.classNames)}\n icon={props?.icon}\n label={props?.label}\n size={pinned ? 5 : 4}\n iconOnly\n />\n ))}\n </div>\n </div>\n );\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { useEffect, useMemo, useState } from 'react';\n\nimport { type ThemedClassName } from '@dxos/react-ui';\n\nimport { type UserState } from '../../calls';\nimport { ResponsiveGrid } from '../ResponsiveGrid';\n\nimport { Participant, SCREENSHARE_SUFFIX } from './Participant';\n\nconst getId = (user: UserState): string => user.id!;\n\nexport type ParticipantGridProps = ThemedClassName<{\n self: UserState;\n users: UserState[];\n fullscreen?: boolean;\n debug?: boolean;\n}>;\n\nexport const ParticipantGrid = ({ classNames, self, users, fullscreen, debug }: ParticipantGridProps) => {\n const [pinned, setPinned] = useState<string | undefined>();\n\n const allUsers = useMemo(() => {\n const allUsers: (UserState & { isSelf?: boolean })[] = [];\n users.forEach((user) => {\n if (!user.joined) {\n return;\n }\n\n allUsers.push({ ...user, isSelf: user.id === self.id });\n if (user.tracks?.screenshareEnabled) {\n const screenshare: UserState = {\n ...user,\n id: user.id + SCREENSHARE_SUFFIX,\n tracks: {\n ...user.tracks,\n video: user.tracks.screenshare,\n videoEnabled: user.tracks.screenshareEnabled,\n } as any, // TODO(burdon): Remove cast.\n };\n\n allUsers.push(screenshare);\n }\n });\n\n return allUsers;\n }, [self, users]);\n\n useEffect(() => {\n if (pinned) {\n // Check expanded user is still in call.\n if (!allUsers.find((user) => user.id === pinned)) {\n setPinned(undefined);\n }\n }\n }, [pinned, allUsers]);\n\n // TODO(burdon): Put self last.\n const sortedUsers: UserState[] = allUsers.sort((a, b) => {\n if (a.isSelf) {\n return 1;\n } else if (b.isSelf) {\n return -1;\n } else if (a.tracks?.screenshareEnabled) {\n return -1;\n } else if (b.tracks?.screenshareEnabled) {\n return 1;\n } else {\n return 0;\n }\n });\n\n // TODO(burdon): Show ghost view of user for a second before leaving.\n return (\n <ResponsiveGrid<UserState>\n classNames={classNames}\n Cell={Participant}\n debug={debug}\n getId={getId}\n items={sortedUsers}\n pinned={pinned}\n autoHideGallery={fullscreen}\n onPinnedChange={setPinned}\n />\n );\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport React from 'react';\n\nimport { useAppGraph, useCapability } from '@dxos/app-framework';\nimport { useActions, useNode } from '@dxos/plugin-graph';\nimport { fullyQualifiedId } from '@dxos/react-client/echo';\nimport {\n Icon,\n IconButton,\n type IconButtonProps,\n Toolbar as NaturalToolbar,\n type ThemedClassName,\n toLocalizedString,\n useTranslation,\n} from '@dxos/react-ui';\nimport { groupHoverControlItemWithTransition, mx } from '@dxos/react-ui-theme';\n\nimport { ThreadCapabilities } from '../../capabilities';\nimport { meta } from '../../meta';\nimport { type ChannelType } from '../../types';\n\nexport type ToolbarProps = ThemedClassName<{\n channel?: ChannelType;\n participants?: number;\n autoHideControls?: boolean;\n isInRoom?: boolean;\n onJoin?: () => void;\n onLeave?: () => void;\n}>;\n\n// TODO(wittjosiah): Use ToolbarMenu.\nexport const Toolbar = ({\n classNames,\n channel,\n participants,\n autoHideControls = true,\n onJoin,\n onLeave,\n}: ToolbarProps) => {\n const { t } = useTranslation(meta.id);\n const { graph } = useAppGraph();\n const call = useCapability(ThreadCapabilities.CallManager);\n\n // Channel app graph node.\n const node = useNode(graph, channel && fullyQualifiedId(channel));\n const actions = useActions(graph, node?.id).filter((action) => action.properties.disposition === 'toolbar');\n\n // Screen sharing.\n const isScreensharing = call.media.screenshareTrack !== undefined;\n const canSharescreen =\n typeof navigator.mediaDevices !== 'undefined' && navigator.mediaDevices.getDisplayMedia !== undefined;\n\n // TODO(wittjosiah): In order to use toolbar, need to update to actually use the graph action callbacks directly.\n return (\n <div className={mx('z-20 flex justify-center m-8', autoHideControls && groupHoverControlItemWithTransition)}>\n <NaturalToolbar.Root classNames={['p-2 bg-modalSurface rounded-md shadow-md', classNames]}>\n <ToggleButton\n active={call.media.audioEnabled}\n state={{\n on: {\n icon: 'ph--microphone--regular',\n label: t('mic off'),\n onClick: () => call.turnAudioOff(),\n classNames: 'bg-callActive',\n },\n off: {\n icon: 'ph--microphone-slash--duotone',\n label: t('mic on'),\n onClick: () => call.turnAudioOn(),\n classNames: [call.joined && 'bg-callAlert'],\n },\n }}\n />\n <ToggleButton\n active={call.media.videoEnabled}\n state={{\n on: {\n icon: 'ph--video-camera--regular',\n label: t('camera off'),\n onClick: () => call.turnVideoOff(),\n },\n off: {\n icon: 'ph--video-camera-slash--duotone',\n label: t('camera on'),\n onClick: () => call.turnVideoOn(),\n },\n }}\n />\n\n {(participants !== undefined && (\n <div className='flex justify-center items-center gap-2 is-[5rem] text-xs text-subdued'>\n <Icon icon='ph--users--regular' size={4} />\n <div>{participants}</div>\n </div>\n )) || <NaturalToolbar.Separator variant='gap' />}\n\n {call.joined && (\n <>\n <ToggleButton\n disabled={!canSharescreen}\n active={isScreensharing}\n state={{\n on: {\n icon: 'ph--monitor--regular',\n label: t('screenshare off'),\n onClick: () => call.turnScreenshareOff(),\n },\n off: {\n icon: 'ph--monitor-arrow-up--duotone',\n label: t('screenshare on'),\n onClick: () => call.turnScreenshareOn(),\n },\n }}\n />\n\n {/* Companion actions. */}\n {actions.map((action) => (\n <IconButton\n key={action.id}\n {...defaultButtonProps}\n icon={action.properties.icon}\n label={toLocalizedString(action.properties.label, t)}\n classNames={action.properties.classNames}\n onClick={() => action.data({ node })}\n />\n ))}\n\n <ToggleButton\n active={call.raisedHand}\n state={{\n on: {\n icon: 'ph--hand-waving--regular',\n label: t('lower hand'),\n onClick: () => call.setRaisedHand(false),\n classNames: [call.joined && 'bg-callAlert'],\n },\n off: {\n icon: 'ph--hand-palm--duotone',\n label: t('raise hand'),\n onClick: () => call.setRaisedHand(true),\n },\n }}\n />\n </>\n )}\n {call.joined ? (\n <IconButton variant='destructive' icon='ph--phone-x--regular' label={t('leave call')} onClick={onLeave} />\n ) : (\n <IconButton variant='primary' icon='ph--phone-incoming--regular' label={t('join call')} onClick={onJoin} />\n )}\n </NaturalToolbar.Root>\n </div>\n );\n};\n\nToolbar.displayName = 'MeetingToolbar';\n\ntype ToolbarButtonProps = Pick<IconButtonProps, 'disabled'> & {\n active?: boolean;\n state: {\n on: Pick<IconButtonProps, 'icon' | 'label' | 'onClick' | 'classNames'>;\n off: Pick<IconButtonProps, 'icon' | 'label' | 'onClick' | 'classNames'>;\n };\n};\n\nconst defaultButtonProps: Partial<IconButtonProps> = {\n size: 5,\n iconOnly: true,\n};\n\nconst ToggleButton = ({ active, state }: ToolbarButtonProps) => (\n <IconButton\n {...defaultButtonProps}\n classNames={[active ? (state.on.classNames ?? 'bg-callActive') : state.off.classNames]}\n icon={active ? state.on.icon : state.off.icon}\n label={active ? state.on.label : state.off.label}\n onClick={active ? state.on.onClick : state.off.onClick}\n />\n);\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["Rx", "React", "useCallback", "useEffect", "useMemo", "useState", "useCapabilities", "useCapability", "Context", "failUndefined", "log", "useClient", "fullyQualifiedId", "getSpace", "useIdentity", "ElevationProvider", "Input", "useTranslation", "ControlGroup", "ControlGroupButton", "ControlItemInput", "MenuProvider", "ToolbarMenu", "createMenuAction", "createMenuItemGroup", "useMenuActions", "useSoundEffect", "StackItem", "React", "useCapability", "React", "useEffect", "useRef", "AudioStream", "tracks", "mediaStreamRef", "useRef", "MediaStream", "ref", "useEffect", "audio", "current", "mediaStream", "srcObject", "resetSrcObject", "addEventListener", "play", "once", "autoPlay", "map", "track", "AudioTrack", "key", "id", "currentTrack", "addTrack", "removeTrack", "React", "forwardRef", "memo", "useEffect", "useRef", "mx", "VideoObject", "memo", "forwardRef", "videoStream", "classNames", "flip", "contain", "rest", "ref", "internalRef", "useRef", "useEffect", "video", "current", "srcObject", "setAttribute", "React", "className", "mx", "v", "displayName", "React", "memo", "useMemo", "useCapability", "React", "mx", "ResponsiveContainer", "children", "React", "div", "role", "className", "mx", "React", "useCallback", "useEffect", "useLayoutEffect", "useMemo", "useState", "useResizeDetector", "invariant", "mx", "ASPECT_RATIO", "MIN_GALLERY_HEIGHT", "DEFAULT_GAP", "maxImageSize", "defaultGetId", "item", "id", "ResponsiveGrid", "classNames", "Cell", "gap", "getId", "items", "pinned", "autoHideGallery", "debug", "onPinnedChange", "width", "containerWidth", "height", "containerHeight", "ref", "containerRef", "useResizeDetector", "refreshRate", "dividerHeight", "setDividerHeight", "useState", "useEffect", "fitAspectRatio", "Math", "min", "pinnedItem", "useMemo", "find", "mainItems", "filter", "hideGallery", "undefined", "time", "columns", "cellWidth", "setLayout", "gridContainerRef", "layout", "calculateLayout", "length", "Date", "now", "bounds", "setBounds", "useLayoutEffect", "current", "t", "setTimeout", "map", "invariant", "el", "querySelector", "getRelativeBounds", "clearTimeout", "handleClick", "useCallback", "React", "div", "className", "mx", "style", "SoloItem", "minHeight", "role", "display", "gridTemplateColumns", "key", "onClick", "ResponsiveContainer", "img", "alt", "container", "containerRect", "getBoundingClientRect", "elementRect", "top", "left", "count", "aspectRatio", "minWastedSpace", "Infinity", "bestColumns", "rows", "cols", "ceil", "itemWidth", "itemHeight", "fitItemsToGrid", "usedWidth", "usedHeight", "wastedSpace", "outerWidth", "outerHeight", "numCols", "numRows", "availableWidth", "availableHeight", "maxCellWidth", "maxCellHeight", "React", "useEffect", "useState", "Icon", "IconButton", "useTranslation", "Waveform", "groupHoverControlItemWithTransition", "mx", "ResponsiveGridItem", "children", "classNames", "item", "style", "name", "self", "pinned", "screenshare", "video", "mute", "wave", "speaking", "onClick", "t", "useTranslation", "meta", "id", "iconProps", "icon", "label", "props", "undefined", "speakingIndicator", "setSpeakingIndicator", "useState", "useEffect", "timeout", "setTimeout", "clearTimeout", "React", "div", "className", "mx", "IconButton", "groupHoverControlItemWithTransition", "iconOnly", "size", "Icon", "Waveform", "active", "SCREENSHARE_SUFFIX", "Participant", "memo", "item", "user", "debug", "props", "call", "useCapability", "ThreadCapabilities", "CallManager", "isSelf", "self", "id", "undefined", "startsWith", "isScreenshare", "endsWith", "pulledVideoStream", "tracks", "screenshareEnabled", "getVideoStream", "screenshare", "videoEnabled", "video", "videoStream", "useMemo", "media", "screenshareVideoStream", "React", "ResponsiveGridItem", "name", "mute", "audioEnabled", "wave", "raisedHand", "speaking", "VideoObject", "flip", "contain", "classNames", "displayName", "React", "useEffect", "useMemo", "useState", "getId", "user", "id", "ParticipantGrid", "classNames", "self", "users", "fullscreen", "debug", "pinned", "setPinned", "useState", "allUsers", "useMemo", "forEach", "joined", "push", "isSelf", "tracks", "screenshareEnabled", "screenshare", "SCREENSHARE_SUFFIX", "video", "videoEnabled", "useEffect", "find", "undefined", "sortedUsers", "sort", "a", "b", "React", "ResponsiveGrid", "Cell", "Participant", "items", "autoHideGallery", "onPinnedChange", "React", "useAppGraph", "useCapability", "useActions", "useNode", "fullyQualifiedId", "Icon", "IconButton", "Toolbar", "NaturalToolbar", "toLocalizedString", "useTranslation", "groupHoverControlItemWithTransition", "mx", "Toolbar", "classNames", "channel", "participants", "autoHideControls", "onJoin", "onLeave", "t", "useTranslation", "meta", "id", "graph", "useAppGraph", "call", "useCapability", "ThreadCapabilities", "CallManager", "node", "useNode", "fullyQualifiedId", "actions", "useActions", "filter", "action", "properties", "disposition", "isScreensharing", "media", "screenshareTrack", "undefined", "canSharescreen", "navigator", "mediaDevices", "getDisplayMedia", "React", "div", "className", "mx", "groupHoverControlItemWithTransition", "NaturalToolbar", "Root", "ToggleButton", "active", "audioEnabled", "state", "on", "icon", "label", "onClick", "turnAudioOff", "off", "turnAudioOn", "joined", "videoEnabled", "turnVideoOff", "turnVideoOn", "Icon", "size", "Separator", "variant", "disabled", "turnScreenshareOff", "turnScreenshareOn", "map", "IconButton", "key", "defaultButtonProps", "toLocalizedString", "data", "raisedHand", "setRaisedHand", "displayName", "iconOnly", "CallRoot", "children", "React", "div", "className", "displayName", "CallAudio", "call", "useCapability", "ThreadCapabilities", "CallManager", "AudioStream", "tracks", "audioTracksToPlay", "CallGrid", "fullscreen", "debug", "useDebugMode", "ParticipantGrid", "self", "users", "CallToolbar", "props", "Toolbar", "isInRoom", "Call", "Root", "Grid", "Audio", "ChannelContainer", "channel", "roomId", "_roomId", "role", "fullscreen", "space", "getSpace", "callManager", "useCapability", "ThreadCapabilities", "CallManager", "fullyQualifiedId", "failUndefined", "identity", "useIdentity", "isNamed", "profile", "displayName", "joinSound", "useSoundEffect", "leaveSound", "extensions", "useCapabilities", "CallExtension", "useEffect", "ctx", "Context", "left", "on", "forEach", "extension", "onLeave", "callStateUpdated", "state", "onCallStateUpdated", "mediaStateUpdated", "onMediaStateUpdated", "dispose", "handleJoin", "useCallback", "joined", "leave", "play", "setRoomId", "join", "Promise", "all", "map", "onJoin", "err", "log", "catch", "handleLeave", "turnAudioOff", "turnVideoOff", "turnScreenshareOff", "isJoined", "React", "StackItem", "Content", "toolbar", "classNames", "DisplayNameMissing", "Call", "Root", "Grid", "Toolbar", "defaultThread", "target", "ChannelToolbar", "attendableId", "onJoinCall", "ChatContainer", "thread", "t", "useTranslation", "meta", "id", "client", "useClient", "setDisplayName", "useState", "handleChange", "event", "value", "handleSave", "halo", "updateProfile", "ControlGroup", "ControlItemInput", "title", "description", "Input", "TextInput", "onChange", "placeholder", "ControlGroupButton", "disabled", "onClick", "useChannelToolbarActions", "creator", "useMemo", "Rx", "make", "nodes", "createMenuItemGroup", "label", "ns", "createMenuAction", "icon", "type", "edges", "source", "useMenuActions", "menuProps", "ElevationProvider", "elevation", "MenuProvider", "ToolbarMenu"]
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/calls/types.ts", "../../../src/calls/call-swarm-synchronizer.ts", "../../../src/calls/util/audio.ts", "../../../src/calls/util/calls-service.ts", "../../../src/calls/util/history-cache.ts", "../../../src/calls/util/task-scheduling.ts", "../../../src/calls/util/media.ts", "../../../src/calls/speaking-monitor.ts", "../../../src/calls/media-manager.ts", "../../../src/calls/call-manager.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { invariant } from '@dxos/invariant';\nimport { buf } from '@dxos/protocols/buf';\nimport {\n type ActivitySchema,\n type UserState as UserStateProto,\n UserStateSchema,\n} from '@dxos/protocols/buf/dxos/edge/calls_pb';\n\n/**\n * Endpoint to the calls service.\n */\nexport const CALLS_URL = 'https://calls-service.dxos.workers.dev';\n\nexport type UserState = buf.MessageInitShape<typeof UserStateSchema>;\n\nexport type ActivityState = buf.MessageInitShape<typeof ActivitySchema>;\n\nexport const codec = {\n encode: (message: UserState): Uint8Array => {\n return buf.toBinary(UserStateSchema, buf.create(UserStateSchema, message));\n },\n decode: (message: Uint8Array): UserStateProto => {\n return buf.fromBinary(UserStateSchema, message);\n },\n};\n\nexport type TrackObject = {\n location?: 'local' | 'remote';\n trackName?: string;\n sessionId?: string;\n mid?: string | null;\n};\n\nexport type SessionDescription = {\n type: 'offer' | 'answer';\n sdp: string;\n};\n\nexport interface ErrorResponse {\n errorCode?: string;\n errorDescription?: string;\n}\n\nexport interface SessionResponse extends ErrorResponse {\n sessionId: string;\n sessionDescription: SessionDescription;\n}\n\nexport interface TracksResponse extends ErrorResponse {\n sessionDescription: SessionDescription;\n requiresImmediateRenegotiation: boolean;\n tracks?: (TrackObject & ErrorResponse)[];\n}\n\nexport interface RenegotiationResponse extends ErrorResponse {}\n\nexport type EncodedTrackName = string & { __brand: 'EncodedTrackName' };\n\nexport const TrackNameCodec = {\n encode: (trackData: TrackObject): EncodedTrackName => {\n invariant(trackData.sessionId);\n invariant(trackData.trackName);\n invariant(trackData.mid);\n return (trackData.sessionId + '/' + trackData.trackName + '/' + trackData.mid) as EncodedTrackName;\n },\n decode: (name: EncodedTrackName): TrackObject => {\n const [sessionId, trackName, mid] = name.split('/');\n return { sessionId, trackName, location: 'remote', mid };\n },\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport md5Hex from 'md5-hex';\n\nimport { DeferredTask, Event, scheduleTaskInterval, synchronized } from '@dxos/async';\nimport { type Identity } from '@dxos/client/halo';\nimport { Context, Resource } from '@dxos/context';\nimport { generateName } from '@dxos/display-name';\nimport { invariant } from '@dxos/invariant';\nimport { PublicKey } from '@dxos/keys';\nimport { log } from '@dxos/log';\nimport { buf } from '@dxos/protocols/buf';\nimport { ActivitySchema } from '@dxos/protocols/buf/dxos/edge/calls_pb';\nimport { type Device, type NetworkService } from '@dxos/protocols/proto/dxos/client/services';\nimport { ConnectionState, type SwarmResponse } from '@dxos/protocols/proto/dxos/edge/messenger';\nimport { isNonNullable } from '@dxos/util';\n\nimport { type ActivityState, type UserState, codec } from './types';\n\nexport type CallState = {\n /**\n * Room id.\n */\n roomId?: string;\n\n /**\n * All users states in the swarm.\n */\n users?: UserState[];\n\n /**\n * Self state inside swarm.\n */\n self?: UserState;\n\n /**\n * Swarm synchronized CRDT transcription. Last write wins.\n */\n activities?: Record<string, ActivityState>;\n\n raisedHand?: boolean;\n speaking?: boolean;\n joined?: boolean;\n\n /**\n * Tracks pushed by self to calls service.\n */\n tracks?: UserState['tracks'];\n};\n\nexport type CallSwarmSynchronizerParams = { networkService: NetworkService };\n\n/**\n * Period for peer to reconnect to the call swarm gracefully if connection was lost abruptly.\n */\nconst DISCONNECTED_ABRUPT_TIMEOUT = 10_000; // [ms]\n\n/**\n * Sends and receives state to/from Swarm network.\n */\nexport class CallSwarmSynchronizer extends Resource {\n public readonly stateUpdated = new Event<CallState>();\n\n private readonly _state: CallState = { activities: {} };\n private readonly _networkService: NetworkService;\n private _lastSwarmEvent?: SwarmResponse = undefined;\n private _reconcileSwarmStateTask?: DeferredTask = undefined;\n\n private _identityKey?: string = undefined;\n private _deviceKey?: string = undefined;\n private _displayName?: string = undefined;\n\n private _swarmCtx?: Context = undefined;\n\n private _sendStateTask?: DeferredTask = undefined;\n\n constructor({ networkService }: CallSwarmSynchronizerParams) {\n super();\n this._networkService = networkService;\n }\n\n /**\n * @internal\n */\n _getState(): CallState {\n return this._state;\n }\n\n setRaisedHand(raisedHand: boolean): void {\n if (this._state.raisedHand === raisedHand) {\n return;\n }\n\n this._state.raisedHand = raisedHand;\n this._notifyAndSchedule();\n }\n\n setSpeaking(speaking: boolean): void {\n if (this._state.speaking === speaking) {\n return;\n }\n\n this._state.speaking = speaking;\n this._notifyAndSchedule();\n }\n\n setJoined(joined: boolean): void {\n if (this._state.joined === joined) {\n return;\n }\n\n this._state.joined = joined;\n this._notifyAndSchedule();\n }\n\n setTracks(tracks: UserState['tracks']): void {\n this._state.tracks = { ...this._state.tracks, ...tracks };\n this._notifyAndSchedule();\n }\n\n setActivity(key: string, payload: ActivityState['payload']): void {\n const lamportTimestamp = LamportTimestampCrdt.increment(\n this._state.activities?.[key]?.lamportTimestamp ?? { id: this._deviceKey },\n );\n this._state.activities![key] = { lamportTimestamp, payload };\n\n this._notifyAndSchedule();\n }\n\n /**\n * @internal\n */\n _setIdentity(identity: Identity): void {\n this._identityKey = identity.identityKey.toHex();\n this._displayName = identity.profile?.displayName ?? generateName(identity.identityKey.toHex());\n }\n\n /**\n * @internal\n */\n _setDevice(device: Device): void {\n this._deviceKey = device.deviceKey.toHex();\n }\n\n /**\n * @internal\n */\n _setRoomId(roomId?: string): void {\n if (this._swarmCtx) {\n log.verbose('joined to a different room', { roomId });\n return;\n }\n\n this._state.roomId = roomId;\n }\n\n protected override async _open(): Promise<void> {\n this._sendStateTask = new DeferredTask(this._ctx, async () => {\n await this._sendState();\n });\n\n this._reconcileSwarmStateTask = new DeferredTask(this._ctx, async () => {\n await this._reconcileSwarmState();\n });\n }\n\n protected override async _close(): Promise<void> {\n this._sendStateTask = undefined;\n this._reconcileSwarmStateTask = undefined;\n }\n\n @synchronized\n async join(): Promise<void> {\n invariant(this._state.roomId);\n invariant(!this._swarmCtx, 'Already joined');\n\n this._swarmCtx = new Context();\n const topic = getTopic(this._state.roomId);\n log('joining swarm', { topic, peer: { identityKey: this._identityKey, peerKey: this._deviceKey } });\n const stream = this._networkService.subscribeSwarmState({ topic });\n stream.subscribe((event) => this._processSwarmEvent(event));\n\n const cleanup = () => {\n void stream.close();\n if (topic && this._identityKey && this._deviceKey) {\n log('leaving swarm', { topic, peer: { identityKey: this._identityKey, peerKey: this._deviceKey } });\n void this._networkService\n .leaveSwarm({\n topic,\n peer: { identityKey: this._identityKey, peerKey: this._deviceKey },\n })\n .catch((err) => log.catch(err));\n }\n window.removeEventListener('beforeunload', cleanup);\n };\n window.addEventListener('beforeunload', cleanup);\n this._swarmCtx.onDispose(cleanup);\n\n this._notifyAndSchedule();\n }\n\n @synchronized\n async leave(): Promise<void> {\n if (!this._swarmCtx) {\n return;\n }\n\n await this._swarmCtx.dispose();\n this._swarmCtx = undefined;\n\n this._state.users = undefined;\n this._state.self = undefined;\n }\n\n async querySwarm(roomId: string) {\n const topic = getTopic(roomId);\n const swarm = await this._networkService.querySwarm({ topic });\n return swarm.peers ?? [];\n }\n\n /**\n * Notify and schedule send state task.\n */\n private _notifyAndSchedule(): void {\n this.stateUpdated.emit(this._state);\n if (this._state.joined) {\n this._sendStateTask?.schedule();\n }\n }\n\n private async _sendState(): Promise<void> {\n if (!this._state.roomId || !this._identityKey || !this._deviceKey || !this._state.joined) {\n return;\n }\n\n const state: UserState = {\n ...this._state,\n id: this._deviceKey,\n name: this._displayName,\n activities: this._state.activities\n ? Object.fromEntries(\n Object.entries(this._state.activities).map(([key, activity]) => [\n key,\n buf.create(ActivitySchema, activity),\n ]),\n )\n : {},\n };\n\n await this._networkService.joinSwarm({\n topic: getTopic(this._state.roomId),\n peer: {\n identityKey: this._identityKey,\n peerKey: this._deviceKey,\n state: codec.encode(state),\n },\n });\n }\n\n private _processSwarmEvent(swarmEvent: SwarmResponse): void {\n if (!this._state.joined) {\n return;\n }\n\n this._lastSwarmEvent = swarmEvent;\n this._reconcileSwarmStateTask!.schedule();\n }\n\n private async _reconcileSwarmState(): Promise<void> {\n const swarmEvent = this._lastSwarmEvent;\n invariant(swarmEvent);\n // We include inactive peers that were disconnected abruptly and have not yet reconnected to not drop them from call.\n // Websocket connection could be unstable and we include graceful period for peers to reconnect.\n const peers = [\n ...(swarmEvent.peers ?? []),\n ...(swarmEvent.inactivePeers ?? []).filter(\n ({ disconnected, connectionState }) =>\n connectionState === ConnectionState.DISCONNECTED_ABRUPT &&\n disconnected &&\n disconnected > Date.now() - DISCONNECTED_ABRUPT_TIMEOUT,\n ),\n ].sort((peer1, peer2) => peer1.peerKey.localeCompare(peer2.peerKey));\n const users = peers\n .map((peer) => {\n try {\n return codec.decode(peer.state!);\n } catch (error) {\n log.error('error decoding peer state', { error, peer });\n return undefined;\n }\n })\n .filter(isNonNullable);\n this._state.users = users;\n this._state.self = users.find((user) => user.id === this._deviceKey);\n log('reconciling swarm state', { users });\n if (users.length === 0) {\n return;\n }\n\n const activityKeys = new Set<string>(users.flatMap((user) => Object.keys(user.activities)));\n [...activityKeys].forEach((key) => {\n const activities = users.map((user) => user.activities?.[key]).filter(isNonNullable);\n const lastActivity = LamportTimestampCrdt.getLastState(activities);\n if (\n lastActivity &&\n lastActivity.lamportTimestamp!.version! > (this._state.activities![key]?.lamportTimestamp?.version ?? 0)\n ) {\n this._state.activities![key] = lastActivity;\n }\n });\n this.stateUpdated.emit(this._state);\n\n // Schedule next reconcile if there are inactive peer to drop them after timeout.\n if (peers.some((peer) => peer.connectionState !== ConnectionState.CONNECTED)) {\n scheduleTaskInterval(\n this._ctx,\n async () => this._reconcileSwarmStateTask!.schedule(),\n Math.min(DISCONNECTED_ABRUPT_TIMEOUT / 2, 1000),\n );\n }\n }\n}\n\ntype LamportTimestamp = ActivityState['lamportTimestamp'];\n\n// TODO(mykola): Factor out.\nclass LamportTimestampCrdt {\n static getLastState<T extends { lamportTimestamp?: LamportTimestamp }>(states: T[]): T | undefined {\n const maxTimestamp = Math.max(...states.map((state) => state.lamportTimestamp?.version ?? 0));\n const sortedStates = states\n .filter(\n (state) =>\n state.lamportTimestamp && state.lamportTimestamp.version === maxTimestamp && state.lamportTimestamp.id,\n )\n .sort((a, b) => a.lamportTimestamp!.id!.localeCompare(b.lamportTimestamp!.id!));\n return sortedStates[0];\n }\n\n static increment(timestamp: LamportTimestamp): LamportTimestamp {\n return {\n ...(timestamp ?? {}),\n version: (timestamp?.version ?? 0) + 1,\n };\n }\n}\n\n// TODO(mykola): Delete once we refactor swarm to accept string as topic.\nconst getTopic = (roomId: string): PublicKey => PublicKey.fromHex(md5Hex(roomId));\n", "//\n// Copyright 2025 DXOS.org\n//\n\nexport const monitorAudioLevel = ({\n mediaStreamTrack,\n intervalMs = 1000 / 10, // 12 fps.\n onMeasure,\n}: {\n mediaStreamTrack: MediaStreamTrack;\n intervalMs?: number;\n onMeasure: (value: number) => void;\n}) => {\n let timeout = -1;\n let interval = -1;\n const audioContext = new AudioContext();\n const stream = new MediaStream();\n stream.addTrack(mediaStreamTrack);\n const mediaStreamAudioSourceNode = audioContext.createMediaStreamSource(stream);\n const analyserNode = audioContext.createAnalyser();\n mediaStreamAudioSourceNode.connect(analyserNode);\n // Since we just need a rough approximation and will be measuring\n // frequently, we want to drop this down from the default of 2048.\n analyserNode.fftSize = 32;\n\n const pcmData = new Float32Array(analyserNode.fftSize);\n let peak = 0;\n\n interval = window.setInterval(() => {\n onMeasure(peak);\n peak = 0;\n }, intervalMs);\n\n const tick = () => {\n timeout = window.setTimeout(() => {\n analyserNode.getFloatTimeDomainData(pcmData);\n let sumSquares = 0.0;\n for (const amplitude of pcmData) {\n sumSquares += amplitude * amplitude;\n }\n const current = Math.sqrt(sumSquares / pcmData.length);\n if (current > peak) {\n peak = current;\n }\n tick();\n }, intervalMs);\n };\n tick();\n\n return () => {\n mediaStreamAudioSourceNode.disconnect();\n analyserNode.disconnect();\n void audioContext.close();\n clearInterval(interval);\n clearTimeout(timeout);\n stream.removeTrack(mediaStreamTrack);\n };\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { PersistentLifecycle, Trigger, scheduleTask } from '@dxos/async';\nimport { type Context, Resource } from '@dxos/context';\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\n\nimport {\n type ErrorResponse,\n type RenegotiationResponse,\n type SessionResponse,\n type TrackObject,\n type TracksResponse,\n} from '../types';\n\nimport { HistoryCache } from './history-cache';\nimport { BulkRequestDispatcher, FIFOScheduler } from './task-scheduling';\n\nconst NETWORK_TIMEOUT = 5_000;\n\nexport type Session = {\n sessionId: string;\n peerConnection: RTCPeerConnection;\n};\n\nexport type CallsServiceConfig = {\n apiBase: string;\n apiExtraParams?: string;\n iceServers?: RTCIceServer[];\n};\n\nexport type HistoryRecord =\n | {\n endpoint: string;\n type: 'request';\n time: string;\n method: string;\n body: any;\n }\n | {\n endpoint: string;\n type: 'response';\n time: string;\n status: number;\n text?: string;\n json?: any;\n };\n\n/**\n * Client for Cloudflare Calls service.\n * API: https://developers.cloudflare.com/calls/https-api/\n * Inspired by client from https://github.com/threepointone/partyserver/tree/main/packages/partytracks\n */\n// TODO(mykola): Expose session errors.\nexport class CallsServicePeer extends Resource {\n public readonly history = new HistoryCache<HistoryRecord>(100);\n\n private readonly _persistentLifecycle = new PersistentLifecycle<Session>({\n start: () => this._startSession(),\n stop: (session) => this._stopSession(session),\n });\n\n private readonly _config: CallsServiceConfig;\n\n taskScheduler = new FIFOScheduler();\n pushTrackDispatcher = new BulkRequestDispatcher<\n {\n trackName: string;\n transceiver: RTCRtpTransceiver;\n },\n { tracks: TrackObject[] }\n >(32);\n\n pullTrackDispatcher = new BulkRequestDispatcher<\n TrackObject,\n {\n /**\n * trackName -> { resolvedTrack, mid }\n */\n trackMap: Map<string, { resolvedTrack: Promise<MediaStreamTrack>; mid: string }>;\n }\n >(32);\n\n closeTrackDispatcher = new BulkRequestDispatcher(32);\n constructor(config: CallsServiceConfig) {\n super();\n this._config = config;\n }\n\n protected override async _open(ctx: Context): Promise<void> {\n await this._persistentLifecycle.open(ctx);\n }\n\n protected override async _close(): Promise<void> {\n await this._persistentLifecycle.close();\n }\n\n get session() {\n return this._persistentLifecycle.state;\n }\n\n private async _startSession() {\n const peerConnection = await this._createRtcConnection();\n const sessionId = await this._initiateCallSession();\n return { sessionId, peerConnection };\n }\n\n private async _stopSession(session: Session): Promise<void> {\n session.peerConnection.close();\n }\n\n private async _createRtcConnection(): Promise<RTCPeerConnection> {\n const peerConnection = new RTCPeerConnection({\n iceServers: this._config.iceServers,\n bundlePolicy: 'max-bundle',\n });\n peerConnection.addEventListener('connectionstatechange', () => {\n if (peerConnection.connectionState === 'failed' || peerConnection.connectionState === 'closed') {\n log.info('calls connection failed', { state: peerConnection.connectionState });\n void this._persistentLifecycle.scheduleRestart();\n }\n });\n\n let iceTimeout = -1;\n peerConnection.addEventListener('iceconnectionstatechange', () => {\n clearTimeout(iceTimeout);\n if (peerConnection.iceConnectionState === 'failed' || peerConnection.iceConnectionState === 'closed') {\n log.info('calls connection to ICEs failed', { state: peerConnection.iceConnectionState });\n void this._persistentLifecycle.scheduleRestart();\n } else if (peerConnection.iceConnectionState === 'disconnected') {\n // TODO(mykola): we should start to inspect the connection stats from here on for\n // any other signs of trouble to guide what to do next (instead of just hoping\n // for the best like we do here for now)\n const timeoutSeconds = 7;\n iceTimeout = window.setTimeout(() => {\n if (peerConnection.iceConnectionState === 'connected') {\n log.info('calls iceConnectionState is connected');\n return;\n }\n\n log.info('calls iceConnectionState timed out', { state: peerConnection.iceConnectionState, timeoutSeconds });\n void this._persistentLifecycle.scheduleRestart();\n }, timeoutSeconds * 1_000);\n }\n });\n\n return peerConnection;\n }\n\n private async _initiateCallSession(): Promise<string> {\n log('creating new session');\n const { sessionId } = await this._fetch<SessionResponse>('/sessions/new?SESSION', { method: 'POST' });\n return sessionId;\n }\n\n private async _fetch<T extends ErrorResponse>(relativePath: string, requestInit?: RequestInit): Promise<T> {\n this.history.push({\n endpoint: relativePath,\n type: 'request',\n time: new Date().toISOString(),\n method: requestInit?.method ?? 'GET',\n body: requestInit?.body,\n });\n // TODO(mykola): Handle access control. Use EdgeClient.\n const response = await fetch(`${this._config.apiBase}${relativePath}`, { ...requestInit, redirect: 'manual' });\n if (response.status >= 400) {\n log.error('error while fetching from Calls service', { status: response.status, text: await response.text() });\n throw new Error('Error while fetching from Calls service');\n }\n\n try {\n const data = (await response.clone().json()) as T;\n this.history.push({\n endpoint: relativePath,\n type: 'response',\n time: new Date().toISOString(),\n status: response.status,\n json: data,\n });\n if (data.errorCode) {\n throw new Error(data.errorDescription);\n }\n\n return data;\n } catch (error) {\n const text = await response.text();\n this.history.push({\n endpoint: relativePath,\n type: 'response',\n time: new Date().toISOString(),\n status: response.status,\n text,\n });\n log.error('Error parsing response from Calls service', {\n error,\n text,\n status: response.status,\n });\n throw error;\n }\n }\n\n private async _pushTrackInBulk({\n ctx,\n peerConnection,\n transceiver,\n sessionId,\n trackName,\n }: {\n ctx: Context;\n peerConnection: RTCPeerConnection;\n transceiver: RTCRtpTransceiver;\n sessionId: string;\n trackName: string;\n }): Promise<TrackObject | void> {\n log.verbose('pushing track ', trackName);\n const pushedTrackPromise = this.pushTrackDispatcher\n .doBulkRequest({ trackName, transceiver }, (tracks) =>\n this.taskScheduler.schedule(async () => {\n // Create offer.\n // Turn on Opus DTX to save bandwidth and set the offer as the local description.\n const offer = await peerConnection.createOffer();\n offer.sdp = offer.sdp?.replace('useinbandfec=1', 'usedtx=1;useinbandfec=1');\n await peerConnection.setLocalDescription(offer);\n\n const response = await this._fetch<TracksResponse>(`/sessions/${sessionId}/tracks/new?PUSHING`, {\n method: 'POST',\n body: JSON.stringify({\n sessionDescription: {\n sdp: offer.sdp,\n type: 'offer',\n },\n tracks: tracks.map(({ trackName, transceiver }) => ({\n trackName,\n mid: transceiver.mid,\n location: 'local',\n })),\n }),\n });\n\n invariant(response.tracks !== undefined);\n if (!response.errorCode) {\n await peerConnection.setRemoteDescription(new RTCSessionDescription(response.sessionDescription));\n await peerConnectionIsConnected(peerConnection);\n }\n\n return {\n tracks: response.tracks,\n };\n }),\n )\n .then(async ({ tracks }) => {\n const trackData = tracks.find((t) => t.mid === transceiver.mid);\n if (trackData) {\n // we wait for the transceiver to start sending data before we emit\n // the track metadata to ensure that the track will be able to be\n // pulled before making the metadata available to anyone else.\n // await waitForTransceiverToSendData(ctx, transceiver);\n return {\n ...trackData,\n sessionId,\n location: 'remote',\n } satisfies TrackObject;\n } else {\n log.error('missing track data');\n }\n });\n\n const onDispose = async () => {\n if (transceiver.mid) {\n await this._closeTrackInBulk(peerConnection, transceiver.mid, sessionId);\n }\n };\n\n ctx?.onDispose(async () => await onDispose());\n this._ctx.onDispose(() => onDispose());\n\n return pushedTrackPromise;\n }\n\n async pushTrack({\n track,\n encodings = [],\n ctx,\n previousTrack,\n }: {\n track: MediaStreamTrack | null;\n ctx: Context;\n encodings?: RTCRtpEncodingParameters[];\n previousTrack?: TrackObject;\n }): Promise<TrackObject | undefined> {\n await this.waitUntilOpen();\n invariant(this.session);\n log('trying to push track', { track, previousTrack, encodings });\n if (previousTrack) {\n const transceiver = this.session.peerConnection.getTransceivers().find((t) => t.mid === previousTrack.mid);\n if (transceiver?.sender.track === track) {\n log.verbose('track already pushed', { track, previousTrack, transceiver });\n return previousTrack;\n } else if (transceiver) {\n log.verbose('replacing track', { track, previousTrack, transceiver });\n transceiver.sender.replaceTrack(track).catch((err) => log.catch(err));\n return previousTrack;\n }\n }\n invariant(track);\n\n // We want a single id for this connection.\n const stableId = crypto.randomUUID();\n const transceiver = this.session.peerConnection!.addTransceiver(track, { direction: 'sendonly' });\n log.verbose('creating transceiver');\n\n const pushedTrackData = await this._pushTrackInBulk({\n ctx,\n peerConnection: this.session.peerConnection!,\n transceiver,\n sessionId: this.session.sessionId!,\n trackName: stableId,\n });\n invariant(pushedTrackData);\n\n const parameters = transceiver.sender.getParameters();\n encodings.forEach((encoding, i) => {\n const existing = parameters.encodings[i];\n parameters.encodings[i] = { ...existing, ...encoding };\n });\n transceiver.sender.setParameters(parameters).catch((err) => log.catch(err));\n\n return pushedTrackData;\n }\n\n // TODO(mykola): Add retry logic if the tracks fails to pull.\n private async _pullTrackInBulk({\n peerConnection,\n sessionId,\n trackData,\n ctx,\n }: {\n peerConnection: RTCPeerConnection;\n sessionId: string;\n trackData: TrackObject;\n ctx?: Context;\n }): Promise<MediaStreamTrack | undefined> {\n let mid = '';\n log('pulling track', { trackName: trackData.trackName });\n const pulledTrackPromise = this.pullTrackDispatcher\n .doBulkRequest(trackData, (tracks) =>\n this.taskScheduler.schedule(async () => {\n const newTrackResponse = await this._fetch<TracksResponse>(`/sessions/${sessionId}/tracks/new?PULLING`, {\n method: 'POST',\n body: JSON.stringify({ tracks }),\n });\n\n if (newTrackResponse.errorCode) {\n throw new Error(newTrackResponse.errorDescription);\n }\n\n invariant(newTrackResponse.tracks);\n const trackMap = tracks.reduce((acc, track) => {\n const pulledTrackData = newTrackResponse.tracks?.find(\n (t) => t.trackName === track.trackName && t.sessionId === track.sessionId,\n );\n\n if (pulledTrackData && pulledTrackData.mid) {\n acc.set(track.trackName!, {\n mid: pulledTrackData.mid,\n resolvedTrack: resolveTrack(peerConnection, (t) => t.mid === pulledTrackData.mid),\n });\n }\n\n return acc;\n }, new Map<string, { resolvedTrack: Promise<MediaStreamTrack>; mid: string }>());\n\n if (newTrackResponse.requiresImmediateRenegotiation) {\n await peerConnection.setRemoteDescription(new RTCSessionDescription(newTrackResponse.sessionDescription));\n const answer = await peerConnection.createAnswer();\n await peerConnection.setLocalDescription(answer);\n\n const renegotiationResponse = await this._fetch<RenegotiationResponse>(\n `/sessions/${sessionId}/renegotiate`,\n {\n method: 'PUT',\n body: JSON.stringify({\n sessionDescription: {\n type: 'answer',\n sdp: peerConnection.currentLocalDescription?.sdp,\n },\n }),\n },\n );\n\n if (renegotiationResponse.errorCode) {\n throw new Error(renegotiationResponse.errorDescription);\n } else {\n await peerConnectionIsConnected(peerConnection);\n }\n }\n\n return { trackMap };\n }),\n )\n .then(({ trackMap }) => {\n const trackInfo = trackMap.get(trackData.trackName!);\n if (trackInfo) {\n return trackInfo.resolvedTrack\n .then((track) => {\n mid = trackInfo.mid;\n return track;\n })\n .catch((err) => log.catch(err));\n } else {\n log.info('missing track info', { trackData, availableTracks: Array.from(trackMap.keys()) });\n }\n });\n\n const onDispose = async () => {\n if (mid) {\n log('closing pulled track ', trackData.trackName);\n await this._closeTrackInBulk(peerConnection, mid, sessionId);\n mid = '';\n }\n };\n\n this._ctx.onDispose(() => onDispose());\n ctx?.onDispose(() => onDispose());\n\n return pulledTrackPromise as Promise<MediaStreamTrack | undefined>;\n }\n\n async pullTrack({\n ctx,\n trackData,\n }: {\n trackData: TrackObject;\n ctx?: Context;\n }): Promise<MediaStreamTrack | undefined> {\n await this.waitUntilOpen();\n\n invariant(this.session);\n const session = this.session;\n return this._pullTrackInBulk({\n peerConnection: session.peerConnection,\n sessionId: session.sessionId,\n trackData,\n ctx,\n });\n }\n\n async _closeTrackInBulk(peerConnection: RTCPeerConnection, mid: string, sessionId: string): Promise<void> {\n const transceiver = peerConnection.getTransceivers().find((t) => t.mid === mid);\n\n if (peerConnection.connectionState !== 'connected' || transceiver === undefined) {\n return;\n }\n await this.closeTrackDispatcher.doBulkRequest({ mid }, (mids) =>\n this.taskScheduler.schedule(async () => {\n transceiver.stop();\n const activeTransceivers = peerConnection\n .getTransceivers()\n .filter((t) => t.mid !== mid && t.direction !== 'stopped');\n\n let requestBody;\n if (activeTransceivers.length > 0) {\n // create an offer\n const offer = await peerConnection.createOffer();\n // And set the offer as the local description\n await peerConnection.setLocalDescription(offer);\n requestBody = {\n tracks: mids,\n sessionDescription: {\n sdp: peerConnection.localDescription?.sdp,\n type: 'offer',\n },\n force: false,\n };\n } else {\n requestBody = {\n tracks: mids,\n force: true,\n };\n }\n\n const response = await this._fetch<TracksResponse>(`/sessions/${sessionId}/tracks/close`, {\n method: 'PUT',\n body: JSON.stringify(requestBody),\n });\n\n if (requestBody.sessionDescription) {\n await peerConnection.setRemoteDescription(new RTCSessionDescription(response.sessionDescription));\n }\n }),\n );\n }\n}\n\nconst resolveTrack = async (\n peerConnection: RTCPeerConnection,\n compare: (t: RTCRtpTransceiver) => boolean,\n timeout = NETWORK_TIMEOUT,\n) =>\n new Promise<MediaStreamTrack>((resolve, reject) => {\n setTimeout(reject, timeout);\n const handler = () => {\n const transceiver = peerConnection.getTransceivers().find(compare);\n if (transceiver) {\n resolve(transceiver.receiver.track);\n peerConnection.removeEventListener('track', handler);\n }\n };\n\n peerConnection.addEventListener('track', handler);\n });\n\nconst peerConnectionIsConnected = async (peerConnection: RTCPeerConnection) => {\n if (peerConnection.connectionState !== 'connected') {\n const connected = new Promise((resolve, reject) => {\n // Timeout after 5s.\n const timeout = setTimeout(() => {\n peerConnection.removeEventListener('connectionstatechange', connectionStateChangeHandler);\n reject(new Error('Connection timeout'));\n }, NETWORK_TIMEOUT);\n\n const connectionStateChangeHandler = () => {\n if (peerConnection.connectionState === 'connected') {\n peerConnection.removeEventListener('connectionstatechange', connectionStateChangeHandler);\n clearTimeout(timeout);\n resolve(undefined);\n }\n };\n peerConnection.addEventListener('connectionstatechange', connectionStateChangeHandler);\n });\n\n await connected;\n }\n};\n\nconst INITIAL_DELAY = 50;\nconst MAX_DELAY = 500;\nconst MAX_RETRIES = 20;\nconst WAIT_FOR_DATA_TIMEOUT = 10_000;\n\nconst waitForTransceiverToSendData = async (ctx: Context, transceiver: RTCRtpTransceiver): Promise<void> => {\n let delay = INITIAL_DELAY;\n let checks = 0;\n const waitForData = new Trigger();\n ctx.onDispose(() => waitForData.throw(new Error('Transceiver was closed')));\n\n const checkStats = async () => {\n if (ctx.disposed) return;\n\n try {\n const stats = await transceiver.sender.getStats();\n let dataFound = false;\n stats.forEach((stat) => {\n if (stat.type === 'outbound-rtp' && stat.bytesSent > 0) {\n dataFound = true;\n }\n });\n\n if (dataFound) {\n waitForData.wake();\n return;\n }\n } catch {\n // Stats might not be available yet, continue checking\n }\n checks++;\n if (checks > MAX_RETRIES) {\n waitForData.throw(new Error('Transceiver did not send data'));\n return;\n }\n\n delay = Math.min(delay * 2, MAX_DELAY); // Exponential backoff with max cap\n scheduleTask(ctx, checkStats, delay);\n };\n\n void checkStats();\n return waitForData.wait({ timeout: WAIT_FOR_DATA_TIMEOUT });\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\n/**\n * Array that holds the last N items.\n */\nexport class HistoryCache<T> {\n private readonly _limit: number;\n private readonly _messages: T[];\n\n constructor(limit = 100) {\n this._limit = limit;\n this._messages = [];\n }\n\n push(...messages: T[]): void {\n if (this._messages.length >= this._limit) {\n this._messages.shift(); // Remove the oldest message\n }\n this._messages.push(...messages); // Add new message\n }\n\n get(): T[] {\n return this._messages;\n }\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nconst DefaultBatchSizeLimit = 64;\n\ntype Task<Value = unknown> = () => Promise<Value>;\n\nexport class FIFOScheduler {\n #schedulerChain: Promise<void>;\n\n constructor() {\n this.#schedulerChain = Promise.resolve();\n }\n\n schedule<T>(task: Task<T>): Promise<T> {\n return new Promise((resolve, reject) => {\n this.#schedulerChain = this.#schedulerChain.then(async () => {\n try {\n resolve(await task());\n } catch (error: any) {\n reject(error);\n }\n });\n });\n }\n}\n\n// TODO(mykola): Reconcile with @dxos/async task scheduling.\nexport class BulkRequestDispatcher<RequestEntryParams, BulkResponse> {\n #currentBatch: RequestEntryParams[];\n #currentBulkResponse: Promise<BulkResponse> | null;\n #batchSizeLimit: number;\n\n constructor(batchSizeLimit: number = DefaultBatchSizeLimit) {\n this.#currentBatch = [];\n this.#currentBulkResponse = null;\n this.#batchSizeLimit = batchSizeLimit;\n }\n\n /**\n * Returns a bulk response promise.\n * At the event loop iteration end, the accumulated entries will be dispatched as a bulk request.\n */\n doBulkRequest(\n params: RequestEntryParams,\n bulkRequestFunc: (bulkCopy: RequestEntryParams[]) => Promise<BulkResponse>,\n ): Promise<BulkResponse> {\n if (this.#currentBatch.length >= this.#batchSizeLimit) {\n // If it reaches the batch size limit, we make another bulk request.\n this.#currentBatch = [];\n this.#currentBulkResponse = null;\n }\n this.#currentBatch.push(params);\n if (this.#currentBulkResponse != null) {\n return this.#currentBulkResponse;\n }\n\n // Save the current batch list reference in the function scope because this.#currentBatch could be reset\n // if the batch limit is reached.\n const batch = this.#currentBatch;\n this.#currentBulkResponse = new Promise((resolve, reject) => {\n // script\n // |\n // V\n // microtasks (Promise)\n // |\n // V\n // macrotasks (setTimeout)\n //\n // macrotasks are run in the event loop iteration end, so we use that moment to make the bulkRequestFunc call.\n setTimeout(() => {\n // When the bulk request happens, the batch list and the response is reset to start another batch.\n // Coming callers will wait for a new response promise.\n this.#currentBulkResponse = null;\n\n // We cut here to make the bulk request.\n const batchCopy = batch.splice(0, batch.length);\n bulkRequestFunc(batchCopy)\n .then((result) => {\n resolve(result);\n })\n .catch((err) => {\n reject(err);\n });\n }, 0);\n });\n\n // This bulk response needs to be processed to extract the the result for the entry.\n return this.#currentBulkResponse;\n }\n}\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { log } from '@dxos/log';\n\nexport const getUserMediaTrack = async (\n kind: MediaDeviceKind,\n constraints: MediaTrackConstraints = {},\n deviceList?: MediaDeviceInfo[],\n): Promise<MediaStreamTrack> => {\n deviceList ??= (await getDeviceList()).filter((device) => device.kind === kind);\n const firstDevice = deviceList[0];\n if (!firstDevice) {\n throw new Error('No devices found');\n }\n\n return acquireTrack(firstDevice, constraints);\n};\n\nconst acquireTrack = async (device: MediaDeviceInfo, constraints: MediaTrackConstraints): Promise<MediaStreamTrack> => {\n const { deviceId, label } = device;\n log.info(`requesting ${label}`);\n\n const mediaStream = await navigator.mediaDevices.getUserMedia(\n device.kind === 'videoinput' ? { video: { ...constraints, deviceId } } : { audio: { ...constraints, deviceId } },\n );\n return device.kind === 'videoinput' ? mediaStream.getVideoTracks()[0] : mediaStream.getAudioTracks()[0];\n};\n\n// TODO(mykola): Handle devicechange event.\nexport const getDeviceList = () => navigator.mediaDevices.enumerateDevices();\n\nconst SCREENSHARE_CONSTRAINTS = {\n video: {\n width: { max: 1920 },\n height: { max: 1080 },\n frameRate: { max: 10 },\n },\n};\n\nexport const getScreenshare = async ({ contentHint }: { contentHint: string }) => {\n // Get 1080p equivalent screenshare with 10fps, but save natural sharing content aspect ratio.\n const ms = await navigator.mediaDevices.getDisplayMedia(SCREENSHARE_CONSTRAINTS);\n ms.getVideoTracks().forEach((track) => {\n if (contentHint && 'contentHint' in track) {\n track.contentHint = contentHint;\n }\n });\n\n return ms;\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { DeferredTask, Event, sleep } from '@dxos/async';\nimport { Resource } from '@dxos/context';\n\nimport { monitorAudioLevel } from './util';\n\nconst NOT_SPEAKING_AFTER = 500; // [ms]\nconst START_SPEAKING_THRESHOLD = 0.05;\nconst CONTINUE_SPEAKING_THRESHOLD = 0.02;\nconst MIN_EVENT_INTERVAL = 100; // [ms]\n\nexport class SpeakingMonitor extends Resource {\n /**\n * Event that is emitted when the user starts or stops speaking.\n * It is debounced to prevent rapid state changes.\n */\n public readonly speakingChanged = new Event<boolean>();\n\n /**\n * Real state of the user speaking.\n */\n private _isSpeaking = false;\n private _lastEventTime = 0;\n private _deferredUpdate?: DeferredTask | undefined;\n\n constructor(private readonly _mediaStreamTrack: MediaStreamTrack) {\n super();\n }\n\n get isSpeaking(): boolean {\n return this._isSpeaking;\n }\n\n protected override async _open(): Promise<void> {\n this._deferredUpdate = new DeferredTask(this._ctx, async () => this._emitSpeakingChanged());\n\n let timeout: NodeJS.Timeout | undefined;\n const cleanup = monitorAudioLevel({\n mediaStreamTrack: this._mediaStreamTrack,\n onMeasure: (vol) => {\n // Once the user has been determined to be speaking, we want\n // to lower the threshold because speech patterns don't always\n // kick up above 0.05.\n const audioLevelAboveThreshold =\n vol > (this._isSpeaking ? CONTINUE_SPEAKING_THRESHOLD : START_SPEAKING_THRESHOLD);\n if (audioLevelAboveThreshold) {\n // User is still speaking, clear timeout & reset.\n clearTimeout(timeout);\n timeout = undefined;\n if (!this._isSpeaking) {\n this._isSpeaking = true;\n this._deferredUpdate?.schedule();\n }\n } else if (timeout === undefined) {\n // User is not speaking and timeout is not set.\n timeout = setTimeout(() => {\n this._isSpeaking = false;\n timeout = undefined;\n this._deferredUpdate?.schedule();\n }, NOT_SPEAKING_AFTER);\n }\n },\n });\n this._ctx.onDispose(() => {\n cleanup();\n clearTimeout(timeout);\n });\n }\n\n /**\n * Emits the speaking changed event with debouncing based on timing.\n */\n private async _emitSpeakingChanged(): Promise<void> {\n const timeSinceLastEvent = Date.now() - this._lastEventTime;\n const timeToNextEvent = MIN_EVENT_INTERVAL - timeSinceLastEvent;\n if (timeToNextEvent > 0) {\n await sleep(timeToNextEvent);\n }\n this._lastEventTime = Date.now();\n this.speakingChanged.emit(this._isSpeaking);\n }\n}\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { DeferredTask, Event, sleep, synchronized } from '@dxos/async';\nimport { type Context, Resource, cancelWithContext } from '@dxos/context';\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\n\nimport { SpeakingMonitor } from './speaking-monitor';\nimport { type EncodedTrackName, TrackNameCodec, type TrackObject } from './types';\nimport {\n type CallsServiceConfig,\n CallsServicePeer,\n createBlackCanvasStreamTrack,\n createInaudibleAudioStreamTrack,\n getScreenshare,\n getUserMediaTrack,\n} from './util';\n\nexport type MediaState = {\n audioDeviceId?: string;\n audioEnabled?: boolean;\n audioTrack?: MediaStreamTrack;\n\n videoDeviceId?: string;\n videoEnabled?: boolean;\n videoTrack?: MediaStreamTrack;\n videoStream?: MediaStream;\n\n screenshareEnabled?: boolean;\n screenshareTrack?: MediaStreamTrack;\n screenshareVideoStream?: MediaStream;\n\n pushedVideoTrack?: TrackObject;\n pushedAudioTrack?: TrackObject;\n pushedScreenshareTrack?: TrackObject;\n peer?: CallsServicePeer;\n\n pulledAudioTracks: Record<EncodedTrackName, { track: MediaStreamTrack; ctx: Context }>;\n /**\n * Includes video feeds and screenshare feeds of other participants.\n */\n pulledVideoStreams: Record<EncodedTrackName, { stream: MediaStream; ctx: Context }>;\n};\n\n// TOOD(burdon): Hard coded.\nconst VIDEO_WIDTH = 1280;\nconst VIDEO_HEIGHT = 720;\nconst MAX_WEB_CAM_FRAMERATE = 24;\nconst MAX_WEB_CAM_BITRATE = 120_0000;\nconst RETRY_INTERVAL = 100;\n\nexport type MediaManagerParams = {\n serviceConfig: CallsServiceConfig;\n};\n\nconst USE_INAUDIBLE_AUDIO = true;\n\nexport class MediaManager extends Resource {\n public readonly stateUpdated = new Event<MediaState>();\n private readonly _state: MediaState = { pulledVideoStreams: {}, pulledAudioTracks: {} };\n private _speakingMonitor?: SpeakingMonitor = undefined;\n\n private _trackToReconcile: EncodedTrackName[] = [];\n private _blackCanvasStreamTrack?: MediaStreamTrack = undefined;\n private _inaudibleAudioStreamTrack?: MediaStreamTrack = undefined;\n private _pushTracksTask?: DeferredTask = undefined;\n private _pullTracksTask?: DeferredTask = undefined;\n\n get isSpeaking() {\n return this._speakingMonitor?.isSpeaking;\n }\n\n /**\n * @internal\n */\n _getState(): MediaState {\n return this._state;\n }\n\n protected override async _open(): Promise<void> {\n this._blackCanvasStreamTrack = await createBlackCanvasStreamTrack({\n ctx: this._ctx,\n width: VIDEO_WIDTH,\n height: VIDEO_HEIGHT,\n });\n this._state.videoTrack = this._blackCanvasStreamTrack;\n this._state.videoStream = new MediaStream();\n this._state.videoStream.addTrack(this._state.videoTrack);\n\n if (USE_INAUDIBLE_AUDIO) {\n this._inaudibleAudioStreamTrack = await createInaudibleAudioStreamTrack({ ctx: this._ctx });\n this._state.audioTrack = this._inaudibleAudioStreamTrack;\n }\n\n this._pushTracksTask = new DeferredTask(this._ctx, async () => {\n await this._pushTracks();\n });\n this._pullTracksTask = new DeferredTask(this._ctx, async () => {\n await this._reconcilePulledMedia();\n });\n }\n\n protected override async _close(): Promise<void> {\n void this._speakingMonitor?.close();\n this._state.videoTrack && this._state.videoStream?.removeTrack(this._state.videoTrack);\n this._state.audioTrack?.stop();\n this._state.videoTrack?.stop();\n this._state.screenshareTrack?.stop();\n this._pushTracksTask = undefined;\n this._pullTracksTask = undefined;\n }\n\n @synchronized\n async join(serviceConfig: CallsServiceConfig): Promise<void> {\n this._state.peer = new CallsServicePeer(serviceConfig);\n await this._state.peer!.open();\n this._pushTracksTask!.schedule();\n }\n\n @synchronized\n async leave(): Promise<void> {\n await Promise.all(Object.values(this._state.pulledAudioTracks).map(({ ctx }) => ctx.dispose()));\n await Promise.all(Object.values(this._state.pulledVideoStreams).map(({ ctx }) => ctx.dispose()));\n this._trackToReconcile = [];\n await this._state.peer?.close();\n this._state.peer = undefined;\n this._state.pushedVideoTrack = undefined;\n this._state.pushedAudioTrack = undefined;\n this._state.pushedScreenshareTrack = undefined;\n this._state.pulledAudioTracks = {};\n this._state.pulledVideoStreams = {};\n }\n\n async turnVideoOn(): Promise<void> {\n this._state.videoStream!.removeTrack(this._state.videoTrack!);\n this._state.videoTrack = await getUserMediaTrack('videoinput', { width: VIDEO_WIDTH, height: VIDEO_HEIGHT });\n this._state.videoStream!.addTrack(this._state.videoTrack);\n this._state.videoEnabled = true;\n this.stateUpdated.emit(this._state);\n this._pushTracksTask!.schedule();\n }\n\n async turnVideoOff(): Promise<void> {\n if (this._state.videoTrack !== this._blackCanvasStreamTrack) {\n this._state.videoStream!.removeTrack(this._state.videoTrack!);\n this._state.videoTrack?.stop();\n this._state.videoTrack = this._blackCanvasStreamTrack;\n this._state.videoStream!.addTrack(this._state.videoTrack!);\n }\n\n this._state.videoEnabled = false;\n this.stateUpdated.emit(this._state);\n this._pushTracksTask!.schedule();\n }\n\n // TODO(mykola): Change to `setAudioEnabled(enabled: boolean)`.\n async turnAudioOn(): Promise<void> {\n void this._speakingMonitor?.close();\n this._state.audioEnabled = true;\n this._state.audioTrack = await getUserMediaTrack('audioinput', {\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true,\n sampleRate: 16_000,\n });\n this.stateUpdated.emit(this._state);\n this._pushTracksTask!.schedule();\n this._speakingMonitor = new SpeakingMonitor(this._state.audioTrack!);\n this._speakingMonitor.speakingChanged.on(this._ctx, () => this.stateUpdated.emit(this._state));\n void this._speakingMonitor.open();\n }\n\n async turnAudioOff(): Promise<void> {\n void this._speakingMonitor?.close();\n this._speakingMonitor = undefined;\n this._state.audioEnabled = false;\n if (USE_INAUDIBLE_AUDIO && this._state.audioTrack !== this._inaudibleAudioStreamTrack) {\n this._state.audioTrack?.stop();\n this._state.audioTrack = this._inaudibleAudioStreamTrack;\n } else {\n this._state.audioTrack?.stop();\n this._state.audioTrack = undefined;\n }\n this.stateUpdated.emit(this._state);\n this._pushTracksTask!.schedule();\n }\n\n async turnScreenshareOn(): Promise<void> {\n const ms = await getScreenshare({ contentHint: 'text' });\n this._state.screenshareVideoStream = ms;\n this._state.screenshareTrack = ms.getVideoTracks()[0];\n this._state.screenshareEnabled = true;\n this.stateUpdated.emit(this._state);\n this._pushTracksTask!.schedule();\n }\n\n async turnScreenshareOff(): Promise<void> {\n this._state.screenshareEnabled = false;\n this._state.screenshareTrack?.stop();\n this._state.screenshareTrack = undefined;\n this.stateUpdated.emit(this._state);\n this._pushTracksTask!.schedule();\n }\n\n /**\n * @internal\n */\n _schedulePullTracks(tracks?: EncodedTrackName[]): void {\n if (\n !tracks ||\n (this._trackToReconcile.every((name) => tracks.includes(name)) && this._trackToReconcile.length === tracks.length)\n ) {\n return;\n }\n\n this._trackToReconcile = tracks;\n this._pullTracksTask!.schedule();\n }\n\n private async _reconcilePulledMedia(): Promise<void> {\n log('reconciling tracks');\n // TODO(mykola): Currently cloudflare fails if you try to pull track immediately after pushing it.\n // Add retry logic, remove sleep.\n // Wait for cloudflare to process the track.\n await cancelWithContext(this._ctx, sleep(800));\n const trackNames = this._trackToReconcile;\n\n const tracksToPull = trackNames.filter(\n (name) => !this._state.pulledAudioTracks[name] && !this._state.pulledVideoStreams[name],\n );\n\n const audioTracksToClose = Object.entries(this._state.pulledAudioTracks).filter(\n ([key]) => !trackNames.some((name) => name === key),\n );\n\n const videoStreamsToClose = Object.entries(this._state.pulledVideoStreams).filter(\n ([key]) => !trackNames.some((name) => name === key),\n );\n\n log('reconciling tracks', {\n trackNames,\n tracksToPull,\n videoStreamsToClose,\n audioTracksToClose,\n currentAudioTracks: Object.keys(this._state.pulledAudioTracks),\n currentVideoStreams: Object.keys(this._state.pulledVideoStreams),\n });\n\n // Pull new tracks.\n const pullResults = await Promise.all(tracksToPull.map((name) => this._pullTrack(name)));\n\n // Close old tracks.\n await Promise.all([...audioTracksToClose, ...videoStreamsToClose].map(([_, { ctx }]) => ctx.dispose()));\n\n log('reconciled tracks', {\n currentAudioTracks: Object.keys(this._state.pulledAudioTracks),\n currentVideoStreams: Object.keys(this._state.pulledVideoStreams),\n });\n this.stateUpdated.emit(this._state);\n\n if (pullResults.some(({ shouldRetry }) => shouldRetry)) {\n await cancelWithContext(this._ctx, sleep(RETRY_INTERVAL));\n log.info('retrying pull tracks', { tracksToPull });\n invariant(this._pullTracksTask);\n this._pullTracksTask.schedule();\n }\n }\n\n private async _pushTracks(): Promise<void> {\n if (!this._state.peer?.isOpen) {\n return;\n }\n\n let updated = false;\n const [pushVideoResult, pushAudioResult, pushScreenshareResult] = await Promise.all([\n this._maybePushTrack(this._state.videoTrack, this._state.pushedVideoTrack, [\n { maxFramerate: MAX_WEB_CAM_FRAMERATE, maxBitrate: MAX_WEB_CAM_BITRATE },\n ]),\n this._maybePushTrack(this._state.audioTrack, this._state.pushedAudioTrack, [{ networkPriority: 'high' }]),\n this._maybePushTrack(this._state.screenshareTrack, this._state.pushedScreenshareTrack),\n ]);\n\n if (pushVideoResult.track !== this._state.pushedVideoTrack) {\n this._state.pushedVideoTrack = pushVideoResult.track;\n updated = true;\n }\n if (pushAudioResult.track !== this._state.pushedAudioTrack) {\n this._state.pushedAudioTrack = pushAudioResult.track;\n updated = true;\n }\n if (pushScreenshareResult.track !== this._state.pushedScreenshareTrack) {\n this._state.pushedScreenshareTrack = pushScreenshareResult.track;\n updated = true;\n }\n\n const shouldRetry = pushVideoResult.shouldRetry || pushAudioResult.shouldRetry || pushScreenshareResult.shouldRetry;\n\n if (updated) {\n this.stateUpdated.emit(this._state);\n }\n\n if (shouldRetry) {\n await cancelWithContext(this._ctx, sleep(RETRY_INTERVAL));\n log.info('retrying push tracks', { pushVideoResult, pushAudioResult, pushScreenshareResult });\n invariant(this._pushTracksTask);\n this._pushTracksTask.schedule();\n }\n }\n\n private async _pullTrack(name: EncodedTrackName): Promise<{ shouldRetry: boolean }> {\n const ctx = this._ctx.derive();\n try {\n const trackData = TrackNameCodec.decode(name);\n // We need to set mid here to `undefined`, because mid is peer specific.\n const track = await this._state.peer!.pullTrack({ trackData: { ...trackData, mid: undefined }, ctx });\n if (track?.readyState === 'ended') {\n throw new Error('Pulled track ended immediately');\n }\n\n switch (track?.kind) {\n case 'audio': {\n this._state.pulledAudioTracks[name] = { track, ctx };\n ctx.onDispose(() => delete this._state.pulledAudioTracks[name]);\n return { shouldRetry: false };\n }\n case 'video': {\n const mediaStream = new MediaStream();\n mediaStream.addTrack(track);\n this._state.pulledVideoStreams[name] = { stream: mediaStream, ctx };\n ctx.onDispose(() => {\n mediaStream.removeTrack(track);\n track.stop();\n delete this._state.pulledVideoStreams[name];\n });\n return { shouldRetry: false };\n }\n default:\n throw new Error(`Invalid track kind: ${track?.kind}`);\n }\n } catch (err) {\n log.info('failed to pull track', { err, name });\n void ctx.dispose();\n return { shouldRetry: true };\n }\n }\n\n private async _maybePushTrack(\n track?: MediaStreamTrack,\n previousTrack?: TrackObject,\n encodings?: RTCRtpEncodingParameters[],\n ): Promise<{ track?: TrackObject; shouldRetry?: boolean }> {\n if (!track && !previousTrack) {\n return { track: undefined };\n }\n\n const ctx = this._ctx.derive();\n\n try {\n return {\n track: await this._state.peer!.pushTrack({\n ctx,\n track: track ?? null,\n previousTrack,\n encodings,\n }),\n };\n } catch (err) {\n log.info('failed to push track', { err, track, previousTrack, encodings });\n void ctx.dispose();\n return { shouldRetry: true };\n }\n }\n}\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { computed } from '@preact/signals-core';\n\nimport { Event, synchronized } from '@dxos/async';\nimport { type Client } from '@dxos/client';\nimport { Resource } from '@dxos/context';\nimport { invariant } from '@dxos/invariant';\nimport { live } from '@dxos/live-object';\nimport { type Tracks } from '@dxos/protocols/proto/dxos/edge/calls';\nimport { isNonNullable } from '@dxos/util';\n\nimport { type CallState, CallSwarmSynchronizer } from './call-swarm-synchronizer';\nimport { MediaManager, type MediaState } from './media-manager';\nimport { type ActivityState, CALLS_URL, type EncodedTrackName, TrackNameCodec, type UserState } from './types';\n\nexport type GlobalState = {\n call: CallState;\n media: MediaState;\n};\n\n/**\n * Top level manager for call state.\n */\nexport class CallManager extends Resource {\n public readonly callStateUpdated = new Event<CallState>();\n // TODO(wittjosiah): Consolidate isSpeaking into the MediaState type.\n public readonly mediaStateUpdated = new Event<[MediaState, boolean]>();\n public readonly left = new Event<string>();\n\n /**\n * Live object state. Is changed on internal events.\n * CAUTION: Do not change directly.\n */\n private readonly _state = live<GlobalState>({\n call: {},\n media: { pulledAudioTracks: {}, pulledVideoStreams: {} },\n });\n\n // TODO(wittjosiah): This shouldn't be necessary, live-object's signals should be granular.\n private readonly _raisedHandSignal = computed(() => this._state.call.raisedHand ?? false);\n private readonly _speakingSignal = computed(() => this._state.call.speaking ?? false);\n private readonly _joinedSignal = computed(() => this._state.call.joined ?? false);\n\n private readonly _swarmSynchronizer: CallSwarmSynchronizer;\n private readonly _mediaManager: MediaManager;\n\n /** @reactive */\n get roomId(): string | undefined {\n return this._state.call.roomId;\n }\n\n /** @reactive */\n get raisedHand(): boolean {\n return this._raisedHandSignal.value;\n }\n\n /** @reactive */\n get speaking(): boolean {\n return this._speakingSignal.value;\n }\n\n /** @reactive */\n get joined(): boolean {\n return this._joinedSignal.value;\n }\n\n /** @reactive */\n get self(): UserState {\n return this._state.call.self ?? {};\n }\n\n /** @reactive */\n get tracks(): Tracks {\n return this._state.call.tracks ?? {};\n }\n\n /** @reactive */\n get users(): UserState[] {\n return this._state.call.users ?? [];\n }\n\n /** @reactive */\n get media() {\n return this._state.media;\n }\n\n /** @reactive */\n get audioTracksToPlay(): MediaStreamTrack[] {\n return (this._state.call.users ?? [])\n .map((user) => (user.tracks?.audioEnabled ? user.tracks?.audio : undefined))\n .filter(isNonNullable)\n .map((track) => this._state.media.pulledAudioTracks[track as EncodedTrackName]?.track)\n .filter(isNonNullable);\n }\n\n /** @reactive */\n get state() {\n return this._state;\n }\n\n /** @reactive */\n getVideoStream(name?: EncodedTrackName): MediaStream | undefined {\n return name ? this._state.media.pulledVideoStreams[name]?.stream : undefined;\n }\n\n /** @reactive */\n getActivity(key: string): ActivityState | undefined {\n return this._state.call.activities?.[key];\n }\n\n setRoomId(roomId: string): void {\n this._swarmSynchronizer._setRoomId(roomId);\n }\n\n setSpeaking(speaking: boolean): void {\n this._swarmSynchronizer.setSpeaking(speaking);\n }\n\n setRaisedHand(raisedHand: boolean): void {\n this._swarmSynchronizer.setRaisedHand(raisedHand);\n }\n\n setActivity(key: string, payload: ActivityState['payload']): void {\n this._swarmSynchronizer.setActivity(key, payload);\n }\n\n turnAudioOn(): Promise<void> {\n return this._mediaManager.turnAudioOn();\n }\n\n turnAudioOff(): Promise<void> {\n return this._mediaManager.turnAudioOff();\n }\n\n turnVideoOn(): Promise<void> {\n return this._mediaManager.turnVideoOn();\n }\n\n turnVideoOff(): Promise<void> {\n return this._mediaManager.turnVideoOff();\n }\n\n turnScreenshareOn(): Promise<void> {\n return this._mediaManager.turnScreenshareOn();\n }\n\n turnScreenshareOff(): Promise<void> {\n return this._mediaManager.turnScreenshareOff();\n }\n\n // TODO(burdon): Can this be mocked?\n constructor(private readonly _client: Client) {\n super();\n this._client.config.getOrThrow('runtime.services.edge.url');\n const networkService = this._client.services.services.NetworkService;\n invariant(networkService, 'network service not found');\n this._swarmSynchronizer = new CallSwarmSynchronizer({ networkService });\n this._mediaManager = new MediaManager();\n }\n\n protected override async _open(): Promise<void> {\n await this._mediaManager.open();\n await this._swarmSynchronizer.open();\n const subscription = this._client.halo.identity.subscribe((identity) => {\n if (identity) {\n this._swarmSynchronizer._setIdentity(identity);\n }\n if (this._client.halo.device) {\n this._swarmSynchronizer._setDevice(this._client.halo.device);\n }\n });\n this._ctx.onDispose(() => subscription.unsubscribe());\n\n this._swarmSynchronizer.stateUpdated.on(this._ctx, (state) => this._onCallStateUpdated(state));\n this._mediaManager.stateUpdated.on(this._ctx, (state) => this._onMediaStateUpdated(state));\n }\n\n protected override async _close(): Promise<void> {\n await this._swarmSynchronizer.leave();\n await this._swarmSynchronizer.close();\n await this._mediaManager.close();\n }\n\n async peek(roomId: string): Promise<number> {\n const peers = await this._swarmSynchronizer.querySwarm(roomId);\n return peers.length;\n }\n\n // TODO(mykola): Reconcile with _swarmSynchronizer.state.joined.\n @synchronized\n async join(): Promise<void> {\n this._swarmSynchronizer.setJoined(true);\n await this._swarmSynchronizer.join();\n await this._mediaManager.join({\n iceServers: this._client.config.get('runtime.services.ice'),\n apiBase: `${CALLS_URL}/api/calls`,\n });\n }\n\n @synchronized\n async leave(): Promise<void> {\n this._swarmSynchronizer.setJoined(false);\n await this._swarmSynchronizer.leave();\n await this._mediaManager.leave();\n this.roomId && this.left.emit(this.roomId);\n }\n\n private _onCallStateUpdated(state: CallState): void {\n const tracksToPull = state.users\n ?.filter((user) => user.joined && user.id !== state.self!.id)\n ?.flatMap((user) => [user.tracks?.video, user.tracks?.audio, user.tracks?.screenshare])\n .filter(isNonNullable);\n this._mediaManager._schedulePullTracks(tracksToPull as EncodedTrackName[]);\n\n this.callStateUpdated.emit(state);\n this._updateState();\n }\n\n private _onMediaStateUpdated(state: MediaState): void {\n this._swarmSynchronizer.setTracks({\n video: state.pushedVideoTrack ? TrackNameCodec.encode(state.pushedVideoTrack) : undefined,\n audio: state.pushedAudioTrack ? TrackNameCodec.encode(state.pushedAudioTrack) : undefined,\n screenshare: state.pushedScreenshareTrack ? TrackNameCodec.encode(state.pushedScreenshareTrack) : undefined,\n videoEnabled: state.videoEnabled,\n audioEnabled: state.audioEnabled,\n screenshareEnabled: state.screenshareEnabled,\n });\n\n const isSpeaking = this._mediaManager.isSpeaking ?? false;\n this._swarmSynchronizer.setSpeaking(isSpeaking);\n\n this.mediaStateUpdated.emit([state, isSpeaking]);\n this._updateState();\n }\n\n /**\n * Only this method is allowed to change state.\n */\n private _updateState(): void {\n this._state.call = this._swarmSynchronizer._getState();\n this._state.media = this._mediaManager._getState();\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;AAIA,SAASA,iBAAiB;AAC1B,SAASC,WAAW;AACpB,SAGEC,uBACK;;AAKA,IAAMC,YAAY;AAMlB,IAAMC,QAAQ;EACnBC,QAAQ,CAACC,YAAAA;AACP,WAAOL,IAAIM,SAASL,iBAAiBD,IAAIO,OAAON,iBAAiBI,OAAAA,CAAAA;EACnE;EACAG,QAAQ,CAACH,YAAAA;AACP,WAAOL,IAAIS,WAAWR,iBAAiBI,OAAAA;EACzC;AACF;AAkCO,IAAMK,iBAAiB;EAC5BN,QAAQ,CAACO,cAAAA;AACPZ,cAAUY,UAAUC,WAAS,QAAA;;;;;;;;;AAC7Bb,cAAUY,UAAUE,WAAS,QAAA;;;;;;;;;AAC7Bd,cAAUY,UAAUG,KAAG,QAAA;;;;;;;;;AACvB,WAAQH,UAAUC,YAAY,MAAMD,UAAUE,YAAY,MAAMF,UAAUG;EAC5E;EACAN,QAAQ,CAACO,SAAAA;AACP,UAAM,CAACH,WAAWC,WAAWC,GAAAA,IAAOC,KAAKC,MAAM,GAAA;AAC/C,WAAO;MAAEJ;MAAWC;MAAWI,UAAU;MAAUH;IAAI;EACzD;AACF;;;ACrEA,OAAOI,YAAY;AAEnB,SAASC,cAAcC,OAAOC,sBAAsBC,oBAAoB;AAExE,SAASC,SAASC,gBAAgB;AAClC,SAASC,oBAAoB;AAC7B,SAASC,aAAAA,kBAAiB;AAC1B,SAASC,iBAAiB;AAC1B,SAASC,WAAW;AACpB,SAASC,OAAAA,YAAW;AACpB,SAASC,sBAAsB;AAE/B,SAASC,uBAA2C;AACpD,SAASC,qBAAqB;;;;;;;;;;;;;;;;;;;;;AAwC9B,IAAMC,8BAA8B;AAK7B,IAAMC,wBAAN,cAAoCC,SAAAA;;;;EAwBzCC,YAAuB;AACrB,WAAO,KAAKC;EACd;EAEAC,cAAcC,YAA2B;AACvC,QAAI,KAAKF,OAAOE,eAAeA,YAAY;AACzC;IACF;AAEA,SAAKF,OAAOE,aAAaA;AACzB,SAAKC,mBAAkB;EACzB;EAEAC,YAAYC,UAAyB;AACnC,QAAI,KAAKL,OAAOK,aAAaA,UAAU;AACrC;IACF;AAEA,SAAKL,OAAOK,WAAWA;AACvB,SAAKF,mBAAkB;EACzB;EAEAG,UAAUC,QAAuB;AAC/B,QAAI,KAAKP,OAAOO,WAAWA,QAAQ;AACjC;IACF;AAEA,SAAKP,OAAOO,SAASA;AACrB,SAAKJ,mBAAkB;EACzB;EAEAK,UAAUC,QAAmC;AAC3C,SAAKT,OAAOS,SAAS;MAAE,GAAG,KAAKT,OAAOS;MAAQ,GAAGA;IAAO;AACxD,SAAKN,mBAAkB;EACzB;EAEAO,YAAYC,KAAaC,SAAyC;AAChE,UAAMC,mBAAmBC,qBAAqBC,UAC5C,KAAKf,OAAOgB,aAAaL,GAAAA,GAAME,oBAAoB;MAAEI,IAAI,KAAKC;IAAW,CAAA;AAE3E,SAAKlB,OAAOgB,WAAYL,GAAAA,IAAO;MAAEE;MAAkBD;IAAQ;AAE3D,SAAKT,mBAAkB;EACzB;;;;EAKAgB,aAAaC,UAA0B;AACrC,SAAKC,eAAeD,SAASE,YAAYC,MAAK;AAC9C,SAAKC,eAAeJ,SAASK,SAASC,eAAeC,aAAaP,SAASE,YAAYC,MAAK,CAAA;EAC9F;;;;EAKAK,WAAWC,QAAsB;AAC/B,SAAKX,aAAaW,OAAOC,UAAUP,MAAK;EAC1C;;;;EAKAQ,WAAWC,QAAuB;AAChC,QAAI,KAAKC,WAAW;AAClBC,UAAIC,QAAQ,8BAA8B;QAAEH;MAAO,GAAA;;;;;;AACnD;IACF;AAEA,SAAKhC,OAAOgC,SAASA;EACvB;EAEA,MAAyBI,QAAuB;AAC9C,SAAKC,iBAAiB,IAAIC,aAAa,KAAKC,MAAM,YAAA;AAChD,YAAM,KAAKC,WAAU;IACvB,CAAA;AAEA,SAAKC,2BAA2B,IAAIH,aAAa,KAAKC,MAAM,YAAA;AAC1D,YAAM,KAAKG,qBAAoB;IACjC,CAAA;EACF;EAEA,MAAyBC,SAAwB;AAC/C,SAAKN,iBAAiBO;AACtB,SAAKH,2BAA2BG;EAClC;EAEA,MACMC,OAAsB;AAC1BC,IAAAA,WAAU,KAAK9C,OAAOgC,QAAM,QAAA;;;;;;;;;AAC5Bc,IAAAA,WAAU,CAAC,KAAKb,WAAW,kBAAA;;;;;;;;;AAE3B,SAAKA,YAAY,IAAIc,QAAAA,QAAAA;;;;AACrB,UAAMC,QAAQC,SAAS,KAAKjD,OAAOgC,MAAM;AACzCE,QAAI,iBAAiB;MAAEc;MAAOE,MAAM;QAAE5B,aAAa,KAAKD;QAAc8B,SAAS,KAAKjC;MAAW;IAAE,GAAA;;;;;;AACjG,UAAMkC,SAAS,KAAKC,gBAAgBC,oBAAoB;MAAEN;IAAM,CAAA;AAChEI,WAAOG,UAAU,CAACC,UAAU,KAAKC,mBAAmBD,KAAAA,CAAAA;AAEpD,UAAME,UAAU,MAAA;AACd,WAAKN,OAAOO,MAAK;AACjB,UAAIX,SAAS,KAAK3B,gBAAgB,KAAKH,YAAY;AACjDgB,YAAI,iBAAiB;UAAEc;UAAOE,MAAM;YAAE5B,aAAa,KAAKD;YAAc8B,SAAS,KAAKjC;UAAW;QAAE,GAAA;;;;;;AACjG,aAAK,KAAKmC,gBACPO,WAAW;UACVZ;UACAE,MAAM;YAAE5B,aAAa,KAAKD;YAAc8B,SAAS,KAAKjC;UAAW;QACnE,CAAA,EACC2C,MAAM,CAACC,QAAQ5B,IAAI2B,MAAMC,KAAAA,QAAAA;;;;;;MAC9B;AACAC,aAAOC,oBAAoB,gBAAgBN,OAAAA;IAC7C;AACAK,WAAOE,iBAAiB,gBAAgBP,OAAAA;AACxC,SAAKzB,UAAUiC,UAAUR,OAAAA;AAEzB,SAAKvD,mBAAkB;EACzB;EAEA,MACMgE,QAAuB;AAC3B,QAAI,CAAC,KAAKlC,WAAW;AACnB;IACF;AAEA,UAAM,KAAKA,UAAUmC,QAAO;AAC5B,SAAKnC,YAAYW;AAEjB,SAAK5C,OAAOqE,QAAQzB;AACpB,SAAK5C,OAAOsE,OAAO1B;EACrB;EAEA,MAAM2B,WAAWvC,QAAgB;AAC/B,UAAMgB,QAAQC,SAASjB,MAAAA;AACvB,UAAMwC,QAAQ,MAAM,KAAKnB,gBAAgBkB,WAAW;MAAEvB;IAAM,CAAA;AAC5D,WAAOwB,MAAMC,SAAS,CAAA;EACxB;;;;EAKQtE,qBAA2B;AACjC,SAAKuE,aAAaC,KAAK,KAAK3E,MAAM;AAClC,QAAI,KAAKA,OAAOO,QAAQ;AACtB,WAAK8B,gBAAgBuC,SAAAA;IACvB;EACF;EAEA,MAAcpC,aAA4B;AACxC,QAAI,CAAC,KAAKxC,OAAOgC,UAAU,CAAC,KAAKX,gBAAgB,CAAC,KAAKH,cAAc,CAAC,KAAKlB,OAAOO,QAAQ;AACxF;IACF;AAEA,UAAMsE,QAAmB;MACvB,GAAG,KAAK7E;MACRiB,IAAI,KAAKC;MACT4D,MAAM,KAAKtD;MACXR,YAAY,KAAKhB,OAAOgB,aACpB+D,OAAOC,YACLD,OAAOE,QAAQ,KAAKjF,OAAOgB,UAAU,EAAEkE,IAAI,CAAC,CAACvE,KAAKwE,QAAAA,MAAc;QAC9DxE;QACAyE,KAAIC,OAAOC,gBAAgBH,QAAAA;OAC5B,CAAA,IAEH,CAAC;IACP;AAEA,UAAM,KAAK9B,gBAAgBkC,UAAU;MACnCvC,OAAOC,SAAS,KAAKjD,OAAOgC,MAAM;MAClCkB,MAAM;QACJ5B,aAAa,KAAKD;QAClB8B,SAAS,KAAKjC;QACd2D,OAAOW,MAAMC,OAAOZ,KAAAA;MACtB;IACF,CAAA;EACF;EAEQpB,mBAAmBiC,YAAiC;AAC1D,QAAI,CAAC,KAAK1F,OAAOO,QAAQ;AACvB;IACF;AAEA,SAAKoF,kBAAkBD;AACvB,SAAKjD,yBAA0BmC,SAAQ;EACzC;EAEA,MAAclC,uBAAsC;AAClD,UAAMgD,aAAa,KAAKC;AACxB7C,IAAAA,WAAU4C,YAAAA,QAAAA;;;;;;;;;AAGV,UAAMjB,QAAQ;SACRiB,WAAWjB,SAAS,CAAA;UACpBiB,WAAWE,iBAAiB,CAAA,GAAIC,OAClC,CAAC,EAAEC,cAAcC,gBAAe,MAC9BA,oBAAoBC,gBAAgBC,uBACpCH,gBACAA,eAAeI,KAAKC,IAAG,IAAKvG,2BAAAA;MAEhCwG,KAAK,CAACC,OAAOC,UAAUD,MAAMlD,QAAQoD,cAAcD,MAAMnD,OAAO,CAAA;AAClE,UAAMkB,QAAQI,MACXS,IAAI,CAAChC,SAAAA;AACJ,UAAI;AACF,eAAOsC,MAAMgB,OAAOtD,KAAK2B,KAAK;MAChC,SAAS4B,OAAO;AACdvE,YAAIuE,MAAM,6BAA6B;UAAEA;UAAOvD;QAAK,GAAA;;;;;;AACrD,eAAON;MACT;IACF,CAAA,EACCiD,OAAOa,aAAAA;AACV,SAAK1G,OAAOqE,QAAQA;AACpB,SAAKrE,OAAOsE,OAAOD,MAAMsC,KAAK,CAACC,SAASA,KAAK3F,OAAO,KAAKC,UAAU;AACnEgB,QAAI,2BAA2B;MAAEmC;IAAM,GAAA;;;;;;AACvC,QAAIA,MAAMwC,WAAW,GAAG;AACtB;IACF;AAEA,UAAMC,eAAe,IAAIC,IAAY1C,MAAM2C,QAAQ,CAACJ,SAAS7B,OAAOkC,KAAKL,KAAK5F,UAAU,CAAA,CAAA;AACxF;SAAI8F;MAAcI,QAAQ,CAACvG,QAAAA;AACzB,YAAMK,aAAaqD,MAAMa,IAAI,CAAC0B,SAASA,KAAK5F,aAAaL,GAAAA,CAAI,EAAEkF,OAAOa,aAAAA;AACtE,YAAMS,eAAerG,qBAAqBsG,aAAapG,UAAAA;AACvD,UACEmG,gBACAA,aAAatG,iBAAkBwG,WAAY,KAAKrH,OAAOgB,WAAYL,GAAAA,GAAME,kBAAkBwG,WAAW,IACtG;AACA,aAAKrH,OAAOgB,WAAYL,GAAAA,IAAOwG;MACjC;IACF,CAAA;AACA,SAAKzC,aAAaC,KAAK,KAAK3E,MAAM;AAGlC,QAAIyE,MAAM6C,KAAK,CAACpE,SAASA,KAAK6C,oBAAoBC,gBAAgBuB,SAAS,GAAG;AAC5EC,2BACE,KAAKjF,MACL,YAAY,KAAKE,yBAA0BmC,SAAQ,GACnD6C,KAAKC,IAAI9H,8BAA8B,GAAG,GAAA,CAAA;IAE9C;EACF;EApPA,YAAY,EAAE+H,eAAc,GAAiC;AAC3D,UAAK,GAhBP,iBAAA,MAAgBjD,gBAAe,IAAIkD,MAAAA,CAAAA,GAEnC,iBAAA,MAAiB5H,UAAoB;MAAEgB,YAAY,CAAC;IAAE,CAAA,GACtD,iBAAA,MAAiBqC,mBAAjB,MAAA,GACA,iBAAA,MAAQsC,mBAAkC/C,MAAAA,GAC1C,iBAAA,MAAQH,4BAA0CG,MAAAA,GAElD,iBAAA,MAAQvB,gBAAwBuB,MAAAA,GAChC,iBAAA,MAAQ1B,cAAsB0B,MAAAA,GAC9B,iBAAA,MAAQpB,gBAAwBoB,MAAAA,GAEhC,iBAAA,MAAQX,aAAsBW,MAAAA,GAE9B,iBAAA,MAAQP,kBAAgCO,MAAAA;AAItC,SAAKS,kBAAkBsE;EACzB;AAkPF;;;;;;;AAKA,IAAM7G,uBAAN,MAAMA;EACJ,OAAOsG,aAAgES,QAA4B;AACjG,UAAMC,eAAeL,KAAKM,IAAG,GAAIF,OAAO3C,IAAI,CAACL,UAAUA,MAAMhE,kBAAkBwG,WAAW,CAAA,CAAA;AAC1F,UAAMW,eAAeH,OAClBhC,OACC,CAAChB,UACCA,MAAMhE,oBAAoBgE,MAAMhE,iBAAiBwG,YAAYS,gBAAgBjD,MAAMhE,iBAAiBI,EAAE,EAEzGmF,KAAK,CAAC6B,GAAGC,MAAMD,EAAEpH,iBAAkBI,GAAIsF,cAAc2B,EAAErH,iBAAkBI,EAAE,CAAA;AAC9E,WAAO+G,aAAa,CAAA;EACtB;EAEA,OAAOjH,UAAUoH,WAA+C;AAC9D,WAAO;MACL,GAAIA,aAAa,CAAC;MAClBd,UAAUc,WAAWd,WAAW,KAAK;IACvC;EACF;AACF;AAGA,IAAMpE,WAAW,CAACjB,WAA8BoG,UAAUC,QAAQC,OAAOtG,MAAAA,CAAAA;;;ACzVlE,IAAMuG,oBAAoB,CAAC,EAChCC,kBACAC,aAAa,MAAO,IACpBC,UAAS,MAKV;AACC,MAAIC,UAAU;AACd,MAAIC,WAAW;AACf,QAAMC,eAAe,IAAIC,aAAAA;AACzB,QAAMC,SAAS,IAAIC,YAAAA;AACnBD,SAAOE,SAAST,gBAAAA;AAChB,QAAMU,6BAA6BL,aAAaM,wBAAwBJ,MAAAA;AACxE,QAAMK,eAAeP,aAAaQ,eAAc;AAChDH,6BAA2BI,QAAQF,YAAAA;AAGnCA,eAAaG,UAAU;AAEvB,QAAMC,UAAU,IAAIC,aAAaL,aAAaG,OAAO;AACrD,MAAIG,OAAO;AAEXd,aAAWe,OAAOC,YAAY,MAAA;AAC5BlB,cAAUgB,IAAAA;AACVA,WAAO;EACT,GAAGjB,UAAAA;AAEH,QAAMoB,OAAO,MAAA;AACXlB,cAAUgB,OAAOG,WAAW,MAAA;AAC1BV,mBAAaW,uBAAuBP,OAAAA;AACpC,UAAIQ,aAAa;AACjB,iBAAWC,aAAaT,SAAS;AAC/BQ,sBAAcC,YAAYA;MAC5B;AACA,YAAMC,UAAUC,KAAKC,KAAKJ,aAAaR,QAAQa,MAAM;AACrD,UAAIH,UAAUR,MAAM;AAClBA,eAAOQ;MACT;AACAL,WAAAA;IACF,GAAGpB,UAAAA;EACL;AACAoB,OAAAA;AAEA,SAAO,MAAA;AACLX,+BAA2BoB,WAAU;AACrClB,iBAAakB,WAAU;AACvB,SAAKzB,aAAa0B,MAAK;AACvBC,kBAAc5B,QAAAA;AACd6B,iBAAa9B,OAAAA;AACbI,WAAO2B,YAAYlC,gBAAAA;EACrB;AACF;;;ACrDA,SAASmC,qBAAqBC,SAASC,oBAAoB;AAC3D,SAAuBC,YAAAA,iBAAgB;AACvC,SAASC,aAAAA,kBAAiB;AAC1B,SAASC,OAAAA,YAAW;;;ACDnB,SAAAC,kBAAA,KAAA,KAAA,OAAA;;;;;;;;;;;;;AACM,IAAMC,eAAN,MAAMA;EASXC,QAAQC,UAAqB;AAC3B,QAAI,KAAKC,UAAUC,UAAU,KAAKC,QAAQ;AACxC,WAAKF,UAAUG,MAAK;IACtB;AACA,SAAKH,UAAUF,KAAI,GAAIC,QAAAA;EACzB;EAEAK,MAAW;AACT,WAAO,KAAKJ;EACd;EAdA,YAAYK,QAAQ,KAAK;AAHzB,IAAAC,kBAAA,MAAiBJ,UAAjB,MAAA;AACA,IAAAI,kBAAA,MAAiBN,aAAjB,MAAA;AAGE,SAAKE,SAASG;AACd,SAAKL,YAAY,CAAA;EACnB;AAYF;A;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtBA,IAAMO,wBAAwB;IAK5B,kBAAA,oBAAA,QAAA;AADK,IAAMC,gBAAN,MAAMA;EAOXC,SAAYC,MAA2B;AACrC,WAAO,IAAIC,QAAQ,CAACC,SAASC,WAAAA;qCACtB,iBAAkB,yBAAA,MAAK,eAAA,EAAgBC,KAAK,YAAA;AAC/C,YAAI;AACFF,kBAAQ,MAAMF,KAAAA,CAAAA;QAChB,SAASK,OAAY;AACnBF,iBAAOE,KAAAA;QACT;MACF,CAAA,CAAA;IACF,CAAA;EACF;EAdA,cAAc;AAFd,8BAAA,MAAA,iBAAA;;aAAA;;mCAGO,iBAAkBJ,QAAQC,QAAO,CAAA;EACxC;AAaF;IAIE,gBAAA,oBAAA,QAAA;IACA,uBAAA,oBAAA,QAAA;IACA,kBAAA,oBAAA,QAAA;AAHK,IAAMI,wBAAN,MAAMA;;;;;EAeXC,cACEC,QACAC,iBACuB;AACvB,QAAI,yBAAA,MAAK,aAAA,EAAcC,UAAM,yBAAI,MAAK,eAAA,GAAiB;qCAEhD,eAAgB,CAAA,CAAE;qCAClB,sBAAuB,IAAA;IAC9B;AACA,6BAAA,MAAK,aAAA,EAAcC,KAAKH,MAAAA;AACxB,QAAI,yBAAA,MAAK,oBAAA,KAAwB,MAAM;AACrC,aAAA,yBAAO,MAAK,oBAAA;IACd;AAIA,UAAMI,QAAAA,yBAAQ,MAAK,aAAA;mCACd,sBAAuB,IAAIX,QAAQ,CAACC,SAASC,WAAAA;AAUhDU,iBAAW,MAAA;uCAGJ,sBAAuB,IAAA;AAG5B,cAAMC,YAAYF,MAAMG,OAAO,GAAGH,MAAMF,MAAM;AAC9CD,wBAAgBK,SAAAA,EACbV,KAAK,CAACY,WAAAA;AACLd,kBAAQc,MAAAA;QACV,CAAA,EACCC,MAAM,CAACC,QAAAA;AACNf,iBAAOe,GAAAA;QACT,CAAA;MACJ,GAAG,CAAA;IACL,CAAA,CAAA;AAGA,WAAA,yBAAO,MAAK,oBAAA;EACd;EAxDA,YAAYC,iBAAyBtB,uBAAuB;AAJ5D,8BAAA,MAAA,eAAA;;aAAA;;AACA,8BAAA,MAAA,sBAAA;;aAAA;;AACA,8BAAA,MAAA,iBAAA;;aAAA;;mCAGO,eAAgB,CAAA,CAAE;mCAClB,sBAAuB,IAAA;mCACvB,iBAAkBsB,cAAAA;EACzB;AAqDF;;;;;;;;;;;;;;;;;AFvEA,IAAMC,kBAAkB;AAoCjB,IAAMC,mBAAN,cAA+BC,UAAAA;EAmCpC,MAAyBC,MAAMC,KAA6B;AAC1D,UAAM,KAAKC,qBAAqBC,KAAKF,GAAAA;EACvC;EAEA,MAAyBG,SAAwB;AAC/C,UAAM,KAAKF,qBAAqBG,MAAK;EACvC;EAEA,IAAIC,UAAU;AACZ,WAAO,KAAKJ,qBAAqBK;EACnC;EAEA,MAAcC,gBAAgB;AAC5B,UAAMC,iBAAiB,MAAM,KAAKC,qBAAoB;AACtD,UAAMC,YAAY,MAAM,KAAKC,qBAAoB;AACjD,WAAO;MAAED;MAAWF;IAAe;EACrC;EAEA,MAAcI,aAAaP,SAAiC;AAC1DA,YAAQG,eAAeJ,MAAK;EAC9B;EAEA,MAAcK,uBAAmD;AAC/D,UAAMD,iBAAiB,IAAIK,kBAAkB;MAC3CC,YAAY,KAAKC,QAAQD;MACzBE,cAAc;IAChB,CAAA;AACAR,mBAAeS,iBAAiB,yBAAyB,MAAA;AACvD,UAAIT,eAAeU,oBAAoB,YAAYV,eAAeU,oBAAoB,UAAU;AAC9FC,QAAAA,KAAIC,KAAK,2BAA2B;UAAEd,OAAOE,eAAeU;QAAgB,GAAA;;;;;;AAC5E,aAAK,KAAKjB,qBAAqBoB,gBAAe;MAChD;IACF,CAAA;AAEA,QAAIC,aAAa;AACjBd,mBAAeS,iBAAiB,4BAA4B,MAAA;AAC1DM,mBAAaD,UAAAA;AACb,UAAId,eAAegB,uBAAuB,YAAYhB,eAAegB,uBAAuB,UAAU;AACpGL,QAAAA,KAAIC,KAAK,mCAAmC;UAAEd,OAAOE,eAAegB;QAAmB,GAAA;;;;;;AACvF,aAAK,KAAKvB,qBAAqBoB,gBAAe;MAChD,WAAWb,eAAegB,uBAAuB,gBAAgB;AAI/D,cAAMC,iBAAiB;AACvBH,qBAAaI,OAAOC,WAAW,MAAA;AAC7B,cAAInB,eAAegB,uBAAuB,aAAa;AACrDL,YAAAA,KAAIC,KAAK,yCAAA,QAAA;;;;;;AACT;UACF;AAEAD,UAAAA,KAAIC,KAAK,sCAAsC;YAAEd,OAAOE,eAAegB;YAAoBC;UAAe,GAAA;;;;;;AAC1G,eAAK,KAAKxB,qBAAqBoB,gBAAe;QAChD,GAAGI,iBAAiB,GAAA;MACtB;IACF,CAAA;AAEA,WAAOjB;EACT;EAEA,MAAcG,uBAAwC;AACpDQ,IAAAA,KAAI,wBAAA,QAAA;;;;;;AACJ,UAAM,EAAET,UAAS,IAAK,MAAM,KAAKkB,OAAwB,yBAAyB;MAAEC,QAAQ;IAAO,CAAA;AACnG,WAAOnB;EACT;EAEA,MAAckB,OAAgCE,cAAsBC,aAAuC;AACzG,SAAKC,QAAQC,KAAK;MAChBC,UAAUJ;MACVK,MAAM;MACNC,OAAM,oBAAIC,KAAAA,GAAOC,YAAW;MAC5BT,QAAQE,aAAaF,UAAU;MAC/BU,MAAMR,aAAaQ;IACrB,CAAA;AAEA,UAAMC,WAAW,MAAMC,MAAM,GAAG,KAAK1B,QAAQ2B,OAAO,GAAGZ,YAAAA,IAAgB;MAAE,GAAGC;MAAaY,UAAU;IAAS,CAAA;AAC5G,QAAIH,SAASI,UAAU,KAAK;AAC1BzB,MAAAA,KAAI0B,MAAM,2CAA2C;QAAED,QAAQJ,SAASI;QAAQE,MAAM,MAAMN,SAASM,KAAI;MAAG,GAAA;;;;;;AAC5G,YAAM,IAAIC,MAAM,yCAAA;IAClB;AAEA,QAAI;AACF,YAAMC,OAAQ,MAAMR,SAASS,MAAK,EAAGC,KAAI;AACzC,WAAKlB,QAAQC,KAAK;QAChBC,UAAUJ;QACVK,MAAM;QACNC,OAAM,oBAAIC,KAAAA,GAAOC,YAAW;QAC5BM,QAAQJ,SAASI;QACjBM,MAAMF;MACR,CAAA;AACA,UAAIA,KAAKG,WAAW;AAClB,cAAM,IAAIJ,MAAMC,KAAKI,gBAAgB;MACvC;AAEA,aAAOJ;IACT,SAASH,OAAO;AACd,YAAMC,OAAO,MAAMN,SAASM,KAAI;AAChC,WAAKd,QAAQC,KAAK;QAChBC,UAAUJ;QACVK,MAAM;QACNC,OAAM,oBAAIC,KAAAA,GAAOC,YAAW;QAC5BM,QAAQJ,SAASI;QACjBE;MACF,CAAA;AACA3B,MAAAA,KAAI0B,MAAM,6CAA6C;QACrDA;QACAC;QACAF,QAAQJ,SAASI;MACnB,GAAA;;;;;;AACA,YAAMC;IACR;EACF;EAEA,MAAcQ,iBAAiB,EAC7BrD,KACAQ,gBACA8C,aACA5C,WACA6C,UAAS,GAOqB;AAC9BpC,IAAAA,KAAIqC,QAAQ,kBAAkBD,WAAAA;;;;;;AAC9B,UAAME,qBAAqB,KAAKC,oBAC7BC,cAAc;MAAEJ;MAAWD;IAAY,GAAG,CAACM,WAC1C,KAAKC,cAAcC,SAAS,YAAA;AAG1B,YAAMC,QAAQ,MAAMvD,eAAewD,YAAW;AAC9CD,YAAME,MAAMF,MAAME,KAAKC,QAAQ,kBAAkB,yBAAA;AACjD,YAAM1D,eAAe2D,oBAAoBJ,KAAAA;AAEzC,YAAMvB,WAAW,MAAM,KAAKZ,OAAuB,aAAalB,SAAAA,uBAAgC;QAC9FmB,QAAQ;QACRU,MAAM6B,KAAKC,UAAU;UACnBC,oBAAoB;YAClBL,KAAKF,MAAME;YACX9B,MAAM;UACR;UACAyB,QAAQA,OAAOW,IAAI,CAAC,EAAEhB,WAAAA,YAAWD,aAAAA,aAAW,OAAQ;YAClDC,WAAAA;YACAiB,KAAKlB,aAAYkB;YACjBC,UAAU;UACZ,EAAA;QACF,CAAA;MACF,CAAA;AAEAC,MAAAA,WAAUlC,SAASoB,WAAWe,QAAAA,QAAAA;;;;;;;;;AAC9B,UAAI,CAACnC,SAASW,WAAW;AACvB,cAAM3C,eAAeoE,qBAAqB,IAAIC,sBAAsBrC,SAAS8B,kBAAkB,CAAA;AAC/F,cAAMQ,0BAA0BtE,cAAAA;MAClC;AAEA,aAAO;QACLoD,QAAQpB,SAASoB;MACnB;IACF,CAAA,CAAA,EAEDmB,KAAK,OAAO,EAAEnB,OAAM,MAAE;AACrB,YAAMoB,YAAYpB,OAAOqB,KAAK,CAACC,MAAMA,EAAEV,QAAQlB,YAAYkB,GAAG;AAC9D,UAAIQ,WAAW;AAKb,eAAO;UACL,GAAGA;UACHtE;UACA+D,UAAU;QACZ;MACF,OAAO;AACLtD,QAAAA,KAAI0B,MAAM,sBAAA,QAAA;;;;;;MACZ;IACF,CAAA;AAEF,UAAMsC,YAAY,YAAA;AAChB,UAAI7B,YAAYkB,KAAK;AACnB,cAAM,KAAKY,kBAAkB5E,gBAAgB8C,YAAYkB,KAAK9D,SAAAA;MAChE;IACF;AAEAV,SAAKmF,UAAU,YAAY,MAAMA,UAAAA,CAAAA;AACjC,SAAKE,KAAKF,UAAU,MAAMA,UAAAA,CAAAA;AAE1B,WAAO1B;EACT;EAEA,MAAM6B,UAAU,EACdC,OACAC,YAAY,CAAA,GACZxF,KACAyF,cAAa,GAMsB;AACnC,UAAM,KAAKC,cAAa;AACxBhB,IAAAA,WAAU,KAAKrE,SAAO,QAAA;;;;;;;;;AACtBc,IAAAA,KAAI,wBAAwB;MAAEoE;MAAOE;MAAeD;IAAU,GAAA;;;;;;AAC9D,QAAIC,eAAe;AACjB,YAAMnC,eAAc,KAAKjD,QAAQG,eAAemF,gBAAe,EAAGV,KAAK,CAACC,MAAMA,EAAEV,QAAQiB,cAAcjB,GAAG;AACzG,UAAIlB,cAAasC,OAAOL,UAAUA,OAAO;AACvCpE,QAAAA,KAAIqC,QAAQ,wBAAwB;UAAE+B;UAAOE;UAAenC,aAAAA;QAAY,GAAA;;;;;;AACxE,eAAOmC;MACT,WAAWnC,cAAa;AACtBnC,QAAAA,KAAIqC,QAAQ,mBAAmB;UAAE+B;UAAOE;UAAenC,aAAAA;QAAY,GAAA;;;;;;AACnEA,QAAAA,aAAYsC,OAAOC,aAAaN,KAAAA,EAAOO,MAAM,CAACC,QAAQ5E,KAAI2E,MAAMC,KAAAA,QAAAA;;;;;;AAChE,eAAON;MACT;IACF;AACAf,IAAAA,WAAUa,OAAAA,QAAAA;;;;;;;;;AAGV,UAAMS,WAAWC,OAAOC,WAAU;AAClC,UAAM5C,cAAc,KAAKjD,QAAQG,eAAgB2F,eAAeZ,OAAO;MAAEa,WAAW;IAAW,CAAA;AAC/FjF,IAAAA,KAAIqC,QAAQ,wBAAA,QAAA;;;;;;AAEZ,UAAM6C,kBAAkB,MAAM,KAAKhD,iBAAiB;MAClDrD;MACAQ,gBAAgB,KAAKH,QAAQG;MAC7B8C;MACA5C,WAAW,KAAKL,QAAQK;MACxB6C,WAAWyC;IACb,CAAA;AACAtB,IAAAA,WAAU2B,iBAAAA,QAAAA;;;;;;;;;AAEV,UAAMC,aAAahD,YAAYsC,OAAOW,cAAa;AACnDf,cAAUgB,QAAQ,CAACC,UAAUC,MAAAA;AAC3B,YAAMC,WAAWL,WAAWd,UAAUkB,CAAAA;AACtCJ,iBAAWd,UAAUkB,CAAAA,IAAK;QAAE,GAAGC;QAAU,GAAGF;MAAS;IACvD,CAAA;AACAnD,gBAAYsC,OAAOgB,cAAcN,UAAAA,EAAYR,MAAM,CAACC,QAAQ5E,KAAI2E,MAAMC,KAAAA,QAAAA;;;;;;AAEtE,WAAOM;EACT;;EAGA,MAAcQ,iBAAiB,EAC7BrG,gBACAE,WACAsE,WACAhF,IAAG,GAMqC;AACxC,QAAIwE,MAAM;AACVrD,IAAAA,KAAI,iBAAiB;MAAEoC,WAAWyB,UAAUzB;IAAU,GAAA;;;;;;AACtD,UAAMuD,qBAAqB,KAAKC,oBAC7BpD,cAAcqB,WAAW,CAACpB,WACzB,KAAKC,cAAcC,SAAS,YAAA;AAC1B,YAAMkD,mBAAmB,MAAM,KAAKpF,OAAuB,aAAalB,SAAAA,uBAAgC;QACtGmB,QAAQ;QACRU,MAAM6B,KAAKC,UAAU;UAAET;QAAO,CAAA;MAChC,CAAA;AAEA,UAAIoD,iBAAiB7D,WAAW;AAC9B,cAAM,IAAIJ,MAAMiE,iBAAiB5D,gBAAgB;MACnD;AAEAsB,MAAAA,WAAUsC,iBAAiBpD,QAAM,QAAA;;;;;;;;;AACjC,YAAMqD,WAAWrD,OAAOsD,OAAO,CAACC,KAAK5B,UAAAA;AACnC,cAAM6B,kBAAkBJ,iBAAiBpD,QAAQqB,KAC/C,CAACC,MAAMA,EAAE3B,cAAcgC,MAAMhC,aAAa2B,EAAExE,cAAc6E,MAAM7E,SAAS;AAG3E,YAAI0G,mBAAmBA,gBAAgB5C,KAAK;AAC1C2C,cAAIE,IAAI9B,MAAMhC,WAAY;YACxBiB,KAAK4C,gBAAgB5C;YACrB8C,eAAeC,aAAa/G,gBAAgB,CAAC0E,MAAMA,EAAEV,QAAQ4C,gBAAgB5C,GAAG;UAClF,CAAA;QACF;AAEA,eAAO2C;MACT,GAAG,oBAAIK,IAAAA,CAAAA;AAEP,UAAIR,iBAAiBS,gCAAgC;AACnD,cAAMjH,eAAeoE,qBAAqB,IAAIC,sBAAsBmC,iBAAiB1C,kBAAkB,CAAA;AACvG,cAAMoD,SAAS,MAAMlH,eAAemH,aAAY;AAChD,cAAMnH,eAAe2D,oBAAoBuD,MAAAA;AAEzC,cAAME,wBAAwB,MAAM,KAAKhG,OACvC,aAAalB,SAAAA,gBACb;UACEmB,QAAQ;UACRU,MAAM6B,KAAKC,UAAU;YACnBC,oBAAoB;cAClBnC,MAAM;cACN8B,KAAKzD,eAAeqH,yBAAyB5D;YAC/C;UACF,CAAA;QACF,CAAA;AAGF,YAAI2D,sBAAsBzE,WAAW;AACnC,gBAAM,IAAIJ,MAAM6E,sBAAsBxE,gBAAgB;QACxD,OAAO;AACL,gBAAM0B,0BAA0BtE,cAAAA;QAClC;MACF;AAEA,aAAO;QAAEyG;MAAS;IACpB,CAAA,CAAA,EAEDlC,KAAK,CAAC,EAAEkC,SAAQ,MAAE;AACjB,YAAMa,YAAYb,SAASc,IAAI/C,UAAUzB,SAAS;AAClD,UAAIuE,WAAW;AACb,eAAOA,UAAUR,cACdvC,KAAK,CAACQ,UAAAA;AACLf,gBAAMsD,UAAUtD;AAChB,iBAAOe;QACT,CAAA,EACCO,MAAM,CAACC,QAAQ5E,KAAI2E,MAAMC,KAAAA,QAAAA;;;;;;MAC9B,OAAO;AACL5E,QAAAA,KAAIC,KAAK,sBAAsB;UAAE4D;UAAWgD,iBAAiBC,MAAMC,KAAKjB,SAASkB,KAAI,CAAA;QAAI,GAAA;;;;;;MAC3F;IACF,CAAA;AAEF,UAAMhD,YAAY,YAAA;AAChB,UAAIX,KAAK;AACPrD,QAAAA,KAAI,yBAAyB6D,UAAUzB,WAAS;;;;;;AAChD,cAAM,KAAK6B,kBAAkB5E,gBAAgBgE,KAAK9D,SAAAA;AAClD8D,cAAM;MACR;IACF;AAEA,SAAKa,KAAKF,UAAU,MAAMA,UAAAA,CAAAA;AAC1BnF,SAAKmF,UAAU,MAAMA,UAAAA,CAAAA;AAErB,WAAO2B;EACT;EAEA,MAAMsB,UAAU,EACdpI,KACAgF,UAAS,GAI+B;AACxC,UAAM,KAAKU,cAAa;AAExBhB,IAAAA,WAAU,KAAKrE,SAAO,QAAA;;;;;;;;;AACtB,UAAMA,UAAU,KAAKA;AACrB,WAAO,KAAKwG,iBAAiB;MAC3BrG,gBAAgBH,QAAQG;MACxBE,WAAWL,QAAQK;MACnBsE;MACAhF;IACF,CAAA;EACF;EAEA,MAAMoF,kBAAkB5E,gBAAmCgE,KAAa9D,WAAkC;AACxG,UAAM4C,cAAc9C,eAAemF,gBAAe,EAAGV,KAAK,CAACC,MAAMA,EAAEV,QAAQA,GAAAA;AAE3E,QAAIhE,eAAeU,oBAAoB,eAAeoC,gBAAgBqB,QAAW;AAC/E;IACF;AACA,UAAM,KAAK0D,qBAAqB1E,cAAc;MAAEa;IAAI,GAAG,CAAC8D,SACtD,KAAKzE,cAAcC,SAAS,YAAA;AAC1BR,kBAAYiF,KAAI;AAChB,YAAMC,qBAAqBhI,eACxBmF,gBAAe,EACf8C,OAAO,CAACvD,MAAMA,EAAEV,QAAQA,OAAOU,EAAEkB,cAAc,SAAA;AAElD,UAAIsC;AACJ,UAAIF,mBAAmBG,SAAS,GAAG;AAEjC,cAAM5E,QAAQ,MAAMvD,eAAewD,YAAW;AAE9C,cAAMxD,eAAe2D,oBAAoBJ,KAAAA;AACzC2E,sBAAc;UACZ9E,QAAQ0E;UACRhE,oBAAoB;YAClBL,KAAKzD,eAAeoI,kBAAkB3E;YACtC9B,MAAM;UACR;UACA0G,OAAO;QACT;MACF,OAAO;AACLH,sBAAc;UACZ9E,QAAQ0E;UACRO,OAAO;QACT;MACF;AAEA,YAAMrG,WAAW,MAAM,KAAKZ,OAAuB,aAAalB,SAAAA,iBAA0B;QACxFmB,QAAQ;QACRU,MAAM6B,KAAKC,UAAUqE,WAAAA;MACvB,CAAA;AAEA,UAAIA,YAAYpE,oBAAoB;AAClC,cAAM9D,eAAeoE,qBAAqB,IAAIC,sBAAsBrC,SAAS8B,kBAAkB,CAAA;MACjG;IACF,CAAA,CAAA;EAEJ;EAxZA,YAAYwE,QAA4B;AACtC,UAAK,GA9BPC,kBAAA,MAAgB/G,WAAU,IAAIgH,aAA4B,GAAA,CAAA,GAE1DD,kBAAA,MAAiB9I,wBAAuB,IAAIgJ,oBAA6B;MACvEC,OAAO,MAAM,KAAK3I,cAAa;MAC/BgI,MAAM,CAAClI,YAAY,KAAKO,aAAaP,OAAAA;IACvC,CAAA,CAAA,GAEA0I,kBAAA,MAAiBhI,WAAjB,MAAA,GAEA8C,kBAAAA,MAAAA,iBAAgB,IAAIsF,cAAAA,CAAAA,GACpBzF,kBAAAA,MAAAA,uBAAsB,IAAI0F,sBAMxB,EAAA,CAAA,GAEFrC,kBAAAA,MAAAA,uBAAsB,IAAIqC,sBAQxB,EAAA,CAAA,GAEFf,kBAAAA,MAAAA,wBAAuB,IAAIe,sBAAsB,EAAA,CAAA;AAG/C,SAAKrI,UAAU+H;EACjB;AAsZF;AAEA,IAAMvB,eAAe,OACnB/G,gBACA6I,SACAC,UAAU1J,oBAEV,IAAI2J,QAA0B,CAACC,SAASC,WAAAA;AACtC9H,aAAW8H,QAAQH,OAAAA;AACnB,QAAMI,UAAU,MAAA;AACd,UAAMpG,cAAc9C,eAAemF,gBAAe,EAAGV,KAAKoE,OAAAA;AAC1D,QAAI/F,aAAa;AACfkG,cAAQlG,YAAYqG,SAASpE,KAAK;AAClC/E,qBAAeoJ,oBAAoB,SAASF,OAAAA;IAC9C;EACF;AAEAlJ,iBAAeS,iBAAiB,SAASyI,OAAAA;AAC3C,CAAA;AAEF,IAAM5E,4BAA4B,OAAOtE,mBAAAA;AACvC,MAAIA,eAAeU,oBAAoB,aAAa;AAClD,UAAM2I,YAAY,IAAIN,QAAQ,CAACC,SAASC,WAAAA;AAEtC,YAAMH,UAAU3H,WAAW,MAAA;AACzBnB,uBAAeoJ,oBAAoB,yBAAyBE,4BAAAA;AAC5DL,eAAO,IAAI1G,MAAM,oBAAA,CAAA;MACnB,GAAGnD,eAAAA;AAEH,YAAMkK,+BAA+B,MAAA;AACnC,YAAItJ,eAAeU,oBAAoB,aAAa;AAClDV,yBAAeoJ,oBAAoB,yBAAyBE,4BAAAA;AAC5DvI,uBAAa+H,OAAAA;AACbE,kBAAQ7E,MAAAA;QACV;MACF;AACAnE,qBAAeS,iBAAiB,yBAAyB6I,4BAAAA;IAC3D,CAAA;AAEA,UAAMD;EACR;AACF;;;AGphBA,SAASE,OAAAA,YAAW;;AAEb,IAAMC,oBAAoB,OAC/BC,MACAC,cAAqC,CAAC,GACtCC,eAAAA;AAEAA,iBAAAA,cAAgB,MAAMC,cAAAA,GAAiBC,OAAO,CAACC,WAAWA,OAAOL,SAASA,IAAAA;AAC1E,QAAMM,cAAcJ,WAAW,CAAA;AAC/B,MAAI,CAACI,aAAa;AAChB,UAAM,IAAIC,MAAM,kBAAA;EAClB;AAEA,SAAOC,aAAaF,aAAaL,WAAAA;AACnC;AAEA,IAAMO,eAAe,OAAOH,QAAyBJ,gBAAAA;AACnD,QAAM,EAAEQ,UAAUC,MAAK,IAAKL;AAC5BP,EAAAA,KAAIa,KAAK,cAAcD,KAAAA,IAAO,QAAA;;;;;;AAE9B,QAAME,cAAc,MAAMC,UAAUC,aAAaC,aAC/CV,OAAOL,SAAS,eAAe;IAAEgB,OAAO;MAAE,GAAGf;MAAaQ;IAAS;EAAE,IAAI;IAAEQ,OAAO;MAAE,GAAGhB;MAAaQ;IAAS;EAAE,CAAA;AAEjH,SAAOJ,OAAOL,SAAS,eAAeY,YAAYM,eAAc,EAAG,CAAA,IAAKN,YAAYO,eAAc,EAAG,CAAA;AACvG;AAGO,IAAMhB,gBAAgB,MAAMU,UAAUC,aAAaM,iBAAgB;AAE1E,IAAMC,0BAA0B;EAC9BL,OAAO;IACLM,OAAO;MAAEC,KAAK;IAAK;IACnBC,QAAQ;MAAED,KAAK;IAAK;IACpBE,WAAW;MAAEF,KAAK;IAAG;EACvB;AACF;AAEO,IAAMG,iBAAiB,OAAO,EAAEC,YAAW,MAA2B;AAE3E,QAAMC,KAAK,MAAMf,UAAUC,aAAae,gBAAgBR,uBAAAA;AACxDO,KAAGV,eAAc,EAAGY,QAAQ,CAACC,UAAAA;AAC3B,QAAIJ,eAAe,iBAAiBI,OAAO;AACzCA,YAAMJ,cAAcA;IACtB;EACF,CAAA;AAEA,SAAOC;AACT;;;AC/CA,SAASI,gBAAAA,eAAcC,SAAAA,QAAOC,aAAa;AAC3C,SAASC,YAAAA,iBAAgB;A;;;;;;;;;;;;;AAIzB,IAAMC,qBAAqB;AAC3B,IAAMC,2BAA2B;AACjC,IAAMC,8BAA8B;AACpC,IAAMC,qBAAqB;AAEpB,IAAMC,kBAAN,cAA8BC,UAAAA;EAkBnC,IAAIC,aAAsB;AACxB,WAAO,KAAKC;EACd;EAEA,MAAyBC,QAAuB;AAC9C,SAAKC,kBAAkB,IAAIC,cAAa,KAAKC,MAAM,YAAY,KAAKC,qBAAoB,CAAA;AAExF,QAAIC;AACJ,UAAMC,UAAUC,kBAAkB;MAChCC,kBAAkB,KAAKC;MACvBC,WAAW,CAACC,QAAAA;AAIV,cAAMC,2BACJD,OAAO,KAAKZ,cAAcL,8BAA8BD;AAC1D,YAAImB,0BAA0B;AAE5BC,uBAAaR,OAAAA;AACbA,oBAAUS;AACV,cAAI,CAAC,KAAKf,aAAa;AACrB,iBAAKA,cAAc;AACnB,iBAAKE,iBAAiBc,SAAAA;UACxB;QACF,WAAWV,YAAYS,QAAW;AAEhCT,oBAAUW,WAAW,MAAA;AACnB,iBAAKjB,cAAc;AACnBM,sBAAUS;AACV,iBAAKb,iBAAiBc,SAAAA;UACxB,GAAGvB,kBAAAA;QACL;MACF;IACF,CAAA;AACA,SAAKW,KAAKc,UAAU,MAAA;AAClBX,cAAAA;AACAO,mBAAaR,OAAAA;IACf,CAAA;EACF;;;;EAKA,MAAcD,uBAAsC;AAClD,UAAMc,qBAAqBC,KAAKC,IAAG,IAAK,KAAKC;AAC7C,UAAMC,kBAAkB3B,qBAAqBuB;AAC7C,QAAII,kBAAkB,GAAG;AACvB,YAAMC,MAAMD,eAAAA;IACd;AACA,SAAKD,iBAAiBF,KAAKC,IAAG;AAC9B,SAAKI,gBAAgBC,KAAK,KAAK1B,WAAW;EAC5C;EAvDA,YAA6BU,mBAAqC;AAChE,UAAK,GAAAiB,kBAAA,MAAA,qBAAA,MAAA;;;;IAVPA,kBAAA,MAAgBF,mBAAhB,MAAA;;;IAKAE,kBAAA,MAAQ3B,eAAR,MAAA,GACA2B,kBAAA,MAAQL,kBAAR,MAAA,GACAK,kBAAA,MAAQzB,mBAAR,MAAA,GAAA,KAE6BQ,oBAAAA,mBAAAA,KATbe,kBAAkB,IAAIG,OAAAA,GAAAA,KAK9B5B,cAAc,OAAA,KACdsB,iBAAiB;EAKzB;AAsDF;;;AChFA,SAASO,gBAAAA,eAAcC,SAAAA,QAAOC,SAAAA,QAAOC,gBAAAA,qBAAoB;AACzD,SAAuBC,YAAAA,WAAUC,yBAAyB;AAC1D,SAASC,aAAAA,kBAAiB;AAC1B,SAASC,OAAAA,YAAW;;;;;;;;;;;;;;;;;;;;;AAwCpB,IAAMC,cAAc;AACpB,IAAMC,eAAe;AACrB,IAAMC,wBAAwB;AAC9B,IAAMC,sBAAsB;AAC5B,IAAMC,iBAAiB;AAMvB,IAAMC,sBAAsB;AAErB,IAAMC,eAAN,cAA2BC,UAAAA;EAWhC,IAAIC,aAAa;AACf,WAAO,KAAKC,kBAAkBD;EAChC;;;;EAKAE,YAAwB;AACtB,WAAO,KAAKC;EACd;EAEA,MAAyBC,QAAuB;AAC9C,SAAKC,0BAA0B,MAAMC,6BAA6B;MAChEC,KAAK,KAAKC;MACVC,OAAOjB;MACPkB,QAAQjB;IACV,CAAA;AACA,SAAKU,OAAOQ,aAAa,KAAKN;AAC9B,SAAKF,OAAOS,cAAc,IAAIC,YAAAA;AAC9B,SAAKV,OAAOS,YAAYE,SAAS,KAAKX,OAAOQ,UAAU;AAEvD,QAAId,qBAAqB;AACvB,WAAKkB,6BAA6B,MAAMC,gCAAgC;QAAET,KAAK,KAAKC;MAAK,CAAA;AACzF,WAAKL,OAAOc,aAAa,KAAKF;IAChC;AAEA,SAAKG,kBAAkB,IAAIC,cAAa,KAAKX,MAAM,YAAA;AACjD,YAAM,KAAKY,YAAW;IACxB,CAAA;AACA,SAAKC,kBAAkB,IAAIF,cAAa,KAAKX,MAAM,YAAA;AACjD,YAAM,KAAKc,sBAAqB;IAClC,CAAA;EACF;EAEA,MAAyBC,SAAwB;AAC/C,SAAK,KAAKtB,kBAAkBuB,MAAAA;AAC5B,SAAKrB,OAAOQ,cAAc,KAAKR,OAAOS,aAAaa,YAAY,KAAKtB,OAAOQ,UAAU;AACrF,SAAKR,OAAOc,YAAYS,KAAAA;AACxB,SAAKvB,OAAOQ,YAAYe,KAAAA;AACxB,SAAKvB,OAAOwB,kBAAkBD,KAAAA;AAC9B,SAAKR,kBAAkBU;AACvB,SAAKP,kBAAkBO;EACzB;EAEA,MACMC,KAAKC,eAAkD;AAC3D,SAAK3B,OAAO4B,OAAO,IAAIC,iBAAiBF,aAAAA;AACxC,UAAM,KAAK3B,OAAO4B,KAAME,KAAI;AAC5B,SAAKf,gBAAiBgB,SAAQ;EAChC;EAEA,MACMC,QAAuB;AAC3B,UAAMC,QAAQC,IAAIC,OAAOC,OAAO,KAAKpC,OAAOqC,iBAAiB,EAAEC,IAAI,CAAC,EAAElC,IAAG,MAAOA,IAAImC,QAAO,CAAA,CAAA;AAC3F,UAAMN,QAAQC,IAAIC,OAAOC,OAAO,KAAKpC,OAAOwC,kBAAkB,EAAEF,IAAI,CAAC,EAAElC,IAAG,MAAOA,IAAImC,QAAO,CAAA,CAAA;AAC5F,SAAKE,oBAAoB,CAAA;AACzB,UAAM,KAAKzC,OAAO4B,MAAMP,MAAAA;AACxB,SAAKrB,OAAO4B,OAAOH;AACnB,SAAKzB,OAAO0C,mBAAmBjB;AAC/B,SAAKzB,OAAO2C,mBAAmBlB;AAC/B,SAAKzB,OAAO4C,yBAAyBnB;AACrC,SAAKzB,OAAOqC,oBAAoB,CAAC;AACjC,SAAKrC,OAAOwC,qBAAqB,CAAC;EACpC;EAEA,MAAMK,cAA6B;AACjC,SAAK7C,OAAOS,YAAaa,YAAY,KAAKtB,OAAOQ,UAAU;AAC3D,SAAKR,OAAOQ,aAAa,MAAMsC,kBAAkB,cAAc;MAAExC,OAAOjB;MAAakB,QAAQjB;IAAa,CAAA;AAC1G,SAAKU,OAAOS,YAAaE,SAAS,KAAKX,OAAOQ,UAAU;AACxD,SAAKR,OAAO+C,eAAe;AAC3B,SAAKC,aAAaC,KAAK,KAAKjD,MAAM;AAClC,SAAKe,gBAAiBgB,SAAQ;EAChC;EAEA,MAAMmB,eAA8B;AAClC,QAAI,KAAKlD,OAAOQ,eAAe,KAAKN,yBAAyB;AAC3D,WAAKF,OAAOS,YAAaa,YAAY,KAAKtB,OAAOQ,UAAU;AAC3D,WAAKR,OAAOQ,YAAYe,KAAAA;AACxB,WAAKvB,OAAOQ,aAAa,KAAKN;AAC9B,WAAKF,OAAOS,YAAaE,SAAS,KAAKX,OAAOQ,UAAU;IAC1D;AAEA,SAAKR,OAAO+C,eAAe;AAC3B,SAAKC,aAAaC,KAAK,KAAKjD,MAAM;AAClC,SAAKe,gBAAiBgB,SAAQ;EAChC;;EAGA,MAAMoB,cAA6B;AACjC,SAAK,KAAKrD,kBAAkBuB,MAAAA;AAC5B,SAAKrB,OAAOoD,eAAe;AAC3B,SAAKpD,OAAOc,aAAa,MAAMgC,kBAAkB,cAAc;MAC7DO,kBAAkB;MAClBC,kBAAkB;MAClBC,iBAAiB;MACjBC,YAAY;IACd,CAAA;AACA,SAAKR,aAAaC,KAAK,KAAKjD,MAAM;AAClC,SAAKe,gBAAiBgB,SAAQ;AAC9B,SAAKjC,mBAAmB,IAAI2D,gBAAgB,KAAKzD,OAAOc,UAAU;AAClE,SAAKhB,iBAAiB4D,gBAAgBC,GAAG,KAAKtD,MAAM,MAAM,KAAK2C,aAAaC,KAAK,KAAKjD,MAAM,CAAA;AAC5F,SAAK,KAAKF,iBAAiBgC,KAAI;EACjC;EAEA,MAAM8B,eAA8B;AAClC,SAAK,KAAK9D,kBAAkBuB,MAAAA;AAC5B,SAAKvB,mBAAmB2B;AACxB,SAAKzB,OAAOoD,eAAe;AAC3B,QAAI1D,uBAAuB,KAAKM,OAAOc,eAAe,KAAKF,4BAA4B;AACrF,WAAKZ,OAAOc,YAAYS,KAAAA;AACxB,WAAKvB,OAAOc,aAAa,KAAKF;IAChC,OAAO;AACL,WAAKZ,OAAOc,YAAYS,KAAAA;AACxB,WAAKvB,OAAOc,aAAaW;IAC3B;AACA,SAAKuB,aAAaC,KAAK,KAAKjD,MAAM;AAClC,SAAKe,gBAAiBgB,SAAQ;EAChC;EAEA,MAAM8B,oBAAmC;AACvC,UAAMC,KAAK,MAAMC,eAAe;MAAEC,aAAa;IAAO,CAAA;AACtD,SAAKhE,OAAOiE,yBAAyBH;AACrC,SAAK9D,OAAOwB,mBAAmBsC,GAAGI,eAAc,EAAG,CAAA;AACnD,SAAKlE,OAAOmE,qBAAqB;AACjC,SAAKnB,aAAaC,KAAK,KAAKjD,MAAM;AAClC,SAAKe,gBAAiBgB,SAAQ;EAChC;EAEA,MAAMqC,qBAAoC;AACxC,SAAKpE,OAAOmE,qBAAqB;AACjC,SAAKnE,OAAOwB,kBAAkBD,KAAAA;AAC9B,SAAKvB,OAAOwB,mBAAmBC;AAC/B,SAAKuB,aAAaC,KAAK,KAAKjD,MAAM;AAClC,SAAKe,gBAAiBgB,SAAQ;EAChC;;;;EAKAsC,oBAAoBC,QAAmC;AACrD,QACE,CAACA,UACA,KAAK7B,kBAAkB8B,MAAM,CAACC,SAASF,OAAOG,SAASD,IAAAA,CAAAA,KAAU,KAAK/B,kBAAkBiC,WAAWJ,OAAOI,QAC3G;AACA;IACF;AAEA,SAAKjC,oBAAoB6B;AACzB,SAAKpD,gBAAiBa,SAAQ;EAChC;EAEA,MAAcZ,wBAAuC;AACnDwD,IAAAA,KAAI,sBAAA,QAAA;;;;;;AAIJ,UAAMC,kBAAkB,KAAKvE,MAAMwE,OAAM,GAAA,CAAA;AACzC,UAAMC,aAAa,KAAKrC;AAExB,UAAMsC,eAAeD,WAAWE,OAC9B,CAACR,SAAS,CAAC,KAAKxE,OAAOqC,kBAAkBmC,IAAAA,KAAS,CAAC,KAAKxE,OAAOwC,mBAAmBgC,IAAAA,CAAK;AAGzF,UAAMS,qBAAqB9C,OAAO+C,QAAQ,KAAKlF,OAAOqC,iBAAiB,EAAE2C,OACvE,CAAC,CAACG,GAAAA,MAAS,CAACL,WAAWM,KAAK,CAACZ,SAASA,SAASW,GAAAA,CAAAA;AAGjD,UAAME,sBAAsBlD,OAAO+C,QAAQ,KAAKlF,OAAOwC,kBAAkB,EAAEwC,OACzE,CAAC,CAACG,GAAAA,MAAS,CAACL,WAAWM,KAAK,CAACZ,SAASA,SAASW,GAAAA,CAAAA;AAGjDR,IAAAA,KAAI,sBAAsB;MACxBG;MACAC;MACAM;MACAJ;MACAK,oBAAoBnD,OAAOoD,KAAK,KAAKvF,OAAOqC,iBAAiB;MAC7DmD,qBAAqBrD,OAAOoD,KAAK,KAAKvF,OAAOwC,kBAAkB;IACjE,GAAA;;;;;;AAGA,UAAMiD,cAAc,MAAMxD,QAAQC,IAAI6C,aAAazC,IAAI,CAACkC,SAAS,KAAKkB,WAAWlB,IAAAA,CAAAA,CAAAA;AAGjF,UAAMvC,QAAQC,IAAI;SAAI+C;SAAuBI;MAAqB/C,IAAI,CAAC,CAACqD,GAAG,EAAEvF,IAAG,CAAE,MAAMA,IAAImC,QAAO,CAAA,CAAA;AAEnGoC,IAAAA,KAAI,qBAAqB;MACvBW,oBAAoBnD,OAAOoD,KAAK,KAAKvF,OAAOqC,iBAAiB;MAC7DmD,qBAAqBrD,OAAOoD,KAAK,KAAKvF,OAAOwC,kBAAkB;IACjE,GAAA;;;;;;AACA,SAAKQ,aAAaC,KAAK,KAAKjD,MAAM;AAElC,QAAIyF,YAAYL,KAAK,CAAC,EAAEQ,YAAW,MAAOA,WAAAA,GAAc;AACtD,YAAMhB,kBAAkB,KAAKvE,MAAMwE,OAAMpF,cAAAA,CAAAA;AACzCkF,MAAAA,KAAIkB,KAAK,wBAAwB;QAAEd;MAAa,GAAA;;;;;;AAChDe,MAAAA,WAAU,KAAK5E,iBAAe,QAAA;;;;;;;;;AAC9B,WAAKA,gBAAgBa,SAAQ;IAC/B;EACF;EAEA,MAAcd,cAA6B;AACzC,QAAI,CAAC,KAAKjB,OAAO4B,MAAMmE,QAAQ;AAC7B;IACF;AAEA,QAAIC,UAAU;AACd,UAAM,CAACC,iBAAiBC,iBAAiBC,qBAAAA,IAAyB,MAAMlE,QAAQC,IAAI;MAClF,KAAKkE,gBAAgB,KAAKpG,OAAOQ,YAAY,KAAKR,OAAO0C,kBAAkB;QACzE;UAAE2D,cAAc9G;UAAuB+G,YAAY9G;QAAoB;OACxE;MACD,KAAK4G,gBAAgB,KAAKpG,OAAOc,YAAY,KAAKd,OAAO2C,kBAAkB;QAAC;UAAE4D,iBAAiB;QAAO;OAAE;MACxG,KAAKH,gBAAgB,KAAKpG,OAAOwB,kBAAkB,KAAKxB,OAAO4C,sBAAsB;KACtF;AAED,QAAIqD,gBAAgBO,UAAU,KAAKxG,OAAO0C,kBAAkB;AAC1D,WAAK1C,OAAO0C,mBAAmBuD,gBAAgBO;AAC/CR,gBAAU;IACZ;AACA,QAAIE,gBAAgBM,UAAU,KAAKxG,OAAO2C,kBAAkB;AAC1D,WAAK3C,OAAO2C,mBAAmBuD,gBAAgBM;AAC/CR,gBAAU;IACZ;AACA,QAAIG,sBAAsBK,UAAU,KAAKxG,OAAO4C,wBAAwB;AACtE,WAAK5C,OAAO4C,yBAAyBuD,sBAAsBK;AAC3DR,gBAAU;IACZ;AAEA,UAAMJ,cAAcK,gBAAgBL,eAAeM,gBAAgBN,eAAeO,sBAAsBP;AAExG,QAAII,SAAS;AACX,WAAKhD,aAAaC,KAAK,KAAKjD,MAAM;IACpC;AAEA,QAAI4F,aAAa;AACf,YAAMhB,kBAAkB,KAAKvE,MAAMwE,OAAMpF,cAAAA,CAAAA;AACzCkF,MAAAA,KAAIkB,KAAK,wBAAwB;QAAEI;QAAiBC;QAAiBC;MAAsB,GAAA;;;;;;AAC3FL,MAAAA,WAAU,KAAK/E,iBAAe,QAAA;;;;;;;;;AAC9B,WAAKA,gBAAgBgB,SAAQ;IAC/B;EACF;EAEA,MAAc2D,WAAWlB,MAA2D;AAClF,UAAMpE,MAAM,KAAKC,KAAKoG,OAAM;AAC5B,QAAI;AACF,YAAMC,YAAYC,eAAeC,OAAOpC,IAAAA;AAExC,YAAMgC,QAAQ,MAAM,KAAKxG,OAAO4B,KAAMiF,UAAU;QAAEH,WAAW;UAAE,GAAGA;UAAWI,KAAKrF;QAAU;QAAGrB;MAAI,CAAA;AACnG,UAAIoG,OAAOO,eAAe,SAAS;AACjC,cAAM,IAAIC,MAAM,gCAAA;MAClB;AAEA,cAAQR,OAAOS,MAAAA;QACb,KAAK,SAAS;AACZ,eAAKjH,OAAOqC,kBAAkBmC,IAAAA,IAAQ;YAAEgC;YAAOpG;UAAI;AACnDA,cAAI8G,UAAU,MAAM,OAAO,KAAKlH,OAAOqC,kBAAkBmC,IAAAA,CAAK;AAC9D,iBAAO;YAAEoB,aAAa;UAAM;QAC9B;QACA,KAAK,SAAS;AACZ,gBAAMuB,cAAc,IAAIzG,YAAAA;AACxByG,sBAAYxG,SAAS6F,KAAAA;AACrB,eAAKxG,OAAOwC,mBAAmBgC,IAAAA,IAAQ;YAAE4C,QAAQD;YAAa/G;UAAI;AAClEA,cAAI8G,UAAU,MAAA;AACZC,wBAAY7F,YAAYkF,KAAAA;AACxBA,kBAAMjF,KAAI;AACV,mBAAO,KAAKvB,OAAOwC,mBAAmBgC,IAAAA;UACxC,CAAA;AACA,iBAAO;YAAEoB,aAAa;UAAM;QAC9B;QACA;AACE,gBAAM,IAAIoB,MAAM,uBAAuBR,OAAOS,IAAAA,EAAM;MACxD;IACF,SAASI,KAAK;AACZ1C,MAAAA,KAAIkB,KAAK,wBAAwB;QAAEwB;QAAK7C;MAAK,GAAA;;;;;;AAC7C,WAAKpE,IAAImC,QAAO;AAChB,aAAO;QAAEqD,aAAa;MAAK;IAC7B;EACF;EAEA,MAAcQ,gBACZI,OACAc,eACAC,WACyD;AACzD,QAAI,CAACf,SAAS,CAACc,eAAe;AAC5B,aAAO;QAAEd,OAAO/E;MAAU;IAC5B;AAEA,UAAMrB,MAAM,KAAKC,KAAKoG,OAAM;AAE5B,QAAI;AACF,aAAO;QACLD,OAAO,MAAM,KAAKxG,OAAO4B,KAAM4F,UAAU;UACvCpH;UACAoG,OAAOA,SAAS;UAChBc;UACAC;QACF,CAAA;MACF;IACF,SAASF,KAAK;AACZ1C,MAAAA,KAAIkB,KAAK,wBAAwB;QAAEwB;QAAKb;QAAOc;QAAeC;MAAU,GAAA;;;;;;AACxE,WAAKnH,IAAImC,QAAO;AAChB,aAAO;QAAEqD,aAAa;MAAK;IAC7B;EACF;;AA1TK,UAAA,GAAA,IAAA,GACL6B,kBAAA,MAAgBzE,gBAAe,IAAI0E,OAAAA,CAAAA,GACnCD,kBAAA,MAAiBzH,UAAqB;MAAEwC,oBAAoB,CAAC;MAAGH,mBAAmB,CAAC;IAAE,CAAA,GACtFoF,kBAAA,MAAQ3H,oBAAqC2B,MAAAA,GAE7CgG,kBAAA,MAAQhF,qBAAwC,CAAA,CAAE,GAClDgF,kBAAA,MAAQvH,2BAA6CuB,MAAAA,GACrDgG,kBAAA,MAAQ7G,8BAAgDa,MAAAA,GACxDgG,kBAAA,MAAQ1G,mBAAiCU,MAAAA,GACzCgG,kBAAA,MAAQvG,mBAAiCO,MAAAA;;AAkT3C;;;;;;;;;AClXA,SAASkG,gBAAgB;AAEzB,SAASC,SAAAA,QAAOC,gBAAAA,qBAAoB;AAEpC,SAASC,YAAAA,iBAAgB;AACzB,SAASC,aAAAA,kBAAiB;AAC1B,SAASC,YAAY;AAErB,SAASC,iBAAAA,sBAAqB;;;;;;;;;;;;;;;;;;;;;AAcvB,IAAMC,cAAN,cAA0BC,UAAAA;;EAwB/B,IAAIC,SAA6B;AAC/B,WAAO,KAAKC,OAAOC,KAAKF;EAC1B;;EAGA,IAAIG,aAAsB;AACxB,WAAO,KAAKC,kBAAkBC;EAChC;;EAGA,IAAIC,WAAoB;AACtB,WAAO,KAAKC,gBAAgBF;EAC9B;;EAGA,IAAIG,SAAkB;AACpB,WAAO,KAAKC,cAAcJ;EAC5B;;EAGA,IAAIK,OAAkB;AACpB,WAAO,KAAKT,OAAOC,KAAKQ,QAAQ,CAAC;EACnC;;EAGA,IAAIC,SAAiB;AACnB,WAAO,KAAKV,OAAOC,KAAKS,UAAU,CAAC;EACrC;;EAGA,IAAIC,QAAqB;AACvB,WAAO,KAAKX,OAAOC,KAAKU,SAAS,CAAA;EACnC;;EAGA,IAAIC,QAAQ;AACV,WAAO,KAAKZ,OAAOY;EACrB;;EAGA,IAAIC,oBAAwC;AAC1C,YAAQ,KAAKb,OAAOC,KAAKU,SAAS,CAAA,GAC/BG,IAAI,CAACC,SAAUA,KAAKL,QAAQM,eAAeD,KAAKL,QAAQO,QAAQC,MAAAA,EAChEC,OAAOC,cAAAA,EACPN,IAAI,CAACO,UAAU,KAAKrB,OAAOY,MAAMU,kBAAkBD,KAAAA,GAA4BA,KAAAA,EAC/EF,OAAOC,cAAAA;EACZ;;EAGA,IAAIG,QAAQ;AACV,WAAO,KAAKvB;EACd;;EAGAwB,eAAeC,MAAkD;AAC/D,WAAOA,OAAO,KAAKzB,OAAOY,MAAMc,mBAAmBD,IAAAA,GAAOE,SAAST;EACrE;;EAGAU,YAAYC,KAAwC;AAClD,WAAO,KAAK7B,OAAOC,KAAK6B,aAAaD,GAAAA;EACvC;EAEAE,UAAUhC,QAAsB;AAC9B,SAAKiC,mBAAmBC,WAAWlC,MAAAA;EACrC;EAEAmC,YAAY7B,UAAyB;AACnC,SAAK2B,mBAAmBE,YAAY7B,QAAAA;EACtC;EAEA8B,cAAcjC,YAA2B;AACvC,SAAK8B,mBAAmBG,cAAcjC,UAAAA;EACxC;EAEAkC,YAAYP,KAAaQ,SAAyC;AAChE,SAAKL,mBAAmBI,YAAYP,KAAKQ,OAAAA;EAC3C;EAEAC,cAA6B;AAC3B,WAAO,KAAKC,cAAcD,YAAW;EACvC;EAEAE,eAA8B;AAC5B,WAAO,KAAKD,cAAcC,aAAY;EACxC;EAEAC,cAA6B;AAC3B,WAAO,KAAKF,cAAcE,YAAW;EACvC;EAEAC,eAA8B;AAC5B,WAAO,KAAKH,cAAcG,aAAY;EACxC;EAEAC,oBAAmC;AACjC,WAAO,KAAKJ,cAAcI,kBAAiB;EAC7C;EAEAC,qBAAoC;AAClC,WAAO,KAAKL,cAAcK,mBAAkB;EAC9C;EAYA,MAAyBC,QAAuB;AAC9C,UAAM,KAAKN,cAAcO,KAAI;AAC7B,UAAM,KAAKd,mBAAmBc,KAAI;AAClC,UAAMC,eAAe,KAAKC,QAAQC,KAAKC,SAASC,UAAU,CAACD,aAAAA;AACzD,UAAIA,UAAU;AACZ,aAAKlB,mBAAmBoB,aAAaF,QAAAA;MACvC;AACA,UAAI,KAAKF,QAAQC,KAAKI,QAAQ;AAC5B,aAAKrB,mBAAmBsB,WAAW,KAAKN,QAAQC,KAAKI,MAAM;MAC7D;IACF,CAAA;AACA,SAAKE,KAAKC,UAAU,MAAMT,aAAaU,YAAW,CAAA;AAElD,SAAKzB,mBAAmB0B,aAAaC,GAAG,KAAKJ,MAAM,CAAChC,UAAU,KAAKqC,oBAAoBrC,KAAAA,CAAAA;AACvF,SAAKgB,cAAcmB,aAAaC,GAAG,KAAKJ,MAAM,CAAChC,UAAU,KAAKsC,qBAAqBtC,KAAAA,CAAAA;EACrF;EAEA,MAAyBuC,SAAwB;AAC/C,UAAM,KAAK9B,mBAAmB+B,MAAK;AACnC,UAAM,KAAK/B,mBAAmBgC,MAAK;AACnC,UAAM,KAAKzB,cAAcyB,MAAK;EAChC;EAEA,MAAMC,KAAKlE,QAAiC;AAC1C,UAAMmE,QAAQ,MAAM,KAAKlC,mBAAmBmC,WAAWpE,MAAAA;AACvD,WAAOmE,MAAME;EACf;;EAGA,MACMC,OAAsB;AAC1B,SAAKrC,mBAAmBsC,UAAU,IAAA;AAClC,UAAM,KAAKtC,mBAAmBqC,KAAI;AAClC,UAAM,KAAK9B,cAAc8B,KAAK;MAC5BE,YAAY,KAAKvB,QAAQwB,OAAOC,IAAI,sBAAA;MACpCC,SAAS,GAAGC,SAAAA;IACd,CAAA;EACF;EAEA,MACMZ,QAAuB;AAC3B,SAAK/B,mBAAmBsC,UAAU,KAAA;AAClC,UAAM,KAAKtC,mBAAmB+B,MAAK;AACnC,UAAM,KAAKxB,cAAcwB,MAAK;AAC9B,SAAKhE,UAAU,KAAK6E,KAAKC,KAAK,KAAK9E,MAAM;EAC3C;EAEQ6D,oBAAoBrC,OAAwB;AAClD,UAAMuD,eAAevD,MAAMZ,OACvBQ,OAAO,CAACJ,SAASA,KAAKR,UAAUQ,KAAKgE,OAAOxD,MAAMd,KAAMsE,EAAE,GAC1DC,QAAQ,CAACjE,SAAS;MAACA,KAAKL,QAAQuE;MAAOlE,KAAKL,QAAQO;MAAOF,KAAKL,QAAQwE;KAAY,EACrF/D,OAAOC,cAAAA;AACV,SAAKmB,cAAc4C,oBAAoBL,YAAAA;AAEvC,SAAKM,iBAAiBP,KAAKtD,KAAAA;AAC3B,SAAK8D,aAAY;EACnB;EAEQxB,qBAAqBtC,OAAyB;AACpD,SAAKS,mBAAmBsD,UAAU;MAChCL,OAAO1D,MAAMgE,mBAAmBC,eAAeC,OAAOlE,MAAMgE,gBAAgB,IAAIrE;MAChFD,OAAOM,MAAMmE,mBAAmBF,eAAeC,OAAOlE,MAAMmE,gBAAgB,IAAIxE;MAChFgE,aAAa3D,MAAMoE,yBAAyBH,eAAeC,OAAOlE,MAAMoE,sBAAsB,IAAIzE;MAClG0E,cAAcrE,MAAMqE;MACpB5E,cAAcO,MAAMP;MACpB6E,oBAAoBtE,MAAMsE;IAC5B,CAAA;AAEA,UAAMC,aAAa,KAAKvD,cAAcuD,cAAc;AACpD,SAAK9D,mBAAmBE,YAAY4D,UAAAA;AAEpC,SAAKC,kBAAkBlB,KAAK;MAACtD;MAAOuE;KAAW;AAC/C,SAAKT,aAAY;EACnB;;;;EAKQA,eAAqB;AAC3B,SAAKrF,OAAOC,OAAO,KAAK+B,mBAAmBgE,UAAS;AACpD,SAAKhG,OAAOY,QAAQ,KAAK2B,cAAcyD,UAAS;EAClD;;EA1FA,YAA6BhD,SAAiB;AAC5C,UAAK,GAAAiD,kBAAA,MAAA,WAAA,MAAA,GAhIPA,kBAAA,MAAgBb,oBAAhB,MAAA;IAEAa,kBAAA,MAAgBF,qBAAhB,MAAA,GACAE,kBAAA,MAAgBrB,QAAhB,MAAA;;;;IAMAqB,kBAAA,MAAiBjG,UAAjB,MAAA;IAMAiG,kBAAA,MAAiB9F,qBAAjB,MAAA,GACA8F,kBAAA,MAAiB3F,mBAAjB,MAAA,GACA2F,kBAAA,MAAiBzF,iBAAjB,MAAA,GAEAyF,kBAAA,MAAiBjE,sBAAjB,MAAA,GACAiE,kBAAA,MAAiB1D,iBAAjB,MAAA,GAAA,KA2G6BS,UAAAA,SAAAA,KA/HboC,mBAAmB,IAAIc,OAAAA,GAAAA,KAEvBH,oBAAoB,IAAIG,OAAAA,GAAAA,KACxBtB,OAAO,IAAIsB,OAAAA,GAAAA,KAMVlG,SAASmG,KAAkB;MAC1ClG,MAAM,CAAC;MACPW,OAAO;QAAEU,mBAAmB,CAAC;QAAGI,oBAAoB,CAAC;MAAE;IACzD,CAAA,GAAA,KAGiBvB,oBAAoBiG,SAAS,MAAM,KAAKpG,OAAOC,KAAKC,cAAc,KAAA,GAAA,KAClEI,kBAAkB8F,SAAS,MAAM,KAAKpG,OAAOC,KAAKI,YAAY,KAAA,GAAA,KAC9DG,gBAAgB4F,SAAS,MAAM,KAAKpG,OAAOC,KAAKM,UAAU,KAAA;AAgHzE,SAAKyC,QAAQwB,OAAO6B,WAAW,2BAAA;AAC/B,UAAMC,iBAAiB,KAAKtD,QAAQuD,SAASA,SAASC;AACtDC,IAAAA,WAAUH,gBAAgB,6BAAA;;;;;;;;;AAC1B,SAAKtE,qBAAqB,IAAI0E,sBAAsB;MAAEJ;IAAe,CAAA;AACrE,SAAK/D,gBAAgB,IAAIoE,aAAAA;EAC3B;AAoFF;;;;;;;",
|
|
6
|
-
"names": ["invariant", "buf", "UserStateSchema", "CALLS_URL", "codec", "encode", "message", "toBinary", "create", "decode", "fromBinary", "TrackNameCodec", "trackData", "sessionId", "trackName", "mid", "name", "split", "location", "md5Hex", "DeferredTask", "Event", "scheduleTaskInterval", "synchronized", "Context", "Resource", "generateName", "invariant", "PublicKey", "log", "buf", "ActivitySchema", "ConnectionState", "isNonNullable", "DISCONNECTED_ABRUPT_TIMEOUT", "CallSwarmSynchronizer", "Resource", "_getState", "_state", "setRaisedHand", "raisedHand", "_notifyAndSchedule", "setSpeaking", "speaking", "setJoined", "joined", "setTracks", "tracks", "setActivity", "key", "payload", "lamportTimestamp", "LamportTimestampCrdt", "increment", "activities", "id", "_deviceKey", "_setIdentity", "identity", "_identityKey", "identityKey", "toHex", "_displayName", "profile", "displayName", "generateName", "_setDevice", "device", "deviceKey", "_setRoomId", "roomId", "_swarmCtx", "log", "verbose", "_open", "_sendStateTask", "DeferredTask", "_ctx", "_sendState", "_reconcileSwarmStateTask", "_reconcileSwarmState", "_close", "undefined", "join", "invariant", "Context", "topic", "getTopic", "peer", "peerKey", "stream", "_networkService", "subscribeSwarmState", "subscribe", "event", "_processSwarmEvent", "cleanup", "close", "leaveSwarm", "catch", "err", "window", "removeEventListener", "addEventListener", "onDispose", "leave", "dispose", "users", "self", "querySwarm", "swarm", "peers", "stateUpdated", "emit", "schedule", "state", "name", "Object", "fromEntries", "entries", "map", "activity", "buf", "create", "ActivitySchema", "joinSwarm", "codec", "encode", "swarmEvent", "_lastSwarmEvent", "inactivePeers", "filter", "disconnected", "connectionState", "ConnectionState", "DISCONNECTED_ABRUPT", "Date", "now", "sort", "peer1", "peer2", "localeCompare", "decode", "error", "isNonNullable", "find", "user", "length", "activityKeys", "Set", "flatMap", "keys", "forEach", "lastActivity", "getLastState", "version", "some", "CONNECTED", "scheduleTaskInterval", "Math", "min", "networkService", "Event", "states", "maxTimestamp", "max", "sortedStates", "a", "b", "timestamp", "PublicKey", "fromHex", "md5Hex", "monitorAudioLevel", "mediaStreamTrack", "intervalMs", "onMeasure", "timeout", "interval", "audioContext", "AudioContext", "stream", "MediaStream", "addTrack", "mediaStreamAudioSourceNode", "createMediaStreamSource", "analyserNode", "createAnalyser", "connect", "fftSize", "pcmData", "Float32Array", "peak", "window", "setInterval", "tick", "setTimeout", "getFloatTimeDomainData", "sumSquares", "amplitude", "current", "Math", "sqrt", "length", "disconnect", "close", "clearInterval", "clearTimeout", "removeTrack", "PersistentLifecycle", "Trigger", "scheduleTask", "Resource", "invariant", "log", "_define_property", "HistoryCache", "push", "messages", "_messages", "length", "_limit", "shift", "get", "limit", "_define_property", "DefaultBatchSizeLimit", "FIFOScheduler", "schedule", "task", "Promise", "resolve", "reject", "then", "error", "BulkRequestDispatcher", "doBulkRequest", "params", "bulkRequestFunc", "length", "push", "batch", "setTimeout", "batchCopy", "splice", "result", "catch", "err", "batchSizeLimit", "NETWORK_TIMEOUT", "CallsServicePeer", "Resource", "_open", "ctx", "_persistentLifecycle", "open", "_close", "close", "session", "state", "_startSession", "peerConnection", "_createRtcConnection", "sessionId", "_initiateCallSession", "_stopSession", "RTCPeerConnection", "iceServers", "_config", "bundlePolicy", "addEventListener", "connectionState", "log", "info", "scheduleRestart", "iceTimeout", "clearTimeout", "iceConnectionState", "timeoutSeconds", "window", "setTimeout", "_fetch", "method", "relativePath", "requestInit", "history", "push", "endpoint", "type", "time", "Date", "toISOString", "body", "response", "fetch", "apiBase", "redirect", "status", "error", "text", "Error", "data", "clone", "json", "errorCode", "errorDescription", "_pushTrackInBulk", "transceiver", "trackName", "verbose", "pushedTrackPromise", "pushTrackDispatcher", "doBulkRequest", "tracks", "taskScheduler", "schedule", "offer", "createOffer", "sdp", "replace", "setLocalDescription", "JSON", "stringify", "sessionDescription", "map", "mid", "location", "invariant", "undefined", "setRemoteDescription", "RTCSessionDescription", "peerConnectionIsConnected", "then", "trackData", "find", "t", "onDispose", "_closeTrackInBulk", "_ctx", "pushTrack", "track", "encodings", "previousTrack", "waitUntilOpen", "getTransceivers", "sender", "replaceTrack", "catch", "err", "stableId", "crypto", "randomUUID", "addTransceiver", "direction", "pushedTrackData", "parameters", "getParameters", "forEach", "encoding", "i", "existing", "setParameters", "_pullTrackInBulk", "pulledTrackPromise", "pullTrackDispatcher", "newTrackResponse", "trackMap", "reduce", "acc", "pulledTrackData", "set", "resolvedTrack", "resolveTrack", "Map", "requiresImmediateRenegotiation", "answer", "createAnswer", "renegotiationResponse", "currentLocalDescription", "trackInfo", "get", "availableTracks", "Array", "from", "keys", "pullTrack", "closeTrackDispatcher", "mids", "stop", "activeTransceivers", "filter", "requestBody", "length", "localDescription", "force", "config", "_define_property", "HistoryCache", "PersistentLifecycle", "start", "FIFOScheduler", "BulkRequestDispatcher", "compare", "timeout", "Promise", "resolve", "reject", "handler", "receiver", "removeEventListener", "connected", "connectionStateChangeHandler", "log", "getUserMediaTrack", "kind", "constraints", "deviceList", "getDeviceList", "filter", "device", "firstDevice", "Error", "acquireTrack", "deviceId", "label", "info", "mediaStream", "navigator", "mediaDevices", "getUserMedia", "video", "audio", "getVideoTracks", "getAudioTracks", "enumerateDevices", "SCREENSHARE_CONSTRAINTS", "width", "max", "height", "frameRate", "getScreenshare", "contentHint", "ms", "getDisplayMedia", "forEach", "track", "DeferredTask", "Event", "sleep", "Resource", "NOT_SPEAKING_AFTER", "START_SPEAKING_THRESHOLD", "CONTINUE_SPEAKING_THRESHOLD", "MIN_EVENT_INTERVAL", "SpeakingMonitor", "Resource", "isSpeaking", "_isSpeaking", "_open", "_deferredUpdate", "DeferredTask", "_ctx", "_emitSpeakingChanged", "timeout", "cleanup", "monitorAudioLevel", "mediaStreamTrack", "_mediaStreamTrack", "onMeasure", "vol", "audioLevelAboveThreshold", "clearTimeout", "undefined", "schedule", "setTimeout", "onDispose", "timeSinceLastEvent", "Date", "now", "_lastEventTime", "timeToNextEvent", "sleep", "speakingChanged", "emit", "_define_property", "Event", "DeferredTask", "Event", "sleep", "synchronized", "Resource", "cancelWithContext", "invariant", "log", "VIDEO_WIDTH", "VIDEO_HEIGHT", "MAX_WEB_CAM_FRAMERATE", "MAX_WEB_CAM_BITRATE", "RETRY_INTERVAL", "USE_INAUDIBLE_AUDIO", "MediaManager", "Resource", "isSpeaking", "_speakingMonitor", "_getState", "_state", "_open", "_blackCanvasStreamTrack", "createBlackCanvasStreamTrack", "ctx", "_ctx", "width", "height", "videoTrack", "videoStream", "MediaStream", "addTrack", "_inaudibleAudioStreamTrack", "createInaudibleAudioStreamTrack", "audioTrack", "_pushTracksTask", "DeferredTask", "_pushTracks", "_pullTracksTask", "_reconcilePulledMedia", "_close", "close", "removeTrack", "stop", "screenshareTrack", "undefined", "join", "serviceConfig", "peer", "CallsServicePeer", "open", "schedule", "leave", "Promise", "all", "Object", "values", "pulledAudioTracks", "map", "dispose", "pulledVideoStreams", "_trackToReconcile", "pushedVideoTrack", "pushedAudioTrack", "pushedScreenshareTrack", "turnVideoOn", "getUserMediaTrack", "videoEnabled", "stateUpdated", "emit", "turnVideoOff", "turnAudioOn", "audioEnabled", "echoCancellation", "noiseSuppression", "autoGainControl", "sampleRate", "SpeakingMonitor", "speakingChanged", "on", "turnAudioOff", "turnScreenshareOn", "ms", "getScreenshare", "contentHint", "screenshareVideoStream", "getVideoTracks", "screenshareEnabled", "turnScreenshareOff", "_schedulePullTracks", "tracks", "every", "name", "includes", "length", "log", "cancelWithContext", "sleep", "trackNames", "tracksToPull", "filter", "audioTracksToClose", "entries", "key", "some", "videoStreamsToClose", "currentAudioTracks", "keys", "currentVideoStreams", "pullResults", "_pullTrack", "_", "shouldRetry", "info", "invariant", "isOpen", "updated", "pushVideoResult", "pushAudioResult", "pushScreenshareResult", "_maybePushTrack", "maxFramerate", "maxBitrate", "networkPriority", "track", "derive", "trackData", "TrackNameCodec", "decode", "pullTrack", "mid", "readyState", "Error", "kind", "onDispose", "mediaStream", "stream", "err", "previousTrack", "encodings", "pushTrack", "_define_property", "Event", "computed", "Event", "synchronized", "Resource", "invariant", "live", "isNonNullable", "CallManager", "Resource", "roomId", "_state", "call", "raisedHand", "_raisedHandSignal", "value", "speaking", "_speakingSignal", "joined", "_joinedSignal", "self", "tracks", "users", "media", "audioTracksToPlay", "map", "user", "audioEnabled", "audio", "undefined", "filter", "isNonNullable", "track", "pulledAudioTracks", "state", "getVideoStream", "name", "pulledVideoStreams", "stream", "getActivity", "key", "activities", "setRoomId", "_swarmSynchronizer", "_setRoomId", "setSpeaking", "setRaisedHand", "setActivity", "payload", "turnAudioOn", "_mediaManager", "turnAudioOff", "turnVideoOn", "turnVideoOff", "turnScreenshareOn", "turnScreenshareOff", "_open", "open", "subscription", "_client", "halo", "identity", "subscribe", "_setIdentity", "device", "_setDevice", "_ctx", "onDispose", "unsubscribe", "stateUpdated", "on", "_onCallStateUpdated", "_onMediaStateUpdated", "_close", "leave", "close", "peek", "peers", "querySwarm", "length", "join", "setJoined", "iceServers", "config", "get", "apiBase", "CALLS_URL", "left", "emit", "tracksToPull", "id", "flatMap", "video", "screenshare", "_schedulePullTracks", "callStateUpdated", "_updateState", "setTracks", "pushedVideoTrack", "TrackNameCodec", "encode", "pushedAudioTrack", "pushedScreenshareTrack", "videoEnabled", "screenshareEnabled", "isSpeaking", "mediaStateUpdated", "_getState", "_define_property", "Event", "live", "computed", "getOrThrow", "networkService", "services", "NetworkService", "invariant", "CallSwarmSynchronizer", "MediaManager"]
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/capabilities/intent-resolver.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { Effect } from 'effect';\n\nimport { Capabilities, type PluginContext, contributes, createIntent, createResolver } from '@dxos/app-framework';\nimport { sleep } from '@dxos/async';\nimport { Obj, Relation, Type } from '@dxos/echo';\nimport { invariant } from '@dxos/invariant';\nimport { ATTENDABLE_PATH_SEPARATOR, DeckAction } from '@dxos/plugin-deck/types';\nimport { ObservabilityAction } from '@dxos/plugin-observability/types';\nimport { CollectionAction, SpaceAction } from '@dxos/plugin-space/types';\nimport { Ref, fullyQualifiedId, getSpace } from '@dxos/react-client/echo';\nimport { AnchoredTo, DataType } from '@dxos/schema';\n\nimport { THREAD_PLUGIN } from '../meta';\nimport { ChannelType, ThreadAction, ThreadType } from '../types';\n\nimport { ThreadCapabilities } from './capabilities';\n\nexport default (context: PluginContext) =>\n contributes(Capabilities.IntentResolver, [\n createResolver({\n intent: ThreadAction.OnSpaceCreated,\n resolve: ({ space, rootCollection }) =>\n Effect.gen(function* () {\n const { dispatch } = context.getCapability(Capabilities.IntentDispatcher);\n const { object: collection } = yield* dispatch(\n createIntent(CollectionAction.CreateQueryCollection, { typename: Type.getTypename(ChannelType) }),\n );\n rootCollection.objects.push(Ref.make(collection));\n\n const { object: channel } = yield* dispatch(\n createIntent(ThreadAction.CreateChannel, { name: 'General', spaceId: space.id }),\n );\n space.db.add(channel);\n }),\n }),\n createResolver({\n intent: ThreadAction.CreateChannel,\n resolve: ({ name }) => ({\n data: {\n object: Obj.make(ChannelType, {\n name,\n defaultThread: Ref.make(Obj.make(ThreadType, { messages: [], status: 'active' })),\n threads: [],\n }),\n },\n }),\n }),\n createResolver({\n intent: ThreadAction.CreateChannelThread,\n resolve: ({ channel }) => {\n const thread = Obj.make(ThreadType, { messages: [], status: 'active' });\n channel.threads.push(Ref.make(thread));\n return {\n data: {\n object: thread,\n },\n };\n },\n }),\n // TODO(wittjosiah): Break this up into more composable pieces.\n createResolver({\n intent: ThreadAction.Create,\n resolve: ({ name, anchor: _anchor, subject }) => {\n const space = getSpace(subject);\n invariant(space, 'Space not found');\n\n const { state } = context.getCapability(ThreadCapabilities.MutableState);\n const subjectId = fullyQualifiedId(subject);\n const thread = Obj.make(ThreadType, { name, messages: [], status: 'staged' });\n const anchor = Relation.make(AnchoredTo, {\n [Relation.Source]: thread,\n [Relation.Target]: subject,\n anchor: _anchor,\n });\n\n const draft = state.drafts[subjectId];\n if (draft) {\n draft.push(anchor);\n } else {\n state.drafts[subjectId] = [anchor];\n }\n\n return {\n intents: [\n createIntent(ThreadAction.Select, { current: fullyQualifiedId(thread) }),\n createIntent(DeckAction.ChangeCompanion, {\n primary: subjectId,\n companion: `${subjectId}${ATTENDABLE_PATH_SEPARATOR}comments`,\n }),\n ],\n };\n },\n }),\n createResolver({\n intent: ThreadAction.AddProposal,\n resolve: ({ text, anchor, sender, subject }) => {\n const space = getSpace(subject);\n invariant(space, 'Space not found');\n\n const subjectId = fullyQualifiedId(subject);\n const proposal = Obj.make(DataType.Message, {\n created: new Date().toISOString(),\n sender,\n blocks: [{ _tag: 'proposal', text }],\n });\n const thread = Obj.make(ThreadType, { name: 'Proposal', messages: [Ref.make(proposal)], status: 'active' });\n\n return {\n intents: [\n createIntent(SpaceAction.AddObject, { object: thread, target: space, hidden: true }),\n createIntent(SpaceAction.AddRelation, {\n space,\n schema: AnchoredTo,\n source: thread,\n target: subject,\n fields: { anchor },\n }),\n createIntent(ThreadAction.Select, { current: fullyQualifiedId(thread) }),\n createIntent(DeckAction.ChangeCompanion, {\n primary: subjectId,\n companion: `${subjectId}${ATTENDABLE_PATH_SEPARATOR}comments`,\n }),\n ],\n };\n },\n }),\n createResolver({\n intent: ThreadAction.Select,\n resolve: ({ current }) => {\n const { state } = context.getCapability(ThreadCapabilities.MutableState);\n state.current = current;\n },\n }),\n createResolver({\n intent: ThreadAction.ToggleResolved,\n resolve: ({ thread }) => {\n if (thread.status === 'active' || thread.status === undefined) {\n thread.status = 'resolved';\n } else if (thread.status === 'resolved') {\n thread.status = 'active';\n }\n\n const space = getSpace(thread);\n invariant(space, 'Space not found');\n const spaceId = space.id;\n\n return {\n intents: [\n createIntent(ObservabilityAction.SendEvent, {\n name: 'threads.toggle-resolved',\n properties: {\n spaceId,\n threadId: thread.id,\n },\n }),\n ],\n };\n },\n }),\n createResolver({\n intent: ThreadAction.Delete,\n resolve: async ({ subject, anchor, thread: _thread }, undo) => {\n const thread = _thread ?? (Relation.getSource(anchor) as ThreadType);\n const { state } = context.getCapability(ThreadCapabilities.MutableState);\n const subjectId = fullyQualifiedId(subject);\n const draft = state.drafts[subjectId];\n if (draft) {\n // Check if we're deleting a draft; if so, remo ve it.\n const index = draft.findIndex((a) => a.id === anchor.id);\n if (index !== -1) {\n draft.splice(index, 1);\n return;\n }\n }\n\n const space = getSpace(anchor);\n if (!space) {\n return;\n }\n\n if (!undo) {\n // TODO(wittjosiah): Without sleep, rendering crashes at `Relation.setSource(anchor)`.\n space.db.remove(anchor);\n await sleep(100);\n space.db.remove(thread);\n\n return {\n undoable: {\n message: ['thread deleted label', { ns: THREAD_PLUGIN }],\n data: { thread, anchor },\n },\n intents: [\n createIntent(ObservabilityAction.SendEvent, {\n name: 'threads.delete',\n properties: {\n spaceId: space.id,\n threadId: thread.id,\n },\n }),\n ],\n };\n } else {\n // TODO(wittjosiah): Without sleep, rendering crashes at `Relation.setSource(anchor)`.\n space.db.add(thread);\n await sleep(100);\n space.db.add(anchor);\n\n return {\n intents: [\n createIntent(ObservabilityAction.SendEvent, {\n name: 'threads.undo-delete',\n properties: {\n spaceId: space.id,\n threadId: thread.id,\n },\n }),\n ],\n };\n }\n },\n }),\n createResolver({\n intent: ThreadAction.AddMessage,\n resolve: ({ anchor, subject, sender, text }) => {\n const thread = Relation.getSource(anchor) as ThreadType;\n const { state } = context.getCapability(ThreadCapabilities.MutableState);\n const subjectId = fullyQualifiedId(subject);\n const space = getSpace(subject);\n invariant(space, 'Space not found');\n\n const message = Obj.make(DataType.Message, {\n created: new Date().toISOString(),\n sender,\n blocks: [{ _tag: 'text', text }],\n // TODO(wittjosiah): Context based on attention.\n // context: context ? Ref.make(context) : undefined,\n });\n thread.messages.push(Ref.make(message));\n\n const intents = [];\n const draft = state.drafts[subjectId]?.find((a) => a.id === anchor.id);\n if (draft) {\n // Move draft to document.\n thread.status = 'active';\n // TODO(wittjosiah): This causes the thread to flash as it transitions from draft to db.\n state.drafts[subjectId] = state.drafts[subjectId]?.filter((a) => a.id !== anchor.id);\n intents.push(createIntent(SpaceAction.AddObject, { object: thread, target: space, hidden: true }));\n intents.push(\n createIntent(SpaceAction.AddRelation, {\n space,\n schema: AnchoredTo,\n source: thread,\n target: subject,\n fields: { anchor: draft.anchor },\n }),\n );\n intents.push(\n createIntent(ObservabilityAction.SendEvent, {\n name: 'threads.create',\n properties: {\n spaceId: space.id,\n threadId: thread.id,\n },\n }),\n );\n }\n\n intents.push(\n createIntent(ObservabilityAction.SendEvent, {\n name: 'threads.message.add',\n properties: {\n spaceId: space.id,\n threadId: thread.id,\n threadLength: thread.messages.length,\n messageId: message.id,\n messageLength: text.length,\n },\n }),\n );\n\n return { intents };\n },\n }),\n createResolver({\n intent: ThreadAction.DeleteMessage,\n resolve: ({ subject, anchor, messageId, message, messageIndex }, undo) => {\n const thread = Relation.getSource(anchor) as ThreadType;\n const space = getSpace(subject);\n invariant(space, 'Space not found');\n\n if (!undo) {\n const messageIndex = thread.messages.findIndex(Ref.hasObjectId(messageId));\n const message = thread.messages[messageIndex]?.target;\n if (!message) {\n return;\n }\n\n if (messageIndex === 0 && thread.messages.length === 1) {\n // If the message is the only message in the thread, delete the thread.\n return {\n intents: [createIntent(ThreadAction.Delete, { subject, anchor })],\n };\n } else {\n thread.messages.splice(messageIndex, 1);\n }\n\n return {\n undoable: {\n message: ['message deleted label', { ns: THREAD_PLUGIN }],\n data: { message, messageIndex },\n },\n intents: [\n createIntent(ObservabilityAction.SendEvent, {\n name: 'threads.message.delete',\n properties: {\n spaceId: space.id,\n threadId: thread.id,\n messageId: message.id,\n },\n }),\n ],\n };\n } else {\n if (messageIndex === undefined || !message) {\n return;\n }\n\n thread.messages.splice(messageIndex, 0, Ref.make(message));\n return {\n intents: [\n createIntent(ObservabilityAction.SendEvent, {\n name: 'threads.message.undo-delete',\n properties: {\n spaceId: space.id,\n threadId: thread.id,\n messageId: message.id,\n },\n }),\n ],\n };\n }\n },\n }),\n ]);\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["Effect", "Capabilities", "contributes", "createIntent", "createResolver", "sleep", "Obj", "Relation", "Type", "invariant", "ATTENDABLE_PATH_SEPARATOR", "DeckAction", "ObservabilityAction", "CollectionAction", "SpaceAction", "Ref", "fullyQualifiedId", "getSpace", "AnchoredTo", "DataType", "context", "contributes", "Capabilities", "IntentResolver", "createResolver", "intent", "ThreadAction", "OnSpaceCreated", "resolve", "space", "rootCollection", "Effect", "gen", "dispatch", "getCapability", "IntentDispatcher", "object", "collection", "createIntent", "CollectionAction", "CreateQueryCollection", "typename", "Type", "getTypename", "ChannelType", "objects", "push", "Ref", "make", "channel", "CreateChannel", "name", "spaceId", "id", "db", "add", "data", "Obj", "defaultThread", "ThreadType", "messages", "status", "threads", "CreateChannelThread", "thread", "Create", "anchor", "_anchor", "subject", "getSpace", "invariant", "state", "ThreadCapabilities", "MutableState", "subjectId", "fullyQualifiedId", "Relation", "AnchoredTo", "Source", "Target", "draft", "drafts", "intents", "Select", "current", "DeckAction", "ChangeCompanion", "primary", "companion", "ATTENDABLE_PATH_SEPARATOR", "AddProposal", "text", "sender", "proposal", "DataType", "Message", "created", "Date", "toISOString", "blocks", "_tag", "SpaceAction", "AddObject", "target", "hidden", "AddRelation", "schema", "source", "fields", "ToggleResolved", "undefined", "ObservabilityAction", "SendEvent", "properties", "threadId", "Delete", "_thread", "undo", "getSource", "index", "findIndex", "a", "splice", "remove", "sleep", "undoable", "message", "ns", "THREAD_PLUGIN", "AddMessage", "find", "filter", "threadLength", "length", "messageId", "messageLength", "DeleteMessage", "messageIndex", "hasObjectId"]
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/capabilities/markdown.ts", "../../../src/extensions/threads.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { EditorView } from '@codemirror/view';\n\nimport { Capabilities, type PluginContext, contributes, createIntent } from '@dxos/app-framework';\nimport { ATTENDABLE_PATH_SEPARATOR, DeckAction } from '@dxos/plugin-deck/types';\nimport { MarkdownCapabilities } from '@dxos/plugin-markdown';\nimport { fullyQualifiedId } from '@dxos/react-client/echo';\nimport { type EditorState, commentClickedEffect, commentsState, overlap } from '@dxos/react-ui-editor';\n\nimport { threads } from '../extensions';\n\nimport { ThreadCapabilities } from './capabilities';\n\nexport default (context: PluginContext) =>\n contributes(MarkdownCapabilities.Extensions, [\n ({ document: doc }) => {\n const { dispatchPromise: dispatch } = context.getCapability(Capabilities.IntentDispatcher);\n const { state } = context.getCapability(ThreadCapabilities.MutableState);\n return threads(state, doc, dispatch);\n },\n ({ document: doc }) => {\n const { state } = context.getCapability(ThreadCapabilities.MutableState);\n\n return EditorView.updateListener.of((update) => {\n if (update.docChanged || update.selectionSet) {\n state.toolbar[fullyQualifiedId(doc)] = selectionOverlapsComment(update.state);\n }\n });\n },\n ({ document: doc }) => {\n const { dispatchPromise: dispatch } = context.getCapability(Capabilities.IntentDispatcher);\n const id = fullyQualifiedId(doc);\n\n return EditorView.updateListener.of((update) => {\n update.transactions.forEach((transaction) => {\n transaction.effects.forEach(async (effect) => {\n if (effect.is(commentClickedEffect)) {\n void dispatch(\n createIntent(DeckAction.ChangeCompanion, {\n primary: id,\n companion: `${id}${ATTENDABLE_PATH_SEPARATOR}comments`,\n }),\n );\n }\n });\n });\n });\n },\n ]);\n\nconst selectionOverlapsComment = (state: EditorState): boolean => {\n // May not be defined if thread plugin not installed.\n const commentState = state.field(commentsState, false);\n if (commentState === undefined) {\n return false;\n }\n\n const { selection } = state;\n for (const range of selection.ranges) {\n if (commentState.comments.some(({ range: commentRange }) => overlap(commentRange, range))) {\n return true;\n }\n }\n\n return false;\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { type Extension } from '@codemirror/state';\nimport { EditorView } from '@codemirror/view';\nimport { computed, effect } from '@preact/signals-core';\n\nimport { type PromiseIntentDispatcher, createIntent } from '@dxos/app-framework';\nimport { Filter, Obj, Query, Relation } from '@dxos/echo';\nimport { type Markdown } from '@dxos/plugin-markdown/types';\nimport { createDocAccessor, fullyQualifiedId, getSource, getSpace, getTextInRange } from '@dxos/react-client/echo';\nimport { comments, createExternalCommentSync } from '@dxos/react-ui-editor';\nimport { AnchoredTo } from '@dxos/schema';\n\nimport { ThreadAction, type ThreadState, ThreadType } from '../types';\n\n// TODO(burdon): Factor out.\nconst getName = (doc: Markdown.Document, anchor: string): string | undefined => {\n if (doc.content) {\n const [start, end] = anchor.split(':');\n return getTextInRange(createDocAccessor(doc.content.target!, ['content']), start, end);\n }\n};\n\n/**\n * Construct plugins.\n */\nexport const threads = (state: ThreadState, doc?: Markdown.Document, dispatch?: PromiseIntentDispatcher): Extension => {\n const space = doc && getSpace(doc);\n if (!doc || !space || !dispatch) {\n // Include no-op comments extension here to ensure that the facets are always present when they are expected.\n // TODO(wittjosiah): The Editor should only look for these facets when comments are available.\n return [comments()];\n }\n\n const query = space.db.query(Query.select(Filter.ids(doc.id)).targetOf(AnchoredTo));\n const unsubscribe = query.subscribe();\n\n const anchors = computed(() =>\n query.objects\n .filter((anchor) => {\n const thread = Relation.getSource(anchor);\n return Obj.instanceOf(ThreadType, thread) && thread.status !== 'resolved';\n })\n .concat(state.drafts[fullyQualifiedId(doc)] ?? []),\n );\n\n return [\n EditorView.domEventHandlers({\n destroy: () => {\n unsubscribe();\n },\n }),\n\n EditorView.updateListener.of((update) => {\n if (update.docChanged) {\n anchors.value.forEach((anchor) => {\n if (anchor.anchor) {\n // Only update if the name has changed, otherwise this will cause an infinite loop.\n // Skip if the name is empty; this means comment text was deleted, but thread name should remain.\n const name = getName(doc, anchor.anchor);\n const thread = Relation.getSource(anchor) as ThreadType;\n if (name && name !== thread.name) {\n thread.name = name;\n }\n }\n });\n }\n }),\n\n createExternalCommentSync(\n fullyQualifiedId(doc),\n (sink) => effect(() => sink()),\n () =>\n anchors.value\n .filter((anchor) => anchor.anchor)\n .map((anchor) => ({ id: fullyQualifiedId(Relation.getSource(anchor)), cursor: anchor.anchor })),\n ),\n\n comments({\n id: fullyQualifiedId(doc),\n onCreate: ({ cursor }) => {\n const name = getName(doc, cursor);\n void dispatch(createIntent(ThreadAction.Create, { anchor: cursor, name, subject: doc }));\n },\n onDelete: ({ id }) => {\n const draft = state.drafts[fullyQualifiedId(doc)];\n if (draft) {\n const index = draft.findIndex((thread) => fullyQualifiedId(thread) === id);\n if (index !== -1) {\n draft.splice(index, 1);\n }\n }\n\n const thread = query.objects.find((object) => getSource(object).id === id);\n if (thread) {\n thread.anchor = undefined;\n }\n },\n onUpdate: ({ id, cursor }) => {\n const draft = state.drafts[fullyQualifiedId(doc)]?.find((thread) => fullyQualifiedId(thread) === id);\n if (draft) {\n const thread = Relation.getSource(draft) as ThreadType;\n thread.name = getName(doc, cursor);\n draft.anchor = cursor;\n }\n\n const relation = query.objects.find((object) => getSource(object).id === id);\n if (relation) {\n const thread = getSource(relation);\n if (Obj.instanceOf(ThreadType, thread)) {\n thread.name = getName(doc, cursor);\n relation.anchor = cursor;\n }\n }\n },\n onSelect: ({ selection }) => {\n const current = selection.current ?? selection.closest;\n if (current) {\n void dispatch(createIntent(ThreadAction.Select, { current }));\n }\n },\n }),\n ];\n};\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;AAIA,SAASA,cAAAA,mBAAkB;AAE3B,SAASC,cAAkCC,aAAaC,gBAAAA,qBAAoB;AAC5E,SAASC,2BAA2BC,kBAAkB;AACtD,SAASC,4BAA4B;AACrC,SAASC,oBAAAA,yBAAwB;AACjC,SAA2BC,sBAAsBC,eAAeC,eAAe;;;ACL/E,SAASC,kBAAkB;AAC3B,SAASC,UAAUC,cAAc;AAEjC,SAAuCC,oBAAoB;AAC3D,SAASC,QAAQC,KAAKC,OAAOC,gBAAgB;AAE7C,SAASC,mBAAmBC,kBAAkBC,WAAWC,UAAUC,sBAAsB;AACzF,SAASC,UAAUC,iCAAiC;AACpD,SAASC,kBAAkB;AAK3B,IAAMC,UAAU,CAACC,KAAwBC,WAAAA;AACvC,MAAID,IAAIE,SAAS;AACf,UAAM,CAACC,OAAOC,GAAAA,IAAOH,OAAOI,MAAM,GAAA;AAClC,WAAOC,eAAeC,kBAAkBP,IAAIE,QAAQM,QAAS;MAAC;KAAU,GAAGL,OAAOC,GAAAA;EACpF;AACF;AAKO,IAAMK,UAAU,CAACC,OAAoBV,KAAyBW,aAAAA;AACnE,QAAMC,QAAQZ,OAAOa,SAASb,GAAAA;AAC9B,MAAI,CAACA,OAAO,CAACY,SAAS,CAACD,UAAU;AAG/B,WAAO;MAACG,SAAAA;;EACV;AAEA,QAAMC,QAAQH,MAAMI,GAAGD,MAAME,MAAMC,OAAOC,OAAOC,IAAIpB,IAAIqB,EAAE,CAAA,EAAGC,SAASC,UAAAA,CAAAA;AACvE,QAAMC,cAAcT,MAAMU,UAAS;AAEnC,QAAMC,UAAUC,SAAS,MACvBZ,MAAMa,QACHC,OAAO,CAAC5B,WAAAA;AACP,UAAM6B,SAASC,SAASC,UAAU/B,MAAAA;AAClC,WAAOgC,IAAIC,WAAWC,YAAYL,MAAAA,KAAWA,OAAOM,WAAW;EACjE,CAAA,EACCC,OAAO3B,MAAM4B,OAAOC,iBAAiBvC,GAAAA,CAAAA,KAAS,CAAA,CAAE,CAAA;AAGrD,SAAO;IACLwC,WAAWC,iBAAiB;MAC1BC,SAAS,MAAA;AACPlB,oBAAAA;MACF;IACF,CAAA;IAEAgB,WAAWG,eAAeC,GAAG,CAACC,WAAAA;AAC5B,UAAIA,OAAOC,YAAY;AACrBpB,gBAAQqB,MAAMC,QAAQ,CAAC/C,WAAAA;AACrB,cAAIA,OAAOA,QAAQ;AAGjB,kBAAMgD,OAAOlD,QAAQC,KAAKC,OAAOA,MAAM;AACvC,kBAAM6B,SAASC,SAASC,UAAU/B,MAAAA;AAClC,gBAAIgD,QAAQA,SAASnB,OAAOmB,MAAM;AAChCnB,qBAAOmB,OAAOA;YAChB;UACF;QACF,CAAA;MACF;IACF,CAAA;IAEAC,0BACEX,iBAAiBvC,GAAAA,GACjB,CAACmD,SAASC,OAAO,MAAMD,KAAAA,CAAAA,GACvB,MACEzB,QAAQqB,MACLlB,OAAO,CAAC5B,WAAWA,OAAOA,MAAM,EAChCoD,IAAI,CAACpD,YAAY;MAAEoB,IAAIkB,iBAAiBR,SAASC,UAAU/B,MAAAA,CAAAA;MAAUqD,QAAQrD,OAAOA;IAAO,EAAA,CAAA;IAGlGa,SAAS;MACPO,IAAIkB,iBAAiBvC,GAAAA;MACrBuD,UAAU,CAAC,EAAED,OAAM,MAAE;AACnB,cAAML,OAAOlD,QAAQC,KAAKsD,MAAAA;AAC1B,aAAK3C,SAAS6C,aAAaC,aAAaC,QAAQ;UAAEzD,QAAQqD;UAAQL;UAAMU,SAAS3D;QAAI,CAAA,CAAA;MACvF;MACA4D,UAAU,CAAC,EAAEvC,GAAE,MAAE;AACf,cAAMwC,QAAQnD,MAAM4B,OAAOC,iBAAiBvC,GAAAA,CAAAA;AAC5C,YAAI6D,OAAO;AACT,gBAAMC,QAAQD,MAAME,UAAU,CAACjC,YAAWS,iBAAiBT,OAAAA,MAAYT,EAAAA;AACvE,cAAIyC,UAAU,IAAI;AAChBD,kBAAMG,OAAOF,OAAO,CAAA;UACtB;QACF;AAEA,cAAMhC,SAASf,MAAMa,QAAQqC,KAAK,CAACC,WAAWlC,UAAUkC,MAAAA,EAAQ7C,OAAOA,EAAAA;AACvE,YAAIS,QAAQ;AACVA,iBAAO7B,SAASkE;QAClB;MACF;MACAC,UAAU,CAAC,EAAE/C,IAAIiC,OAAM,MAAE;AACvB,cAAMO,QAAQnD,MAAM4B,OAAOC,iBAAiBvC,GAAAA,CAAAA,GAAOiE,KAAK,CAACnC,WAAWS,iBAAiBT,MAAAA,MAAYT,EAAAA;AACjG,YAAIwC,OAAO;AACT,gBAAM/B,SAASC,SAASC,UAAU6B,KAAAA;AAClC/B,iBAAOmB,OAAOlD,QAAQC,KAAKsD,MAAAA;AAC3BO,gBAAM5D,SAASqD;QACjB;AAEA,cAAMe,WAAWtD,MAAMa,QAAQqC,KAAK,CAACC,WAAWlC,UAAUkC,MAAAA,EAAQ7C,OAAOA,EAAAA;AACzE,YAAIgD,UAAU;AACZ,gBAAMvC,SAASE,UAAUqC,QAAAA;AACzB,cAAIpC,IAAIC,WAAWC,YAAYL,MAAAA,GAAS;AACtCA,mBAAOmB,OAAOlD,QAAQC,KAAKsD,MAAAA;AAC3Be,qBAASpE,SAASqD;UACpB;QACF;MACF;MACAgB,UAAU,CAAC,EAAEC,UAAS,MAAE;AACtB,cAAMC,UAAUD,UAAUC,WAAWD,UAAUE;AAC/C,YAAID,SAAS;AACX,eAAK7D,SAAS6C,aAAaC,aAAaiB,QAAQ;YAAEF;UAAQ,CAAA,CAAA;QAC5D;MACF;IACF,CAAA;;AAEJ;;;AD7GA,IAAA,mBAAe,CAACG,YACdC,YAAYC,qBAAqBC,YAAY;EAC3C,CAAC,EAAEC,UAAUC,IAAG,MAAE;AAChB,UAAM,EAAEC,iBAAiBC,SAAQ,IAAKP,QAAQQ,cAAcC,aAAaC,gBAAgB;AACzF,UAAM,EAAEC,MAAK,IAAKX,QAAQQ,cAAcI,mBAAmBC,YAAY;AACvE,WAAOC,QAAQH,OAAON,KAAKE,QAAAA;EAC7B;EACA,CAAC,EAAEH,UAAUC,IAAG,MAAE;AAChB,UAAM,EAAEM,MAAK,IAAKX,QAAQQ,cAAcI,mBAAmBC,YAAY;AAEvE,WAAOE,YAAWC,eAAeC,GAAG,CAACC,WAAAA;AACnC,UAAIA,OAAOC,cAAcD,OAAOE,cAAc;AAC5CT,cAAMU,QAAQC,kBAAiBjB,GAAAA,CAAAA,IAAQkB,yBAAyBL,OAAOP,KAAK;MAC9E;IACF,CAAA;EACF;EACA,CAAC,EAAEP,UAAUC,IAAG,MAAE;AAChB,UAAM,EAAEC,iBAAiBC,SAAQ,IAAKP,QAAQQ,cAAcC,aAAaC,gBAAgB;AACzF,UAAMc,KAAKF,kBAAiBjB,GAAAA;AAE5B,WAAOU,YAAWC,eAAeC,GAAG,CAACC,WAAAA;AACnCA,aAAOO,aAAaC,QAAQ,CAACC,gBAAAA;AAC3BA,oBAAYC,QAAQF,QAAQ,OAAOG,YAAAA;AACjC,cAAIA,QAAOC,GAAGC,oBAAAA,GAAuB;AACnC,iBAAKxB,SACHyB,cAAaC,WAAWC,iBAAiB;cACvCC,SAASX;cACTY,WAAW,GAAGZ,EAAAA,GAAKa,yBAAAA;YACrB,CAAA,CAAA;UAEJ;QACF,CAAA;MACF,CAAA;IACF,CAAA;EACF;CACD;AAEH,IAAMd,2BAA2B,CAACZ,UAAAA;AAEhC,QAAM2B,eAAe3B,MAAM4B,MAAMC,eAAe,KAAA;AAChD,MAAIF,iBAAiBG,QAAW;AAC9B,WAAO;EACT;AAEA,QAAM,EAAEC,UAAS,IAAK/B;AACtB,aAAWgC,SAASD,UAAUE,QAAQ;AACpC,QAAIN,aAAaO,SAASC,KAAK,CAAC,EAAEH,OAAOI,aAAY,MAAOC,QAAQD,cAAcJ,KAAAA,CAAAA,GAAS;AACzF,aAAO;IACT;EACF;AAEA,SAAO;AACT;",
|
|
6
|
-
"names": ["EditorView", "Capabilities", "contributes", "createIntent", "ATTENDABLE_PATH_SEPARATOR", "DeckAction", "MarkdownCapabilities", "fullyQualifiedId", "commentClickedEffect", "commentsState", "overlap", "EditorView", "computed", "effect", "createIntent", "Filter", "Obj", "Query", "Relation", "createDocAccessor", "fullyQualifiedId", "getSource", "getSpace", "getTextInRange", "comments", "createExternalCommentSync", "AnchoredTo", "getName", "doc", "anchor", "content", "start", "end", "split", "getTextInRange", "createDocAccessor", "target", "threads", "state", "dispatch", "space", "getSpace", "comments", "query", "db", "Query", "select", "Filter", "ids", "id", "targetOf", "AnchoredTo", "unsubscribe", "subscribe", "anchors", "computed", "objects", "filter", "thread", "Relation", "getSource", "Obj", "instanceOf", "ThreadType", "status", "concat", "drafts", "fullyQualifiedId", "EditorView", "domEventHandlers", "destroy", "updateListener", "of", "update", "docChanged", "value", "forEach", "name", "createExternalCommentSync", "sink", "effect", "map", "cursor", "onCreate", "createIntent", "ThreadAction", "Create", "subject", "onDelete", "draft", "index", "findIndex", "splice", "find", "object", "undefined", "onUpdate", "relation", "onSelect", "selection", "current", "closest", "Select", "context", "contributes", "MarkdownCapabilities", "Extensions", "document", "doc", "dispatchPromise", "dispatch", "getCapability", "Capabilities", "IntentDispatcher", "state", "ThreadCapabilities", "MutableState", "threads", "EditorView", "updateListener", "of", "update", "docChanged", "selectionSet", "toolbar", "fullyQualifiedId", "selectionOverlapsComment", "id", "transactions", "forEach", "transaction", "effects", "effect", "is", "commentClickedEffect", "createIntent", "DeckAction", "ChangeCompanion", "primary", "companion", "ATTENDABLE_PATH_SEPARATOR", "commentState", "field", "commentsState", "undefined", "selection", "range", "ranges", "comments", "some", "commentRange", "overlap"]
|
|
7
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
|
|
2
|
-
import "./chunk-LE2LIYGX.mjs";
|
|
3
|
-
import "./chunk-P6E247RF.mjs";
|
|
4
|
-
import {
|
|
5
|
-
Call
|
|
6
|
-
} from "./chunk-SNKFZQST.mjs";
|
|
7
|
-
import "./chunk-4T45PCKP.mjs";
|
|
8
|
-
import "./chunk-PYTVBN5J.mjs";
|
|
9
|
-
import "./chunk-DKCQCENK.mjs";
|
|
10
|
-
import "./chunk-JNPKMT7O.mjs";
|
|
11
|
-
import "./chunk-57XR3LEF.mjs";
|
|
12
|
-
import "./chunk-2V3WSLUZ.mjs";
|
|
13
|
-
import {
|
|
14
|
-
THREAD_PLUGIN
|
|
15
|
-
} from "./chunk-GRLRWTRU.mjs";
|
|
16
|
-
|
|
17
|
-
// src/capabilities/react-root.tsx
|
|
18
|
-
import React from "react";
|
|
19
|
-
import { Capabilities, contributes } from "@dxos/app-framework";
|
|
20
|
-
var react_root_default = () => {
|
|
21
|
-
return contributes(Capabilities.ReactRoot, {
|
|
22
|
-
id: THREAD_PLUGIN,
|
|
23
|
-
root: () => /* @__PURE__ */ React.createElement(Call.Audio, null)
|
|
24
|
-
});
|
|
25
|
-
};
|
|
26
|
-
export {
|
|
27
|
-
react_root_default as default
|
|
28
|
-
};
|
|
29
|
-
//# sourceMappingURL=react-root-4JWDRIQB.mjs.map
|