@dxos/plugin-thread 0.8.4-main.abd8ff62ef → 0.8.4-main.bc2380dfbc
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/LICENSE +102 -5
- package/README.md +1 -1
- package/dist/lib/neutral/ChannelArticle-ACZD7YFT.mjs +28 -0
- package/dist/lib/neutral/ChannelArticle-ACZD7YFT.mjs.map +7 -0
- package/dist/lib/neutral/ChannelChat-6YTD5HWL.mjs +10 -0
- package/dist/lib/neutral/ThreadCompanion-NQWPS2H6.mjs +208 -0
- package/dist/lib/neutral/ThreadCompanion-NQWPS2H6.mjs.map +7 -0
- package/dist/lib/neutral/ThreadContainer-XYEPEOSD.mjs +61 -0
- package/dist/lib/neutral/ThreadContainer-XYEPEOSD.mjs.map +7 -0
- package/dist/lib/neutral/ThreadPlugin.mjs +80 -0
- package/dist/lib/neutral/ThreadPlugin.mjs.map +7 -0
- package/dist/lib/neutral/ThreadPlugin.node.mjs +40 -0
- package/dist/lib/neutral/ThreadPlugin.node.mjs.map +7 -0
- package/dist/lib/neutral/ThreadPlugin.workerd.mjs +24 -0
- package/dist/lib/neutral/ThreadPlugin.workerd.mjs.map +7 -0
- package/dist/lib/neutral/ThreadSettings-5MKTDK3A.mjs +15 -0
- package/dist/lib/neutral/ThreadSettings-5MKTDK3A.mjs.map +7 -0
- package/dist/lib/{browser/add-message-LRVGIHDH.mjs → neutral/add-message-FBIROBEZ.mjs} +8 -10
- package/dist/lib/neutral/add-message-FBIROBEZ.mjs.map +7 -0
- package/dist/lib/neutral/app-graph-builder-7Q6MA6RT.mjs +120 -0
- package/dist/lib/neutral/app-graph-builder-7Q6MA6RT.mjs.map +7 -0
- package/dist/lib/{browser/append-channel-message-CO3M6FSA.mjs → neutral/append-channel-message-FTFAD3PK.mjs} +5 -5
- package/dist/lib/neutral/append-channel-message-FTFAD3PK.mjs.map +7 -0
- package/dist/lib/neutral/blueprint-definition-S3EBOH4R.mjs +15 -0
- package/dist/lib/neutral/blueprint-definition-S3EBOH4R.mjs.map +7 -0
- package/dist/lib/neutral/blueprints/index.mjs +8 -0
- package/dist/lib/neutral/capabilities/index.mjs +25 -0
- package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
- package/dist/lib/{browser/blueprints/index.mjs → neutral/chunk-5T5LPLBN.mjs} +4 -5
- package/dist/lib/neutral/chunk-5T5LPLBN.mjs.map +7 -0
- package/dist/lib/neutral/chunk-7GHUS3IX.mjs +20 -0
- package/dist/lib/neutral/chunk-7GHUS3IX.mjs.map +7 -0
- package/dist/lib/neutral/chunk-D5LGFCUY.mjs +55 -0
- package/dist/lib/neutral/chunk-D5LGFCUY.mjs.map +7 -0
- package/dist/lib/neutral/chunk-JLY4NVTA.mjs +38 -0
- package/dist/lib/neutral/chunk-JLY4NVTA.mjs.map +7 -0
- package/dist/lib/neutral/chunk-KRXHIW4P.mjs +164 -0
- package/dist/lib/neutral/chunk-KRXHIW4P.mjs.map +7 -0
- package/dist/lib/{browser/chunk-TPNZ43NB.mjs → neutral/chunk-PE7IH7EL.mjs} +86 -73
- package/dist/lib/neutral/chunk-PE7IH7EL.mjs.map +7 -0
- package/dist/lib/neutral/chunk-QFDT33VT.mjs +69 -0
- package/dist/lib/neutral/chunk-QFDT33VT.mjs.map +7 -0
- package/dist/lib/neutral/chunk-QMLVLKE3.mjs +8 -0
- package/dist/lib/neutral/chunk-QMLVLKE3.mjs.map +7 -0
- package/dist/lib/neutral/components/index.mjs +539 -0
- package/dist/lib/neutral/components/index.mjs.map +7 -0
- package/dist/lib/neutral/containers/index.mjs +15 -0
- package/dist/lib/neutral/containers/index.mjs.map +7 -0
- package/dist/lib/{browser/create-BTGLHLBA.mjs → neutral/create-OAQJ6LXN.mjs} +7 -10
- package/dist/lib/neutral/create-OAQJ6LXN.mjs.map +7 -0
- package/dist/lib/{browser/create-channel-ZXKSLHGN.mjs → neutral/create-channel-3E4FJ662.mjs} +4 -4
- package/dist/lib/neutral/create-channel-3E4FJ662.mjs.map +7 -0
- package/dist/lib/neutral/create-object-HIEWSBZB.mjs +27 -0
- package/dist/lib/neutral/create-object-HIEWSBZB.mjs.map +7 -0
- package/dist/lib/{browser/create-proposals-AV5CREPV.mjs → neutral/create-proposals-GRYZXRMV.mjs} +4 -4
- package/dist/lib/neutral/create-proposals-GRYZXRMV.mjs.map +7 -0
- package/dist/lib/{browser/delete-GLYEP7NE.mjs → neutral/delete-HCCG5RVR.mjs} +7 -9
- package/dist/lib/neutral/delete-HCCG5RVR.mjs.map +7 -0
- package/dist/lib/{browser/delete-message-RQ72ZY5D.mjs → neutral/delete-message-DHFRACB4.mjs} +6 -7
- package/dist/lib/neutral/delete-message-DHFRACB4.mjs.map +7 -0
- package/dist/lib/neutral/hooks/index.mjs +10 -0
- package/dist/lib/neutral/index.mjs +28 -0
- package/dist/lib/neutral/index.mjs.map +7 -0
- package/dist/lib/neutral/markdown-BUORNCPG.mjs +83 -0
- package/dist/lib/neutral/markdown-BUORNCPG.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/lib/neutral/meta.mjs +10 -0
- package/dist/lib/neutral/meta.mjs.map +7 -0
- package/dist/lib/{browser/on-create-space-SPE3QVFZ.mjs → neutral/on-create-space-OEBRKOAM.mjs} +5 -6
- package/dist/lib/neutral/on-create-space-OEBRKOAM.mjs.map +7 -0
- package/dist/lib/neutral/operation-handler-RU6K2S4L.mjs +13 -0
- package/dist/lib/neutral/operation-handler-RU6K2S4L.mjs.map +7 -0
- package/dist/lib/neutral/operations/index.mjs +8 -0
- package/dist/lib/neutral/operations/index.mjs.map +7 -0
- package/dist/lib/neutral/plugin.mjs +16 -0
- package/dist/lib/neutral/plugin.mjs.map +7 -0
- package/dist/lib/neutral/react-surface-XY23GVZH.mjs +76 -0
- package/dist/lib/neutral/react-surface-XY23GVZH.mjs.map +7 -0
- package/dist/lib/{browser/restore-VX7FLZOZ.mjs → neutral/restore-P4ZLXLF7.mjs} +5 -5
- package/dist/lib/neutral/restore-P4ZLXLF7.mjs.map +7 -0
- package/dist/lib/{browser/restore-message-D65NSWUA.mjs → neutral/restore-message-AUBOP2DF.mjs} +5 -5
- package/dist/lib/neutral/restore-message-AUBOP2DF.mjs.map +7 -0
- package/dist/lib/{browser/select-AT4L7EBU.mjs → neutral/select-LIVAMBCE.mjs} +6 -8
- package/dist/lib/neutral/select-LIVAMBCE.mjs.map +7 -0
- package/dist/lib/neutral/settings-HK4EB6TF.mjs +30 -0
- package/dist/lib/neutral/settings-HK4EB6TF.mjs.map +7 -0
- package/dist/lib/neutral/state-UU7VEAKV.mjs +22 -0
- package/dist/lib/neutral/state-UU7VEAKV.mjs.map +7 -0
- package/dist/lib/neutral/testing/index.mjs +58 -0
- package/dist/lib/neutral/testing/index.mjs.map +7 -0
- package/dist/lib/{browser/toggle-resolved-JD3D4WBZ.mjs → neutral/toggle-resolved-RQBDQZSV.mjs} +5 -5
- package/dist/lib/neutral/toggle-resolved-RQBDQZSV.mjs.map +7 -0
- package/dist/lib/{browser → neutral}/translations.mjs +2 -2
- package/dist/lib/neutral/translations.mjs.map +7 -0
- package/dist/lib/neutral/types/index.mjs +12 -0
- package/dist/lib/neutral/types/index.mjs.map +7 -0
- package/dist/lib/neutral/undo-mappings-HOKL2L3M.mjs +54 -0
- package/dist/lib/neutral/undo-mappings-HOKL2L3M.mjs.map +7 -0
- package/dist/types/src/ThreadPlugin.d.ts.map +1 -1
- package/dist/types/src/ThreadPlugin.node.d.ts.map +1 -1
- package/dist/types/src/ThreadPlugin.workerd.d.ts +4 -0
- package/dist/types/src/ThreadPlugin.workerd.d.ts.map +1 -0
- package/dist/types/src/capabilities/create-object.d.ts +11 -0
- package/dist/types/src/capabilities/create-object.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +7 -6
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/markdown.d.ts +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/capabilities/settings.d.ts.map +1 -1
- package/dist/types/src/components/Chat/Chat.d.ts +8 -1
- package/dist/types/src/components/Chat/Chat.d.ts.map +1 -1
- package/dist/types/src/components/CommentsPanel/CommentsThread.d.ts.map +1 -1
- package/dist/types/src/components/MessagePanel/MessagePanel.d.ts.map +1 -1
- package/dist/types/src/components/ThreadSettings/ThreadSettings.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +0 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/containers/ChannelArticle/ChannelArticle.d.ts +13 -0
- package/dist/types/src/containers/ChannelArticle/ChannelArticle.d.ts.map +1 -0
- package/dist/types/src/containers/{ChannelContainer/ChannelContainer.stories.d.ts → ChannelArticle/ChannelArticle.stories.d.ts} +4 -4
- package/dist/types/src/containers/ChannelArticle/ChannelArticle.stories.d.ts.map +1 -0
- package/dist/types/src/containers/ChannelArticle/index.d.ts +2 -0
- package/dist/types/src/containers/{CallDebugPanel → ChannelArticle}/index.d.ts.map +1 -1
- package/dist/types/src/containers/ChannelChat/ChannelChat.d.ts +4 -0
- package/dist/types/src/containers/ChannelChat/ChannelChat.d.ts.map +1 -1
- package/dist/types/src/containers/ThreadCompanion/ThreadCompanion.d.ts.map +1 -1
- package/dist/types/src/containers/index.d.ts +1 -3
- package/dist/types/src/containers/index.d.ts.map +1 -1
- package/dist/types/src/extensions/threads.d.ts +1 -1
- package/dist/types/src/extensions/threads.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +0 -4
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +3 -5
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/operations/add-message.d.ts +2 -2
- package/dist/types/src/operations/add-message.d.ts.map +1 -1
- package/dist/types/src/operations/append-channel-message.d.ts +2 -2
- package/dist/types/src/operations/append-channel-message.d.ts.map +1 -1
- package/dist/types/src/operations/create-channel.d.ts +2 -2
- package/dist/types/src/operations/create-channel.d.ts.map +1 -1
- package/dist/types/src/operations/create-proposals.d.ts +2 -2
- package/dist/types/src/operations/create-proposals.d.ts.map +1 -1
- package/dist/types/src/operations/create.d.ts +2 -2
- package/dist/types/src/operations/create.d.ts.map +1 -1
- package/dist/types/src/operations/delete-message.d.ts +2 -2
- package/dist/types/src/operations/delete-message.d.ts.map +1 -1
- package/dist/types/src/operations/delete.d.ts +2 -2
- package/dist/types/src/operations/delete.d.ts.map +1 -1
- package/dist/types/src/operations/index.d.ts +0 -1
- package/dist/types/src/operations/index.d.ts.map +1 -1
- package/dist/types/src/operations/on-create-space.d.ts +2 -2
- package/dist/types/src/operations/on-create-space.d.ts.map +1 -1
- package/dist/types/src/operations/restore-message.d.ts +2 -2
- package/dist/types/src/operations/restore-message.d.ts.map +1 -1
- package/dist/types/src/operations/restore.d.ts +2 -2
- package/dist/types/src/operations/restore.d.ts.map +1 -1
- package/dist/types/src/operations/select.d.ts +2 -2
- package/dist/types/src/operations/select.d.ts.map +1 -1
- package/dist/types/src/operations/toggle-resolved.d.ts +2 -2
- package/dist/types/src/operations/toggle-resolved.d.ts.map +1 -1
- package/dist/types/src/plugin.d.ts +4 -0
- package/dist/types/src/plugin.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/ThreadCapabilities.d.ts +13 -0
- package/dist/types/src/types/ThreadCapabilities.d.ts.map +1 -0
- package/dist/types/src/{operations/definitions.d.ts → types/ThreadOperation.d.ts} +1 -1
- package/dist/types/src/types/ThreadOperation.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +3 -1
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/src/types/types.d.ts +1 -1
- package/dist/types/src/types/types.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +4 -1
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +123 -99
- package/src/ThreadPlugin.node.ts +5 -50
- package/src/ThreadPlugin.test.ts +3 -3
- package/src/ThreadPlugin.tsx +6 -59
- package/src/ThreadPlugin.workerd.ts +20 -0
- package/src/blueprints/thread-blueprint.ts +1 -1
- package/src/capabilities/app-graph-builder.ts +18 -69
- package/src/capabilities/create-object.ts +29 -0
- package/src/capabilities/index.ts +1 -2
- package/src/capabilities/markdown.ts +1 -1
- package/src/capabilities/react-surface.tsx +4 -26
- package/src/capabilities/settings.ts +1 -3
- package/src/capabilities/undo-mappings.ts +1 -1
- package/src/components/Chat/Chat.tsx +52 -12
- package/src/components/CommentsPanel/CommentsPanel.stories.tsx +1 -1
- package/src/components/CommentsPanel/CommentsPanel.tsx +4 -4
- package/src/components/CommentsPanel/CommentsThread.tsx +2 -3
- package/src/components/MessagePanel/MessagePanel.tsx +7 -8
- package/src/components/ThreadSettings/ThreadSettings.tsx +0 -1
- package/src/components/index.ts +0 -1
- package/src/containers/{ChannelContainer/ChannelContainer.stories.tsx → ChannelArticle/ChannelArticle.stories.tsx} +10 -10
- package/src/containers/ChannelArticle/ChannelArticle.tsx +42 -0
- package/src/containers/ChannelArticle/index.ts +5 -0
- package/src/containers/ChannelChat/ChannelChat.tsx +12 -2
- package/src/containers/ThreadCompanion/ThreadCompanion.tsx +10 -12
- package/src/containers/index.ts +1 -3
- package/src/extensions/command.ts +1 -1
- package/src/extensions/threads.ts +2 -2
- package/src/hooks/analytics.ts +1 -1
- package/src/hooks/index.ts +0 -5
- package/src/index.ts +3 -10
- package/src/meta.ts +1 -2
- package/src/operations/add-message.ts +4 -4
- package/src/operations/append-channel-message.ts +20 -19
- package/src/operations/create-channel.ts +2 -2
- package/src/operations/create-proposals.ts +2 -2
- package/src/operations/create.ts +3 -3
- package/src/operations/delete-message.ts +4 -4
- package/src/operations/delete.ts +3 -3
- package/src/operations/index.ts +0 -2
- package/src/operations/on-create-space.ts +3 -3
- package/src/operations/restore-message.ts +3 -3
- package/src/operations/restore.ts +3 -3
- package/src/operations/select.ts +2 -2
- package/src/operations/toggle-resolved.ts +3 -3
- package/src/plugin.ts +11 -0
- package/src/translations.ts +2 -2
- package/src/types/ThreadCapabilities.ts +26 -0
- package/src/{operations/definitions.ts → types/ThreadOperation.ts} +5 -4
- package/src/types/index.ts +4 -1
- package/src/types/types.ts +0 -2
- package/src/util.ts +36 -4
- package/dist/lib/browser/add-message-LRVGIHDH.mjs.map +0 -7
- package/dist/lib/browser/append-channel-message-CO3M6FSA.mjs.map +0 -7
- package/dist/lib/browser/blueprints/index.mjs.map +0 -7
- package/dist/lib/browser/chunk-E4GG3NX2.mjs +0 -29
- package/dist/lib/browser/chunk-E4GG3NX2.mjs.map +0 -7
- package/dist/lib/browser/chunk-TPNZ43NB.mjs.map +0 -7
- package/dist/lib/browser/create-BTGLHLBA.mjs.map +0 -7
- package/dist/lib/browser/create-channel-ZXKSLHGN.mjs.map +0 -7
- package/dist/lib/browser/create-proposals-AV5CREPV.mjs.map +0 -7
- package/dist/lib/browser/delete-GLYEP7NE.mjs.map +0 -7
- package/dist/lib/browser/delete-message-RQ72ZY5D.mjs.map +0 -7
- package/dist/lib/browser/index.mjs +0 -1821
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/on-create-space-SPE3QVFZ.mjs.map +0 -7
- package/dist/lib/browser/operations/index.mjs +0 -13
- package/dist/lib/browser/operations/index.mjs.map +0 -7
- package/dist/lib/browser/restore-VX7FLZOZ.mjs.map +0 -7
- package/dist/lib/browser/restore-message-D65NSWUA.mjs.map +0 -7
- package/dist/lib/browser/select-AT4L7EBU.mjs.map +0 -7
- package/dist/lib/browser/toggle-resolved-JD3D4WBZ.mjs.map +0 -7
- package/dist/lib/browser/translations.mjs.map +0 -7
- package/dist/lib/browser/types/index.mjs +0 -10
- package/dist/lib/node-esm/add-message-4EAQ2ZPI.mjs +0 -90
- package/dist/lib/node-esm/add-message-4EAQ2ZPI.mjs.map +0 -7
- package/dist/lib/node-esm/append-channel-message-F7KGBSWP.mjs +0 -41
- package/dist/lib/node-esm/append-channel-message-F7KGBSWP.mjs.map +0 -7
- package/dist/lib/node-esm/blueprints/index.mjs +0 -38
- package/dist/lib/node-esm/blueprints/index.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-BVEZBGIY.mjs +0 -30
- package/dist/lib/node-esm/chunk-BVEZBGIY.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +0 -11
- package/dist/lib/node-esm/chunk-XKUMDYGR.mjs +0 -259
- package/dist/lib/node-esm/chunk-XKUMDYGR.mjs.map +0 -7
- package/dist/lib/node-esm/create-DEZFPN2Y.mjs +0 -56
- package/dist/lib/node-esm/create-DEZFPN2Y.mjs.map +0 -7
- package/dist/lib/node-esm/create-channel-6VHTC2OR.mjs +0 -20
- package/dist/lib/node-esm/create-channel-6VHTC2OR.mjs.map +0 -7
- package/dist/lib/node-esm/create-proposals-P5O2ICOL.mjs +0 -57
- package/dist/lib/node-esm/create-proposals-P5O2ICOL.mjs.map +0 -7
- package/dist/lib/node-esm/delete-QG45QLPY.mjs +0 -60
- package/dist/lib/node-esm/delete-QG45QLPY.mjs.map +0 -7
- package/dist/lib/node-esm/delete-message-PGNLB6TL.mjs +0 -56
- package/dist/lib/node-esm/delete-message-PGNLB6TL.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -1822
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/on-create-space-TFBSHWQ4.mjs +0 -25
- package/dist/lib/node-esm/on-create-space-TFBSHWQ4.mjs.map +0 -7
- package/dist/lib/node-esm/operations/index.mjs +0 -14
- package/dist/lib/node-esm/operations/index.mjs.map +0 -7
- package/dist/lib/node-esm/restore-E27OAIFJ.mjs +0 -33
- package/dist/lib/node-esm/restore-E27OAIFJ.mjs.map +0 -7
- package/dist/lib/node-esm/restore-message-J3CH6NGI.mjs +0 -34
- package/dist/lib/node-esm/restore-message-J3CH6NGI.mjs.map +0 -7
- package/dist/lib/node-esm/select-UU6Q2XAB.mjs +0 -27
- package/dist/lib/node-esm/select-UU6Q2XAB.mjs.map +0 -7
- package/dist/lib/node-esm/toggle-resolved-VS6NKXL3.mjs +0 -37
- package/dist/lib/node-esm/toggle-resolved-VS6NKXL3.mjs.map +0 -7
- package/dist/lib/node-esm/translations.mjs +0 -91
- package/dist/lib/node-esm/translations.mjs.map +0 -7
- package/dist/lib/node-esm/types/index.mjs +0 -11
- package/dist/types/src/calls/call-manager.d.ts +0 -87
- package/dist/types/src/calls/call-manager.d.ts.map +0 -1
- package/dist/types/src/calls/call-swarm-synchronizer.d.ts +0 -66
- package/dist/types/src/calls/call-swarm-synchronizer.d.ts.map +0 -1
- package/dist/types/src/calls/index.d.ts +0 -7
- package/dist/types/src/calls/index.d.ts.map +0 -1
- package/dist/types/src/calls/media-manager.d.ts +0 -60
- package/dist/types/src/calls/media-manager.d.ts.map +0 -1
- package/dist/types/src/calls/speaking-monitor.d.ts +0 -21
- package/dist/types/src/calls/speaking-monitor.d.ts.map +0 -1
- package/dist/types/src/calls/types.d.ts +0 -45
- package/dist/types/src/calls/types.d.ts.map +0 -1
- package/dist/types/src/calls/util/audio.d.ts +0 -6
- package/dist/types/src/calls/util/audio.d.ts.map +0 -1
- package/dist/types/src/calls/util/calls-service.d.ts +0 -77
- package/dist/types/src/calls/util/calls-service.d.ts.map +0 -1
- package/dist/types/src/calls/util/history-cache.d.ts +0 -11
- package/dist/types/src/calls/util/history-cache.d.ts.map +0 -1
- package/dist/types/src/calls/util/index.d.ts +0 -5
- package/dist/types/src/calls/util/index.d.ts.map +0 -1
- package/dist/types/src/calls/util/media.d.ts +0 -6
- package/dist/types/src/calls/util/media.d.ts.map +0 -1
- package/dist/types/src/calls/util/stub-media-streams.d.ts +0 -18
- package/dist/types/src/calls/util/stub-media-streams.d.ts.map +0 -1
- package/dist/types/src/calls/util/task-scheduling.d.ts +0 -17
- package/dist/types/src/calls/util/task-scheduling.d.ts.map +0 -1
- package/dist/types/src/calls-service.stories.d.ts +0 -23
- package/dist/types/src/calls-service.stories.d.ts.map +0 -1
- package/dist/types/src/capabilities/call-manager.d.ts +0 -6
- package/dist/types/src/capabilities/call-manager.d.ts.map +0 -1
- package/dist/types/src/capabilities/react-root.d.ts +0 -9
- package/dist/types/src/capabilities/react-root.d.ts.map +0 -1
- package/dist/types/src/components/Call/Call.d.ts +0 -45
- package/dist/types/src/components/Call/Call.d.ts.map +0 -1
- package/dist/types/src/components/Call/Toolbar.d.ts +0 -16
- package/dist/types/src/components/Call/Toolbar.d.ts.map +0 -1
- package/dist/types/src/components/Call/index.d.ts +0 -3
- package/dist/types/src/components/Call/index.d.ts.map +0 -1
- package/dist/types/src/components/Lobby/Lobby.d.ts +0 -36
- package/dist/types/src/components/Lobby/Lobby.d.ts.map +0 -1
- package/dist/types/src/components/Lobby/index.d.ts +0 -2
- package/dist/types/src/components/Lobby/index.d.ts.map +0 -1
- package/dist/types/src/components/Media/AudioStream.d.ts +0 -6
- package/dist/types/src/components/Media/AudioStream.d.ts.map +0 -1
- package/dist/types/src/components/Media/VideoObject.d.ts +0 -15
- package/dist/types/src/components/Media/VideoObject.d.ts.map +0 -1
- package/dist/types/src/components/Media/VideoObject.stories.d.ts +0 -22
- package/dist/types/src/components/Media/VideoObject.stories.d.ts.map +0 -1
- package/dist/types/src/components/Media/index.d.ts +0 -3
- package/dist/types/src/components/Media/index.d.ts.map +0 -1
- package/dist/types/src/components/Participant/Participant.d.ts +0 -6
- package/dist/types/src/components/Participant/Participant.d.ts.map +0 -1
- package/dist/types/src/components/Participant/ParticipantGrid.d.ts +0 -11
- package/dist/types/src/components/Participant/ParticipantGrid.d.ts.map +0 -1
- package/dist/types/src/components/Participant/index.d.ts +0 -3
- package/dist/types/src/components/Participant/index.d.ts.map +0 -1
- package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.d.ts +0 -32
- package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.d.ts.map +0 -1
- package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts +0 -178
- package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts.map +0 -1
- package/dist/types/src/components/ResponsiveGrid/ResponsiveGridItem.d.ts +0 -21
- package/dist/types/src/components/ResponsiveGrid/ResponsiveGridItem.d.ts.map +0 -1
- package/dist/types/src/components/ResponsiveGrid/ResponsivePanel.d.ts +0 -12
- package/dist/types/src/components/ResponsiveGrid/ResponsivePanel.d.ts.map +0 -1
- package/dist/types/src/components/ResponsiveGrid/ResponsivePanel.stories.d.ts +0 -164
- package/dist/types/src/components/ResponsiveGrid/ResponsivePanel.stories.d.ts.map +0 -1
- package/dist/types/src/components/ResponsiveGrid/index.d.ts +0 -4
- package/dist/types/src/components/ResponsiveGrid/index.d.ts.map +0 -1
- package/dist/types/src/containers/CallDebugPanel/CallDebugPanel.d.ts +0 -15
- package/dist/types/src/containers/CallDebugPanel/CallDebugPanel.d.ts.map +0 -1
- package/dist/types/src/containers/CallDebugPanel/index.d.ts +0 -2
- package/dist/types/src/containers/CallSidebar/CallSidebar.d.ts +0 -3
- package/dist/types/src/containers/CallSidebar/CallSidebar.d.ts.map +0 -1
- package/dist/types/src/containers/CallSidebar/index.d.ts +0 -2
- package/dist/types/src/containers/CallSidebar/index.d.ts.map +0 -1
- package/dist/types/src/containers/ChannelContainer/ChannelContainer.d.ts +0 -12
- package/dist/types/src/containers/ChannelContainer/ChannelContainer.d.ts.map +0 -1
- package/dist/types/src/containers/ChannelContainer/ChannelContainer.stories.d.ts.map +0 -1
- package/dist/types/src/containers/ChannelContainer/index.d.ts +0 -2
- package/dist/types/src/containers/ChannelContainer/index.d.ts.map +0 -1
- package/dist/types/src/hooks/useBlackCanvasStreamTrack.d.ts +0 -2
- package/dist/types/src/hooks/useBlackCanvasStreamTrack.d.ts.map +0 -1
- package/dist/types/src/hooks/useDebugMode.d.ts +0 -2
- package/dist/types/src/hooks/useDebugMode.d.ts.map +0 -1
- package/dist/types/src/hooks/useInaudibleAudioStreamTrack.d.ts +0 -2
- package/dist/types/src/hooks/useInaudibleAudioStreamTrack.d.ts.map +0 -1
- package/dist/types/src/hooks/useVideoStreamTrack.d.ts +0 -3
- package/dist/types/src/hooks/useVideoStreamTrack.d.ts.map +0 -1
- package/dist/types/src/operations/definitions.d.ts.map +0 -1
- package/dist/types/src/types/capabilities.d.ts +0 -25
- package/dist/types/src/types/capabilities.d.ts.map +0 -1
- package/src/calls/call-manager.ts +0 -270
- package/src/calls/call-swarm-synchronizer.ts +0 -350
- package/src/calls/index.ts +0 -10
- package/src/calls/media-manager.ts +0 -378
- package/src/calls/speaking-monitor.ts +0 -85
- package/src/calls/types.ts +0 -74
- package/src/calls/util/audio.ts +0 -58
- package/src/calls/util/calls-service.ts +0 -582
- package/src/calls/util/history-cache.ts +0 -27
- package/src/calls/util/index.ts +0 -8
- package/src/calls/util/media.ts +0 -52
- package/src/calls/util/stub-media-streams.ts +0 -129
- package/src/calls/util/task-scheduling.ts +0 -92
- package/src/calls-service.stories.tsx +0 -230
- package/src/capabilities/call-manager.ts +0 -27
- package/src/capabilities/react-root.tsx +0 -20
- package/src/components/Call/Call.tsx +0 -93
- package/src/components/Call/Toolbar.tsx +0 -199
- package/src/components/Call/index.ts +0 -6
- package/src/components/Lobby/Lobby.tsx +0 -123
- package/src/components/Lobby/index.ts +0 -5
- package/src/components/Media/AudioStream.tsx +0 -67
- package/src/components/Media/VideoObject.stories.tsx +0 -59
- package/src/components/Media/VideoObject.tsx +0 -58
- package/src/components/Media/index.ts +0 -6
- package/src/components/Participant/Participant.tsx +0 -77
- package/src/components/Participant/ParticipantGrid.tsx +0 -88
- package/src/components/Participant/index.ts +0 -6
- package/src/components/ResponsiveGrid/ResponsiveGrid.stories.tsx +0 -158
- package/src/components/ResponsiveGrid/ResponsiveGrid.tsx +0 -341
- package/src/components/ResponsiveGrid/ResponsiveGridItem.tsx +0 -134
- package/src/components/ResponsiveGrid/ResponsivePanel.stories.tsx +0 -54
- package/src/components/ResponsiveGrid/ResponsivePanel.tsx +0 -31
- package/src/components/ResponsiveGrid/index.ts +0 -7
- package/src/containers/CallDebugPanel/CallDebugPanel.tsx +0 -173
- package/src/containers/CallDebugPanel/index.ts +0 -5
- package/src/containers/CallSidebar/CallSidebar.tsx +0 -18
- package/src/containers/CallSidebar/index.ts +0 -5
- package/src/containers/ChannelContainer/ChannelContainer.tsx +0 -223
- package/src/containers/ChannelContainer/index.ts +0 -5
- package/src/hooks/useBlackCanvasStreamTrack.tsx +0 -27
- package/src/hooks/useDebugMode.ts +0 -25
- package/src/hooks/useInaudibleAudioStreamTrack.tsx +0 -27
- package/src/hooks/useVideoStreamTrack.tsx +0 -36
- package/src/types/capabilities.ts +0 -37
- package/src/typings/peermetrics-webrtc-stats.d.ts +0 -46
- package/src/typings.d.ts +0 -8
- /package/dist/lib/{browser/chunk-J5LGTIGS.mjs.map → neutral/ChannelChat-6YTD5HWL.mjs.map} +0 -0
- /package/dist/lib/{browser/types → neutral/blueprints}/index.mjs.map +0 -0
- /package/dist/lib/{browser → neutral}/chunk-J5LGTIGS.mjs +0 -0
- /package/dist/lib/{node-esm/chunk-HSLMI22Q.mjs.map → neutral/chunk-J5LGTIGS.mjs.map} +0 -0
- /package/dist/lib/{node-esm/types → neutral/hooks}/index.mjs.map +0 -0
|
@@ -1,582 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2024 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { PersistentLifecycle, Trigger, scheduleTask } from '@dxos/async';
|
|
6
|
-
import { type Context, Resource } from '@dxos/context';
|
|
7
|
-
import { invariant } from '@dxos/invariant';
|
|
8
|
-
import { log } from '@dxos/log';
|
|
9
|
-
|
|
10
|
-
import {
|
|
11
|
-
type ErrorResponse,
|
|
12
|
-
type RenegotiationResponse,
|
|
13
|
-
type SessionResponse,
|
|
14
|
-
type TrackObject,
|
|
15
|
-
type TracksResponse,
|
|
16
|
-
} from '../types';
|
|
17
|
-
import { HistoryCache } from './history-cache';
|
|
18
|
-
import { BulkRequestDispatcher, FIFOScheduler } from './task-scheduling';
|
|
19
|
-
|
|
20
|
-
const NETWORK_TIMEOUT = 5_000;
|
|
21
|
-
|
|
22
|
-
export type Session = {
|
|
23
|
-
sessionId: string;
|
|
24
|
-
peerConnection: RTCPeerConnection;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export type CallsServiceConfig = {
|
|
28
|
-
apiBase: string;
|
|
29
|
-
apiExtraProps?: string;
|
|
30
|
-
iceServers?: RTCIceServer[];
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export type HistoryRecord =
|
|
34
|
-
| {
|
|
35
|
-
endpoint: string;
|
|
36
|
-
type: 'request';
|
|
37
|
-
time: string;
|
|
38
|
-
method: string;
|
|
39
|
-
body: any;
|
|
40
|
-
}
|
|
41
|
-
| {
|
|
42
|
-
endpoint: string;
|
|
43
|
-
type: 'response';
|
|
44
|
-
time: string;
|
|
45
|
-
status: number;
|
|
46
|
-
text?: string;
|
|
47
|
-
json?: any;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Client for Cloudflare Calls service.
|
|
52
|
-
* API: https://developers.cloudflare.com/calls/https-api/
|
|
53
|
-
* Inspired by client from https://github.com/threepointone/partyserver/tree/main/packages/partytracks
|
|
54
|
-
*/
|
|
55
|
-
// TODO(mykola): Expose session errors.
|
|
56
|
-
export class CallsServicePeer extends Resource {
|
|
57
|
-
public readonly history = new HistoryCache<HistoryRecord>(100);
|
|
58
|
-
|
|
59
|
-
private readonly _persistentLifecycle = new PersistentLifecycle<Session>({
|
|
60
|
-
start: () => this._startSession(),
|
|
61
|
-
stop: (session) => this._stopSession(session),
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
private readonly _config: CallsServiceConfig;
|
|
65
|
-
|
|
66
|
-
taskScheduler = new FIFOScheduler();
|
|
67
|
-
pushTrackDispatcher = new BulkRequestDispatcher<
|
|
68
|
-
{
|
|
69
|
-
trackName: string;
|
|
70
|
-
transceiver: RTCRtpTransceiver;
|
|
71
|
-
},
|
|
72
|
-
{ tracks: TrackObject[] }
|
|
73
|
-
>(32);
|
|
74
|
-
|
|
75
|
-
pullTrackDispatcher = new BulkRequestDispatcher<
|
|
76
|
-
TrackObject,
|
|
77
|
-
{
|
|
78
|
-
/**
|
|
79
|
-
* trackName -> { resolvedTrack, mid }
|
|
80
|
-
*/
|
|
81
|
-
trackMap: Map<string, { resolvedTrack: Promise<MediaStreamTrack>; mid: string }>;
|
|
82
|
-
}
|
|
83
|
-
>(32);
|
|
84
|
-
|
|
85
|
-
closeTrackDispatcher = new BulkRequestDispatcher(32);
|
|
86
|
-
constructor(config: CallsServiceConfig) {
|
|
87
|
-
super();
|
|
88
|
-
this._config = config;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
protected override async _open(ctx: Context): Promise<void> {
|
|
92
|
-
await this._persistentLifecycle.open(ctx);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
protected override async _close(): Promise<void> {
|
|
96
|
-
await this._persistentLifecycle.close();
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
get session() {
|
|
100
|
-
return this._persistentLifecycle.state;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
private async _startSession() {
|
|
104
|
-
const peerConnection = await this._createRtcConnection();
|
|
105
|
-
const sessionId = await this._initiateCallSession();
|
|
106
|
-
return { sessionId, peerConnection };
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
private async _stopSession(session: Session): Promise<void> {
|
|
110
|
-
session.peerConnection.close();
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
private async _createRtcConnection(): Promise<RTCPeerConnection> {
|
|
114
|
-
const peerConnection = new RTCPeerConnection({
|
|
115
|
-
iceServers: this._config.iceServers,
|
|
116
|
-
bundlePolicy: 'max-bundle',
|
|
117
|
-
});
|
|
118
|
-
peerConnection.addEventListener('connectionstatechange', () => {
|
|
119
|
-
if (peerConnection.connectionState === 'failed' || peerConnection.connectionState === 'closed') {
|
|
120
|
-
log.info('calls connection failed', { state: peerConnection.connectionState });
|
|
121
|
-
void this._persistentLifecycle.scheduleRestart();
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
let iceTimeout = -1;
|
|
126
|
-
peerConnection.addEventListener('iceconnectionstatechange', () => {
|
|
127
|
-
clearTimeout(iceTimeout);
|
|
128
|
-
if (peerConnection.iceConnectionState === 'failed' || peerConnection.iceConnectionState === 'closed') {
|
|
129
|
-
log.info('calls connection to ICEs failed', { state: peerConnection.iceConnectionState });
|
|
130
|
-
void this._persistentLifecycle.scheduleRestart();
|
|
131
|
-
} else if (peerConnection.iceConnectionState === 'disconnected') {
|
|
132
|
-
// TODO(mykola): we should start to inspect the connection stats from here on for
|
|
133
|
-
// any other signs of trouble to guide what to do next (instead of just hoping
|
|
134
|
-
// for the best like we do here for now)
|
|
135
|
-
const timeoutSeconds = 7;
|
|
136
|
-
iceTimeout = window.setTimeout(() => {
|
|
137
|
-
if (peerConnection.iceConnectionState === 'connected') {
|
|
138
|
-
log.info('calls iceConnectionState is connected');
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
log.info('calls iceConnectionState timed out', { state: peerConnection.iceConnectionState, timeoutSeconds });
|
|
143
|
-
void this._persistentLifecycle.scheduleRestart();
|
|
144
|
-
}, timeoutSeconds * 1_000);
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
return peerConnection;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
private async _initiateCallSession(): Promise<string> {
|
|
152
|
-
log('creating new session');
|
|
153
|
-
const { sessionId } = await this._fetch<SessionResponse>('/sessions/new?SESSION', { method: 'POST' });
|
|
154
|
-
return sessionId;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
private async _fetch<T extends ErrorResponse>(relativePath: string, requestInit?: RequestInit): Promise<T> {
|
|
158
|
-
this.history.push({
|
|
159
|
-
endpoint: relativePath,
|
|
160
|
-
type: 'request',
|
|
161
|
-
time: new Date().toISOString(),
|
|
162
|
-
method: requestInit?.method ?? 'GET',
|
|
163
|
-
body: requestInit?.body,
|
|
164
|
-
});
|
|
165
|
-
// TODO(mykola): Handle access control. Use EdgeClient.
|
|
166
|
-
const response = await fetch(`${this._config.apiBase}${relativePath}`, { ...requestInit, redirect: 'manual' });
|
|
167
|
-
if (response.status >= 400) {
|
|
168
|
-
log.error('error while fetching from Calls service', { status: response.status, text: await response.text() });
|
|
169
|
-
throw new Error('Error while fetching from Calls service');
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
try {
|
|
173
|
-
const data = (await response.clone().json()) as T;
|
|
174
|
-
this.history.push({
|
|
175
|
-
endpoint: relativePath,
|
|
176
|
-
type: 'response',
|
|
177
|
-
time: new Date().toISOString(),
|
|
178
|
-
status: response.status,
|
|
179
|
-
json: data,
|
|
180
|
-
});
|
|
181
|
-
if (data.errorCode) {
|
|
182
|
-
throw new Error(data.errorDescription);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return data;
|
|
186
|
-
} catch (error) {
|
|
187
|
-
const text = await response.text();
|
|
188
|
-
this.history.push({
|
|
189
|
-
endpoint: relativePath,
|
|
190
|
-
type: 'response',
|
|
191
|
-
time: new Date().toISOString(),
|
|
192
|
-
status: response.status,
|
|
193
|
-
text,
|
|
194
|
-
});
|
|
195
|
-
log.error('Error parsing response from Calls service', {
|
|
196
|
-
error,
|
|
197
|
-
text,
|
|
198
|
-
status: response.status,
|
|
199
|
-
});
|
|
200
|
-
throw error;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
private async _pushTrackInBulk({
|
|
205
|
-
ctx,
|
|
206
|
-
peerConnection,
|
|
207
|
-
transceiver,
|
|
208
|
-
sessionId,
|
|
209
|
-
trackName,
|
|
210
|
-
}: {
|
|
211
|
-
ctx: Context;
|
|
212
|
-
peerConnection: RTCPeerConnection;
|
|
213
|
-
transceiver: RTCRtpTransceiver;
|
|
214
|
-
sessionId: string;
|
|
215
|
-
trackName: string;
|
|
216
|
-
}): Promise<TrackObject | void> {
|
|
217
|
-
log.verbose('pushing track ', trackName);
|
|
218
|
-
const pushedTrackPromise = this.pushTrackDispatcher
|
|
219
|
-
.doBulkRequest({ trackName, transceiver }, (tracks) =>
|
|
220
|
-
this.taskScheduler.schedule(async () => {
|
|
221
|
-
// Create offer.
|
|
222
|
-
// Turn on Opus DTX to save bandwidth and set the offer as the local description.
|
|
223
|
-
const offer = await peerConnection.createOffer();
|
|
224
|
-
offer.sdp = offer.sdp?.replace('useinbandfec=1', 'usedtx=1;useinbandfec=1');
|
|
225
|
-
await peerConnection.setLocalDescription(offer);
|
|
226
|
-
|
|
227
|
-
const response = await this._fetch<TracksResponse>(`/sessions/${sessionId}/tracks/new?PUSHING`, {
|
|
228
|
-
method: 'POST',
|
|
229
|
-
body: JSON.stringify({
|
|
230
|
-
sessionDescription: {
|
|
231
|
-
sdp: offer.sdp,
|
|
232
|
-
type: 'offer',
|
|
233
|
-
},
|
|
234
|
-
tracks: tracks.map(({ trackName, transceiver }) => ({
|
|
235
|
-
trackName,
|
|
236
|
-
mid: transceiver.mid,
|
|
237
|
-
location: 'local',
|
|
238
|
-
})),
|
|
239
|
-
}),
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
invariant(response.tracks !== undefined);
|
|
243
|
-
if (!response.errorCode) {
|
|
244
|
-
await peerConnection.setRemoteDescription(new RTCSessionDescription(response.sessionDescription));
|
|
245
|
-
await peerConnectionIsConnected(peerConnection);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
return {
|
|
249
|
-
tracks: response.tracks,
|
|
250
|
-
};
|
|
251
|
-
}),
|
|
252
|
-
)
|
|
253
|
-
.then(async ({ tracks }) => {
|
|
254
|
-
const trackData = tracks.find((t) => t.mid === transceiver.mid);
|
|
255
|
-
if (trackData) {
|
|
256
|
-
// we wait for the transceiver to start sending data before we emit
|
|
257
|
-
// the track metadata to ensure that the track will be able to be
|
|
258
|
-
// pulled before making the metadata available to anyone else.
|
|
259
|
-
// await waitForTransceiverToSendData(ctx, transceiver);
|
|
260
|
-
return {
|
|
261
|
-
...trackData,
|
|
262
|
-
sessionId,
|
|
263
|
-
location: 'remote',
|
|
264
|
-
} satisfies TrackObject;
|
|
265
|
-
} else {
|
|
266
|
-
log.error('missing track data');
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
const onDispose = async () => {
|
|
271
|
-
if (transceiver.mid) {
|
|
272
|
-
await this._closeTrackInBulk(peerConnection, transceiver.mid, sessionId);
|
|
273
|
-
}
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
ctx?.onDispose(async () => await onDispose());
|
|
277
|
-
this._ctx.onDispose(() => onDispose());
|
|
278
|
-
|
|
279
|
-
return pushedTrackPromise;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
async pushTrack({
|
|
283
|
-
track,
|
|
284
|
-
encodings = [],
|
|
285
|
-
ctx,
|
|
286
|
-
previousTrack,
|
|
287
|
-
}: {
|
|
288
|
-
track: MediaStreamTrack | null;
|
|
289
|
-
ctx: Context;
|
|
290
|
-
encodings?: RTCRtpEncodingParameters[];
|
|
291
|
-
previousTrack?: TrackObject;
|
|
292
|
-
}): Promise<TrackObject | undefined> {
|
|
293
|
-
await this.waitUntilOpen();
|
|
294
|
-
invariant(this.session);
|
|
295
|
-
log('trying to push track', { track, previousTrack, encodings });
|
|
296
|
-
if (previousTrack) {
|
|
297
|
-
const transceiver = this.session.peerConnection.getTransceivers().find((t) => t.mid === previousTrack.mid);
|
|
298
|
-
if (transceiver?.sender.track === track) {
|
|
299
|
-
log.verbose('track already pushed', { track, previousTrack, transceiver });
|
|
300
|
-
return previousTrack;
|
|
301
|
-
} else if (transceiver) {
|
|
302
|
-
log.verbose('replacing track', { track, previousTrack, transceiver });
|
|
303
|
-
transceiver.sender.replaceTrack(track).catch((err) => log.catch(err));
|
|
304
|
-
return previousTrack;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
invariant(track);
|
|
308
|
-
|
|
309
|
-
// We want a single id for this connection.
|
|
310
|
-
const stableId = crypto.randomUUID();
|
|
311
|
-
const transceiver = this.session.peerConnection!.addTransceiver(track, { direction: 'sendonly' });
|
|
312
|
-
log.verbose('creating transceiver');
|
|
313
|
-
|
|
314
|
-
const pushedTrackData = await this._pushTrackInBulk({
|
|
315
|
-
ctx,
|
|
316
|
-
peerConnection: this.session.peerConnection!,
|
|
317
|
-
transceiver,
|
|
318
|
-
sessionId: this.session.sessionId!,
|
|
319
|
-
trackName: stableId,
|
|
320
|
-
});
|
|
321
|
-
invariant(pushedTrackData);
|
|
322
|
-
|
|
323
|
-
const parameters = transceiver.sender.getParameters();
|
|
324
|
-
encodings.forEach((encoding, i) => {
|
|
325
|
-
const existing = parameters.encodings[i];
|
|
326
|
-
parameters.encodings[i] = { ...existing, ...encoding };
|
|
327
|
-
});
|
|
328
|
-
transceiver.sender.setParameters(parameters).catch((err) => log.catch(err));
|
|
329
|
-
|
|
330
|
-
return pushedTrackData;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// TODO(mykola): Add retry logic if the tracks fails to pull.
|
|
334
|
-
private async _pullTrackInBulk({
|
|
335
|
-
peerConnection,
|
|
336
|
-
sessionId,
|
|
337
|
-
trackData,
|
|
338
|
-
ctx,
|
|
339
|
-
}: {
|
|
340
|
-
peerConnection: RTCPeerConnection;
|
|
341
|
-
sessionId: string;
|
|
342
|
-
trackData: TrackObject;
|
|
343
|
-
ctx?: Context;
|
|
344
|
-
}): Promise<MediaStreamTrack | undefined> {
|
|
345
|
-
let mid = '';
|
|
346
|
-
log('pulling track', { trackName: trackData.trackName });
|
|
347
|
-
const pulledTrackPromise = this.pullTrackDispatcher
|
|
348
|
-
.doBulkRequest(trackData, (tracks) =>
|
|
349
|
-
this.taskScheduler.schedule(async () => {
|
|
350
|
-
const newTrackResponse = await this._fetch<TracksResponse>(`/sessions/${sessionId}/tracks/new?PULLING`, {
|
|
351
|
-
method: 'POST',
|
|
352
|
-
body: JSON.stringify({ tracks }),
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
if (newTrackResponse.errorCode) {
|
|
356
|
-
throw new Error(newTrackResponse.errorDescription);
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
invariant(newTrackResponse.tracks);
|
|
360
|
-
const trackMap = tracks.reduce((acc, track) => {
|
|
361
|
-
const pulledTrackData = newTrackResponse.tracks?.find(
|
|
362
|
-
(t) => t.trackName === track.trackName && t.sessionId === track.sessionId,
|
|
363
|
-
);
|
|
364
|
-
|
|
365
|
-
if (pulledTrackData && pulledTrackData.mid) {
|
|
366
|
-
acc.set(track.trackName!, {
|
|
367
|
-
mid: pulledTrackData.mid,
|
|
368
|
-
resolvedTrack: resolveTrack(peerConnection, (t) => t.mid === pulledTrackData.mid),
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
return acc;
|
|
373
|
-
}, new Map<string, { resolvedTrack: Promise<MediaStreamTrack>; mid: string }>());
|
|
374
|
-
|
|
375
|
-
if (newTrackResponse.requiresImmediateRenegotiation) {
|
|
376
|
-
await peerConnection.setRemoteDescription(new RTCSessionDescription(newTrackResponse.sessionDescription));
|
|
377
|
-
const answer = await peerConnection.createAnswer();
|
|
378
|
-
await peerConnection.setLocalDescription(answer);
|
|
379
|
-
|
|
380
|
-
const renegotiationResponse = await this._fetch<RenegotiationResponse>(
|
|
381
|
-
`/sessions/${sessionId}/renegotiate`,
|
|
382
|
-
{
|
|
383
|
-
method: 'PUT',
|
|
384
|
-
body: JSON.stringify({
|
|
385
|
-
sessionDescription: {
|
|
386
|
-
type: 'answer',
|
|
387
|
-
sdp: peerConnection.currentLocalDescription?.sdp,
|
|
388
|
-
},
|
|
389
|
-
}),
|
|
390
|
-
},
|
|
391
|
-
);
|
|
392
|
-
|
|
393
|
-
if (renegotiationResponse.errorCode) {
|
|
394
|
-
throw new Error(renegotiationResponse.errorDescription);
|
|
395
|
-
} else {
|
|
396
|
-
await peerConnectionIsConnected(peerConnection);
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
return { trackMap };
|
|
401
|
-
}),
|
|
402
|
-
)
|
|
403
|
-
.then(({ trackMap }) => {
|
|
404
|
-
const trackInfo = trackMap.get(trackData.trackName!);
|
|
405
|
-
if (trackInfo) {
|
|
406
|
-
return trackInfo.resolvedTrack
|
|
407
|
-
.then((track) => {
|
|
408
|
-
mid = trackInfo.mid;
|
|
409
|
-
return track;
|
|
410
|
-
})
|
|
411
|
-
.catch((err) => log.catch(err));
|
|
412
|
-
} else {
|
|
413
|
-
log.info('missing track info', { trackData, availableTracks: Array.from(trackMap.keys()) });
|
|
414
|
-
}
|
|
415
|
-
});
|
|
416
|
-
|
|
417
|
-
const onDispose = async () => {
|
|
418
|
-
if (mid) {
|
|
419
|
-
log('closing pulled track ', trackData.trackName);
|
|
420
|
-
await this._closeTrackInBulk(peerConnection, mid, sessionId);
|
|
421
|
-
mid = '';
|
|
422
|
-
}
|
|
423
|
-
};
|
|
424
|
-
|
|
425
|
-
this._ctx.onDispose(() => onDispose());
|
|
426
|
-
ctx?.onDispose(() => onDispose());
|
|
427
|
-
|
|
428
|
-
return pulledTrackPromise as Promise<MediaStreamTrack | undefined>;
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
async pullTrack({
|
|
432
|
-
ctx,
|
|
433
|
-
trackData,
|
|
434
|
-
}: {
|
|
435
|
-
trackData: TrackObject;
|
|
436
|
-
ctx?: Context;
|
|
437
|
-
}): Promise<MediaStreamTrack | undefined> {
|
|
438
|
-
await this.waitUntilOpen();
|
|
439
|
-
|
|
440
|
-
invariant(this.session);
|
|
441
|
-
const session = this.session;
|
|
442
|
-
return this._pullTrackInBulk({
|
|
443
|
-
peerConnection: session.peerConnection,
|
|
444
|
-
sessionId: session.sessionId,
|
|
445
|
-
trackData,
|
|
446
|
-
ctx,
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
async _closeTrackInBulk(peerConnection: RTCPeerConnection, mid: string, sessionId: string): Promise<void> {
|
|
451
|
-
const transceiver = peerConnection.getTransceivers().find((t) => t.mid === mid);
|
|
452
|
-
|
|
453
|
-
if (peerConnection.connectionState !== 'connected' || transceiver === undefined) {
|
|
454
|
-
return;
|
|
455
|
-
}
|
|
456
|
-
await this.closeTrackDispatcher.doBulkRequest({ mid }, (mids) =>
|
|
457
|
-
this.taskScheduler.schedule(async () => {
|
|
458
|
-
transceiver.stop();
|
|
459
|
-
const activeTransceivers = peerConnection
|
|
460
|
-
.getTransceivers()
|
|
461
|
-
.filter((t) => t.mid !== mid && t.direction !== 'stopped');
|
|
462
|
-
|
|
463
|
-
let requestBody;
|
|
464
|
-
if (activeTransceivers.length > 0) {
|
|
465
|
-
// create an offer
|
|
466
|
-
const offer = await peerConnection.createOffer();
|
|
467
|
-
// And set the offer as the local description
|
|
468
|
-
await peerConnection.setLocalDescription(offer);
|
|
469
|
-
requestBody = {
|
|
470
|
-
tracks: mids,
|
|
471
|
-
sessionDescription: {
|
|
472
|
-
sdp: peerConnection.localDescription?.sdp,
|
|
473
|
-
type: 'offer',
|
|
474
|
-
},
|
|
475
|
-
force: false,
|
|
476
|
-
};
|
|
477
|
-
} else {
|
|
478
|
-
requestBody = {
|
|
479
|
-
tracks: mids,
|
|
480
|
-
force: true,
|
|
481
|
-
};
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
const response = await this._fetch<TracksResponse>(`/sessions/${sessionId}/tracks/close`, {
|
|
485
|
-
method: 'PUT',
|
|
486
|
-
body: JSON.stringify(requestBody),
|
|
487
|
-
});
|
|
488
|
-
|
|
489
|
-
if (requestBody.sessionDescription) {
|
|
490
|
-
await peerConnection.setRemoteDescription(new RTCSessionDescription(response.sessionDescription));
|
|
491
|
-
}
|
|
492
|
-
}),
|
|
493
|
-
);
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
const resolveTrack = async (
|
|
498
|
-
peerConnection: RTCPeerConnection,
|
|
499
|
-
compare: (t: RTCRtpTransceiver) => boolean,
|
|
500
|
-
timeout = NETWORK_TIMEOUT,
|
|
501
|
-
) =>
|
|
502
|
-
new Promise<MediaStreamTrack>((resolve, reject) => {
|
|
503
|
-
setTimeout(reject, timeout);
|
|
504
|
-
const handler = () => {
|
|
505
|
-
const transceiver = peerConnection.getTransceivers().find(compare);
|
|
506
|
-
if (transceiver) {
|
|
507
|
-
resolve(transceiver.receiver.track);
|
|
508
|
-
peerConnection.removeEventListener('track', handler);
|
|
509
|
-
}
|
|
510
|
-
};
|
|
511
|
-
|
|
512
|
-
peerConnection.addEventListener('track', handler);
|
|
513
|
-
});
|
|
514
|
-
|
|
515
|
-
const peerConnectionIsConnected = async (peerConnection: RTCPeerConnection) => {
|
|
516
|
-
if (peerConnection.connectionState !== 'connected') {
|
|
517
|
-
const connected = new Promise((resolve, reject) => {
|
|
518
|
-
// Timeout after 5s.
|
|
519
|
-
const timeout = setTimeout(() => {
|
|
520
|
-
peerConnection.removeEventListener('connectionstatechange', connectionStateChangeHandler);
|
|
521
|
-
reject(new Error('Connection timeout'));
|
|
522
|
-
}, NETWORK_TIMEOUT);
|
|
523
|
-
|
|
524
|
-
const connectionStateChangeHandler = () => {
|
|
525
|
-
if (peerConnection.connectionState === 'connected') {
|
|
526
|
-
peerConnection.removeEventListener('connectionstatechange', connectionStateChangeHandler);
|
|
527
|
-
clearTimeout(timeout);
|
|
528
|
-
resolve(undefined);
|
|
529
|
-
}
|
|
530
|
-
};
|
|
531
|
-
peerConnection.addEventListener('connectionstatechange', connectionStateChangeHandler);
|
|
532
|
-
});
|
|
533
|
-
|
|
534
|
-
await connected;
|
|
535
|
-
}
|
|
536
|
-
};
|
|
537
|
-
|
|
538
|
-
const INITIAL_DELAY = 50;
|
|
539
|
-
const MAX_DELAY = 500;
|
|
540
|
-
const MAX_RETRIES = 20;
|
|
541
|
-
const WAIT_FOR_DATA_TIMEOUT = 10_000;
|
|
542
|
-
|
|
543
|
-
const waitForTransceiverToSendData = async (ctx: Context, transceiver: RTCRtpTransceiver): Promise<void> => {
|
|
544
|
-
let delay = INITIAL_DELAY;
|
|
545
|
-
let checks = 0;
|
|
546
|
-
const waitForData = new Trigger();
|
|
547
|
-
ctx.onDispose(() => waitForData.throw(new Error('Transceiver was closed')));
|
|
548
|
-
|
|
549
|
-
const checkStats = async () => {
|
|
550
|
-
if (ctx.disposed) {
|
|
551
|
-
return;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
try {
|
|
555
|
-
const stats = await transceiver.sender.getStats();
|
|
556
|
-
let dataFound = false;
|
|
557
|
-
stats.forEach((stat) => {
|
|
558
|
-
if (stat.type === 'outbound-rtp' && stat.bytesSent > 0) {
|
|
559
|
-
dataFound = true;
|
|
560
|
-
}
|
|
561
|
-
});
|
|
562
|
-
|
|
563
|
-
if (dataFound) {
|
|
564
|
-
waitForData.wake();
|
|
565
|
-
return;
|
|
566
|
-
}
|
|
567
|
-
} catch {
|
|
568
|
-
// Stats might not be available yet, continue checking
|
|
569
|
-
}
|
|
570
|
-
checks++;
|
|
571
|
-
if (checks > MAX_RETRIES) {
|
|
572
|
-
waitForData.throw(new Error('Transceiver did not send data'));
|
|
573
|
-
return;
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
delay = Math.min(delay * 2, MAX_DELAY); // Exponential backoff with max cap
|
|
577
|
-
scheduleTask(ctx, checkStats, delay);
|
|
578
|
-
};
|
|
579
|
-
|
|
580
|
-
void checkStats();
|
|
581
|
-
return waitForData.wait({ timeout: WAIT_FOR_DATA_TIMEOUT });
|
|
582
|
-
};
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2025 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Array that holds the last N items.
|
|
7
|
-
*/
|
|
8
|
-
export class HistoryCache<T> {
|
|
9
|
-
private readonly _limit: number;
|
|
10
|
-
private readonly _messages: T[];
|
|
11
|
-
|
|
12
|
-
constructor(limit = 100) {
|
|
13
|
-
this._limit = limit;
|
|
14
|
-
this._messages = [];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
push(...messages: T[]): void {
|
|
18
|
-
if (this._messages.length >= this._limit) {
|
|
19
|
-
this._messages.shift(); // Remove the oldest message
|
|
20
|
-
}
|
|
21
|
-
this._messages.push(...messages); // Add new message
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
get(): T[] {
|
|
25
|
-
return this._messages;
|
|
26
|
-
}
|
|
27
|
-
}
|
package/src/calls/util/index.ts
DELETED
package/src/calls/util/media.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2025 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { log } from '@dxos/log';
|
|
6
|
-
|
|
7
|
-
export const getUserMediaTrack = async (
|
|
8
|
-
kind: MediaDeviceKind,
|
|
9
|
-
constraints: MediaTrackConstraints = {},
|
|
10
|
-
deviceList?: MediaDeviceInfo[],
|
|
11
|
-
): Promise<MediaStreamTrack> => {
|
|
12
|
-
deviceList ??= (await getDeviceList()).filter((device) => device.kind === kind);
|
|
13
|
-
const firstDevice = deviceList[0];
|
|
14
|
-
if (!firstDevice) {
|
|
15
|
-
throw new Error('No devices found');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
return acquireTrack(firstDevice, constraints);
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const acquireTrack = async (device: MediaDeviceInfo, constraints: MediaTrackConstraints): Promise<MediaStreamTrack> => {
|
|
22
|
-
const { deviceId, label } = device;
|
|
23
|
-
log.info(`requesting ${label}`);
|
|
24
|
-
|
|
25
|
-
const mediaStream = await navigator.mediaDevices.getUserMedia(
|
|
26
|
-
device.kind === 'videoinput' ? { video: { ...constraints, deviceId } } : { audio: { ...constraints, deviceId } },
|
|
27
|
-
);
|
|
28
|
-
return device.kind === 'videoinput' ? mediaStream.getVideoTracks()[0] : mediaStream.getAudioTracks()[0];
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
// TODO(mykola): Handle devicechange event.
|
|
32
|
-
export const getDeviceList = () => navigator.mediaDevices.enumerateDevices();
|
|
33
|
-
|
|
34
|
-
const SCREENSHARE_CONSTRAINTS = {
|
|
35
|
-
video: {
|
|
36
|
-
width: { max: 1920 },
|
|
37
|
-
height: { max: 1080 },
|
|
38
|
-
frameRate: { max: 10 },
|
|
39
|
-
},
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export const getScreenshare = async ({ contentHint }: { contentHint: string }) => {
|
|
43
|
-
// Get 1080p equivalent screenshare with 10fps, but save natural sharing content aspect ratio.
|
|
44
|
-
const ms = await navigator.mediaDevices.getDisplayMedia(SCREENSHARE_CONSTRAINTS);
|
|
45
|
-
ms.getVideoTracks().forEach((track) => {
|
|
46
|
-
if (contentHint && 'contentHint' in track) {
|
|
47
|
-
track.contentHint = contentHint;
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
return ms;
|
|
52
|
-
};
|