tempest-react-sdk 0.57.0 → 0.59.0
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/README.md +14 -2
- package/bin/lib/css/findings.mjs +1 -0
- package/bin/lib/css/semantic.mjs +70 -6
- package/bin/lib/css/semantic.test.mjs +52 -1
- package/bin/lib/icons/generate.test.mjs +4 -4
- package/dist/br/geocode.cjs +1 -1
- package/dist/br/geocode.cjs.map +1 -1
- package/dist/br/geocode.js +1 -1
- package/dist/br/geocode.js.map +1 -1
- package/dist/capture/use-barcode-scanner.cjs +1 -1
- package/dist/capture/use-barcode-scanner.cjs.map +1 -1
- package/dist/capture/use-barcode-scanner.js +1 -1
- package/dist/capture/use-barcode-scanner.js.map +1 -1
- package/dist/components/AIChat/AIChat.cjs +1 -1
- package/dist/components/AIChat/AIChat.cjs.map +1 -1
- package/dist/components/AIChat/AIChat.js +1 -1
- package/dist/components/AIChat/AIChat.js.map +1 -1
- package/dist/components/AIChat/AIChatTurn.cjs +1 -1
- package/dist/components/AIChat/AIChatTurn.cjs.map +1 -1
- package/dist/components/AIChat/AIChatTurn.js +1 -1
- package/dist/components/AIChat/AIChatTurn.js.map +1 -1
- package/dist/components/Alert/Alert.module.cjs.map +1 -1
- package/dist/components/Alert/Alert.module.js.map +1 -1
- package/dist/components/AppBar/use-sticky-body-warning.cjs +1 -1
- package/dist/components/AppBar/use-sticky-body-warning.cjs.map +1 -1
- package/dist/components/AppBar/use-sticky-body-warning.js +1 -1
- package/dist/components/AppBar/use-sticky-body-warning.js.map +1 -1
- package/dist/components/AudioPlayer/AudioPlayer.cjs +1 -1
- package/dist/components/AudioPlayer/AudioPlayer.cjs.map +1 -1
- package/dist/components/AudioPlayer/AudioPlayer.js +2 -2
- package/dist/components/AudioPlayer/AudioPlayer.js.map +1 -1
- package/dist/components/AudioRecorder/AudioRecorder.cjs +1 -1
- package/dist/components/AudioRecorder/AudioRecorder.cjs.map +1 -1
- package/dist/components/AudioRecorder/AudioRecorder.js +1 -1
- package/dist/components/AudioRecorder/AudioRecorder.js.map +1 -1
- package/dist/components/Badge/Badge.module.cjs.map +1 -1
- package/dist/components/Badge/Badge.module.js.map +1 -1
- package/dist/components/BarList/BarList.module.cjs.map +1 -1
- package/dist/components/BarList/BarList.module.js.map +1 -1
- package/dist/components/BottomSheet/BottomSheet.module.cjs.map +1 -1
- package/dist/components/BottomSheet/BottomSheet.module.js.map +1 -1
- package/dist/components/Chat/Chat.cjs +1 -1
- package/dist/components/Chat/Chat.cjs.map +1 -1
- package/dist/components/Chat/Chat.js +1 -1
- package/dist/components/Chat/Chat.js.map +1 -1
- package/dist/components/DataTable/DataTable.module.cjs.map +1 -1
- package/dist/components/DataTable/DataTable.module.js.map +1 -1
- package/dist/components/Dropzone/Dropzone.module.cjs.map +1 -1
- package/dist/components/Dropzone/Dropzone.module.js.map +1 -1
- package/dist/components/ErrorText/ErrorText.module.cjs.map +1 -1
- package/dist/components/ErrorText/ErrorText.module.js.map +1 -1
- package/dist/components/FilterBar/FilterBar.cjs +1 -1
- package/dist/components/FilterBar/FilterBar.cjs.map +1 -1
- package/dist/components/FilterBar/FilterBar.js +1 -1
- package/dist/components/FilterBar/FilterBar.js.map +1 -1
- package/dist/components/FilterBar/filter-apply.cjs +1 -1
- package/dist/components/FilterBar/filter-apply.cjs.map +1 -1
- package/dist/components/FilterBar/filter-apply.js +1 -1
- package/dist/components/FilterBar/filter-apply.js.map +1 -1
- package/dist/components/ImageCropper/ImageCropper.cjs +1 -1
- package/dist/components/ImageCropper/ImageCropper.cjs.map +1 -1
- package/dist/components/ImageCropper/ImageCropper.js +1 -1
- package/dist/components/ImageCropper/ImageCropper.js.map +1 -1
- package/dist/components/Markdown/Markdown.module.cjs.map +1 -1
- package/dist/components/Markdown/Markdown.module.js.map +1 -1
- package/dist/components/PasswordInput/PasswordInput.module.cjs.map +1 -1
- package/dist/components/PasswordInput/PasswordInput.module.js.map +1 -1
- package/dist/components/SegmentedControl/SegmentedControl.module.cjs.map +1 -1
- package/dist/components/SegmentedControl/SegmentedControl.module.js.map +1 -1
- package/dist/components/Sidebar/Sidebar.module.cjs.map +1 -1
- package/dist/components/Sidebar/Sidebar.module.js.map +1 -1
- package/dist/components/StepperInput/StepperInput.module.cjs.map +1 -1
- package/dist/components/StepperInput/StepperInput.module.js.map +1 -1
- package/dist/components/Tag/Tag.module.cjs.map +1 -1
- package/dist/components/Tag/Tag.module.js.map +1 -1
- package/dist/components/Timeline/Timeline.module.cjs.map +1 -1
- package/dist/components/Timeline/Timeline.module.js.map +1 -1
- package/dist/components/Toggle/Toggle.module.cjs.map +1 -1
- package/dist/components/Toggle/Toggle.module.js.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroup.module.cjs.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroup.module.js.map +1 -1
- package/dist/components/VideoPlayer/VideoPlayer.cjs +1 -1
- package/dist/components/VideoPlayer/VideoPlayer.cjs.map +1 -1
- package/dist/components/VideoPlayer/VideoPlayer.js +2 -2
- package/dist/components/VideoPlayer/VideoPlayer.js.map +1 -1
- package/dist/components/VirtualTable/VirtualTable.cjs +1 -1
- package/dist/components/VirtualTable/VirtualTable.cjs.map +1 -1
- package/dist/components/VirtualTable/VirtualTable.js +1 -1
- package/dist/components/VirtualTable/VirtualTable.js.map +1 -1
- package/dist/feature-flags/growthbook-adapter.cjs +1 -1
- package/dist/feature-flags/growthbook-adapter.cjs.map +1 -1
- package/dist/feature-flags/growthbook-adapter.js +1 -1
- package/dist/feature-flags/growthbook-adapter.js.map +1 -1
- package/dist/hooks/use-focus-trap.cjs +1 -1
- package/dist/hooks/use-focus-trap.cjs.map +1 -1
- package/dist/hooks/use-focus-trap.js +1 -1
- package/dist/hooks/use-focus-trap.js.map +1 -1
- package/dist/hooks/use-push-to-talk.cjs +1 -1
- package/dist/hooks/use-push-to-talk.cjs.map +1 -1
- package/dist/hooks/use-push-to-talk.js +1 -1
- package/dist/hooks/use-push-to-talk.js.map +1 -1
- package/dist/http/describe-api-error.cjs +1 -1
- package/dist/http/describe-api-error.cjs.map +1 -1
- package/dist/http/describe-api-error.js +12 -8
- package/dist/http/describe-api-error.js.map +1 -1
- package/dist/http/errors.cjs +1 -1
- package/dist/http/errors.cjs.map +1 -1
- package/dist/http/errors.js +21 -16
- package/dist/http/errors.js.map +1 -1
- package/dist/http/resumable-upload.cjs +1 -1
- package/dist/http/resumable-upload.cjs.map +1 -1
- package/dist/http/resumable-upload.js +1 -1
- package/dist/http/resumable-upload.js.map +1 -1
- package/dist/icons/generated/aliases.cjs +1 -1
- package/dist/icons/generated/aliases.cjs.map +1 -1
- package/dist/icons/generated/aliases.js +1 -0
- package/dist/icons/generated/aliases.js.map +1 -1
- package/dist/icons/generated/icon-names.cjs +1 -1
- package/dist/icons/generated/icon-names.cjs.map +1 -1
- package/dist/icons/generated/icon-names.js +1 -1
- package/dist/icons/generated/icon-names.js.map +1 -1
- package/dist/icons/generated/loaders.cjs +1 -1
- package/dist/icons/generated/loaders.cjs.map +1 -1
- package/dist/icons/generated/loaders.js +48 -42
- package/dist/icons/generated/loaders.js.map +1 -1
- package/dist/icons/generated/shard-02.cjs +1 -1
- package/dist/icons/generated/shard-02.cjs.map +1 -1
- package/dist/icons/generated/shard-02.js +20 -20
- package/dist/icons/generated/shard-02.js.map +1 -1
- package/dist/icons/generated/shard-03.cjs +1 -1
- package/dist/icons/generated/shard-03.cjs.map +1 -1
- package/dist/icons/generated/shard-03.js +41 -41
- package/dist/icons/generated/shard-03.js.map +1 -1
- package/dist/icons/generated/shard-04.cjs +1 -1
- package/dist/icons/generated/shard-04.cjs.map +1 -1
- package/dist/icons/generated/shard-04.js +41 -41
- package/dist/icons/generated/shard-04.js.map +1 -1
- package/dist/icons/generated/shard-05.cjs +1 -1
- package/dist/icons/generated/shard-05.cjs.map +1 -1
- package/dist/icons/generated/shard-05.js +41 -41
- package/dist/icons/generated/shard-05.js.map +1 -1
- package/dist/icons/generated/shard-06.cjs +1 -1
- package/dist/icons/generated/shard-06.cjs.map +1 -1
- package/dist/icons/generated/shard-06.js +41 -41
- package/dist/icons/generated/shard-06.js.map +1 -1
- package/dist/icons/generated/shard-07.cjs +1 -1
- package/dist/icons/generated/shard-07.cjs.map +1 -1
- package/dist/icons/generated/shard-07.js +41 -41
- package/dist/icons/generated/shard-07.js.map +1 -1
- package/dist/icons/generated/shard-08.cjs +1 -1
- package/dist/icons/generated/shard-08.cjs.map +1 -1
- package/dist/icons/generated/shard-08.js +41 -41
- package/dist/icons/generated/shard-08.js.map +1 -1
- package/dist/icons/generated/shard-09.cjs +1 -1
- package/dist/icons/generated/shard-09.cjs.map +1 -1
- package/dist/icons/generated/shard-09.js +41 -41
- package/dist/icons/generated/shard-09.js.map +1 -1
- package/dist/icons/generated/shard-10.cjs +1 -1
- package/dist/icons/generated/shard-10.cjs.map +1 -1
- package/dist/icons/generated/shard-10.js +41 -41
- package/dist/icons/generated/shard-10.js.map +1 -1
- package/dist/icons/generated/shard-11.cjs +1 -1
- package/dist/icons/generated/shard-11.cjs.map +1 -1
- package/dist/icons/generated/shard-11.js +41 -41
- package/dist/icons/generated/shard-11.js.map +1 -1
- package/dist/icons/generated/shard-12.cjs +1 -1
- package/dist/icons/generated/shard-12.cjs.map +1 -1
- package/dist/icons/generated/shard-12.js +41 -41
- package/dist/icons/generated/shard-12.js.map +1 -1
- package/dist/icons/generated/shard-13.cjs +1 -1
- package/dist/icons/generated/shard-13.cjs.map +1 -1
- package/dist/icons/generated/shard-13.js +41 -41
- package/dist/icons/generated/shard-13.js.map +1 -1
- package/dist/icons/generated/shard-14.cjs +1 -1
- package/dist/icons/generated/shard-14.cjs.map +1 -1
- package/dist/icons/generated/shard-14.js +41 -41
- package/dist/icons/generated/shard-14.js.map +1 -1
- package/dist/icons/generated/shard-15.cjs +1 -1
- package/dist/icons/generated/shard-15.cjs.map +1 -1
- package/dist/icons/generated/shard-15.js +41 -41
- package/dist/icons/generated/shard-15.js.map +1 -1
- package/dist/icons/generated/shard-16.cjs +1 -1
- package/dist/icons/generated/shard-16.cjs.map +1 -1
- package/dist/icons/generated/shard-16.js +41 -41
- package/dist/icons/generated/shard-16.js.map +1 -1
- package/dist/icons/generated/shard-17.cjs +1 -1
- package/dist/icons/generated/shard-17.cjs.map +1 -1
- package/dist/icons/generated/shard-17.js +41 -41
- package/dist/icons/generated/shard-17.js.map +1 -1
- package/dist/icons/generated/shard-18.cjs +1 -1
- package/dist/icons/generated/shard-18.cjs.map +1 -1
- package/dist/icons/generated/shard-18.js +41 -41
- package/dist/icons/generated/shard-18.js.map +1 -1
- package/dist/icons/generated/shard-19.cjs +1 -1
- package/dist/icons/generated/shard-19.cjs.map +1 -1
- package/dist/icons/generated/shard-19.js +41 -41
- package/dist/icons/generated/shard-19.js.map +1 -1
- package/dist/icons/generated/shard-20.cjs +1 -1
- package/dist/icons/generated/shard-20.cjs.map +1 -1
- package/dist/icons/generated/shard-20.js +41 -41
- package/dist/icons/generated/shard-20.js.map +1 -1
- package/dist/icons/generated/shard-21.cjs +1 -1
- package/dist/icons/generated/shard-21.cjs.map +1 -1
- package/dist/icons/generated/shard-21.js +41 -41
- package/dist/icons/generated/shard-21.js.map +1 -1
- package/dist/icons/generated/shard-22.cjs +1 -1
- package/dist/icons/generated/shard-22.cjs.map +1 -1
- package/dist/icons/generated/shard-22.js +41 -41
- package/dist/icons/generated/shard-22.js.map +1 -1
- package/dist/icons/generated/shard-23.cjs +1 -1
- package/dist/icons/generated/shard-23.cjs.map +1 -1
- package/dist/icons/generated/shard-23.js +41 -41
- package/dist/icons/generated/shard-23.js.map +1 -1
- package/dist/icons/generated/shard-24.cjs +1 -1
- package/dist/icons/generated/shard-24.cjs.map +1 -1
- package/dist/icons/generated/shard-24.js +41 -41
- package/dist/icons/generated/shard-24.js.map +1 -1
- package/dist/icons/generated/shard-25.cjs +1 -1
- package/dist/icons/generated/shard-25.cjs.map +1 -1
- package/dist/icons/generated/shard-25.js +41 -41
- package/dist/icons/generated/shard-25.js.map +1 -1
- package/dist/icons/generated/shard-26.cjs +1 -1
- package/dist/icons/generated/shard-26.cjs.map +1 -1
- package/dist/icons/generated/shard-26.js +41 -41
- package/dist/icons/generated/shard-26.js.map +1 -1
- package/dist/icons/generated/shard-27.cjs +1 -1
- package/dist/icons/generated/shard-27.cjs.map +1 -1
- package/dist/icons/generated/shard-27.js +41 -41
- package/dist/icons/generated/shard-27.js.map +1 -1
- package/dist/icons/generated/shard-28.cjs +1 -1
- package/dist/icons/generated/shard-28.cjs.map +1 -1
- package/dist/icons/generated/shard-28.js +41 -41
- package/dist/icons/generated/shard-28.js.map +1 -1
- package/dist/icons/generated/shard-29.cjs +1 -1
- package/dist/icons/generated/shard-29.cjs.map +1 -1
- package/dist/icons/generated/shard-29.js +41 -41
- package/dist/icons/generated/shard-29.js.map +1 -1
- package/dist/icons/generated/shard-30.cjs +1 -1
- package/dist/icons/generated/shard-30.cjs.map +1 -1
- package/dist/icons/generated/shard-30.js +41 -41
- package/dist/icons/generated/shard-30.js.map +1 -1
- package/dist/icons/generated/shard-31.cjs +1 -1
- package/dist/icons/generated/shard-31.cjs.map +1 -1
- package/dist/icons/generated/shard-31.js +41 -41
- package/dist/icons/generated/shard-31.js.map +1 -1
- package/dist/icons/generated/shard-32.cjs +1 -1
- package/dist/icons/generated/shard-32.cjs.map +1 -1
- package/dist/icons/generated/shard-32.js +41 -41
- package/dist/icons/generated/shard-32.js.map +1 -1
- package/dist/icons/generated/shard-33.cjs +1 -1
- package/dist/icons/generated/shard-33.cjs.map +1 -1
- package/dist/icons/generated/shard-33.js +41 -41
- package/dist/icons/generated/shard-33.js.map +1 -1
- package/dist/icons/generated/shard-34.cjs +1 -1
- package/dist/icons/generated/shard-34.cjs.map +1 -1
- package/dist/icons/generated/shard-34.js +41 -41
- package/dist/icons/generated/shard-34.js.map +1 -1
- package/dist/icons/generated/shard-35.cjs +1 -1
- package/dist/icons/generated/shard-35.cjs.map +1 -1
- package/dist/icons/generated/shard-35.js +41 -41
- package/dist/icons/generated/shard-35.js.map +1 -1
- package/dist/icons/generated/shard-36.cjs +1 -1
- package/dist/icons/generated/shard-36.cjs.map +1 -1
- package/dist/icons/generated/shard-36.js +41 -41
- package/dist/icons/generated/shard-36.js.map +1 -1
- package/dist/icons/generated/shard-37.cjs +1 -1
- package/dist/icons/generated/shard-37.cjs.map +1 -1
- package/dist/icons/generated/shard-37.js +41 -41
- package/dist/icons/generated/shard-37.js.map +1 -1
- package/dist/icons/generated/shard-38.cjs +1 -1
- package/dist/icons/generated/shard-38.cjs.map +1 -1
- package/dist/icons/generated/shard-38.js +41 -41
- package/dist/icons/generated/shard-38.js.map +1 -1
- package/dist/icons/generated/shard-39.cjs +1 -1
- package/dist/icons/generated/shard-39.cjs.map +1 -1
- package/dist/icons/generated/shard-39.js +41 -41
- package/dist/icons/generated/shard-39.js.map +1 -1
- package/dist/icons/generated/shard-40.cjs +1 -1
- package/dist/icons/generated/shard-40.cjs.map +1 -1
- package/dist/icons/generated/shard-40.js +41 -41
- package/dist/icons/generated/shard-40.js.map +1 -1
- package/dist/icons/generated/shard-41.cjs +1 -1
- package/dist/icons/generated/shard-41.cjs.map +1 -1
- package/dist/icons/generated/shard-41.js +41 -41
- package/dist/icons/generated/shard-41.js.map +1 -1
- package/dist/icons/generated/shard-42.cjs +1 -1
- package/dist/icons/generated/shard-42.cjs.map +1 -1
- package/dist/icons/generated/shard-42.js +41 -41
- package/dist/icons/generated/shard-42.js.map +1 -1
- package/dist/icons/generated/shard-43.cjs +1 -1
- package/dist/icons/generated/shard-43.cjs.map +1 -1
- package/dist/icons/generated/shard-43.js +41 -41
- package/dist/icons/generated/shard-43.js.map +1 -1
- package/dist/icons/generated/shard-44.cjs +1 -1
- package/dist/icons/generated/shard-44.cjs.map +1 -1
- package/dist/icons/generated/shard-44.js +43 -10
- package/dist/icons/generated/shard-44.js.map +1 -1
- package/dist/icons/generated/shard-45.cjs +2 -0
- package/dist/icons/generated/shard-45.cjs.map +1 -0
- package/dist/icons/generated/shard-45.js +15 -0
- package/dist/icons/generated/shard-45.js.map +1 -0
- package/dist/icons/material-symbols.cjs +1 -1
- package/dist/icons/material-symbols.cjs.map +1 -1
- package/dist/icons/material-symbols.js +3 -3
- package/dist/icons/material-symbols.js.map +1 -1
- package/dist/icons.d.ts +4 -4
- package/dist/query/foreign-client-warning.cjs +1 -1
- package/dist/query/foreign-client-warning.cjs.map +1 -1
- package/dist/query/foreign-client-warning.js +1 -1
- package/dist/query/foreign-client-warning.js.map +1 -1
- package/dist/styles/Alert.css +1 -1
- package/dist/styles/Badge.css +1 -1
- package/dist/styles/BarList.css +3 -3
- package/dist/styles/BottomSheet.css +1 -1
- package/dist/styles/DataTable.css +1 -1
- package/dist/styles/Dropzone.css +1 -1
- package/dist/styles/ErrorText.css +1 -1
- package/dist/styles/Markdown.css +1 -1
- package/dist/styles/PasswordInput.css +1 -1
- package/dist/styles/SegmentedControl.css +1 -1
- package/dist/styles/Sidebar.css +2 -2
- package/dist/styles/StepperInput.css +1 -1
- package/dist/styles/Tag.css +1 -1
- package/dist/styles/Timeline.css +1 -1
- package/dist/styles/Toggle.css +1 -1
- package/dist/styles/ToggleGroup.css +1 -1
- package/dist/styles/advanced.css +2 -2
- package/dist/styles/core.css +4 -2
- package/dist/styles/data.css +6 -6
- package/dist/styles/feedback.css +3 -3
- package/dist/styles/forms.css +3 -3
- package/dist/styles/navigation.css +3 -3
- package/dist/styles/overlay.css +1 -1
- package/dist/styles/utility.css +1 -1
- package/dist/styles.css +1 -1
- package/dist/tempest-react-sdk.cjs +1 -1
- package/dist/tempest-react-sdk.d.ts +81 -7
- package/dist/tempest-react-sdk.js +347 -346
- package/dist/theme/create-theme.cjs +3 -3
- package/dist/theme/create-theme.cjs.map +1 -1
- package/dist/theme/create-theme.js +15 -14
- package/dist/theme/create-theme.js.map +1 -1
- package/dist/utils/dev-mode.cjs +1 -1
- package/dist/utils/dev-mode.cjs.map +1 -1
- package/dist/utils/dev-mode.js +7 -2
- package/dist/utils/dev-mode.js.map +1 -1
- package/dist/utils/json-frame.cjs +1 -1
- package/dist/utils/json-frame.cjs.map +1 -1
- package/dist/utils/json-frame.js +1 -1
- package/dist/utils/json-frame.js.map +1 -1
- package/dist/vision/core/providers.cjs +1 -1
- package/dist/vision/core/providers.cjs.map +1 -1
- package/dist/vision/core/providers.js +22 -3
- package/dist/vision/core/providers.js.map +1 -1
- package/dist/vision/core/session.cjs +1 -1
- package/dist/vision/core/session.cjs.map +1 -1
- package/dist/vision/core/session.js +22 -15
- package/dist/vision/core/session.js.map +1 -1
- package/dist/vision/fusion.cjs.map +1 -1
- package/dist/vision/fusion.js.map +1 -1
- package/dist/vision/index.cjs +1 -1
- package/dist/vision/index.cjs.map +1 -1
- package/dist/vision/index.js +17 -16
- package/dist/vision/index.js.map +1 -1
- package/dist/vision/normalization.cjs +2 -0
- package/dist/vision/normalization.cjs.map +1 -0
- package/dist/vision/normalization.js +49 -0
- package/dist/vision/normalization.js.map +1 -0
- package/dist/vision/results.cjs +1 -1
- package/dist/vision/results.cjs.map +1 -1
- package/dist/vision/results.js +8 -2
- package/dist/vision/results.js.map +1 -1
- package/dist/vision/tasks/classifier.cjs +1 -1
- package/dist/vision/tasks/classifier.cjs.map +1 -1
- package/dist/vision/tasks/classifier.js +36 -32
- package/dist/vision/tasks/classifier.js.map +1 -1
- package/dist/vision.cjs +1 -1
- package/dist/vision.d.ts +218 -13
- package/dist/vision.js +19 -18
- package/dist/vite/tempest-pwa-manifest.cjs +1 -1
- package/dist/vite/tempest-pwa-manifest.cjs.map +1 -1
- package/dist/vite/tempest-pwa-manifest.js +1 -1
- package/dist/vite/tempest-pwa-manifest.js.map +1 -1
- package/dist/webrtc/peer-link.cjs +1 -1
- package/dist/webrtc/peer-link.cjs.map +1 -1
- package/dist/webrtc/peer-link.js +1 -1
- package/dist/webrtc/peer-link.js.map +1 -1
- package/dist/webrtc/peer-mesh.cjs +1 -1
- package/dist/webrtc/peer-mesh.cjs.map +1 -1
- package/dist/webrtc/peer-mesh.js +1 -1
- package/dist/webrtc/peer-mesh.js.map +1 -1
- package/dist/ws/create-web-socket.cjs +1 -1
- package/dist/ws/create-web-socket.cjs.map +1 -1
- package/dist/ws/create-web-socket.js +1 -1
- package/dist/ws/create-web-socket.js.map +1 -1
- package/package.json +1 -1
package/dist/vision.d.ts
CHANGED
|
@@ -204,7 +204,27 @@ export declare class Classifier extends VisionTask {
|
|
|
204
204
|
private readonly _mean;
|
|
205
205
|
private readonly _std;
|
|
206
206
|
private readonly _applySoftmax;
|
|
207
|
+
private readonly _normalization;
|
|
207
208
|
private constructor();
|
|
209
|
+
/**
|
|
210
|
+
* Whether a softmax is applied to the model's output before ranking.
|
|
211
|
+
*
|
|
212
|
+
* Resolved once at construction. Worth reading when confidences look
|
|
213
|
+
* compressed: a second softmax over an already-normalized vector leaves the
|
|
214
|
+
* ordering intact and the numbers meaningless, which is invisible to any check
|
|
215
|
+
* that only looks at the predicted class.
|
|
216
|
+
*/
|
|
217
|
+
get appliesSoftmax(): boolean;
|
|
218
|
+
/**
|
|
219
|
+
* Which preprocessing this classifier applies to every image.
|
|
220
|
+
*
|
|
221
|
+
* One of the {@link Normalization} preset names, or `"custom"` when the caller
|
|
222
|
+
* supplied `mean`/`std` directly. Worth reading when a model underperforms:
|
|
223
|
+
* feeding a classifier a differently prepared tensor than it was trained on
|
|
224
|
+
* degrades it without throwing anything, so "what does this assume" is the
|
|
225
|
+
* first question.
|
|
226
|
+
*/
|
|
227
|
+
get normalization(): string;
|
|
208
228
|
private _pipelineCache;
|
|
209
229
|
/**
|
|
210
230
|
* Run the model once on a zero tensor, paying one-time costs up front.
|
|
@@ -227,7 +247,14 @@ export declare class Classifier extends VisionTask {
|
|
|
227
247
|
* fails if it is actually asked to preprocess something.
|
|
228
248
|
*/
|
|
229
249
|
private get _pipeline();
|
|
230
|
-
/**
|
|
250
|
+
/**
|
|
251
|
+
* Load the model, resolve labels, and settle the preprocessing.
|
|
252
|
+
*
|
|
253
|
+
* @param model The model source — a URL, or the bytes.
|
|
254
|
+
* @param options Labels, input size, normalization, and session options.
|
|
255
|
+
* @throws {RangeError} If `normalization` names an unknown preset, or names
|
|
256
|
+
* one while `mean`/`std` are also given.
|
|
257
|
+
*/
|
|
231
258
|
static create(model: ModelSource, options?: ClassifierOptions): Promise<Classifier>;
|
|
232
259
|
/** Class labels indexed by class id. */
|
|
233
260
|
get labels(): readonly string[];
|
|
@@ -276,14 +303,27 @@ export declare interface ClassifierOptions extends OrtSessionOptions {
|
|
|
276
303
|
* Runtime will accept. Defaults to `[224, 224]`.
|
|
277
304
|
*/
|
|
278
305
|
readonly inputSize?: readonly [number, number];
|
|
279
|
-
/**
|
|
306
|
+
/**
|
|
307
|
+
* Which preprocessing this model expects — see {@link Normalization}.
|
|
308
|
+
*
|
|
309
|
+
* Defaults to `"auto"`, which reads the model's own export metadata and picks
|
|
310
|
+
* `"ultralytics"` (raw `[0, 1]`) for an Ultralytics classification head and
|
|
311
|
+
* `"imagenet"` for everything else.
|
|
312
|
+
*/
|
|
313
|
+
readonly normalization?: Normalization;
|
|
314
|
+
/** Per-channel RGB mean, overriding the preset. Defaults to the preset's. */
|
|
280
315
|
readonly mean?: readonly [number, number, number];
|
|
281
|
-
/** Per-channel RGB standard deviation
|
|
316
|
+
/** Per-channel RGB standard deviation, overriding the preset. */
|
|
282
317
|
readonly std?: readonly [number, number, number];
|
|
283
318
|
/**
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
319
|
+
* Whether the model's output still needs a softmax.
|
|
320
|
+
*
|
|
321
|
+
* Left undefined (the default), this reads the model's metadata and answers
|
|
322
|
+
* `false` for an Ultralytics classification export, whose graph already ends
|
|
323
|
+
* in one — applying a second softmax to a probability vector keeps the
|
|
324
|
+
* ranking but flattens the confidences, so the top-1 stays right while every
|
|
325
|
+
* number attached to it is wrong. Detection covers that family; for any other
|
|
326
|
+
* model that already emits probabilities, pass `false` explicitly.
|
|
287
327
|
*/
|
|
288
328
|
readonly applySoftmax?: boolean;
|
|
289
329
|
}
|
|
@@ -369,6 +409,9 @@ export declare function computeImageLuminance(source: LuminanceSource, reusableC
|
|
|
369
409
|
*/
|
|
370
410
|
export declare type CropSource = "detector_input" | "original";
|
|
371
411
|
|
|
412
|
+
/** Name reported when the caller supplied `mean`/`std` directly. */
|
|
413
|
+
export declare const CUSTOM_NORMALIZATION = "custom";
|
|
414
|
+
|
|
372
415
|
/**
|
|
373
416
|
* One declared dimension: a number when the graph pins it, `null` when the
|
|
374
417
|
* dimension is symbolic (dynamic).
|
|
@@ -951,6 +994,29 @@ export declare const DEFAULT_PROVIDERS: readonly string[];
|
|
|
951
994
|
readonly raiseOnEmpty?: boolean;
|
|
952
995
|
}
|
|
953
996
|
|
|
997
|
+
/**
|
|
998
|
+
* Narrow a provider list to the ones this browser can actually offer.
|
|
999
|
+
*
|
|
1000
|
+
* ORT-Web exposes no equivalent of Node's `session.getProviders()`, so there is
|
|
1001
|
+
* no way to ask which provider a session ended up on. What the browser *does*
|
|
1002
|
+
* answer is whether the underlying API exists at all — no `navigator.gpu`, or no
|
|
1003
|
+
* adapter behind it, means `webgpu` was never going to run — and that covers the
|
|
1004
|
+
* case that actually bites: a page asking for WebGPU on a device without it,
|
|
1005
|
+
* silently getting WASM, and being several times slower than intended with no
|
|
1006
|
+
* error to point at.
|
|
1007
|
+
*
|
|
1008
|
+
* This is best-effort by construction. A provider that survives here can still
|
|
1009
|
+
* fail inside ORT for a reason the browser does not surface (a missing shader
|
|
1010
|
+
* feature, an exhausted device), so a surviving entry means "not ruled out",
|
|
1011
|
+
* not "confirmed running". Anything this function does not know how to test is
|
|
1012
|
+
* kept rather than dropped: guessing a provider away would be worse than
|
|
1013
|
+
* admitting ignorance about it.
|
|
1014
|
+
*
|
|
1015
|
+
* @param requested Providers in preference order, already resolved.
|
|
1016
|
+
* @returns The subset that is not ruled out, in the same order.
|
|
1017
|
+
*/
|
|
1018
|
+
export declare function detectProviders(requested: readonly string[]): Promise<string[]>;
|
|
1019
|
+
|
|
954
1020
|
/**
|
|
955
1021
|
* Convert an HWC BGR uint8 buffer (OpenCV layout) to the SDK's HWC RGB.
|
|
956
1022
|
*
|
|
@@ -1039,6 +1105,12 @@ export declare const DEFAULT_PROVIDERS: readonly string[];
|
|
|
1039
1105
|
readonly needsSourceImage: boolean;
|
|
1040
1106
|
}
|
|
1041
1107
|
|
|
1108
|
+
/** Mean that leaves an image untouched — what an Ultralytics classifier expects. */
|
|
1109
|
+
export declare const IDENTITY_MEAN: readonly [number, number, number];
|
|
1110
|
+
|
|
1111
|
+
/** Deviation that leaves an image untouched — what an Ultralytics classifier expects. */
|
|
1112
|
+
export declare const IDENTITY_STD: readonly [number, number, number];
|
|
1113
|
+
|
|
1042
1114
|
/** Anything {@link loadImage} accepts as an image input. */
|
|
1043
1115
|
export declare type ImageInput = string | Blob | HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap | ImageData | RGBImage;
|
|
1044
1116
|
|
|
@@ -1046,6 +1118,12 @@ export declare const DEFAULT_PROVIDERS: readonly string[];
|
|
|
1046
1118
|
export declare class ImageLoadError extends OrtVisionError {
|
|
1047
1119
|
}
|
|
1048
1120
|
|
|
1121
|
+
/** Per-channel RGB mean of ImageNet, the torchvision preprocessing convention. */
|
|
1122
|
+
export declare const IMAGENET_MEAN: readonly [number, number, number];
|
|
1123
|
+
|
|
1124
|
+
/** Per-channel RGB standard deviation of ImageNet. */
|
|
1125
|
+
export declare const IMAGENET_STD: readonly [number, number, number];
|
|
1126
|
+
|
|
1049
1127
|
/** Raised when ONNX Runtime fails while executing a model. */
|
|
1050
1128
|
export declare class InferenceError extends OrtVisionError {
|
|
1051
1129
|
}
|
|
@@ -1076,6 +1154,17 @@ export declare const DEFAULT_PROVIDERS: readonly string[];
|
|
|
1076
1154
|
*/
|
|
1077
1155
|
export declare function isLuminanceAcceptable(luminance: number, threshold: number): boolean;
|
|
1078
1156
|
|
|
1157
|
+
/**
|
|
1158
|
+
* Whether a metadata map came out of `YOLO(...).export(format="onnx")`.
|
|
1159
|
+
*
|
|
1160
|
+
* Every Ultralytics export stamps `author` and `task` into its metadata, and the
|
|
1161
|
+
* pair is unambiguous: `"Ultralytics"` plus `"classify"` is a classification head
|
|
1162
|
+
* from that codebase and nothing else.
|
|
1163
|
+
*
|
|
1164
|
+
* @param metadata The model's custom metadata map.
|
|
1165
|
+
*/
|
|
1166
|
+
export declare function isUltralyticsClassifier(metadata: Readonly<Record<string, string>>): boolean;
|
|
1167
|
+
|
|
1079
1168
|
/** Raised when class labels cannot be resolved from the supplied spec. */
|
|
1080
1169
|
export declare class LabelMapError extends OrtVisionError {
|
|
1081
1170
|
}
|
|
@@ -1348,6 +1437,39 @@ export declare const DEFAULT_PROVIDERS: readonly string[];
|
|
|
1348
1437
|
export declare class NoDetectionsError extends OrtVisionError {
|
|
1349
1438
|
}
|
|
1350
1439
|
|
|
1440
|
+
/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */
|
|
1441
|
+
/**
|
|
1442
|
+
* Which preprocessing a classifier expects its input to have had.
|
|
1443
|
+
*
|
|
1444
|
+
* A classifier is trained on a specific tensor, and feeding it a differently
|
|
1445
|
+
* prepared one degrades it silently — no exception, no warning, just worse
|
|
1446
|
+
* predictions. The two families this SDK sees most disagree completely:
|
|
1447
|
+
* torchvision-style models want the ImageNet mean and deviation subtracted and
|
|
1448
|
+
* divided out, while an Ultralytics classification head consumes raw `[0, 1]`.
|
|
1449
|
+
*
|
|
1450
|
+
* Guessing wrong is not detectable from the outside, but it is not a guess: an
|
|
1451
|
+
* Ultralytics export stamps `author` and `task` into its own metadata, and every
|
|
1452
|
+
* task in this SDK already reads that map for the class names.
|
|
1453
|
+
*
|
|
1454
|
+
* Mirrors `ort_vision_sdk.normalization` in the Python SDK; the two must agree,
|
|
1455
|
+
* because the same model file is driven by both.
|
|
1456
|
+
*/
|
|
1457
|
+
/**
|
|
1458
|
+
* Which preprocessing the classifier expects its input to have had.
|
|
1459
|
+
*
|
|
1460
|
+
* - `"auto"` (the default wherever it is accepted) reads the model's own export
|
|
1461
|
+
* metadata and picks. An Ultralytics classification head gets
|
|
1462
|
+
* `"ultralytics"`; anything else gets `"imagenet"`.
|
|
1463
|
+
* - `"imagenet"` subtracts the ImageNet mean and divides by the ImageNet
|
|
1464
|
+
* deviation — the torchvision convention.
|
|
1465
|
+
* - `"ultralytics"` leaves the image in `[0, 1]`. Ultralytics' own classifier
|
|
1466
|
+
* applies no mean/std at all, so anything else feeds it images it never saw
|
|
1467
|
+
* in training.
|
|
1468
|
+
* - `"none"` is the same arithmetic as `"ultralytics"` — identity — under a
|
|
1469
|
+
* name that says "this model wants raw `[0, 1]`" rather than naming a vendor.
|
|
1470
|
+
*/
|
|
1471
|
+
export declare type Normalization = "auto" | "imagenet" | "ultralytics" | "none";
|
|
1472
|
+
|
|
1351
1473
|
/**
|
|
1352
1474
|
* Convert a uint8 image to a normalized float32 array (HWC layout preserved).
|
|
1353
1475
|
*
|
|
@@ -1364,8 +1486,32 @@ export declare const DEFAULT_PROVIDERS: readonly string[];
|
|
|
1364
1486
|
*/
|
|
1365
1487
|
export declare class OrtSession {
|
|
1366
1488
|
private readonly _session;
|
|
1489
|
+
/**
|
|
1490
|
+
* Execution providers this session is expected to run on.
|
|
1491
|
+
*
|
|
1492
|
+
* The requested list narrowed to what this browser can actually offer — a
|
|
1493
|
+
* `webgpu` entry survives only where an adapter exists. Best-effort: ORT-Web
|
|
1494
|
+
* exposes no way to ask which provider a session ended up on, so an entry
|
|
1495
|
+
* here means "not ruled out", not "confirmed". See
|
|
1496
|
+
* {@link requestedProviders} for what was asked for.
|
|
1497
|
+
*
|
|
1498
|
+
* When nothing survives — a caller asking for `webgpu` alone on a device
|
|
1499
|
+
* without it — this falls back to {@link FALLBACK_PROVIDER}, which ORT-Web
|
|
1500
|
+
* can always run. Handing ORT the unsatisfiable list instead makes
|
|
1501
|
+
* `InferenceSession.create` reject with "no available backend found", so the
|
|
1502
|
+
* page gets no inference at all rather than the slow-but-working fallback
|
|
1503
|
+
* the `console.warn` describes. Measured in a real Chromium, where
|
|
1504
|
+
* `navigator.gpu` exists but yields no adapter.
|
|
1505
|
+
*/
|
|
1367
1506
|
readonly providers: readonly string[];
|
|
1368
1507
|
private readonly _metadata;
|
|
1508
|
+
/**
|
|
1509
|
+
* Execution providers that were asked for, after defaults were applied.
|
|
1510
|
+
*
|
|
1511
|
+
* Kept separate because ORT-Web falls back silently: a page that asks for
|
|
1512
|
+
* `webgpu` on a device without it runs on WASM and is told nothing.
|
|
1513
|
+
*/
|
|
1514
|
+
readonly requestedProviders: readonly string[];
|
|
1369
1515
|
private constructor();
|
|
1370
1516
|
/**
|
|
1371
1517
|
* Load an ONNX model into an ORT inference session.
|
|
@@ -1449,7 +1595,12 @@ export declare const DEFAULT_PROVIDERS: readonly string[];
|
|
|
1449
1595
|
}
|
|
1450
1596
|
|
|
1451
1597
|
export declare interface OrtSessionOptions {
|
|
1452
|
-
/**
|
|
1598
|
+
/**
|
|
1599
|
+
* Execution providers in preference order. `undefined` uses {@link DEFAULT_PROVIDERS}.
|
|
1600
|
+
*
|
|
1601
|
+
* Naming one explicitly also opts into a `console.warn` when this browser
|
|
1602
|
+
* cannot offer it, instead of falling back in silence.
|
|
1603
|
+
*/
|
|
1453
1604
|
readonly providers?: readonly string[];
|
|
1454
1605
|
/** Optional ORT session options forwarded to `InferenceSession.create`. */
|
|
1455
1606
|
readonly sessionOptions?: ort.InferenceSession.SessionOptions;
|
|
@@ -1484,7 +1635,14 @@ export declare const DEFAULT_PROVIDERS: readonly string[];
|
|
|
1484
1635
|
constructor(message: string, options?: ErrorOptions);
|
|
1485
1636
|
}
|
|
1486
1637
|
|
|
1487
|
-
/**
|
|
1638
|
+
/**
|
|
1639
|
+
* Name of the `[K, 4]` float32 xyxy output, in **letterboxed** input pixels.
|
|
1640
|
+
*
|
|
1641
|
+
* A file fused by `ort-vision-sdk` 0.9.0 or later reports the box that was
|
|
1642
|
+
* actually classified: clamped to the image the crop came from, exactly as
|
|
1643
|
+
* RoiAlign received it. Older files report the raw box, so one that ran off the
|
|
1644
|
+
* frame draws a rectangle wider than the region the classifier saw.
|
|
1645
|
+
*/
|
|
1488
1646
|
export declare const OUTPUT_BOXES = "boxes";
|
|
1489
1647
|
|
|
1490
1648
|
/** Name of the `[K]` int64 detector-class output. */
|
|
@@ -1529,9 +1687,20 @@ export declare const DEFAULT_PROVIDERS: readonly string[];
|
|
|
1529
1687
|
get top1(): number;
|
|
1530
1688
|
/** Probability of the top-1 class. */
|
|
1531
1689
|
get top1conf(): number;
|
|
1532
|
-
/**
|
|
1690
|
+
/**
|
|
1691
|
+
* Indices of the top-5 most probable classes, descending.
|
|
1692
|
+
*
|
|
1693
|
+
* The array is the memoised selection itself, not a copy — reading it twice
|
|
1694
|
+
* hands back the same object. Treat it as read-only: writing into it edits
|
|
1695
|
+
* what every later read of this `Probs` returns.
|
|
1696
|
+
*/
|
|
1533
1697
|
get top5(): Int32Array;
|
|
1534
|
-
/**
|
|
1698
|
+
/**
|
|
1699
|
+
* Probabilities of the top-5 classes, descending.
|
|
1700
|
+
*
|
|
1701
|
+
* Shares the memoised selection with {@link Probs.top5}, under the same
|
|
1702
|
+
* read-only caveat.
|
|
1703
|
+
*/
|
|
1535
1704
|
get top5conf(): Float32Array;
|
|
1536
1705
|
private _cache;
|
|
1537
1706
|
/**
|
|
@@ -1552,12 +1721,14 @@ export declare const DEFAULT_PROVIDERS: readonly string[];
|
|
|
1552
1721
|
* A full sort to read five entries out of a thousand-class vector costs
|
|
1553
1722
|
* O(n log n) plus an index array the size of the vector; keeping `k` slots
|
|
1554
1723
|
* ordered by insertion and scanning once costs O(n·k) with no allocation
|
|
1555
|
-
* beyond the result. Measured on 1000 classes
|
|
1556
|
-
* 1.
|
|
1724
|
+
* beyond the result. Measured on 1000 classes over 2000 iterations, 134.5 µs
|
|
1725
|
+
* against 1.5 µs for the same output.
|
|
1557
1726
|
*
|
|
1558
1727
|
* Ties keep the lower class index first, matching the stable sort this
|
|
1559
1728
|
* replaced: a candidate only displaces an entry it is strictly greater
|
|
1560
|
-
* than.
|
|
1729
|
+
* than. That is also what keeps this selection in step with the Python
|
|
1730
|
+
* SDK's `np.argsort(-data, kind="stable")`, where the sort is C and the
|
|
1731
|
+
* cost this avoids does not arise.
|
|
1561
1732
|
*
|
|
1562
1733
|
* @param k - How many classes to select.
|
|
1563
1734
|
* @returns Indices and probabilities, descending by probability.
|
|
@@ -1722,6 +1893,16 @@ export declare const DEFAULT_PROVIDERS: readonly string[];
|
|
|
1722
1893
|
*/
|
|
1723
1894
|
export declare function resizeToTensorData(image: RGBImage, targetWidth: number, targetHeight: number, mean?: readonly [number, number, number], std?: readonly [number, number, number]): FusedResizeResult;
|
|
1724
1895
|
|
|
1896
|
+
/** What {@link resolveNormalization} settled on. */
|
|
1897
|
+
export declare interface ResolvedNormalization {
|
|
1898
|
+
/** The preset name, or `"custom"` when the caller supplied the values. */
|
|
1899
|
+
readonly name: string;
|
|
1900
|
+
/** Per-channel mean to subtract. */
|
|
1901
|
+
readonly mean: readonly [number, number, number];
|
|
1902
|
+
/** Per-channel deviation to divide by. */
|
|
1903
|
+
readonly std: readonly [number, number, number];
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1725
1906
|
/**
|
|
1726
1907
|
* Decide the input size a task will preprocess to.
|
|
1727
1908
|
*
|
|
@@ -1757,6 +1938,30 @@ export declare const DEFAULT_PROVIDERS: readonly string[];
|
|
|
1757
1938
|
readonly numClasses?: number;
|
|
1758
1939
|
}
|
|
1759
1940
|
|
|
1941
|
+
/**
|
|
1942
|
+
* Settle which `mean`/`std` to apply, and what to call the choice.
|
|
1943
|
+
*
|
|
1944
|
+
* Explicit `mean`/`std` always win — they are the escape hatch for a model whose
|
|
1945
|
+
* preprocessing neither preset describes. Anything they leave open falls back to
|
|
1946
|
+
* the preset, so passing only a `mean` does not silently reset the deviation
|
|
1947
|
+
* to 1.
|
|
1948
|
+
*
|
|
1949
|
+
* Warns (via `console.warn`) when the model is an Ultralytics export and the
|
|
1950
|
+
* supplied values are not the identity it was trained with. Nothing fails in
|
|
1951
|
+
* that case: the prediction has the right shape and is simply less accurate,
|
|
1952
|
+
* which is exactly why it is worth saying out loud.
|
|
1953
|
+
*
|
|
1954
|
+
* @param metadata The model's custom metadata map, read to detect the family.
|
|
1955
|
+
* @param options The preset asked for, plus any explicit `mean`/`std`.
|
|
1956
|
+
* @throws {RangeError} If `normalization` is not a known preset, or names one
|
|
1957
|
+
* while `mean`/`std` are also supplied — two answers to the same question.
|
|
1958
|
+
*/
|
|
1959
|
+
export declare function resolveNormalization(metadata: Readonly<Record<string, string>>, options?: {
|
|
1960
|
+
readonly normalization?: Normalization;
|
|
1961
|
+
readonly mean?: readonly [number, number, number];
|
|
1962
|
+
readonly std?: readonly [number, number, number];
|
|
1963
|
+
}): ResolvedNormalization;
|
|
1964
|
+
|
|
1760
1965
|
/**
|
|
1761
1966
|
* Resolve the execution providers to pass to `InferenceSession.create`.
|
|
1762
1967
|
*
|
package/dist/vision.js
CHANGED
|
@@ -6,21 +6,22 @@ import { Boxes as p, ClassificationResults as m, DetectClassifyResults as h, Det
|
|
|
6
6
|
import { COCO_CLASSES as b, defaultLabels as x, resolveLabels as S } from "./vision/labels.js";
|
|
7
7
|
import { classificationNumClasses as C, declaredShapesFrom as w, detectionNumClasses as T, resolveInputSize as E, spatialInputSize as D } from "./vision/core/graph.js";
|
|
8
8
|
import { modelNames as O, parseNames as k, readModelMetadata as A } from "./vision/core/metadata.js";
|
|
9
|
-
import { DEFAULT_PROVIDERS as j,
|
|
10
|
-
import { OrtSession as
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
|
|
9
|
+
import { DEFAULT_PROVIDERS as j, detectProviders as M, resolveProviders as N } from "./vision/core/providers.js";
|
|
10
|
+
import { OrtSession as P } from "./vision/core/session.js";
|
|
11
|
+
import { CUSTOM_NORMALIZATION as F, IDENTITY_MEAN as I, IDENTITY_STD as L, IMAGENET_MEAN as R, IMAGENET_STD as z, isUltralyticsClassifier as B, resolveNormalization as V } from "./vision/normalization.js";
|
|
12
|
+
import { loadImage as H } from "./vision/io/image.js";
|
|
13
|
+
import { FUSION_KIND_DETECT_CLASSIFY as U, INPUT_IMAGE as W, INPUT_PAD as G, INPUT_SCALE as K, INPUT_SOURCE as q, METADATA_PREFIX as J, OUTPUT_BOXES as Y, OUTPUT_CLASSES as X, OUTPUT_NUM_DETECTIONS as Z, OUTPUT_PROBS as Q, OUTPUT_SCORES as $, readFusionSpec as ee } from "./vision/fusion.js";
|
|
14
|
+
import { fromCv2 as te, letterbox as ne, normalize as re, resize as ie, toCHW as ae, toCv2 as oe, toFloat32 as se, toFloat32Tensor as ce, toTensor as le } from "./vision/preprocess/image.js";
|
|
15
|
+
import { LetterboxPipeline as ue, ResizePipeline as de, letterboxToTensorData as fe, resizeToTensorData as pe, writePlanarFloat32 as me, zeroTensorData as he } from "./vision/preprocess/pipeline.js";
|
|
16
|
+
import { softmax as ge, topK as _e } from "./vision/postprocess/classification.js";
|
|
17
|
+
import { batchedNms as ve, decodeYolo as ye, decodeYoloAnchors as be, nms as xe } from "./vision/postprocess/detection.js";
|
|
18
|
+
import { decodeYoloSeg as Se } from "./vision/postprocess/segmentation.js";
|
|
19
|
+
import { VisionTask as Ce, requireDetections as we } from "./vision/tasks/base.js";
|
|
20
|
+
import { Classifier as Te } from "./vision/tasks/classifier.js";
|
|
21
|
+
import { DetectClassify as Ee } from "./vision/tasks/detectClassify.js";
|
|
22
|
+
import { Detector as De } from "./vision/tasks/detector.js";
|
|
23
|
+
import { Segmenter as Oe } from "./vision/tasks/segmenter.js";
|
|
24
|
+
import { VERSION as ke } from "./vision/index.js";
|
|
25
|
+
import { LUMINANCE_SAMPLE_MAX_EDGE as Ae, LowLuminanceError as je, computeImageLuminance as Me, isLuminanceAcceptable as Ne } from "./vision/luminance.js";
|
|
26
|
+
import { useLiveLuminance as Pe } from "./vision/use-live-luminance.js";
|
|
27
|
+
export { l as BoundingBox, p as Boxes, b as COCO_CLASSES, F as CUSTOM_NORMALIZATION, m as ClassificationResults, Te as Classifier, j as DEFAULT_PROVIDERS, Ee as DetectClassify, h as DetectClassifyResults, g as DetectionResults, De as Detector, U as FUSION_KIND_DETECT_CLASSIFY, t as FusionError, I as IDENTITY_MEAN, L as IDENTITY_STD, R as IMAGENET_MEAN, z as IMAGENET_STD, W as INPUT_IMAGE, G as INPUT_PAD, K as INPUT_SCALE, q as INPUT_SOURCE, n as ImageLoadError, r as InferenceError, Ae as LUMINANCE_SAMPLE_MAX_EDGE, i as LabelMapError, ue as LetterboxPipeline, je as LowLuminanceError, J as METADATA_PREFIX, u as Mask, _ as Masks, a as ModelLoadError, o as NoDetectionsError, Y as OUTPUT_BOXES, X as OUTPUT_CLASSES, Z as OUTPUT_NUM_DETECTIONS, Q as OUTPUT_PROBS, $ as OUTPUT_SCORES, P as OrtSession, s as OrtVisionError, v as Probs, c as ProviderNotAvailableError, d as RGBImage, de as ResizePipeline, y as SegmentationResults, Oe as Segmenter, f as SpeedTimer, ke as VERSION, Ce as VisionTask, ve as batchedNms, C as classificationNumClasses, Me as computeImageLuminance, w as declaredShapesFrom, ye as decodeYolo, be as decodeYoloAnchors, Se as decodeYoloSeg, x as defaultLabels, M as detectProviders, T as detectionNumClasses, te as fromCv2, Ne as isLuminanceAcceptable, B as isUltralyticsClassifier, ne as letterbox, fe as letterboxToTensorData, H as loadImage, O as modelNames, xe as nms, re as normalize, k as parseNames, ee as readFusionSpec, A as readModelMetadata, we as requireDetections, ie as resize, pe as resizeToTensorData, E as resolveInputSize, S as resolveLabels, V as resolveNormalization, N as resolveProviders, ge as softmax, D as spatialInputSize, ae as toCHW, oe as toCv2, se as toFloat32, ce as toFloat32Tensor, le as toTensor, _e as topK, e as useCameraStream, Pe as useLiveLuminance, me as writePlanarFloat32, he as zeroTensorData };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
const e=require("./base-url.cjs");function t(t,n){return`${e.basePrefix(t)}${n}`.replace(/([^:]\/)\/+/g,`$1`)}function n(t,n){let r=e.basePrefix(t);return r===`/`?n.startsWith(`/`)?n:`/${n}`:n.startsWith(r)?n:`${r}${n.replace(/^\//,``)}`}function r(e){let t=5381;for(let n=0;n<e.length;n++)t=(t<<5)+t+e.charCodeAt(n)>>>0;return t.toString(16)}function i(e={}){let{fileName:i=`precache-manifest.json`,additionalUrls:a=[],exclude:o=/\.map$/,includeHtml:s=!0,appShell:c=`/index.html`}=e,l=`/`;return{name:`tempest-pwa-manifest`,apply:`build`,configResolved(e){l=e.base??`/`},generateBundle(e,u){let d=new Set(a.map(e=>n(l,e)));c&&d.add(n(l,c));for(let e of Object.keys(u))e!==i&&(o.test(e)||!
|
|
1
|
+
const e=require("./base-url.cjs");function t(t,n){return`${e.basePrefix(t)}${n}`.replace(/([^:]\/)\/+/g,`$1`)}function n(t,n){let r=e.basePrefix(t);return r===`/`?n.startsWith(`/`)?n:`/${n}`:n.startsWith(r)?n:`${r}${n.replace(/^\//,``)}`}function r(e){let t=5381;for(let n=0;n<e.length;n++)t=(t<<5)+t+e.charCodeAt(n)>>>0;return t.toString(16)}function i(e={}){let{fileName:i=`precache-manifest.json`,additionalUrls:a=[],exclude:o=/\.map$/,includeHtml:s=!0,appShell:c=`/index.html`}=e,l=`/`;return{name:`tempest-pwa-manifest`,apply:`build`,configResolved(e){l=e.base??`/`},generateBundle(e,u){let d=new Set(a.map(e=>n(l,e)));c&&d.add(n(l,c));for(let e of Object.keys(u))e!==i&&(o.test(e)||(s||!e.endsWith(`.html`))&&d.add(t(l,e)));let f=[...d].sort(),p=r(f.join(`
|
|
2
2
|
`));this.emitFile({type:`asset`,fileName:i,source:JSON.stringify({version:p,urls:f})})}}}exports.tempestPwaManifest=i;
|
|
3
3
|
//# sourceMappingURL=tempest-pwa-manifest.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tempest-pwa-manifest.cjs","names":[],"sources":["../../src/vite/tempest-pwa-manifest.ts"],"sourcesContent":["import type { Plugin } from \"vite\";\nimport { basePrefix } from \"./base-url\";\n\n/**\n * A Vite plugin object. Typed loosely so the SDK's published declarations stay\n * free of `vite`'s internal types (which the `.d.ts` rollup can't analyze);\n * assign the result straight into a `plugins: [...]` array.\n */\nexport type TempestVitePlugin = { name: string } & Record<string, unknown>;\n\n/** Options for {@link tempestPwaManifest}. */\nexport interface TempestPwaManifestOptions {\n /** Output file name (under the build root). Default `precache-manifest.json`. */\n fileName?: string;\n /**\n * Extra URLs to precache that Vite doesn't emit into the bundle — typically\n * `public/` assets like the web manifest and icons. Default `[]`.\n *\n * Write these relative to the site root (`/icon.svg`); the resolved Vite\n * `base` is prefixed for you. An entry that already carries the base is\n * left alone, so spelling it out by hand is still correct.\n */\n additionalUrls?: string[];\n /** Emitted files matching this are skipped. Default `/\\.map$/` (source maps). */\n exclude?: RegExp;\n /** Include emitted `.html` documents (the app shell). Default `true`. */\n includeHtml?: boolean;\n /**\n * App-shell document always added to the manifest, even if Vite emits it\n * after this plugin runs. Must match `installPrecache`'s `navigateFallback`\n * so offline navigations resolve. Pass `false` to disable. Default `/index.html`.\n *\n * Like {@link TempestPwaManifestOptions.additionalUrls}, this is prefixed\n * with the resolved Vite `base`.\n */\n appShell?: string | false;\n}\n\nfunction joinBase(base: string, file: string): string {\n return `${basePrefix(base)}${file}`.replace(/([^:]\\/)\\/+/g, \"$1\");\n}\n\n/**\n * Prefix a caller-supplied, root-absolute URL with the resolved Vite `base`.\n *\n * Idempotent: a URL that already starts with the base is returned untouched,\n * so configs written before this was applied — spelling the base out by hand —\n * keep producing the same manifest instead of gaining a doubled prefix.\n */\nfunction withBase(base: string, url: string): string {\n const prefix = basePrefix(base);\n if (prefix === \"/\") return url.startsWith(\"/\") ? url : `/${url}`;\n if (url.startsWith(prefix)) return url;\n return `${prefix}${url.replace(/^\\//, \"\")}`;\n}\n\n/** Deterministic djb2 hash → hex. Stable across rebuilds with the same assets. */\nfunction hash(input: string): string {\n let h = 5381;\n for (let i = 0; i < input.length; i++) {\n h = ((h << 5) + h + input.charCodeAt(i)) >>> 0;\n }\n return h.toString(16);\n}\n\n/**\n * Vite build plugin that emits a `precache-manifest.json` listing every built\n * asset (plus any `additionalUrls`) as root-absolute URLs, with a content-based\n * `version`. It is the dependency-free counterpart to Workbox's `__WB_MANIFEST`:\n * `installPrecache` (from `tempest-react-sdk/sw`) reads this file at the service\n * worker's `install` event to cache the app shell for offline use.\n *\n * @example\n * // vite.config.ts\n * import { createViteConfig, tempestPwaManifest } from \"tempest-react-sdk/vite\";\n *\n * export default createViteConfig({\n * plugins: [tempestPwaManifest({ additionalUrls: [\"/manifest.webmanifest\", \"/icon.svg\"] })],\n * });\n */\nexport function tempestPwaManifest(options: TempestPwaManifestOptions = {}): TempestVitePlugin {\n const {\n fileName = \"precache-manifest.json\",\n additionalUrls = [],\n exclude = /\\.map$/,\n includeHtml = true,\n appShell = \"/index.html\",\n } = options;\n\n let base = \"/\";\n\n const plugin: Plugin = {\n name: \"tempest-pwa-manifest\",\n apply: \"build\",\n configResolved(config) {\n base = config.base ?? \"/\";\n },\n generateBundle(_outputOptions, bundle) {\n const urls = new Set<string>(additionalUrls.map((url) => withBase(base, url)));\n // Vite may emit index.html after this hook, so guarantee the shell.\n if (appShell) urls.add(withBase(base, appShell));\n for (const file of Object.keys(bundle)) {\n if (file === fileName) continue;\n if (exclude.test(file)) continue;\n if (!includeHtml && file.endsWith(\".html\")) continue;\n urls.add(joinBase(base, file));\n }\n\n const list = [...urls].sort();\n const version = hash(list.join(\"\\n\"));\n this.emitFile({\n type: \"asset\",\n fileName,\n source: JSON.stringify({ version, urls: list }),\n });\n },\n };\n\n return plugin as TempestVitePlugin;\n}\n"],"mappings":"kCAsCA,SAAS,EAAS,EAAc,EAAsB,CAClD,MAAO,GAAG,EAAA,WAAW,CAAI,IAAI,IAAO,QAAQ,eAAgB,IAAI,CACpE,CASA,SAAS,EAAS,EAAc,EAAqB,CACjD,IAAM,EAAS,EAAA,WAAW,CAAI,EAG9B,OAFI,IAAW,IAAY,EAAI,WAAW,GAAG,EAAI,EAAM,IAAI,IACvD,EAAI,WAAW,CAAM,EAAU,EAC5B,GAAG,IAAS,EAAI,QAAQ,MAAO,EAAE,GAC5C,CAGA,SAAS,EAAK,EAAuB,CACjC,IAAI,EAAI,KACR,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,OAAQ,IAC9B,GAAM,GAAK,GAAK,EAAI,EAAM,WAAW,CAAC,IAAO,EAEjD,OAAO,EAAE,SAAS,EAAE,CACxB,CAiBA,SAAgB,EAAmB,EAAqC,CAAC,EAAsB,CAC3F,GAAM,CACF,WAAW,yBACX,iBAAiB,CAAC,EAClB,UAAU,SACV,cAAc,GACd,WAAW,eACX,EAEA,EAAO,IA6BX,MAAO,CA1BH,KAAM,uBACN,MAAO,QACP,eAAe,EAAQ,CACnB,EAAO,EAAO,MAAQ,GAC1B,EACA,eAAe,EAAgB,EAAQ,CACnC,IAAM,EAAO,IAAI,IAAY,EAAe,IAAK,GAAQ,EAAS,EAAM,CAAG,CAAC,CAAC,EAEzE,GAAU,EAAK,IAAI,EAAS,EAAM,CAAQ,CAAC,EAC/C,IAAK,IAAM,KAAQ,OAAO,KAAK,CAAM,EAC7B,IAAS,IACT,EAAQ,KAAK,CAAI,
|
|
1
|
+
{"version":3,"file":"tempest-pwa-manifest.cjs","names":[],"sources":["../../src/vite/tempest-pwa-manifest.ts"],"sourcesContent":["import type { Plugin } from \"vite\";\nimport { basePrefix } from \"./base-url\";\n\n/**\n * A Vite plugin object. Typed loosely so the SDK's published declarations stay\n * free of `vite`'s internal types (which the `.d.ts` rollup can't analyze);\n * assign the result straight into a `plugins: [...]` array.\n */\nexport type TempestVitePlugin = { name: string } & Record<string, unknown>;\n\n/** Options for {@link tempestPwaManifest}. */\nexport interface TempestPwaManifestOptions {\n /** Output file name (under the build root). Default `precache-manifest.json`. */\n fileName?: string;\n /**\n * Extra URLs to precache that Vite doesn't emit into the bundle — typically\n * `public/` assets like the web manifest and icons. Default `[]`.\n *\n * Write these relative to the site root (`/icon.svg`); the resolved Vite\n * `base` is prefixed for you. An entry that already carries the base is\n * left alone, so spelling it out by hand is still correct.\n */\n additionalUrls?: string[];\n /** Emitted files matching this are skipped. Default `/\\.map$/` (source maps). */\n exclude?: RegExp;\n /** Include emitted `.html` documents (the app shell). Default `true`. */\n includeHtml?: boolean;\n /**\n * App-shell document always added to the manifest, even if Vite emits it\n * after this plugin runs. Must match `installPrecache`'s `navigateFallback`\n * so offline navigations resolve. Pass `false` to disable. Default `/index.html`.\n *\n * Like {@link TempestPwaManifestOptions.additionalUrls}, this is prefixed\n * with the resolved Vite `base`.\n */\n appShell?: string | false;\n}\n\nfunction joinBase(base: string, file: string): string {\n return `${basePrefix(base)}${file}`.replace(/([^:]\\/)\\/+/g, \"$1\");\n}\n\n/**\n * Prefix a caller-supplied, root-absolute URL with the resolved Vite `base`.\n *\n * Idempotent: a URL that already starts with the base is returned untouched,\n * so configs written before this was applied — spelling the base out by hand —\n * keep producing the same manifest instead of gaining a doubled prefix.\n */\nfunction withBase(base: string, url: string): string {\n const prefix = basePrefix(base);\n if (prefix === \"/\") return url.startsWith(\"/\") ? url : `/${url}`;\n if (url.startsWith(prefix)) return url;\n return `${prefix}${url.replace(/^\\//, \"\")}`;\n}\n\n/** Deterministic djb2 hash → hex. Stable across rebuilds with the same assets. */\nfunction hash(input: string): string {\n let h = 5381;\n for (let i = 0; i < input.length; i++) {\n h = ((h << 5) + h + input.charCodeAt(i)) >>> 0;\n }\n return h.toString(16);\n}\n\n/**\n * Vite build plugin that emits a `precache-manifest.json` listing every built\n * asset (plus any `additionalUrls`) as root-absolute URLs, with a content-based\n * `version`. It is the dependency-free counterpart to Workbox's `__WB_MANIFEST`:\n * `installPrecache` (from `tempest-react-sdk/sw`) reads this file at the service\n * worker's `install` event to cache the app shell for offline use.\n *\n * @example\n * // vite.config.ts\n * import { createViteConfig, tempestPwaManifest } from \"tempest-react-sdk/vite\";\n *\n * export default createViteConfig({\n * plugins: [tempestPwaManifest({ additionalUrls: [\"/manifest.webmanifest\", \"/icon.svg\"] })],\n * });\n */\nexport function tempestPwaManifest(options: TempestPwaManifestOptions = {}): TempestVitePlugin {\n const {\n fileName = \"precache-manifest.json\",\n additionalUrls = [],\n exclude = /\\.map$/,\n includeHtml = true,\n appShell = \"/index.html\",\n } = options;\n\n let base = \"/\";\n\n const plugin: Plugin = {\n name: \"tempest-pwa-manifest\",\n apply: \"build\",\n configResolved(config) {\n base = config.base ?? \"/\";\n },\n generateBundle(_outputOptions, bundle) {\n const urls = new Set<string>(additionalUrls.map((url) => withBase(base, url)));\n // Vite may emit index.html after this hook, so guarantee the shell.\n if (appShell) urls.add(withBase(base, appShell));\n for (const file of Object.keys(bundle)) {\n if (file === fileName) continue;\n if (exclude.test(file)) continue;\n if (!includeHtml && file.endsWith(\".html\")) continue;\n urls.add(joinBase(base, file));\n }\n\n const list = [...urls].sort();\n const version = hash(list.join(\"\\n\"));\n this.emitFile({\n type: \"asset\",\n fileName,\n source: JSON.stringify({ version, urls: list }),\n });\n },\n };\n\n return plugin as TempestVitePlugin;\n}\n"],"mappings":"kCAsCA,SAAS,EAAS,EAAc,EAAsB,CAClD,MAAO,GAAG,EAAA,WAAW,CAAI,IAAI,IAAO,QAAQ,eAAgB,IAAI,CACpE,CASA,SAAS,EAAS,EAAc,EAAqB,CACjD,IAAM,EAAS,EAAA,WAAW,CAAI,EAG9B,OAFI,IAAW,IAAY,EAAI,WAAW,GAAG,EAAI,EAAM,IAAI,IACvD,EAAI,WAAW,CAAM,EAAU,EAC5B,GAAG,IAAS,EAAI,QAAQ,MAAO,EAAE,GAC5C,CAGA,SAAS,EAAK,EAAuB,CACjC,IAAI,EAAI,KACR,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,OAAQ,IAC9B,GAAM,GAAK,GAAK,EAAI,EAAM,WAAW,CAAC,IAAO,EAEjD,OAAO,EAAE,SAAS,EAAE,CACxB,CAiBA,SAAgB,EAAmB,EAAqC,CAAC,EAAsB,CAC3F,GAAM,CACF,WAAW,yBACX,iBAAiB,CAAC,EAClB,UAAU,SACV,cAAc,GACd,WAAW,eACX,EAEA,EAAO,IA6BX,MAAO,CA1BH,KAAM,uBACN,MAAO,QACP,eAAe,EAAQ,CACnB,EAAO,EAAO,MAAQ,GAC1B,EACA,eAAe,EAAgB,EAAQ,CACnC,IAAM,EAAO,IAAI,IAAY,EAAe,IAAK,GAAQ,EAAS,EAAM,CAAG,CAAC,CAAC,EAEzE,GAAU,EAAK,IAAI,EAAS,EAAM,CAAQ,CAAC,EAC/C,IAAK,IAAM,KAAQ,OAAO,KAAK,CAAM,EAC7B,IAAS,IACT,EAAQ,KAAK,CAAI,IAChB,GAAe,GAAK,SAAS,OAAO,IACzC,EAAK,IAAI,EAAS,EAAM,CAAI,CAAC,GAGjC,IAAM,EAAO,CAAC,GAAG,CAAI,CAAC,CAAC,KAAK,EACtB,EAAU,EAAK,EAAK,KAAK;CAAI,CAAC,EACpC,KAAK,SAAS,CACV,KAAM,QACN,WACA,OAAQ,KAAK,UAAU,CAAE,UAAS,KAAM,CAAK,CAAC,CAClD,CAAC,CACL,CAGG,CACX"}
|
|
@@ -23,7 +23,7 @@ function i(e = {}) {
|
|
|
23
23
|
generateBundle(e, u) {
|
|
24
24
|
let d = new Set(a.map((e) => n(l, e)));
|
|
25
25
|
c && d.add(n(l, c));
|
|
26
|
-
for (let e of Object.keys(u)) e !== i && (o.test(e) ||
|
|
26
|
+
for (let e of Object.keys(u)) e !== i && (o.test(e) || (s || !e.endsWith(".html")) && d.add(t(l, e)));
|
|
27
27
|
let f = [...d].sort(), p = r(f.join("\n"));
|
|
28
28
|
this.emitFile({
|
|
29
29
|
type: "asset",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tempest-pwa-manifest.js","names":[],"sources":["../../src/vite/tempest-pwa-manifest.ts"],"sourcesContent":["import type { Plugin } from \"vite\";\nimport { basePrefix } from \"./base-url\";\n\n/**\n * A Vite plugin object. Typed loosely so the SDK's published declarations stay\n * free of `vite`'s internal types (which the `.d.ts` rollup can't analyze);\n * assign the result straight into a `plugins: [...]` array.\n */\nexport type TempestVitePlugin = { name: string } & Record<string, unknown>;\n\n/** Options for {@link tempestPwaManifest}. */\nexport interface TempestPwaManifestOptions {\n /** Output file name (under the build root). Default `precache-manifest.json`. */\n fileName?: string;\n /**\n * Extra URLs to precache that Vite doesn't emit into the bundle — typically\n * `public/` assets like the web manifest and icons. Default `[]`.\n *\n * Write these relative to the site root (`/icon.svg`); the resolved Vite\n * `base` is prefixed for you. An entry that already carries the base is\n * left alone, so spelling it out by hand is still correct.\n */\n additionalUrls?: string[];\n /** Emitted files matching this are skipped. Default `/\\.map$/` (source maps). */\n exclude?: RegExp;\n /** Include emitted `.html` documents (the app shell). Default `true`. */\n includeHtml?: boolean;\n /**\n * App-shell document always added to the manifest, even if Vite emits it\n * after this plugin runs. Must match `installPrecache`'s `navigateFallback`\n * so offline navigations resolve. Pass `false` to disable. Default `/index.html`.\n *\n * Like {@link TempestPwaManifestOptions.additionalUrls}, this is prefixed\n * with the resolved Vite `base`.\n */\n appShell?: string | false;\n}\n\nfunction joinBase(base: string, file: string): string {\n return `${basePrefix(base)}${file}`.replace(/([^:]\\/)\\/+/g, \"$1\");\n}\n\n/**\n * Prefix a caller-supplied, root-absolute URL with the resolved Vite `base`.\n *\n * Idempotent: a URL that already starts with the base is returned untouched,\n * so configs written before this was applied — spelling the base out by hand —\n * keep producing the same manifest instead of gaining a doubled prefix.\n */\nfunction withBase(base: string, url: string): string {\n const prefix = basePrefix(base);\n if (prefix === \"/\") return url.startsWith(\"/\") ? url : `/${url}`;\n if (url.startsWith(prefix)) return url;\n return `${prefix}${url.replace(/^\\//, \"\")}`;\n}\n\n/** Deterministic djb2 hash → hex. Stable across rebuilds with the same assets. */\nfunction hash(input: string): string {\n let h = 5381;\n for (let i = 0; i < input.length; i++) {\n h = ((h << 5) + h + input.charCodeAt(i)) >>> 0;\n }\n return h.toString(16);\n}\n\n/**\n * Vite build plugin that emits a `precache-manifest.json` listing every built\n * asset (plus any `additionalUrls`) as root-absolute URLs, with a content-based\n * `version`. It is the dependency-free counterpart to Workbox's `__WB_MANIFEST`:\n * `installPrecache` (from `tempest-react-sdk/sw`) reads this file at the service\n * worker's `install` event to cache the app shell for offline use.\n *\n * @example\n * // vite.config.ts\n * import { createViteConfig, tempestPwaManifest } from \"tempest-react-sdk/vite\";\n *\n * export default createViteConfig({\n * plugins: [tempestPwaManifest({ additionalUrls: [\"/manifest.webmanifest\", \"/icon.svg\"] })],\n * });\n */\nexport function tempestPwaManifest(options: TempestPwaManifestOptions = {}): TempestVitePlugin {\n const {\n fileName = \"precache-manifest.json\",\n additionalUrls = [],\n exclude = /\\.map$/,\n includeHtml = true,\n appShell = \"/index.html\",\n } = options;\n\n let base = \"/\";\n\n const plugin: Plugin = {\n name: \"tempest-pwa-manifest\",\n apply: \"build\",\n configResolved(config) {\n base = config.base ?? \"/\";\n },\n generateBundle(_outputOptions, bundle) {\n const urls = new Set<string>(additionalUrls.map((url) => withBase(base, url)));\n // Vite may emit index.html after this hook, so guarantee the shell.\n if (appShell) urls.add(withBase(base, appShell));\n for (const file of Object.keys(bundle)) {\n if (file === fileName) continue;\n if (exclude.test(file)) continue;\n if (!includeHtml && file.endsWith(\".html\")) continue;\n urls.add(joinBase(base, file));\n }\n\n const list = [...urls].sort();\n const version = hash(list.join(\"\\n\"));\n this.emitFile({\n type: \"asset\",\n fileName,\n source: JSON.stringify({ version, urls: list }),\n });\n },\n };\n\n return plugin as TempestVitePlugin;\n}\n"],"mappings":";;AAsCA,SAAS,EAAS,GAAc,GAAsB;CAClD,OAAO,GAAG,EAAW,CAAI,IAAI,IAAO,QAAQ,gBAAgB,IAAI;AACpE;AASA,SAAS,EAAS,GAAc,GAAqB;CACjD,IAAM,IAAS,EAAW,CAAI;CAG9B,OAFI,MAAW,MAAY,EAAI,WAAW,GAAG,IAAI,IAAM,IAAI,MACvD,EAAI,WAAW,CAAM,IAAU,IAC5B,GAAG,IAAS,EAAI,QAAQ,OAAO,EAAE;AAC5C;AAGA,SAAS,EAAK,GAAuB;CACjC,IAAI,IAAI;CACR,KAAK,IAAI,IAAI,GAAG,IAAI,EAAM,QAAQ,KAC9B,KAAM,KAAK,KAAK,IAAI,EAAM,WAAW,CAAC,MAAO;CAEjD,OAAO,EAAE,SAAS,EAAE;AACxB;AAiBA,SAAgB,EAAmB,IAAqC,CAAC,GAAsB;CAC3F,IAAM,EACF,cAAW,0BACX,oBAAiB,CAAC,GAClB,aAAU,UACV,iBAAc,IACd,cAAW,kBACX,GAEA,IAAO;CA6BX,OAAO;EA1BH,MAAM;EACN,OAAO;EACP,eAAe,GAAQ;GACnB,IAAO,EAAO,QAAQ;EAC1B;EACA,eAAe,GAAgB,GAAQ;GACnC,IAAM,IAAO,IAAI,IAAY,EAAe,KAAK,MAAQ,EAAS,GAAM,CAAG,CAAC,CAAC;GAE7E,AAAI,KAAU,EAAK,IAAI,EAAS,GAAM,CAAQ,CAAC;GAC/C,KAAK,IAAM,KAAQ,OAAO,KAAK,CAAM,GAC7B,MAAS,MACT,EAAQ,KAAK,CAAI,
|
|
1
|
+
{"version":3,"file":"tempest-pwa-manifest.js","names":[],"sources":["../../src/vite/tempest-pwa-manifest.ts"],"sourcesContent":["import type { Plugin } from \"vite\";\nimport { basePrefix } from \"./base-url\";\n\n/**\n * A Vite plugin object. Typed loosely so the SDK's published declarations stay\n * free of `vite`'s internal types (which the `.d.ts` rollup can't analyze);\n * assign the result straight into a `plugins: [...]` array.\n */\nexport type TempestVitePlugin = { name: string } & Record<string, unknown>;\n\n/** Options for {@link tempestPwaManifest}. */\nexport interface TempestPwaManifestOptions {\n /** Output file name (under the build root). Default `precache-manifest.json`. */\n fileName?: string;\n /**\n * Extra URLs to precache that Vite doesn't emit into the bundle — typically\n * `public/` assets like the web manifest and icons. Default `[]`.\n *\n * Write these relative to the site root (`/icon.svg`); the resolved Vite\n * `base` is prefixed for you. An entry that already carries the base is\n * left alone, so spelling it out by hand is still correct.\n */\n additionalUrls?: string[];\n /** Emitted files matching this are skipped. Default `/\\.map$/` (source maps). */\n exclude?: RegExp;\n /** Include emitted `.html` documents (the app shell). Default `true`. */\n includeHtml?: boolean;\n /**\n * App-shell document always added to the manifest, even if Vite emits it\n * after this plugin runs. Must match `installPrecache`'s `navigateFallback`\n * so offline navigations resolve. Pass `false` to disable. Default `/index.html`.\n *\n * Like {@link TempestPwaManifestOptions.additionalUrls}, this is prefixed\n * with the resolved Vite `base`.\n */\n appShell?: string | false;\n}\n\nfunction joinBase(base: string, file: string): string {\n return `${basePrefix(base)}${file}`.replace(/([^:]\\/)\\/+/g, \"$1\");\n}\n\n/**\n * Prefix a caller-supplied, root-absolute URL with the resolved Vite `base`.\n *\n * Idempotent: a URL that already starts with the base is returned untouched,\n * so configs written before this was applied — spelling the base out by hand —\n * keep producing the same manifest instead of gaining a doubled prefix.\n */\nfunction withBase(base: string, url: string): string {\n const prefix = basePrefix(base);\n if (prefix === \"/\") return url.startsWith(\"/\") ? url : `/${url}`;\n if (url.startsWith(prefix)) return url;\n return `${prefix}${url.replace(/^\\//, \"\")}`;\n}\n\n/** Deterministic djb2 hash → hex. Stable across rebuilds with the same assets. */\nfunction hash(input: string): string {\n let h = 5381;\n for (let i = 0; i < input.length; i++) {\n h = ((h << 5) + h + input.charCodeAt(i)) >>> 0;\n }\n return h.toString(16);\n}\n\n/**\n * Vite build plugin that emits a `precache-manifest.json` listing every built\n * asset (plus any `additionalUrls`) as root-absolute URLs, with a content-based\n * `version`. It is the dependency-free counterpart to Workbox's `__WB_MANIFEST`:\n * `installPrecache` (from `tempest-react-sdk/sw`) reads this file at the service\n * worker's `install` event to cache the app shell for offline use.\n *\n * @example\n * // vite.config.ts\n * import { createViteConfig, tempestPwaManifest } from \"tempest-react-sdk/vite\";\n *\n * export default createViteConfig({\n * plugins: [tempestPwaManifest({ additionalUrls: [\"/manifest.webmanifest\", \"/icon.svg\"] })],\n * });\n */\nexport function tempestPwaManifest(options: TempestPwaManifestOptions = {}): TempestVitePlugin {\n const {\n fileName = \"precache-manifest.json\",\n additionalUrls = [],\n exclude = /\\.map$/,\n includeHtml = true,\n appShell = \"/index.html\",\n } = options;\n\n let base = \"/\";\n\n const plugin: Plugin = {\n name: \"tempest-pwa-manifest\",\n apply: \"build\",\n configResolved(config) {\n base = config.base ?? \"/\";\n },\n generateBundle(_outputOptions, bundle) {\n const urls = new Set<string>(additionalUrls.map((url) => withBase(base, url)));\n // Vite may emit index.html after this hook, so guarantee the shell.\n if (appShell) urls.add(withBase(base, appShell));\n for (const file of Object.keys(bundle)) {\n if (file === fileName) continue;\n if (exclude.test(file)) continue;\n if (!includeHtml && file.endsWith(\".html\")) continue;\n urls.add(joinBase(base, file));\n }\n\n const list = [...urls].sort();\n const version = hash(list.join(\"\\n\"));\n this.emitFile({\n type: \"asset\",\n fileName,\n source: JSON.stringify({ version, urls: list }),\n });\n },\n };\n\n return plugin as TempestVitePlugin;\n}\n"],"mappings":";;AAsCA,SAAS,EAAS,GAAc,GAAsB;CAClD,OAAO,GAAG,EAAW,CAAI,IAAI,IAAO,QAAQ,gBAAgB,IAAI;AACpE;AASA,SAAS,EAAS,GAAc,GAAqB;CACjD,IAAM,IAAS,EAAW,CAAI;CAG9B,OAFI,MAAW,MAAY,EAAI,WAAW,GAAG,IAAI,IAAM,IAAI,MACvD,EAAI,WAAW,CAAM,IAAU,IAC5B,GAAG,IAAS,EAAI,QAAQ,OAAO,EAAE;AAC5C;AAGA,SAAS,EAAK,GAAuB;CACjC,IAAI,IAAI;CACR,KAAK,IAAI,IAAI,GAAG,IAAI,EAAM,QAAQ,KAC9B,KAAM,KAAK,KAAK,IAAI,EAAM,WAAW,CAAC,MAAO;CAEjD,OAAO,EAAE,SAAS,EAAE;AACxB;AAiBA,SAAgB,EAAmB,IAAqC,CAAC,GAAsB;CAC3F,IAAM,EACF,cAAW,0BACX,oBAAiB,CAAC,GAClB,aAAU,UACV,iBAAc,IACd,cAAW,kBACX,GAEA,IAAO;CA6BX,OAAO;EA1BH,MAAM;EACN,OAAO;EACP,eAAe,GAAQ;GACnB,IAAO,EAAO,QAAQ;EAC1B;EACA,eAAe,GAAgB,GAAQ;GACnC,IAAM,IAAO,IAAI,IAAY,EAAe,KAAK,MAAQ,EAAS,GAAM,CAAG,CAAC,CAAC;GAE7E,AAAI,KAAU,EAAK,IAAI,EAAS,GAAM,CAAQ,CAAC;GAC/C,KAAK,IAAM,KAAQ,OAAO,KAAK,CAAM,GAC7B,MAAS,MACT,EAAQ,KAAK,CAAI,MAChB,KAAe,GAAK,SAAS,OAAO,MACzC,EAAK,IAAI,EAAS,GAAM,CAAI,CAAC;GAGjC,IAAM,IAAO,CAAC,GAAG,CAAI,CAAC,CAAC,KAAK,GACtB,IAAU,EAAK,EAAK,KAAK,IAAI,CAAC;GACpC,KAAK,SAAS;IACV,MAAM;IACN;IACA,QAAQ,KAAK,UAAU;KAAE;KAAS,MAAM;IAAK,CAAC;GAClD,CAAC;EACL;CAGG;AACX"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function e(e){return new RTCPeerConnection({iceServers:e,bundlePolicy:`max-bundle`,rtcpMuxPolicy:`require`})}function t(e,t,n){let r=Number(e.mid);if(e.mid!==null&&Number.isInteger(r)&&n[r])return n[r];let i=t.transceivers.indexOf(e);return i>=0?n[i]??null:null}async function n(e){let t=e.pendingCandidates.splice(0,e.pendingCandidates.length);for(let n of t)try{await e.pc.addIceCandidate(n)}catch{}}async function r(e,t){if(!e.remoteReady){e.pendingCandidates.push(t);return}try{await e.pc.addIceCandidate(t)}catch{}}async function i(e,t,n){for(let[r,i]of t.entries()){let t=e.transceivers[r],a=n.get(i.name)??null;if(
|
|
1
|
+
function e(e){return new RTCPeerConnection({iceServers:e,bundlePolicy:`max-bundle`,rtcpMuxPolicy:`require`})}function t(e,t,n){let r=Number(e.mid);if(e.mid!==null&&Number.isInteger(r)&&n[r])return n[r];let i=t.transceivers.indexOf(e);return i>=0?n[i]??null:null}async function n(e){let t=e.pendingCandidates.splice(0,e.pendingCandidates.length);for(let n of t)try{await e.pc.addIceCandidate(n)}catch{}}async function r(e,t){if(!e.remoteReady){e.pendingCandidates.push(t);return}try{await e.pc.addIceCandidate(t)}catch{}}async function i(e,t,n){for(let[r,i]of t.entries()){let t=e.transceivers[r],a=n.get(i.name)??null;if(t&&a)try{await t.sender.replaceTrack(a)}catch{}}}function a(e){e.transceivers=e.pc.getTransceivers().filter(e=>e.mid!==null).sort((e,t)=>Number(e.mid)-Number(t.mid));for(let t of e.transceivers)t.direction!==`sendrecv`&&(t.direction=`sendrecv`)}exports.acceptCandidate=r,exports.adoptTransceivers=a,exports.attachLocalTracks=i,exports.createPeerConnection=e,exports.drainCandidates=n,exports.slotOf=t;
|
|
2
2
|
//# sourceMappingURL=peer-link.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"peer-link.cjs","names":[],"sources":["../../src/webrtc/peer-link.ts"],"sourcesContent":["import type { MeshSlot } from \"./mesh-types\";\n\n/** One remote peer's connection and everything the mesh tracks about it. */\nexport interface PeerLink {\n peerId: string;\n pc: RTCPeerConnection;\n /**\n * Transceivers in slot order.\n *\n * Held explicitly rather than re-read from `getTransceivers()` so slot\n * lookup stays O(1) and cannot drift if a browser reorders.\n */\n transceivers: RTCRtpTransceiver[];\n /** Candidates that arrived before the remote description they belong to. */\n pendingCandidates: RTCIceCandidateInit[];\n /** Whether `setRemoteDescription` has landed, which gates the queue. */\n remoteReady: boolean;\n /** Whether an offer is in flight, so a re-entrant call does not stack one. */\n makingOffer: boolean;\n /** Whether this side offers. Exactly one side of a link does. */\n isOfferer: boolean;\n}\n\n/** Open a connection with the policies a mesh needs. */\nexport function createPeerConnection(iceServers: RTCIceServer[]): RTCPeerConnection {\n return new RTCPeerConnection({\n iceServers,\n bundlePolicy: \"max-bundle\",\n rtcpMuxPolicy: \"require\",\n });\n}\n\n/**\n * Resolve which slot a transceiver carries.\n *\n * The offerer allocates the m-lines in slot order, so a transceiver's `mid` is\n * its ordinal and both ends read the same one. That makes `mid` the slot's wire\n * identity, and the **only** identifier correct on both sides of a link.\n *\n * Position in the link's own array is a fallback for a `mid` that is not a plain\n * ordinal, and never the primary: a browser answering an offer appends the\n * negotiated transceivers *after* any it already held, so positional lookup\n * silently resolves to the wrong slot — the camera arriving in the screen tile —\n * or to none at all, dropping the track.\n *\n * @param transceiver - The transceiver a track arrived on.\n * @param link - The link it belongs to.\n * @param slots - The mesh's slot list.\n * @returns The slot, or `null` when neither route names one.\n */\nexport function slotOf(\n transceiver: RTCRtpTransceiver,\n link: PeerLink,\n slots: readonly MeshSlot[],\n): MeshSlot | null {\n const ordinal = Number(transceiver.mid);\n if (transceiver.mid !== null && Number.isInteger(ordinal) && slots[ordinal]) {\n return slots[ordinal];\n }\n const index = link.transceivers.indexOf(transceiver);\n return index >= 0 ? (slots[index] ?? null) : null;\n}\n\n/**\n * Feed a link every candidate that arrived before its remote description.\n *\n * `addIceCandidate` throws while `remoteDescription` is `null`, and candidates\n * routinely beat the offer or answer they belong to. Without the queue the\n * connection loses them and sits in `checking` until it times out — a failure\n * with no error anywhere.\n *\n * @param link - The link whose queue is drained.\n */\nexport async function drainCandidates(link: PeerLink): Promise<void> {\n const queued = link.pendingCandidates.splice(0, link.pendingCandidates.length);\n for (const candidate of queued) {\n try {\n await link.pc.addIceCandidate(candidate);\n } catch {\n /* a candidate the browser rejects is not fatal to the connection */\n }\n }\n}\n\n/**\n * Hand a candidate to the connection, or park it until the description lands.\n *\n * @param link - The link the candidate belongs to.\n * @param init - The candidate, already in `RTCIceCandidateInit` shape.\n */\nexport async function acceptCandidate(link: PeerLink, init: RTCIceCandidateInit): Promise<void> {\n if (!link.remoteReady) {\n link.pendingCandidates.push(init);\n return;\n }\n try {\n await link.pc.addIceCandidate(init);\n } catch {\n /* a candidate the browser rejects is not fatal to the connection */\n }\n}\n\n/**\n * Publish every held local track onto a link's slots.\n *\n * Called once the transceivers exist — up front for the offerer, after the offer\n * lands for the answerer — so a microphone that was already live when the peer\n * joined starts flowing without waiting for a toggle.\n *\n * @param link - The link to publish onto.\n * @param slots - The mesh's slot list.\n * @param tracks - The current local track per slot name.\n */\nexport async function attachLocalTracks(\n link: PeerLink,\n slots: readonly MeshSlot[],\n tracks: Map<string, MediaStreamTrack | null>,\n): Promise<void> {\n for (const [index, slot] of slots.entries()) {\n const transceiver = link.transceivers[index];\n const track = tracks.get(slot.name) ?? null;\n if (!transceiver || !track) continue;\n try {\n await transceiver.sender.replaceTrack(track);\n } catch {\n /* the browser refused the track; the slot simply stays silent */\n }\n }\n}\n\n/**\n * Adopt the transceivers a remote offer created, in `mid` order.\n *\n * The answering side allocates **nothing** up front, and that is the whole\n * subtlety: applying a remote offer creates one transceiver per m-line, in\n * m-line order, and browsers do not reuse transceivers the answerer made\n * beforehand. Pre-allocating leaves dead, never-negotiated transceivers sitting\n * in front of the live ones, which is how slot lookup ends up pointing at the\n * wrong media or at nothing.\n *\n * Each adopted transceiver is switched to `sendrecv` so this side may publish on\n * it too; without that a peer that answered could hear but never be heard.\n *\n * @param link - The link that just applied a remote offer.\n */\nexport function adoptTransceivers(link: PeerLink): void {\n link.transceivers = link.pc\n .getTransceivers()\n .filter((transceiver) => transceiver.mid !== null)\n .sort((a, b) => Number(a.mid) - Number(b.mid));\n for (const transceiver of link.transceivers) {\n if (transceiver.direction !== \"sendrecv\") transceiver.direction = \"sendrecv\";\n }\n}\n"],"mappings":"AAwBA,SAAgB,EAAqB,EAA+C,CAChF,OAAO,IAAI,kBAAkB,CACzB,aACA,aAAc,aACd,cAAe,SACnB,CAAC,CACL,CAoBA,SAAgB,EACZ,EACA,EACA,EACe,CACf,IAAM,EAAU,OAAO,EAAY,GAAG,EACtC,GAAI,EAAY,MAAQ,MAAQ,OAAO,UAAU,CAAO,GAAK,EAAM,GAC/D,OAAO,EAAM,GAEjB,IAAM,EAAQ,EAAK,aAAa,QAAQ,CAAW,EACnD,OAAO,GAAS,EAAK,EAAM,IAAU,KAAQ,IACjD,CAYA,eAAsB,EAAgB,EAA+B,CACjE,IAAM,EAAS,EAAK,kBAAkB,OAAO,EAAG,EAAK,kBAAkB,MAAM,EAC7E,IAAK,IAAM,KAAa,EACpB,GAAI,CACA,MAAM,EAAK,GAAG,gBAAgB,CAAS,CAC3C,MAAQ,CAER,CAER,CAQA,eAAsB,EAAgB,EAAgB,EAA0C,CAC5F,GAAI,CAAC,EAAK,YAAa,CACnB,EAAK,kBAAkB,KAAK,CAAI,EAChC,MACJ,CACA,GAAI,CACA,MAAM,EAAK,GAAG,gBAAgB,CAAI,CACtC,MAAQ,CAER,CACJ,CAaA,eAAsB,EAClB,EACA,EACA,EACa,CACb,IAAK,GAAM,CAAC,EAAO,KAAS,EAAM,QAAQ,EAAG,CACzC,IAAM,EAAc,EAAK,aAAa,GAChC,EAAQ,EAAO,IAAI,EAAK,IAAI,GAAK,KACnC,
|
|
1
|
+
{"version":3,"file":"peer-link.cjs","names":[],"sources":["../../src/webrtc/peer-link.ts"],"sourcesContent":["import type { MeshSlot } from \"./mesh-types\";\n\n/** One remote peer's connection and everything the mesh tracks about it. */\nexport interface PeerLink {\n peerId: string;\n pc: RTCPeerConnection;\n /**\n * Transceivers in slot order.\n *\n * Held explicitly rather than re-read from `getTransceivers()` so slot\n * lookup stays O(1) and cannot drift if a browser reorders.\n */\n transceivers: RTCRtpTransceiver[];\n /** Candidates that arrived before the remote description they belong to. */\n pendingCandidates: RTCIceCandidateInit[];\n /** Whether `setRemoteDescription` has landed, which gates the queue. */\n remoteReady: boolean;\n /** Whether an offer is in flight, so a re-entrant call does not stack one. */\n makingOffer: boolean;\n /** Whether this side offers. Exactly one side of a link does. */\n isOfferer: boolean;\n}\n\n/** Open a connection with the policies a mesh needs. */\nexport function createPeerConnection(iceServers: RTCIceServer[]): RTCPeerConnection {\n return new RTCPeerConnection({\n iceServers,\n bundlePolicy: \"max-bundle\",\n rtcpMuxPolicy: \"require\",\n });\n}\n\n/**\n * Resolve which slot a transceiver carries.\n *\n * The offerer allocates the m-lines in slot order, so a transceiver's `mid` is\n * its ordinal and both ends read the same one. That makes `mid` the slot's wire\n * identity, and the **only** identifier correct on both sides of a link.\n *\n * Position in the link's own array is a fallback for a `mid` that is not a plain\n * ordinal, and never the primary: a browser answering an offer appends the\n * negotiated transceivers *after* any it already held, so positional lookup\n * silently resolves to the wrong slot — the camera arriving in the screen tile —\n * or to none at all, dropping the track.\n *\n * @param transceiver - The transceiver a track arrived on.\n * @param link - The link it belongs to.\n * @param slots - The mesh's slot list.\n * @returns The slot, or `null` when neither route names one.\n */\nexport function slotOf(\n transceiver: RTCRtpTransceiver,\n link: PeerLink,\n slots: readonly MeshSlot[],\n): MeshSlot | null {\n const ordinal = Number(transceiver.mid);\n if (transceiver.mid !== null && Number.isInteger(ordinal) && slots[ordinal]) {\n return slots[ordinal];\n }\n const index = link.transceivers.indexOf(transceiver);\n return index >= 0 ? (slots[index] ?? null) : null;\n}\n\n/**\n * Feed a link every candidate that arrived before its remote description.\n *\n * `addIceCandidate` throws while `remoteDescription` is `null`, and candidates\n * routinely beat the offer or answer they belong to. Without the queue the\n * connection loses them and sits in `checking` until it times out — a failure\n * with no error anywhere.\n *\n * @param link - The link whose queue is drained.\n */\nexport async function drainCandidates(link: PeerLink): Promise<void> {\n const queued = link.pendingCandidates.splice(0, link.pendingCandidates.length);\n for (const candidate of queued) {\n try {\n await link.pc.addIceCandidate(candidate);\n } catch {\n /* a candidate the browser rejects is not fatal to the connection */\n }\n }\n}\n\n/**\n * Hand a candidate to the connection, or park it until the description lands.\n *\n * @param link - The link the candidate belongs to.\n * @param init - The candidate, already in `RTCIceCandidateInit` shape.\n */\nexport async function acceptCandidate(link: PeerLink, init: RTCIceCandidateInit): Promise<void> {\n if (!link.remoteReady) {\n link.pendingCandidates.push(init);\n return;\n }\n try {\n await link.pc.addIceCandidate(init);\n } catch {\n /* a candidate the browser rejects is not fatal to the connection */\n }\n}\n\n/**\n * Publish every held local track onto a link's slots.\n *\n * Called once the transceivers exist — up front for the offerer, after the offer\n * lands for the answerer — so a microphone that was already live when the peer\n * joined starts flowing without waiting for a toggle.\n *\n * @param link - The link to publish onto.\n * @param slots - The mesh's slot list.\n * @param tracks - The current local track per slot name.\n */\nexport async function attachLocalTracks(\n link: PeerLink,\n slots: readonly MeshSlot[],\n tracks: Map<string, MediaStreamTrack | null>,\n): Promise<void> {\n for (const [index, slot] of slots.entries()) {\n const transceiver = link.transceivers[index];\n const track = tracks.get(slot.name) ?? null;\n if (!transceiver || !track) continue;\n try {\n await transceiver.sender.replaceTrack(track);\n } catch {\n /* the browser refused the track; the slot simply stays silent */\n }\n }\n}\n\n/**\n * Adopt the transceivers a remote offer created, in `mid` order.\n *\n * The answering side allocates **nothing** up front, and that is the whole\n * subtlety: applying a remote offer creates one transceiver per m-line, in\n * m-line order, and browsers do not reuse transceivers the answerer made\n * beforehand. Pre-allocating leaves dead, never-negotiated transceivers sitting\n * in front of the live ones, which is how slot lookup ends up pointing at the\n * wrong media or at nothing.\n *\n * Each adopted transceiver is switched to `sendrecv` so this side may publish on\n * it too; without that a peer that answered could hear but never be heard.\n *\n * @param link - The link that just applied a remote offer.\n */\nexport function adoptTransceivers(link: PeerLink): void {\n link.transceivers = link.pc\n .getTransceivers()\n .filter((transceiver) => transceiver.mid !== null)\n .sort((a, b) => Number(a.mid) - Number(b.mid));\n for (const transceiver of link.transceivers) {\n if (transceiver.direction !== \"sendrecv\") transceiver.direction = \"sendrecv\";\n }\n}\n"],"mappings":"AAwBA,SAAgB,EAAqB,EAA+C,CAChF,OAAO,IAAI,kBAAkB,CACzB,aACA,aAAc,aACd,cAAe,SACnB,CAAC,CACL,CAoBA,SAAgB,EACZ,EACA,EACA,EACe,CACf,IAAM,EAAU,OAAO,EAAY,GAAG,EACtC,GAAI,EAAY,MAAQ,MAAQ,OAAO,UAAU,CAAO,GAAK,EAAM,GAC/D,OAAO,EAAM,GAEjB,IAAM,EAAQ,EAAK,aAAa,QAAQ,CAAW,EACnD,OAAO,GAAS,EAAK,EAAM,IAAU,KAAQ,IACjD,CAYA,eAAsB,EAAgB,EAA+B,CACjE,IAAM,EAAS,EAAK,kBAAkB,OAAO,EAAG,EAAK,kBAAkB,MAAM,EAC7E,IAAK,IAAM,KAAa,EACpB,GAAI,CACA,MAAM,EAAK,GAAG,gBAAgB,CAAS,CAC3C,MAAQ,CAER,CAER,CAQA,eAAsB,EAAgB,EAAgB,EAA0C,CAC5F,GAAI,CAAC,EAAK,YAAa,CACnB,EAAK,kBAAkB,KAAK,CAAI,EAChC,MACJ,CACA,GAAI,CACA,MAAM,EAAK,GAAG,gBAAgB,CAAI,CACtC,MAAQ,CAER,CACJ,CAaA,eAAsB,EAClB,EACA,EACA,EACa,CACb,IAAK,GAAM,CAAC,EAAO,KAAS,EAAM,QAAQ,EAAG,CACzC,IAAM,EAAc,EAAK,aAAa,GAChC,EAAQ,EAAO,IAAI,EAAK,IAAI,GAAK,KACnC,GAAC,GAAgB,EACrB,GAAI,CACA,MAAM,EAAY,OAAO,aAAa,CAAK,CAC/C,MAAQ,CAER,CACJ,CACJ,CAiBA,SAAgB,EAAkB,EAAsB,CACpD,EAAK,aAAe,EAAK,GACpB,gBAAgB,CAAC,CACjB,OAAQ,GAAgB,EAAY,MAAQ,IAAI,CAAC,CACjD,MAAM,EAAG,IAAM,OAAO,EAAE,GAAG,EAAI,OAAO,EAAE,GAAG,CAAC,EACjD,IAAK,IAAM,KAAe,EAAK,aACvB,EAAY,YAAc,aAAY,EAAY,UAAY,WAE1E"}
|
package/dist/webrtc/peer-link.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"peer-link.js","names":[],"sources":["../../src/webrtc/peer-link.ts"],"sourcesContent":["import type { MeshSlot } from \"./mesh-types\";\n\n/** One remote peer's connection and everything the mesh tracks about it. */\nexport interface PeerLink {\n peerId: string;\n pc: RTCPeerConnection;\n /**\n * Transceivers in slot order.\n *\n * Held explicitly rather than re-read from `getTransceivers()` so slot\n * lookup stays O(1) and cannot drift if a browser reorders.\n */\n transceivers: RTCRtpTransceiver[];\n /** Candidates that arrived before the remote description they belong to. */\n pendingCandidates: RTCIceCandidateInit[];\n /** Whether `setRemoteDescription` has landed, which gates the queue. */\n remoteReady: boolean;\n /** Whether an offer is in flight, so a re-entrant call does not stack one. */\n makingOffer: boolean;\n /** Whether this side offers. Exactly one side of a link does. */\n isOfferer: boolean;\n}\n\n/** Open a connection with the policies a mesh needs. */\nexport function createPeerConnection(iceServers: RTCIceServer[]): RTCPeerConnection {\n return new RTCPeerConnection({\n iceServers,\n bundlePolicy: \"max-bundle\",\n rtcpMuxPolicy: \"require\",\n });\n}\n\n/**\n * Resolve which slot a transceiver carries.\n *\n * The offerer allocates the m-lines in slot order, so a transceiver's `mid` is\n * its ordinal and both ends read the same one. That makes `mid` the slot's wire\n * identity, and the **only** identifier correct on both sides of a link.\n *\n * Position in the link's own array is a fallback for a `mid` that is not a plain\n * ordinal, and never the primary: a browser answering an offer appends the\n * negotiated transceivers *after* any it already held, so positional lookup\n * silently resolves to the wrong slot — the camera arriving in the screen tile —\n * or to none at all, dropping the track.\n *\n * @param transceiver - The transceiver a track arrived on.\n * @param link - The link it belongs to.\n * @param slots - The mesh's slot list.\n * @returns The slot, or `null` when neither route names one.\n */\nexport function slotOf(\n transceiver: RTCRtpTransceiver,\n link: PeerLink,\n slots: readonly MeshSlot[],\n): MeshSlot | null {\n const ordinal = Number(transceiver.mid);\n if (transceiver.mid !== null && Number.isInteger(ordinal) && slots[ordinal]) {\n return slots[ordinal];\n }\n const index = link.transceivers.indexOf(transceiver);\n return index >= 0 ? (slots[index] ?? null) : null;\n}\n\n/**\n * Feed a link every candidate that arrived before its remote description.\n *\n * `addIceCandidate` throws while `remoteDescription` is `null`, and candidates\n * routinely beat the offer or answer they belong to. Without the queue the\n * connection loses them and sits in `checking` until it times out — a failure\n * with no error anywhere.\n *\n * @param link - The link whose queue is drained.\n */\nexport async function drainCandidates(link: PeerLink): Promise<void> {\n const queued = link.pendingCandidates.splice(0, link.pendingCandidates.length);\n for (const candidate of queued) {\n try {\n await link.pc.addIceCandidate(candidate);\n } catch {\n /* a candidate the browser rejects is not fatal to the connection */\n }\n }\n}\n\n/**\n * Hand a candidate to the connection, or park it until the description lands.\n *\n * @param link - The link the candidate belongs to.\n * @param init - The candidate, already in `RTCIceCandidateInit` shape.\n */\nexport async function acceptCandidate(link: PeerLink, init: RTCIceCandidateInit): Promise<void> {\n if (!link.remoteReady) {\n link.pendingCandidates.push(init);\n return;\n }\n try {\n await link.pc.addIceCandidate(init);\n } catch {\n /* a candidate the browser rejects is not fatal to the connection */\n }\n}\n\n/**\n * Publish every held local track onto a link's slots.\n *\n * Called once the transceivers exist — up front for the offerer, after the offer\n * lands for the answerer — so a microphone that was already live when the peer\n * joined starts flowing without waiting for a toggle.\n *\n * @param link - The link to publish onto.\n * @param slots - The mesh's slot list.\n * @param tracks - The current local track per slot name.\n */\nexport async function attachLocalTracks(\n link: PeerLink,\n slots: readonly MeshSlot[],\n tracks: Map<string, MediaStreamTrack | null>,\n): Promise<void> {\n for (const [index, slot] of slots.entries()) {\n const transceiver = link.transceivers[index];\n const track = tracks.get(slot.name) ?? null;\n if (!transceiver || !track) continue;\n try {\n await transceiver.sender.replaceTrack(track);\n } catch {\n /* the browser refused the track; the slot simply stays silent */\n }\n }\n}\n\n/**\n * Adopt the transceivers a remote offer created, in `mid` order.\n *\n * The answering side allocates **nothing** up front, and that is the whole\n * subtlety: applying a remote offer creates one transceiver per m-line, in\n * m-line order, and browsers do not reuse transceivers the answerer made\n * beforehand. Pre-allocating leaves dead, never-negotiated transceivers sitting\n * in front of the live ones, which is how slot lookup ends up pointing at the\n * wrong media or at nothing.\n *\n * Each adopted transceiver is switched to `sendrecv` so this side may publish on\n * it too; without that a peer that answered could hear but never be heard.\n *\n * @param link - The link that just applied a remote offer.\n */\nexport function adoptTransceivers(link: PeerLink): void {\n link.transceivers = link.pc\n .getTransceivers()\n .filter((transceiver) => transceiver.mid !== null)\n .sort((a, b) => Number(a.mid) - Number(b.mid));\n for (const transceiver of link.transceivers) {\n if (transceiver.direction !== \"sendrecv\") transceiver.direction = \"sendrecv\";\n }\n}\n"],"mappings":";AAwBA,SAAgB,EAAqB,GAA+C;CAChF,OAAO,IAAI,kBAAkB;EACzB;EACA,cAAc;EACd,eAAe;CACnB,CAAC;AACL;AAoBA,SAAgB,EACZ,GACA,GACA,GACe;CACf,IAAM,IAAU,OAAO,EAAY,GAAG;CACtC,IAAI,EAAY,QAAQ,QAAQ,OAAO,UAAU,CAAO,KAAK,EAAM,IAC/D,OAAO,EAAM;CAEjB,IAAM,IAAQ,EAAK,aAAa,QAAQ,CAAW;CACnD,OAAO,KAAS,IAAK,EAAM,MAAU,OAAQ;AACjD;AAYA,eAAsB,EAAgB,GAA+B;CACjE,IAAM,IAAS,EAAK,kBAAkB,OAAO,GAAG,EAAK,kBAAkB,MAAM;CAC7E,KAAK,IAAM,KAAa,GACpB,IAAI;EACA,MAAM,EAAK,GAAG,gBAAgB,CAAS;CAC3C,QAAQ,CAER;AAER;AAQA,eAAsB,EAAgB,GAAgB,GAA0C;CAC5F,IAAI,CAAC,EAAK,aAAa;EACnB,EAAK,kBAAkB,KAAK,CAAI;EAChC;CACJ;CACA,IAAI;EACA,MAAM,EAAK,GAAG,gBAAgB,CAAI;CACtC,QAAQ,CAER;AACJ;AAaA,eAAsB,EAClB,GACA,GACA,GACa;CACb,KAAK,IAAM,CAAC,GAAO,MAAS,EAAM,QAAQ,GAAG;EACzC,IAAM,IAAc,EAAK,aAAa,IAChC,IAAQ,EAAO,IAAI,EAAK,IAAI,KAAK;EACnC,
|
|
1
|
+
{"version":3,"file":"peer-link.js","names":[],"sources":["../../src/webrtc/peer-link.ts"],"sourcesContent":["import type { MeshSlot } from \"./mesh-types\";\n\n/** One remote peer's connection and everything the mesh tracks about it. */\nexport interface PeerLink {\n peerId: string;\n pc: RTCPeerConnection;\n /**\n * Transceivers in slot order.\n *\n * Held explicitly rather than re-read from `getTransceivers()` so slot\n * lookup stays O(1) and cannot drift if a browser reorders.\n */\n transceivers: RTCRtpTransceiver[];\n /** Candidates that arrived before the remote description they belong to. */\n pendingCandidates: RTCIceCandidateInit[];\n /** Whether `setRemoteDescription` has landed, which gates the queue. */\n remoteReady: boolean;\n /** Whether an offer is in flight, so a re-entrant call does not stack one. */\n makingOffer: boolean;\n /** Whether this side offers. Exactly one side of a link does. */\n isOfferer: boolean;\n}\n\n/** Open a connection with the policies a mesh needs. */\nexport function createPeerConnection(iceServers: RTCIceServer[]): RTCPeerConnection {\n return new RTCPeerConnection({\n iceServers,\n bundlePolicy: \"max-bundle\",\n rtcpMuxPolicy: \"require\",\n });\n}\n\n/**\n * Resolve which slot a transceiver carries.\n *\n * The offerer allocates the m-lines in slot order, so a transceiver's `mid` is\n * its ordinal and both ends read the same one. That makes `mid` the slot's wire\n * identity, and the **only** identifier correct on both sides of a link.\n *\n * Position in the link's own array is a fallback for a `mid` that is not a plain\n * ordinal, and never the primary: a browser answering an offer appends the\n * negotiated transceivers *after* any it already held, so positional lookup\n * silently resolves to the wrong slot — the camera arriving in the screen tile —\n * or to none at all, dropping the track.\n *\n * @param transceiver - The transceiver a track arrived on.\n * @param link - The link it belongs to.\n * @param slots - The mesh's slot list.\n * @returns The slot, or `null` when neither route names one.\n */\nexport function slotOf(\n transceiver: RTCRtpTransceiver,\n link: PeerLink,\n slots: readonly MeshSlot[],\n): MeshSlot | null {\n const ordinal = Number(transceiver.mid);\n if (transceiver.mid !== null && Number.isInteger(ordinal) && slots[ordinal]) {\n return slots[ordinal];\n }\n const index = link.transceivers.indexOf(transceiver);\n return index >= 0 ? (slots[index] ?? null) : null;\n}\n\n/**\n * Feed a link every candidate that arrived before its remote description.\n *\n * `addIceCandidate` throws while `remoteDescription` is `null`, and candidates\n * routinely beat the offer or answer they belong to. Without the queue the\n * connection loses them and sits in `checking` until it times out — a failure\n * with no error anywhere.\n *\n * @param link - The link whose queue is drained.\n */\nexport async function drainCandidates(link: PeerLink): Promise<void> {\n const queued = link.pendingCandidates.splice(0, link.pendingCandidates.length);\n for (const candidate of queued) {\n try {\n await link.pc.addIceCandidate(candidate);\n } catch {\n /* a candidate the browser rejects is not fatal to the connection */\n }\n }\n}\n\n/**\n * Hand a candidate to the connection, or park it until the description lands.\n *\n * @param link - The link the candidate belongs to.\n * @param init - The candidate, already in `RTCIceCandidateInit` shape.\n */\nexport async function acceptCandidate(link: PeerLink, init: RTCIceCandidateInit): Promise<void> {\n if (!link.remoteReady) {\n link.pendingCandidates.push(init);\n return;\n }\n try {\n await link.pc.addIceCandidate(init);\n } catch {\n /* a candidate the browser rejects is not fatal to the connection */\n }\n}\n\n/**\n * Publish every held local track onto a link's slots.\n *\n * Called once the transceivers exist — up front for the offerer, after the offer\n * lands for the answerer — so a microphone that was already live when the peer\n * joined starts flowing without waiting for a toggle.\n *\n * @param link - The link to publish onto.\n * @param slots - The mesh's slot list.\n * @param tracks - The current local track per slot name.\n */\nexport async function attachLocalTracks(\n link: PeerLink,\n slots: readonly MeshSlot[],\n tracks: Map<string, MediaStreamTrack | null>,\n): Promise<void> {\n for (const [index, slot] of slots.entries()) {\n const transceiver = link.transceivers[index];\n const track = tracks.get(slot.name) ?? null;\n if (!transceiver || !track) continue;\n try {\n await transceiver.sender.replaceTrack(track);\n } catch {\n /* the browser refused the track; the slot simply stays silent */\n }\n }\n}\n\n/**\n * Adopt the transceivers a remote offer created, in `mid` order.\n *\n * The answering side allocates **nothing** up front, and that is the whole\n * subtlety: applying a remote offer creates one transceiver per m-line, in\n * m-line order, and browsers do not reuse transceivers the answerer made\n * beforehand. Pre-allocating leaves dead, never-negotiated transceivers sitting\n * in front of the live ones, which is how slot lookup ends up pointing at the\n * wrong media or at nothing.\n *\n * Each adopted transceiver is switched to `sendrecv` so this side may publish on\n * it too; without that a peer that answered could hear but never be heard.\n *\n * @param link - The link that just applied a remote offer.\n */\nexport function adoptTransceivers(link: PeerLink): void {\n link.transceivers = link.pc\n .getTransceivers()\n .filter((transceiver) => transceiver.mid !== null)\n .sort((a, b) => Number(a.mid) - Number(b.mid));\n for (const transceiver of link.transceivers) {\n if (transceiver.direction !== \"sendrecv\") transceiver.direction = \"sendrecv\";\n }\n}\n"],"mappings":";AAwBA,SAAgB,EAAqB,GAA+C;CAChF,OAAO,IAAI,kBAAkB;EACzB;EACA,cAAc;EACd,eAAe;CACnB,CAAC;AACL;AAoBA,SAAgB,EACZ,GACA,GACA,GACe;CACf,IAAM,IAAU,OAAO,EAAY,GAAG;CACtC,IAAI,EAAY,QAAQ,QAAQ,OAAO,UAAU,CAAO,KAAK,EAAM,IAC/D,OAAO,EAAM;CAEjB,IAAM,IAAQ,EAAK,aAAa,QAAQ,CAAW;CACnD,OAAO,KAAS,IAAK,EAAM,MAAU,OAAQ;AACjD;AAYA,eAAsB,EAAgB,GAA+B;CACjE,IAAM,IAAS,EAAK,kBAAkB,OAAO,GAAG,EAAK,kBAAkB,MAAM;CAC7E,KAAK,IAAM,KAAa,GACpB,IAAI;EACA,MAAM,EAAK,GAAG,gBAAgB,CAAS;CAC3C,QAAQ,CAER;AAER;AAQA,eAAsB,EAAgB,GAAgB,GAA0C;CAC5F,IAAI,CAAC,EAAK,aAAa;EACnB,EAAK,kBAAkB,KAAK,CAAI;EAChC;CACJ;CACA,IAAI;EACA,MAAM,EAAK,GAAG,gBAAgB,CAAI;CACtC,QAAQ,CAER;AACJ;AAaA,eAAsB,EAClB,GACA,GACA,GACa;CACb,KAAK,IAAM,CAAC,GAAO,MAAS,EAAM,QAAQ,GAAG;EACzC,IAAM,IAAc,EAAK,aAAa,IAChC,IAAQ,EAAO,IAAI,EAAK,IAAI,KAAK;EACnC,IAAC,KAAgB,GACrB,IAAI;GACA,MAAM,EAAY,OAAO,aAAa,CAAK;EAC/C,QAAQ,CAER;CACJ;AACJ;AAiBA,SAAgB,EAAkB,GAAsB;CACpD,EAAK,eAAe,EAAK,GACpB,gBAAgB,CAAC,CACjB,QAAQ,MAAgB,EAAY,QAAQ,IAAI,CAAC,CACjD,MAAM,GAAG,MAAM,OAAO,EAAE,GAAG,IAAI,OAAO,EAAE,GAAG,CAAC;CACjD,KAAK,IAAM,KAAe,EAAK,cAC3B,AAAI,EAAY,cAAc,eAAY,EAAY,YAAY;AAE1E"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./link-stats.cjs"),t=require("./mesh-quality.cjs"),n=require("./peer-link.cjs");function r(r){let{slots:i,send:a}=r,o=new Map,s=new Map,c=new Map,l=r.iceServers??[],u=r.setLocalDescription??((e,t)=>e.setLocalDescription(t)),d=r.quality??{},f=!1,p=new Map,m=null,h=()=>Object.fromEntries(i.map(e=>[e.name,null])),g=()=>{r.onPeers?.([...s.values()].map(e=>({...e})))},_=async t=>{if(f)return;let n=!1;for(let r of[...o.values()]){if(r.pc.connectionState!==`connected`)continue;let i=p.get(r.peerId);i===void 0&&(i=e.createLinkStatsSampler(t.kind===void 0?{}:{kind:t.kind}),p.set(r.peerId,i));let a=await i.sample(r.pc),o=s.get(r.peerId);o!==void 0&&(o.stats=a,n=!0,t.onStats?.(r.peerId,a))}n&&g()},v=()=>{let e=r.stats;if(e===void 0)return;let t=!f&&o.size>0;if(t&&m===null){m=setInterval(()=>void _(e),e.intervalMs??2e3);return}!t&&m!==null&&(clearInterval(m),m=null)},y=()=>{if(f)return;let e=[...o.values()].map(e=>e.pc.connectionState);e.some(e=>e===`connected`)?r.onState?.(`connected`):e.length>0?r.onState?.(`connecting`,`negotiating`):r.onState?.(`connected`,`alone`)},b=async e=>{d=e;let n=t.scaleForRoom(e,o.size),r=t.resolveDegradation(e,n);for(let e of o.values())await t.applyQualityToLink(e.transceivers,i,n,r)},x=async e=>{if(!e.makingOffer){e.makingOffer=!0;try{let t=await e.pc.createOffer();if(!t.sdp){r.onNotice?.(`empty_local_offer_sdp`);return}await u(e.pc,t),a({type:`offer`,to:e.peerId,sdp:e.pc.localDescription?.sdp??t.sdp})}catch{r.onNotice?.(`offer_failed`)}finally{e.makingOffer=!1}}},S=e=>e.streams?.[0]||(typeof MediaStream>`u`?null:new MediaStream([e.track])),C=(e,t)=>{let r=n.slotOf(t.transceiver,e,i),a=s.get(e.peerId)
|
|
1
|
+
const e=require("./link-stats.cjs"),t=require("./mesh-quality.cjs"),n=require("./peer-link.cjs");function r(r){let{slots:i,send:a}=r,o=new Map,s=new Map,c=new Map,l=r.iceServers??[],u=r.setLocalDescription??((e,t)=>e.setLocalDescription(t)),d=r.quality??{},f=!1,p=new Map,m=null,h=()=>Object.fromEntries(i.map(e=>[e.name,null])),g=()=>{r.onPeers?.([...s.values()].map(e=>({...e})))},_=async t=>{if(f)return;let n=!1;for(let r of[...o.values()]){if(r.pc.connectionState!==`connected`)continue;let i=p.get(r.peerId);i===void 0&&(i=e.createLinkStatsSampler(t.kind===void 0?{}:{kind:t.kind}),p.set(r.peerId,i));let a=await i.sample(r.pc),o=s.get(r.peerId);o!==void 0&&(o.stats=a,n=!0,t.onStats?.(r.peerId,a))}n&&g()},v=()=>{let e=r.stats;if(e===void 0)return;let t=!f&&o.size>0;if(t&&m===null){m=setInterval(()=>void _(e),e.intervalMs??2e3);return}!t&&m!==null&&(clearInterval(m),m=null)},y=()=>{if(f)return;let e=[...o.values()].map(e=>e.pc.connectionState);e.some(e=>e===`connected`)?r.onState?.(`connected`):e.length>0?r.onState?.(`connecting`,`negotiating`):r.onState?.(`connected`,`alone`)},b=async e=>{d=e;let n=t.scaleForRoom(e,o.size),r=t.resolveDegradation(e,n);for(let e of o.values())await t.applyQualityToLink(e.transceivers,i,n,r)},x=async e=>{if(!e.makingOffer){e.makingOffer=!0;try{let t=await e.pc.createOffer();if(!t.sdp){r.onNotice?.(`empty_local_offer_sdp`);return}await u(e.pc,t),a({type:`offer`,to:e.peerId,sdp:e.pc.localDescription?.sdp??t.sdp})}catch{r.onNotice?.(`offer_failed`)}finally{e.makingOffer=!1}}},S=e=>e.streams?.[0]||(typeof MediaStream>`u`?null:new MediaStream([e.track])),C=(e,t)=>{let r=n.slotOf(t.transceiver,e,i),a=s.get(e.peerId);r&&a&&(a.streams={...a.streams,[r.name]:S(t)},t.track.onended=()=>{let t=s.get(e.peerId);t&&(t.streams={...t.streams,[r.name]:null},g())},g())},w=e=>{let t=o.get(e);t&&(t.pc.close(),o.delete(e)),s.delete(e),p.delete(e),b(d),v(),g(),y()},T=async(e,{offerer:t})=>{if(o.has(e))return;let r=n.createPeerConnection(l),u={peerId:e,pc:r,transceivers:[],pendingCandidates:[],remoteReady:!1,makingOffer:!1,isOfferer:t};o.set(e,u),s.set(e,{peerId:e,connection:r.connectionState,streams:s.get(e)?.streams??h()}),t&&(u.transceivers=i.map(e=>r.addTransceiver(e.kind,{direction:`sendrecv`})),await n.attachLocalTracks(u,i,c)),r.onicecandidate=t=>{a({type:`ice`,to:e,candidate:t.candidate?.candidate??null,sdpMid:t.candidate?.sdpMid??null,sdpMLineIndex:t.candidate?.sdpMLineIndex??null})},r.ontrack=e=>C(u,e),r.onconnectionstatechange=()=>{let t=s.get(e);if(t&&(t.connection=r.connectionState),r.connectionState===`failed`||r.connectionState===`closed`){w(e);return}g(),y()},r.onnegotiationneeded=()=>{u.isOfferer&&x(u)},v(),g(),y(),t&&await x(u)},E=async(e,t)=>{o.has(e)||await T(e,{offerer:!1});let s=o.get(e);if(!s)return;await s.pc.setRemoteDescription({type:`offer`,sdp:t}),s.remoteReady=!0,await n.drainCandidates(s),s.isOfferer||(n.adoptTransceivers(s),await n.attachLocalTracks(s,i,c));let l=await s.pc.createAnswer();if(!l.sdp){r.onNotice?.(`empty_local_answer_sdp`);return}await u(s.pc,l),a({type:`answer`,to:e,sdp:s.pc.localDescription?.sdp??l.sdp}),await b(d)};return r.onState?.(`connecting`,`signaling`),{addPeer:T,removePeer:w,accept:async e=>{if(e.type===`offer`){await E(e.from,e.sdp);return}let t=o.get(e.from);if(t){if(e.type===`answer`){await t.pc.setRemoteDescription({type:`answer`,sdp:e.sdp}),t.remoteReady=!0,await n.drainCandidates(t),await b(d);return}e.candidate!==null&&await n.acceptCandidate(t,{candidate:e.candidate,sdpMid:e.sdpMid??void 0,sdpMLineIndex:e.sdpMLineIndex??void 0})}},setLocalTrack:async(e,t)=>{c.set(e,t);let n=i.findIndex(t=>t.name===e);if(!(n<0)){for(let e of o.values()){let r=e.transceivers[n];if(r)try{await r.sender.replaceTrack(t)}catch{}}await b(d)}},applyQuality:b,setIceServers:e=>{l=e},stop:()=>{for(let e of o.values())e.pc.close();o.clear(),s.clear(),p.clear(),f=!0,v(),g(),r.onState?.(`closed`)},getConnection:e=>o.get(e)?.pc??null,get peers(){return[...s.values()].map(e=>({...e}))}}}exports.createPeerMesh=r;
|
|
2
2
|
//# sourceMappingURL=peer-mesh.cjs.map
|