tempest-react-sdk 0.78.0 → 0.79.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 +6 -6
- package/bin/lib/openapi/generate.mjs +168 -64
- package/bin/lib/openapi/generate.pagination.test.mjs +3 -2
- package/bin/lib/openapi/generate.test.mjs +263 -1
- package/dist/access/Can.cjs.map +1 -1
- package/dist/access/Can.js.map +1 -1
- package/dist/access/access-control-context.cjs.map +1 -1
- package/dist/access/access-control-context.js.map +1 -1
- package/dist/access/create-role-access-control.cjs.map +1 -1
- package/dist/access/create-role-access-control.js.map +1 -1
- package/dist/access/permissions-from-token.cjs.map +1 -1
- package/dist/access/permissions-from-token.js.map +1 -1
- package/dist/access/use-can.cjs.map +1 -1
- package/dist/access/use-can.js.map +1 -1
- package/dist/app/AppProviders.cjs.map +1 -1
- package/dist/app/AppProviders.js.map +1 -1
- package/dist/audio/audio-bus.cjs.map +1 -1
- package/dist/audio/audio-bus.js.map +1 -1
- package/dist/audio/audio-output.cjs.map +1 -1
- package/dist/audio/audio-output.js.map +1 -1
- package/dist/audio/audio-player.cjs.map +1 -1
- package/dist/audio/audio-player.js.map +1 -1
- package/dist/audio/audio-recorder.cjs.map +1 -1
- package/dist/audio/audio-recorder.js.map +1 -1
- package/dist/audio/duration.cjs.map +1 -1
- package/dist/audio/duration.js.map +1 -1
- package/dist/audio/level-meter.cjs.map +1 -1
- package/dist/audio/level-meter.js.map +1 -1
- package/dist/audio/media-access.cjs.map +1 -1
- package/dist/audio/media-access.js.map +1 -1
- package/dist/audio/noise-floor.cjs.map +1 -1
- package/dist/audio/noise-floor.js.map +1 -1
- package/dist/audio/sfx-pool.cjs.map +1 -1
- package/dist/audio/sfx-pool.js.map +1 -1
- package/dist/audio/use-audio-bus.cjs.map +1 -1
- package/dist/audio/use-audio-bus.js.map +1 -1
- package/dist/audio/use-audio-recorder.cjs.map +1 -1
- package/dist/audio/use-audio-recorder.js.map +1 -1
- package/dist/audio/use-audio.cjs.map +1 -1
- package/dist/audio/use-audio.js.map +1 -1
- package/dist/audio/use-microphone.cjs +1 -1
- package/dist/audio/use-microphone.cjs.map +1 -1
- package/dist/audio/use-microphone.js +1 -5
- package/dist/audio/use-microphone.js.map +1 -1
- package/dist/audio/use-sfx-pool.cjs.map +1 -1
- package/dist/audio/use-sfx-pool.js.map +1 -1
- package/dist/audio/voice-activity.cjs.map +1 -1
- package/dist/audio/voice-activity.js.map +1 -1
- package/dist/audio/voice-chain-stages.cjs.map +1 -1
- package/dist/audio/voice-chain-stages.js.map +1 -1
- package/dist/audio/voice-chain.cjs.map +1 -1
- package/dist/audio/voice-chain.js.map +1 -1
- package/dist/audio/wav.cjs.map +1 -1
- package/dist/audio/wav.js.map +1 -1
- package/dist/auth/AuthGuard.cjs.map +1 -1
- package/dist/auth/AuthGuard.js.map +1 -1
- package/dist/auth/create-auth-store.cjs.map +1 -1
- package/dist/auth/create-auth-store.js.map +1 -1
- package/dist/auth/create-tempest-auth.cjs +1 -1
- package/dist/auth/create-tempest-auth.cjs.map +1 -1
- package/dist/auth/create-tempest-auth.js +1 -3
- package/dist/auth/create-tempest-auth.js.map +1 -1
- package/dist/auth/jwt.cjs.map +1 -1
- package/dist/auth/jwt.js.map +1 -1
- package/dist/auth/lazy-with-retry.cjs.map +1 -1
- package/dist/auth/lazy-with-retry.js.map +1 -1
- package/dist/auth/passkey.cjs.map +1 -1
- package/dist/auth/passkey.js.map +1 -1
- package/dist/auth/refresh-queue.cjs.map +1 -1
- package/dist/auth/refresh-queue.js.map +1 -1
- package/dist/auth/use-passkey.cjs +1 -1
- package/dist/auth/use-passkey.cjs.map +1 -1
- package/dist/auth/use-passkey.js +1 -1
- package/dist/auth/use-passkey.js.map +1 -1
- package/dist/br/BrazilMap.cjs.map +1 -1
- package/dist/br/BrazilMap.js.map +1 -1
- package/dist/br/BrazilMap.module.cjs.map +1 -1
- package/dist/br/BrazilMap.module.js.map +1 -1
- package/dist/br/BrazilStateCitySelect.cjs.map +1 -1
- package/dist/br/BrazilStateCitySelect.js.map +1 -1
- package/dist/br/BrazilStateMap.cjs.map +1 -1
- package/dist/br/BrazilStateMap.js.map +1 -1
- package/dist/br/MapLegend.cjs.map +1 -1
- package/dist/br/MapLegend.js.map +1 -1
- package/dist/br/MapLegend.module.cjs.map +1 -1
- package/dist/br/MapLegend.module.js.map +1 -1
- package/dist/br/MapMarkers.cjs.map +1 -1
- package/dist/br/MapMarkers.js.map +1 -1
- package/dist/br/MapTooltip.cjs.map +1 -1
- package/dist/br/MapTooltip.js.map +1 -1
- package/dist/br/MunicipalitySearch.cjs +1 -1
- package/dist/br/MunicipalitySearch.cjs.map +1 -1
- package/dist/br/MunicipalitySearch.js +2 -5
- package/dist/br/MunicipalitySearch.js.map +1 -1
- package/dist/br/MunicipalitySearch.module.cjs.map +1 -1
- package/dist/br/MunicipalitySearch.module.js.map +1 -1
- package/dist/br/PixQRCode.cjs.map +1 -1
- package/dist/br/PixQRCode.js.map +1 -1
- package/dist/br/PixQRCode.module.cjs.map +1 -1
- package/dist/br/PixQRCode.module.js.map +1 -1
- package/dist/br/boleto.cjs.map +1 -1
- package/dist/br/boleto.js.map +1 -1
- package/dist/br/br-geo.cjs.map +1 -1
- package/dist/br/br-geo.js.map +1 -1
- package/dist/br/data/br-centroids.cjs.map +1 -1
- package/dist/br/data/br-centroids.js.map +1 -1
- package/dist/br/data/br-locations.cjs.map +1 -1
- package/dist/br/data/br-locations.js.map +1 -1
- package/dist/br/data/br-uf-geo.cjs.map +1 -1
- package/dist/br/data/br-uf-geo.js.map +1 -1
- package/dist/br/data/mun/AC.cjs.map +1 -1
- package/dist/br/data/mun/AC.js.map +1 -1
- package/dist/br/data/mun/AL.cjs.map +1 -1
- package/dist/br/data/mun/AL.js.map +1 -1
- package/dist/br/data/mun/AM.cjs.map +1 -1
- package/dist/br/data/mun/AM.js.map +1 -1
- package/dist/br/data/mun/AP.cjs.map +1 -1
- package/dist/br/data/mun/AP.js.map +1 -1
- package/dist/br/data/mun/BA.cjs.map +1 -1
- package/dist/br/data/mun/BA.js.map +1 -1
- package/dist/br/data/mun/CE.cjs.map +1 -1
- package/dist/br/data/mun/CE.js.map +1 -1
- package/dist/br/data/mun/DF.cjs.map +1 -1
- package/dist/br/data/mun/DF.js.map +1 -1
- package/dist/br/data/mun/ES.cjs.map +1 -1
- package/dist/br/data/mun/ES.js.map +1 -1
- package/dist/br/data/mun/GO.cjs.map +1 -1
- package/dist/br/data/mun/GO.js.map +1 -1
- package/dist/br/data/mun/MA.cjs.map +1 -1
- package/dist/br/data/mun/MA.js.map +1 -1
- package/dist/br/data/mun/MG.cjs.map +1 -1
- package/dist/br/data/mun/MG.js.map +1 -1
- package/dist/br/data/mun/MS.cjs.map +1 -1
- package/dist/br/data/mun/MS.js.map +1 -1
- package/dist/br/data/mun/MT.cjs.map +1 -1
- package/dist/br/data/mun/MT.js.map +1 -1
- package/dist/br/data/mun/PA.cjs.map +1 -1
- package/dist/br/data/mun/PA.js.map +1 -1
- package/dist/br/data/mun/PB.cjs.map +1 -1
- package/dist/br/data/mun/PB.js.map +1 -1
- package/dist/br/data/mun/PE.cjs.map +1 -1
- package/dist/br/data/mun/PE.js.map +1 -1
- package/dist/br/data/mun/PI.cjs.map +1 -1
- package/dist/br/data/mun/PI.js.map +1 -1
- package/dist/br/data/mun/PR.cjs.map +1 -1
- package/dist/br/data/mun/PR.js.map +1 -1
- package/dist/br/data/mun/RJ.cjs.map +1 -1
- package/dist/br/data/mun/RJ.js.map +1 -1
- package/dist/br/data/mun/RN.cjs.map +1 -1
- package/dist/br/data/mun/RN.js.map +1 -1
- package/dist/br/data/mun/RO.cjs.map +1 -1
- package/dist/br/data/mun/RO.js.map +1 -1
- package/dist/br/data/mun/RR.cjs.map +1 -1
- package/dist/br/data/mun/RR.js.map +1 -1
- package/dist/br/data/mun/RS.cjs.map +1 -1
- package/dist/br/data/mun/RS.js.map +1 -1
- package/dist/br/data/mun/SC.cjs.map +1 -1
- package/dist/br/data/mun/SC.js.map +1 -1
- package/dist/br/data/mun/SE.cjs.map +1 -1
- package/dist/br/data/mun/SE.js.map +1 -1
- package/dist/br/data/mun/SP.cjs.map +1 -1
- package/dist/br/data/mun/SP.js.map +1 -1
- package/dist/br/data/mun/TO.cjs.map +1 -1
- package/dist/br/data/mun/TO.js.map +1 -1
- package/dist/br/geocode.cjs.map +1 -1
- package/dist/br/geocode.js.map +1 -1
- package/dist/br/holidays.cjs.map +1 -1
- package/dist/br/holidays.js.map +1 -1
- package/dist/br/locations.cjs.map +1 -1
- package/dist/br/locations.js.map +1 -1
- package/dist/br/nfe.cjs.map +1 -1
- package/dist/br/nfe.js.map +1 -1
- package/dist/br/pix.cjs +1 -1
- package/dist/br/pix.cjs.map +1 -1
- package/dist/br/pix.js +108 -74
- package/dist/br/pix.js.map +1 -1
- package/dist/br/regions.cjs.map +1 -1
- package/dist/br/regions.js.map +1 -1
- package/dist/br/scales.cjs.map +1 -1
- package/dist/br/scales.js.map +1 -1
- package/dist/br/state-geo.cjs.map +1 -1
- package/dist/br/state-geo.js.map +1 -1
- package/dist/br/svg-utils.cjs.map +1 -1
- package/dist/br/svg-utils.js.map +1 -1
- package/dist/br/use-map-hover.cjs.map +1 -1
- package/dist/br/use-map-hover.js.map +1 -1
- package/dist/br/use-map-zoom.cjs.map +1 -1
- package/dist/br/use-map-zoom.js.map +1 -1
- package/dist/br/whatsapp.cjs.map +1 -1
- package/dist/br/whatsapp.js.map +1 -1
- package/dist/br.cjs.map +1 -1
- package/dist/br.d.ts +6 -2
- package/dist/br.js.map +1 -1
- package/dist/capture/barcode.cjs.map +1 -1
- package/dist/capture/barcode.js.map +1 -1
- package/dist/capture/media-recorder.cjs.map +1 -1
- package/dist/capture/media-recorder.js.map +1 -1
- package/dist/capture/use-barcode-scanner.cjs.map +1 -1
- package/dist/capture/use-barcode-scanner.js.map +1 -1
- package/dist/capture/use-screen-capture.cjs +1 -1
- package/dist/capture/use-screen-capture.cjs.map +1 -1
- package/dist/capture/use-screen-capture.js +1 -7
- package/dist/capture/use-screen-capture.js.map +1 -1
- package/dist/capture/use-speech-recognition.cjs +1 -1
- package/dist/capture/use-speech-recognition.cjs.map +1 -1
- package/dist/capture/use-speech-recognition.js +35 -36
- package/dist/capture/use-speech-recognition.js.map +1 -1
- package/dist/capture/use-torch.cjs.map +1 -1
- package/dist/capture/use-torch.js.map +1 -1
- package/dist/capture/use-video-recorder.cjs.map +1 -1
- package/dist/capture/use-video-recorder.js.map +1 -1
- package/dist/capture/video-recorder.cjs.map +1 -1
- package/dist/capture/video-recorder.js.map +1 -1
- package/dist/charts/AreaChart.cjs.map +1 -1
- package/dist/charts/AreaChart.js.map +1 -1
- package/dist/charts/BarChart.cjs.map +1 -1
- package/dist/charts/BarChart.js.map +1 -1
- package/dist/charts/LineChart.cjs.map +1 -1
- package/dist/charts/LineChart.js.map +1 -1
- package/dist/charts/PieChart.cjs.map +1 -1
- package/dist/charts/PieChart.js.map +1 -1
- package/dist/charts/RadarChart.cjs.map +1 -1
- package/dist/charts/RadarChart.js.map +1 -1
- package/dist/charts/palette.cjs.map +1 -1
- package/dist/charts/palette.js.map +1 -1
- package/dist/charts/scales.cjs.map +1 -1
- package/dist/charts/scales.js.map +1 -1
- package/dist/charts/types.cjs.map +1 -1
- package/dist/charts/types.js.map +1 -1
- package/dist/charts/use-chart-colors.cjs.map +1 -1
- package/dist/charts/use-chart-colors.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 -5
- package/dist/components/AIChat/AIChat.js.map +1 -1
- package/dist/components/AIChat/AIChat.module.cjs.map +1 -1
- package/dist/components/AIChat/AIChat.module.js.map +1 -1
- package/dist/components/AIChat/AIChatComposer.cjs +1 -1
- package/dist/components/AIChat/AIChatComposer.cjs.map +1 -1
- package/dist/components/AIChat/AIChatComposer.js +1 -7
- package/dist/components/AIChat/AIChatComposer.js.map +1 -1
- package/dist/components/AIChat/AIChatTurn.cjs.map +1 -1
- package/dist/components/AIChat/AIChatTurn.js.map +1 -1
- package/dist/components/AIChat/ai-chat-turns.cjs.map +1 -1
- package/dist/components/AIChat/ai-chat-turns.js.map +1 -1
- package/dist/components/Accordion/Accordion.cjs.map +1 -1
- package/dist/components/Accordion/Accordion.js.map +1 -1
- package/dist/components/Accordion/Accordion.module.cjs.map +1 -1
- package/dist/components/Accordion/Accordion.module.js.map +1 -1
- package/dist/components/Alert/Alert.cjs.map +1 -1
- package/dist/components/Alert/Alert.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/AppBar.cjs.map +1 -1
- package/dist/components/AppBar/AppBar.js.map +1 -1
- package/dist/components/AppBar/AppBar.module.cjs.map +1 -1
- package/dist/components/AppBar/AppBar.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/AppShell/AppShell.cjs.map +1 -1
- package/dist/components/AppShell/AppShell.js.map +1 -1
- package/dist/components/AppShell/AppShell.module.cjs.map +1 -1
- package/dist/components/AppShell/AppShell.module.js.map +1 -1
- package/dist/components/AspectRatio/AspectRatio.cjs.map +1 -1
- package/dist/components/AspectRatio/AspectRatio.js.map +1 -1
- package/dist/components/AspectRatio/AspectRatio.module.cjs.map +1 -1
- package/dist/components/AspectRatio/AspectRatio.module.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 +1 -7
- package/dist/components/AudioPlayer/AudioPlayer.js.map +1 -1
- package/dist/components/AudioPlayer/AudioPlayer.module.cjs.map +1 -1
- package/dist/components/AudioPlayer/AudioPlayer.module.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 +16 -21
- package/dist/components/AudioRecorder/AudioRecorder.js.map +1 -1
- package/dist/components/AudioRecorder/AudioRecorder.module.cjs.map +1 -1
- package/dist/components/AudioRecorder/AudioRecorder.module.js.map +1 -1
- package/dist/components/Avatar/Avatar.cjs.map +1 -1
- package/dist/components/Avatar/Avatar.js.map +1 -1
- package/dist/components/Avatar/Avatar.module.cjs.map +1 -1
- package/dist/components/Avatar/Avatar.module.js.map +1 -1
- package/dist/components/AvatarGroup/AvatarGroup.cjs.map +1 -1
- package/dist/components/AvatarGroup/AvatarGroup.js.map +1 -1
- package/dist/components/AvatarGroup/AvatarGroup.module.cjs.map +1 -1
- package/dist/components/AvatarGroup/AvatarGroup.module.js.map +1 -1
- package/dist/components/Badge/Badge.cjs.map +1 -1
- package/dist/components/Badge/Badge.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/Banner/Banner.cjs.map +1 -1
- package/dist/components/Banner/Banner.js.map +1 -1
- package/dist/components/Banner/Banner.module.cjs.map +1 -1
- package/dist/components/Banner/Banner.module.js.map +1 -1
- package/dist/components/BarList/BarList.cjs.map +1 -1
- package/dist/components/BarList/BarList.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/BarList/bar-list-model.cjs.map +1 -1
- package/dist/components/BarList/bar-list-model.js.map +1 -1
- package/dist/components/BarcodeScanner/BarcodeScanner.cjs.map +1 -1
- package/dist/components/BarcodeScanner/BarcodeScanner.js.map +1 -1
- package/dist/components/BarcodeScanner/BarcodeScanner.module.cjs.map +1 -1
- package/dist/components/BarcodeScanner/BarcodeScanner.module.js.map +1 -1
- package/dist/components/BottomNavigation/BottomNavigation.cjs.map +1 -1
- package/dist/components/BottomNavigation/BottomNavigation.js.map +1 -1
- package/dist/components/BottomNavigation/BottomNavigation.module.cjs.map +1 -1
- package/dist/components/BottomNavigation/BottomNavigation.module.js.map +1 -1
- package/dist/components/BottomSheet/BottomSheet.cjs.map +1 -1
- package/dist/components/BottomSheet/BottomSheet.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/Breadcrumbs/Breadcrumbs.cjs.map +1 -1
- package/dist/components/Breadcrumbs/Breadcrumbs.js.map +1 -1
- package/dist/components/Breadcrumbs/Breadcrumbs.module.cjs.map +1 -1
- package/dist/components/Breadcrumbs/Breadcrumbs.module.js.map +1 -1
- package/dist/components/Button/Button.cjs.map +1 -1
- package/dist/components/Button/Button.js.map +1 -1
- package/dist/components/Button/Button.module.cjs.map +1 -1
- package/dist/components/Button/Button.module.js.map +1 -1
- package/dist/components/Button/ButtonContent.cjs.map +1 -1
- package/dist/components/Button/ButtonContent.js.map +1 -1
- package/dist/components/Button/ButtonSlot.cjs.map +1 -1
- package/dist/components/Button/ButtonSlot.js.map +1 -1
- package/dist/components/Button/button-class.cjs.map +1 -1
- package/dist/components/Button/button-class.js.map +1 -1
- package/dist/components/Button/link-rel.cjs.map +1 -1
- package/dist/components/Button/link-rel.js.map +1 -1
- package/dist/components/Button/slot.cjs.map +1 -1
- package/dist/components/Button/slot.js.map +1 -1
- package/dist/components/Calendar/Calendar.cjs.map +1 -1
- package/dist/components/Calendar/Calendar.js.map +1 -1
- package/dist/components/Calendar/Calendar.module.cjs.map +1 -1
- package/dist/components/Calendar/Calendar.module.js.map +1 -1
- package/dist/components/Card/Card.cjs.map +1 -1
- package/dist/components/Card/Card.js.map +1 -1
- package/dist/components/Card/Card.module.cjs.map +1 -1
- package/dist/components/Card/Card.module.js.map +1 -1
- package/dist/components/Carousel/Carousel.cjs.map +1 -1
- package/dist/components/Carousel/Carousel.js.map +1 -1
- package/dist/components/Carousel/Carousel.module.cjs.map +1 -1
- package/dist/components/Carousel/Carousel.module.js.map +1 -1
- package/dist/components/Center/Center.cjs.map +1 -1
- package/dist/components/Center/Center.js.map +1 -1
- package/dist/components/Center/Center.module.cjs.map +1 -1
- package/dist/components/Center/Center.module.js.map +1 -1
- package/dist/components/Chat/Chat.cjs.map +1 -1
- package/dist/components/Chat/Chat.js.map +1 -1
- package/dist/components/Chat/Chat.module.cjs.map +1 -1
- package/dist/components/Chat/Chat.module.js.map +1 -1
- package/dist/components/Chat/ChatActionsMenu.cjs.map +1 -1
- package/dist/components/Chat/ChatActionsMenu.js.map +1 -1
- package/dist/components/Chat/ChatAttachments.cjs.map +1 -1
- package/dist/components/Chat/ChatAttachments.js.map +1 -1
- package/dist/components/Chat/ChatBubble.cjs.map +1 -1
- package/dist/components/Chat/ChatBubble.js.map +1 -1
- package/dist/components/Chat/ChatComposer.cjs.map +1 -1
- package/dist/components/Chat/ChatComposer.js.map +1 -1
- package/dist/components/Chat/chat-groups.cjs +1 -1
- package/dist/components/Chat/chat-groups.cjs.map +1 -1
- package/dist/components/Chat/chat-groups.js +2 -6
- package/dist/components/Chat/chat-groups.js.map +1 -1
- package/dist/components/Chat/chat-receipt.cjs.map +1 -1
- package/dist/components/Chat/chat-receipt.js.map +1 -1
- package/dist/components/Checkbox/Checkbox.cjs.map +1 -1
- package/dist/components/Checkbox/Checkbox.js.map +1 -1
- package/dist/components/Checkbox/Checkbox.module.cjs.map +1 -1
- package/dist/components/Checkbox/Checkbox.module.js.map +1 -1
- package/dist/components/ChipInput/ChipInput.cjs +1 -1
- package/dist/components/ChipInput/ChipInput.cjs.map +1 -1
- package/dist/components/ChipInput/ChipInput.js +2 -12
- package/dist/components/ChipInput/ChipInput.js.map +1 -1
- package/dist/components/ChipInput/ChipInput.module.cjs.map +1 -1
- package/dist/components/ChipInput/ChipInput.module.js.map +1 -1
- package/dist/components/ClickOutside/ClickOutside.cjs.map +1 -1
- package/dist/components/ClickOutside/ClickOutside.js.map +1 -1
- package/dist/components/CodeBlock/CodeBlock.cjs.map +1 -1
- package/dist/components/CodeBlock/CodeBlock.js.map +1 -1
- package/dist/components/CodeBlock/CodeBlock.module.cjs.map +1 -1
- package/dist/components/CodeBlock/CodeBlock.module.js.map +1 -1
- package/dist/components/CodeBlock/tokenize.cjs.map +1 -1
- package/dist/components/CodeBlock/tokenize.js.map +1 -1
- package/dist/components/Collapsible/Collapsible.cjs.map +1 -1
- package/dist/components/Collapsible/Collapsible.js.map +1 -1
- package/dist/components/Collapsible/Collapsible.module.cjs.map +1 -1
- package/dist/components/Collapsible/Collapsible.module.js.map +1 -1
- package/dist/components/Combobox/Combobox.cjs.map +1 -1
- package/dist/components/Combobox/Combobox.js.map +1 -1
- package/dist/components/Combobox/Combobox.module.cjs.map +1 -1
- package/dist/components/Combobox/Combobox.module.js.map +1 -1
- package/dist/components/Combobox/use-listbox-dismiss.cjs.map +1 -1
- package/dist/components/Combobox/use-listbox-dismiss.js.map +1 -1
- package/dist/components/Command/Command.cjs +1 -1
- package/dist/components/Command/Command.cjs.map +1 -1
- package/dist/components/Command/Command.js +4 -11
- package/dist/components/Command/Command.js.map +1 -1
- package/dist/components/Command/Command.module.cjs.map +1 -1
- package/dist/components/Command/Command.module.js.map +1 -1
- package/dist/components/ConditionalWrapper/ConditionalWrapper.cjs.map +1 -1
- package/dist/components/ConditionalWrapper/ConditionalWrapper.js.map +1 -1
- package/dist/components/ConfirmDialog/ConfirmDialog.cjs.map +1 -1
- package/dist/components/ConfirmDialog/ConfirmDialog.js.map +1 -1
- package/dist/components/ContextMenu/ContextMenu.cjs +1 -1
- package/dist/components/ContextMenu/ContextMenu.cjs.map +1 -1
- package/dist/components/ContextMenu/ContextMenu.js +1 -1
- package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
- package/dist/components/ContextMenu/ContextMenu.module.cjs.map +1 -1
- package/dist/components/ContextMenu/ContextMenu.module.js.map +1 -1
- package/dist/components/CopyButton/CopyButton.cjs.map +1 -1
- package/dist/components/CopyButton/CopyButton.js.map +1 -1
- package/dist/components/CopyButton/CopyButton.module.cjs.map +1 -1
- package/dist/components/CopyButton/CopyButton.module.js.map +1 -1
- package/dist/components/DataList/DataList.cjs.map +1 -1
- package/dist/components/DataList/DataList.js.map +1 -1
- package/dist/components/DataList/DataList.module.cjs.map +1 -1
- package/dist/components/DataList/DataList.module.js.map +1 -1
- package/dist/components/DataTable/DataTable.cjs +1 -1
- package/dist/components/DataTable/DataTable.cjs.map +1 -1
- package/dist/components/DataTable/DataTable.js +6 -14
- package/dist/components/DataTable/DataTable.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/DataTable/EditableCell.cjs +1 -1
- package/dist/components/DataTable/EditableCell.cjs.map +1 -1
- package/dist/components/DataTable/EditableCell.js +1 -9
- package/dist/components/DataTable/EditableCell.js.map +1 -1
- package/dist/components/DataTable/LoadingRows.cjs.map +1 -1
- package/dist/components/DataTable/LoadingRows.js.map +1 -1
- package/dist/components/DataTable/edit-labels.cjs.map +1 -1
- package/dist/components/DataTable/edit-labels.js.map +1 -1
- package/dist/components/DataTable/use-dev-warnings.cjs.map +1 -1
- package/dist/components/DataTable/use-dev-warnings.js.map +1 -1
- package/dist/components/DatePicker/DatePicker.cjs.map +1 -1
- package/dist/components/DatePicker/DatePicker.js.map +1 -1
- package/dist/components/DateRangePicker/DateRangePicker.cjs.map +1 -1
- package/dist/components/DateRangePicker/DateRangePicker.js.map +1 -1
- package/dist/components/DateRangePicker/DateRangePicker.module.cjs.map +1 -1
- package/dist/components/DateRangePicker/DateRangePicker.module.js.map +1 -1
- package/dist/components/DescriptionList/DescriptionList.cjs.map +1 -1
- package/dist/components/DescriptionList/DescriptionList.js.map +1 -1
- package/dist/components/DescriptionList/DescriptionList.module.cjs.map +1 -1
- package/dist/components/DescriptionList/DescriptionList.module.js.map +1 -1
- package/dist/components/Divider/Divider.cjs.map +1 -1
- package/dist/components/Divider/Divider.js.map +1 -1
- package/dist/components/Divider/Divider.module.cjs.map +1 -1
- package/dist/components/Divider/Divider.module.js.map +1 -1
- package/dist/components/Drawer/Drawer.cjs.map +1 -1
- package/dist/components/Drawer/Drawer.js.map +1 -1
- package/dist/components/Drawer/Drawer.module.cjs.map +1 -1
- package/dist/components/Drawer/Drawer.module.js.map +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.cjs +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.cjs.map +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.js +2 -14
- package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.module.cjs.map +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.module.js.map +1 -1
- package/dist/components/Dropzone/Dropzone.cjs.map +1 -1
- package/dist/components/Dropzone/Dropzone.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/EmptyState/EmptyState.cjs.map +1 -1
- package/dist/components/EmptyState/EmptyState.js.map +1 -1
- package/dist/components/EmptyState/EmptyState.module.cjs.map +1 -1
- package/dist/components/EmptyState/EmptyState.module.js.map +1 -1
- package/dist/components/ErrorState/ErrorState.cjs.map +1 -1
- package/dist/components/ErrorState/ErrorState.js.map +1 -1
- package/dist/components/ErrorState/ErrorState.module.cjs.map +1 -1
- package/dist/components/ErrorState/ErrorState.module.js.map +1 -1
- package/dist/components/ErrorText/ErrorText.cjs.map +1 -1
- package/dist/components/ErrorText/ErrorText.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/FileUpload/FileUpload.cjs +1 -1
- package/dist/components/FileUpload/FileUpload.cjs.map +1 -1
- package/dist/components/FileUpload/FileUpload.js +7 -17
- package/dist/components/FileUpload/FileUpload.js.map +1 -1
- package/dist/components/FileUpload/FileUpload.module.cjs.map +1 -1
- package/dist/components/FileUpload/FileUpload.module.js.map +1 -1
- package/dist/components/FilterBar/FilterBar.cjs.map +1 -1
- package/dist/components/FilterBar/FilterBar.js.map +1 -1
- package/dist/components/FilterBar/FilterBar.module.cjs.map +1 -1
- package/dist/components/FilterBar/FilterBar.module.js.map +1 -1
- package/dist/components/FilterBar/filter-apply.cjs.map +1 -1
- package/dist/components/FilterBar/filter-apply.js.map +1 -1
- package/dist/components/FilterBar/filter-model.cjs.map +1 -1
- package/dist/components/FilterBar/filter-model.js.map +1 -1
- package/dist/components/FilterBar/filter-query.cjs +1 -1
- package/dist/components/FilterBar/filter-query.cjs.map +1 -1
- package/dist/components/FilterBar/filter-query.js +2 -5
- package/dist/components/FilterBar/filter-query.js.map +1 -1
- package/dist/components/FilterPanel/FilterPanel.cjs.map +1 -1
- package/dist/components/FilterPanel/FilterPanel.js.map +1 -1
- package/dist/components/FilterPanel/FilterPanel.module.cjs.map +1 -1
- package/dist/components/FilterPanel/FilterPanel.module.js.map +1 -1
- package/dist/components/FloatingActionButton/FloatingActionButton.cjs.map +1 -1
- package/dist/components/FloatingActionButton/FloatingActionButton.js.map +1 -1
- package/dist/components/FloatingActionButton/FloatingActionButton.module.cjs.map +1 -1
- package/dist/components/FloatingActionButton/FloatingActionButton.module.js.map +1 -1
- package/dist/components/For/For.cjs.map +1 -1
- package/dist/components/For/For.js.map +1 -1
- package/dist/components/Form/Form.cjs.map +1 -1
- package/dist/components/Form/Form.js.map +1 -1
- package/dist/components/Form/Form.module.cjs.map +1 -1
- package/dist/components/Form/Form.module.js.map +1 -1
- package/dist/components/HoverCard/HoverCard.cjs.map +1 -1
- package/dist/components/HoverCard/HoverCard.js.map +1 -1
- package/dist/components/HoverCard/HoverCard.module.cjs.map +1 -1
- package/dist/components/HoverCard/HoverCard.module.js.map +1 -1
- package/dist/components/Image/Image.cjs.map +1 -1
- package/dist/components/Image/Image.js.map +1 -1
- package/dist/components/Image/Image.module.cjs.map +1 -1
- package/dist/components/Image/Image.module.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 +4 -8
- package/dist/components/ImageCropper/ImageCropper.js.map +1 -1
- package/dist/components/ImageCropper/ImageCropper.module.cjs.map +1 -1
- package/dist/components/ImageCropper/ImageCropper.module.js.map +1 -1
- package/dist/components/ImageCropper/crop-geometry.cjs.map +1 -1
- package/dist/components/ImageCropper/crop-geometry.js.map +1 -1
- package/dist/components/Input/Input.cjs.map +1 -1
- package/dist/components/Input/Input.js.map +1 -1
- package/dist/components/Input/Input.module.cjs.map +1 -1
- package/dist/components/Input/Input.module.js.map +1 -1
- package/dist/components/InstallBanner/InstallBanner.cjs.map +1 -1
- package/dist/components/InstallBanner/InstallBanner.js.map +1 -1
- package/dist/components/InstallBanner/InstallBanner.module.cjs.map +1 -1
- package/dist/components/InstallBanner/InstallBanner.module.js.map +1 -1
- package/dist/components/InstallButton/InstallButton.cjs.map +1 -1
- package/dist/components/InstallButton/InstallButton.js.map +1 -1
- package/dist/components/InstallButton/InstallButton.module.cjs.map +1 -1
- package/dist/components/InstallButton/InstallButton.module.js.map +1 -1
- package/dist/components/InstallButton/install-hints.cjs.map +1 -1
- package/dist/components/InstallButton/install-hints.js.map +1 -1
- package/dist/components/Kanban/Kanban.cjs.map +1 -1
- package/dist/components/Kanban/Kanban.js.map +1 -1
- package/dist/components/Kanban/Kanban.module.cjs.map +1 -1
- package/dist/components/Kanban/Kanban.module.js.map +1 -1
- package/dist/components/Kbd/Kbd.cjs.map +1 -1
- package/dist/components/Kbd/Kbd.js.map +1 -1
- package/dist/components/Kbd/Kbd.module.cjs.map +1 -1
- package/dist/components/Kbd/Kbd.module.js.map +1 -1
- package/dist/components/Label/Label.cjs.map +1 -1
- package/dist/components/Label/Label.js.map +1 -1
- package/dist/components/Label/Label.module.cjs.map +1 -1
- package/dist/components/Label/Label.module.js.map +1 -1
- package/dist/components/Layout/Layout.cjs.map +1 -1
- package/dist/components/Layout/Layout.js.map +1 -1
- package/dist/components/Layout/Layout.module.cjs.map +1 -1
- package/dist/components/Layout/Layout.module.js.map +1 -1
- package/dist/components/Lightbox/Lightbox.cjs +1 -1
- package/dist/components/Lightbox/Lightbox.cjs.map +1 -1
- package/dist/components/Lightbox/Lightbox.js +1 -1
- package/dist/components/Lightbox/Lightbox.js.map +1 -1
- package/dist/components/Lightbox/Lightbox.module.cjs.map +1 -1
- package/dist/components/Lightbox/Lightbox.module.js.map +1 -1
- package/dist/components/ListTile/ListTile.cjs.map +1 -1
- package/dist/components/ListTile/ListTile.js.map +1 -1
- package/dist/components/ListTile/ListTile.module.cjs.map +1 -1
- package/dist/components/ListTile/ListTile.module.js.map +1 -1
- package/dist/components/Markdown/Markdown.cjs.map +1 -1
- package/dist/components/Markdown/Markdown.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/Markdown/markdown-parse.cjs +2 -2
- package/dist/components/Markdown/markdown-parse.cjs.map +1 -1
- package/dist/components/Markdown/markdown-parse.js +8 -27
- package/dist/components/Markdown/markdown-parse.js.map +1 -1
- package/dist/components/Masonry/Masonry.cjs.map +1 -1
- package/dist/components/Masonry/Masonry.js.map +1 -1
- package/dist/components/Masonry/Masonry.module.cjs.map +1 -1
- package/dist/components/Masonry/Masonry.module.js.map +1 -1
- package/dist/components/Masonry/masonry-layout.cjs.map +1 -1
- package/dist/components/Masonry/masonry-layout.js.map +1 -1
- package/dist/components/Menubar/Menubar.cjs.map +1 -1
- package/dist/components/Menubar/Menubar.js.map +1 -1
- package/dist/components/Menubar/Menubar.module.cjs.map +1 -1
- package/dist/components/Menubar/Menubar.module.js.map +1 -1
- package/dist/components/Modal/Modal.cjs.map +1 -1
- package/dist/components/Modal/Modal.js.map +1 -1
- package/dist/components/Modal/Modal.module.cjs.map +1 -1
- package/dist/components/Modal/Modal.module.js.map +1 -1
- package/dist/components/ModalsManager/ModalsManager.cjs.map +1 -1
- package/dist/components/ModalsManager/ModalsManager.js.map +1 -1
- package/dist/components/ModalsManager/ModalsManager.module.cjs.map +1 -1
- package/dist/components/ModalsManager/ModalsManager.module.js.map +1 -1
- package/dist/components/Money/Money.cjs.map +1 -1
- package/dist/components/Money/Money.js.map +1 -1
- package/dist/components/MultiSelect/MultiSelect.cjs.map +1 -1
- package/dist/components/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/components/MultiSelect/MultiSelect.module.cjs.map +1 -1
- package/dist/components/MultiSelect/MultiSelect.module.js.map +1 -1
- package/dist/components/NProgress/NProgress.cjs.map +1 -1
- package/dist/components/NProgress/NProgress.js.map +1 -1
- package/dist/components/NProgress/NProgress.module.cjs.map +1 -1
- package/dist/components/NProgress/NProgress.module.js.map +1 -1
- package/dist/components/Navbar/Navbar.cjs.map +1 -1
- package/dist/components/Navbar/Navbar.js.map +1 -1
- package/dist/components/Navbar/Navbar.module.cjs.map +1 -1
- package/dist/components/Navbar/Navbar.module.js.map +1 -1
- package/dist/components/NavigationMenu/NavigationMenu.cjs.map +1 -1
- package/dist/components/NavigationMenu/NavigationMenu.js.map +1 -1
- package/dist/components/NavigationMenu/NavigationMenu.module.cjs.map +1 -1
- package/dist/components/NavigationMenu/NavigationMenu.module.js.map +1 -1
- package/dist/components/NavigationRail/NavigationRail.cjs.map +1 -1
- package/dist/components/NavigationRail/NavigationRail.js.map +1 -1
- package/dist/components/NavigationRail/NavigationRail.module.cjs.map +1 -1
- package/dist/components/NavigationRail/NavigationRail.module.js.map +1 -1
- package/dist/components/NotificationCenter/NotificationCenter.cjs.map +1 -1
- package/dist/components/NotificationCenter/NotificationCenter.js.map +1 -1
- package/dist/components/NotificationCenter/NotificationCenter.module.cjs.map +1 -1
- package/dist/components/NotificationCenter/NotificationCenter.module.js.map +1 -1
- package/dist/components/NotificationCenter/use-notification-inbox.cjs.map +1 -1
- package/dist/components/NotificationCenter/use-notification-inbox.js.map +1 -1
- package/dist/components/OfflineIndicator/OfflineIndicator.cjs.map +1 -1
- package/dist/components/OfflineIndicator/OfflineIndicator.js.map +1 -1
- package/dist/components/OfflineIndicator/OfflineIndicator.module.cjs.map +1 -1
- package/dist/components/OfflineIndicator/OfflineIndicator.module.js.map +1 -1
- package/dist/components/Page/Page.cjs.map +1 -1
- package/dist/components/Page/Page.js.map +1 -1
- package/dist/components/Page/Page.module.cjs.map +1 -1
- package/dist/components/Page/Page.module.js.map +1 -1
- package/dist/components/Pagination/Pagination.cjs.map +1 -1
- package/dist/components/Pagination/Pagination.js.map +1 -1
- package/dist/components/Pagination/Pagination.module.cjs.map +1 -1
- package/dist/components/Pagination/Pagination.module.js.map +1 -1
- package/dist/components/PasswordInput/PasswordInput.cjs.map +1 -1
- package/dist/components/PasswordInput/PasswordInput.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/PinInput/PinInput.cjs.map +1 -1
- package/dist/components/PinInput/PinInput.js.map +1 -1
- package/dist/components/PinInput/PinInput.module.cjs.map +1 -1
- package/dist/components/PinInput/PinInput.module.js.map +1 -1
- package/dist/components/Popover/Popover.cjs.map +1 -1
- package/dist/components/Popover/Popover.js.map +1 -1
- package/dist/components/Popover/Popover.module.cjs.map +1 -1
- package/dist/components/Popover/Popover.module.js.map +1 -1
- package/dist/components/Portal/Portal.cjs.map +1 -1
- package/dist/components/Portal/Portal.js.map +1 -1
- package/dist/components/Portal/anchor-position.cjs.map +1 -1
- package/dist/components/Portal/anchor-position.js.map +1 -1
- package/dist/components/Portal/escape-layer.cjs.map +1 -1
- package/dist/components/Portal/escape-layer.js.map +1 -1
- package/dist/components/Portal/portal-host.cjs.map +1 -1
- package/dist/components/Portal/portal-host.js.map +1 -1
- package/dist/components/Portal/tab-bridge.cjs +1 -1
- package/dist/components/Portal/tab-bridge.cjs.map +1 -1
- package/dist/components/Portal/tab-bridge.js +1 -5
- package/dist/components/Portal/tab-bridge.js.map +1 -1
- package/dist/components/Progress/Progress.cjs.map +1 -1
- package/dist/components/Progress/Progress.js.map +1 -1
- package/dist/components/Progress/Progress.module.cjs.map +1 -1
- package/dist/components/Progress/Progress.module.js.map +1 -1
- package/dist/components/QRCode/QRCode.cjs.map +1 -1
- package/dist/components/QRCode/QRCode.js.map +1 -1
- package/dist/components/QRCode/QRCode.module.cjs.map +1 -1
- package/dist/components/QRCode/QRCode.module.js.map +1 -1
- package/dist/components/QRCode/qr-encode.cjs +1 -1
- package/dist/components/QRCode/qr-encode.cjs.map +1 -1
- package/dist/components/QRCode/qr-encode.js +7 -13
- package/dist/components/QRCode/qr-encode.js.map +1 -1
- package/dist/components/QRCode/qr-tables.cjs.map +1 -1
- package/dist/components/QRCode/qr-tables.js.map +1 -1
- package/dist/components/Radio/Radio.cjs.map +1 -1
- package/dist/components/Radio/Radio.js.map +1 -1
- package/dist/components/Radio/Radio.module.cjs.map +1 -1
- package/dist/components/Radio/Radio.module.js.map +1 -1
- package/dist/components/RangeSlider/RangeSlider.cjs.map +1 -1
- package/dist/components/RangeSlider/RangeSlider.js.map +1 -1
- package/dist/components/RangeSlider/RangeSlider.module.cjs.map +1 -1
- package/dist/components/RangeSlider/RangeSlider.module.js.map +1 -1
- package/dist/components/RatingStars/RatingStars.cjs.map +1 -1
- package/dist/components/RatingStars/RatingStars.js.map +1 -1
- package/dist/components/RatingStars/RatingStars.module.cjs.map +1 -1
- package/dist/components/RatingStars/RatingStars.module.js.map +1 -1
- package/dist/components/RefreshIndicator/RefreshIndicator.cjs +1 -1
- package/dist/components/RefreshIndicator/RefreshIndicator.cjs.map +1 -1
- package/dist/components/RefreshIndicator/RefreshIndicator.js +10 -18
- package/dist/components/RefreshIndicator/RefreshIndicator.js.map +1 -1
- package/dist/components/RefreshIndicator/RefreshIndicator.module.cjs.map +1 -1
- package/dist/components/RefreshIndicator/RefreshIndicator.module.js.map +1 -1
- package/dist/components/RelativeTime/RelativeTime.cjs.map +1 -1
- package/dist/components/RelativeTime/RelativeTime.js.map +1 -1
- package/dist/components/Resizable/Resizable.cjs +1 -1
- package/dist/components/Resizable/Resizable.cjs.map +1 -1
- package/dist/components/Resizable/Resizable.js +1 -9
- package/dist/components/Resizable/Resizable.js.map +1 -1
- package/dist/components/Resizable/Resizable.module.cjs.map +1 -1
- package/dist/components/Resizable/Resizable.module.js.map +1 -1
- package/dist/components/Responsive/Responsive.cjs.map +1 -1
- package/dist/components/Responsive/Responsive.js.map +1 -1
- package/dist/components/Reveal/Reveal.cjs.map +1 -1
- package/dist/components/Reveal/Reveal.js.map +1 -1
- package/dist/components/Reveal/Reveal.module.cjs.map +1 -1
- package/dist/components/Reveal/Reveal.module.js.map +1 -1
- package/dist/components/Reveal/reveal-threshold.cjs.map +1 -1
- package/dist/components/Reveal/reveal-threshold.js.map +1 -1
- package/dist/components/SafeArea/SafeArea.cjs.map +1 -1
- package/dist/components/SafeArea/SafeArea.js.map +1 -1
- package/dist/components/SafeArea/SafeArea.module.cjs.map +1 -1
- package/dist/components/SafeArea/SafeArea.module.js.map +1 -1
- package/dist/components/Scheduler/Scheduler.cjs.map +1 -1
- package/dist/components/Scheduler/Scheduler.js.map +1 -1
- package/dist/components/Scheduler/Scheduler.module.cjs.map +1 -1
- package/dist/components/Scheduler/Scheduler.module.js.map +1 -1
- package/dist/components/Scheduler/scheduler-layout.cjs.map +1 -1
- package/dist/components/Scheduler/scheduler-layout.js.map +1 -1
- package/dist/components/ScrollArea/ScrollArea.cjs.map +1 -1
- package/dist/components/ScrollArea/ScrollArea.js.map +1 -1
- package/dist/components/ScrollArea/ScrollArea.module.cjs.map +1 -1
- package/dist/components/ScrollArea/ScrollArea.module.js.map +1 -1
- package/dist/components/SearchBar/SearchBar.cjs.map +1 -1
- package/dist/components/SearchBar/SearchBar.js.map +1 -1
- package/dist/components/SearchBar/SearchBar.module.cjs.map +1 -1
- package/dist/components/SearchBar/SearchBar.module.js.map +1 -1
- package/dist/components/SectionHeader/SectionHeader.cjs.map +1 -1
- package/dist/components/SectionHeader/SectionHeader.js.map +1 -1
- package/dist/components/SectionHeader/SectionHeader.module.cjs.map +1 -1
- package/dist/components/SectionHeader/SectionHeader.module.js.map +1 -1
- package/dist/components/SegmentedControl/SegmentedControl.cjs.map +1 -1
- package/dist/components/SegmentedControl/SegmentedControl.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/Select/CaretIcon.cjs.map +1 -1
- package/dist/components/Select/CaretIcon.js.map +1 -1
- package/dist/components/Select/Select.cjs.map +1 -1
- package/dist/components/Select/Select.js.map +1 -1
- package/dist/components/Select/Select.module.cjs.map +1 -1
- package/dist/components/Select/Select.module.js.map +1 -1
- package/dist/components/Select/options.cjs.map +1 -1
- package/dist/components/Select/options.js.map +1 -1
- package/dist/components/Sidebar/Sidebar.cjs +1 -1
- package/dist/components/Sidebar/Sidebar.cjs.map +1 -1
- package/dist/components/Sidebar/Sidebar.js +13 -23
- package/dist/components/Sidebar/Sidebar.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/Sidebar/SidebarEntry.cjs.map +1 -1
- package/dist/components/Sidebar/SidebarEntry.js.map +1 -1
- package/dist/components/Sidebar/active-nav-key.cjs.map +1 -1
- package/dist/components/Sidebar/active-nav-key.js.map +1 -1
- package/dist/components/SignaturePad/SignaturePad.cjs +1 -1
- package/dist/components/SignaturePad/SignaturePad.cjs.map +1 -1
- package/dist/components/SignaturePad/SignaturePad.js +1 -5
- package/dist/components/SignaturePad/SignaturePad.js.map +1 -1
- package/dist/components/SignaturePad/SignaturePad.module.cjs.map +1 -1
- package/dist/components/SignaturePad/SignaturePad.module.js.map +1 -1
- package/dist/components/Skeleton/Skeleton.cjs.map +1 -1
- package/dist/components/Skeleton/Skeleton.js.map +1 -1
- package/dist/components/Skeleton/Skeleton.module.cjs.map +1 -1
- package/dist/components/Skeleton/Skeleton.module.js.map +1 -1
- package/dist/components/Slider/Slider.cjs.map +1 -1
- package/dist/components/Slider/Slider.js.map +1 -1
- package/dist/components/Slider/Slider.module.cjs.map +1 -1
- package/dist/components/Slider/Slider.module.js.map +1 -1
- package/dist/components/Spacer/Spacer.cjs.map +1 -1
- package/dist/components/Spacer/Spacer.js.map +1 -1
- package/dist/components/Spacer/Spacer.module.cjs.map +1 -1
- package/dist/components/Spacer/Spacer.module.js.map +1 -1
- package/dist/components/Sparkline/Sparkline.cjs.map +1 -1
- package/dist/components/Sparkline/Sparkline.js.map +1 -1
- package/dist/components/Sparkline/Sparkline.module.cjs.map +1 -1
- package/dist/components/Sparkline/Sparkline.module.js.map +1 -1
- package/dist/components/Sparkline/sparkline-geometry.cjs.map +1 -1
- package/dist/components/Sparkline/sparkline-geometry.js.map +1 -1
- package/dist/components/Spinner/Spinner.cjs.map +1 -1
- package/dist/components/Spinner/Spinner.js.map +1 -1
- package/dist/components/Spinner/Spinner.module.cjs.map +1 -1
- package/dist/components/Spinner/Spinner.module.js.map +1 -1
- package/dist/components/Stat/Stat.cjs.map +1 -1
- package/dist/components/Stat/Stat.js.map +1 -1
- package/dist/components/Stat/Stat.module.cjs.map +1 -1
- package/dist/components/Stat/Stat.module.js.map +1 -1
- package/dist/components/Stepper/Stepper.cjs.map +1 -1
- package/dist/components/Stepper/Stepper.js.map +1 -1
- package/dist/components/Stepper/Stepper.module.cjs.map +1 -1
- package/dist/components/Stepper/Stepper.module.js.map +1 -1
- package/dist/components/StepperInput/StepperInput.cjs.map +1 -1
- package/dist/components/StepperInput/StepperInput.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/Switch/Switch.cjs.map +1 -1
- package/dist/components/Switch/Switch.js.map +1 -1
- package/dist/components/Switch/Switch.module.cjs.map +1 -1
- package/dist/components/Switch/Switch.module.js.map +1 -1
- package/dist/components/SyncStatusBadge/SyncStatusBadge.cjs.map +1 -1
- package/dist/components/SyncStatusBadge/SyncStatusBadge.js.map +1 -1
- package/dist/components/SyncStatusBadge/SyncStatusBadge.module.cjs.map +1 -1
- package/dist/components/SyncStatusBadge/SyncStatusBadge.module.js.map +1 -1
- package/dist/components/Table/Table.cjs.map +1 -1
- package/dist/components/Table/Table.js.map +1 -1
- package/dist/components/Table/Table.module.cjs.map +1 -1
- package/dist/components/Table/Table.module.js.map +1 -1
- package/dist/components/Tabs/Tabs.cjs.map +1 -1
- package/dist/components/Tabs/Tabs.js.map +1 -1
- package/dist/components/Tabs/Tabs.module.cjs.map +1 -1
- package/dist/components/Tabs/Tabs.module.js.map +1 -1
- package/dist/components/Tag/Tag.cjs.map +1 -1
- package/dist/components/Tag/Tag.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/Textarea/Textarea.cjs.map +1 -1
- package/dist/components/Textarea/Textarea.js.map +1 -1
- package/dist/components/Textarea/Textarea.module.cjs.map +1 -1
- package/dist/components/Textarea/Textarea.module.js.map +1 -1
- package/dist/components/TimePicker/TimePicker.cjs.map +1 -1
- package/dist/components/TimePicker/TimePicker.js.map +1 -1
- package/dist/components/TimePicker/TimePicker.module.cjs.map +1 -1
- package/dist/components/TimePicker/TimePicker.module.js.map +1 -1
- package/dist/components/Timeline/Timeline.cjs.map +1 -1
- package/dist/components/Timeline/Timeline.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/Toast/Toast.module.cjs.map +1 -1
- package/dist/components/Toast/Toast.module.js.map +1 -1
- package/dist/components/Toast/ToastProvider.cjs.map +1 -1
- package/dist/components/Toast/ToastProvider.js.map +1 -1
- package/dist/components/Toggle/Toggle.cjs.map +1 -1
- package/dist/components/Toggle/Toggle.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.cjs.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroup.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/Tooltip/Tooltip.cjs.map +1 -1
- package/dist/components/Tooltip/Tooltip.js.map +1 -1
- package/dist/components/Tooltip/Tooltip.module.cjs.map +1 -1
- package/dist/components/Tooltip/Tooltip.module.js.map +1 -1
- package/dist/components/Tour/Tour.cjs +1 -1
- package/dist/components/Tour/Tour.cjs.map +1 -1
- package/dist/components/Tour/Tour.js +1 -5
- package/dist/components/Tour/Tour.js.map +1 -1
- package/dist/components/Tour/Tour.module.cjs.map +1 -1
- package/dist/components/Tour/Tour.module.js.map +1 -1
- package/dist/components/Tour/tour-position.cjs.map +1 -1
- package/dist/components/Tour/tour-position.js.map +1 -1
- package/dist/components/Transfer/Transfer.cjs.map +1 -1
- package/dist/components/Transfer/Transfer.js.map +1 -1
- package/dist/components/Transfer/Transfer.module.cjs.map +1 -1
- package/dist/components/Transfer/Transfer.module.js.map +1 -1
- package/dist/components/Transfer/transfer-state.cjs.map +1 -1
- package/dist/components/Transfer/transfer-state.js.map +1 -1
- package/dist/components/TreeView/TreeView.cjs.map +1 -1
- package/dist/components/TreeView/TreeView.js.map +1 -1
- package/dist/components/TreeView/TreeView.module.cjs.map +1 -1
- package/dist/components/TreeView/TreeView.module.js.map +1 -1
- package/dist/components/TruncateText/TruncateText.cjs.map +1 -1
- package/dist/components/TruncateText/TruncateText.js.map +1 -1
- package/dist/components/TruncateText/TruncateText.module.cjs.map +1 -1
- package/dist/components/TruncateText/TruncateText.module.js.map +1 -1
- package/dist/components/UpdatePrompt/UpdatePrompt.cjs.map +1 -1
- package/dist/components/UpdatePrompt/UpdatePrompt.js.map +1 -1
- package/dist/components/UpdatePrompt/UpdatePrompt.module.cjs.map +1 -1
- package/dist/components/UpdatePrompt/UpdatePrompt.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 +1 -7
- package/dist/components/VideoPlayer/VideoPlayer.js.map +1 -1
- package/dist/components/VideoPlayer/VideoPlayer.module.cjs.map +1 -1
- package/dist/components/VideoPlayer/VideoPlayer.module.js.map +1 -1
- package/dist/components/VideoPlayer/playback-rates.cjs.map +1 -1
- package/dist/components/VideoPlayer/playback-rates.js.map +1 -1
- package/dist/components/VirtualList/VirtualList.cjs.map +1 -1
- package/dist/components/VirtualList/VirtualList.js.map +1 -1
- package/dist/components/VirtualList/VirtualList.module.cjs.map +1 -1
- package/dist/components/VirtualList/VirtualList.module.js.map +1 -1
- package/dist/components/VirtualTable/VirtualTable.cjs.map +1 -1
- package/dist/components/VirtualTable/VirtualTable.js.map +1 -1
- package/dist/components/VirtualTable/VirtualTable.module.cjs.map +1 -1
- package/dist/components/VirtualTable/VirtualTable.module.js.map +1 -1
- package/dist/components/VisuallyHidden/VisuallyHidden.cjs.map +1 -1
- package/dist/components/VisuallyHidden/VisuallyHidden.js.map +1 -1
- package/dist/components/VisuallyHidden/VisuallyHidden.module.cjs.map +1 -1
- package/dist/components/VisuallyHidden/VisuallyHidden.module.js.map +1 -1
- package/dist/components/Wizard/Wizard.cjs +1 -1
- package/dist/components/Wizard/Wizard.cjs.map +1 -1
- package/dist/components/Wizard/Wizard.js +4 -11
- package/dist/components/Wizard/Wizard.js.map +1 -1
- package/dist/components/Wizard/Wizard.module.cjs.map +1 -1
- package/dist/components/Wizard/Wizard.module.js.map +1 -1
- package/dist/data/create-data-provider.cjs.map +1 -1
- package/dist/data/create-data-provider.js.map +1 -1
- package/dist/data/data-provider-context.cjs.map +1 -1
- package/dist/data/data-provider-context.js.map +1 -1
- package/dist/data/use-resource.cjs.map +1 -1
- package/dist/data/use-resource.js.map +1 -1
- package/dist/editor/RichTextEditor.cjs.map +1 -1
- package/dist/editor/RichTextEditor.js.map +1 -1
- package/dist/editor/RichTextEditor.module.cjs.map +1 -1
- package/dist/editor/RichTextEditor.module.js.map +1 -1
- package/dist/editor.js +1 -2
- package/dist/error-boundary/ErrorBoundary.cjs.map +1 -1
- package/dist/error-boundary/ErrorBoundary.js.map +1 -1
- package/dist/error-boundary/use-error-handler.cjs.map +1 -1
- package/dist/error-boundary/use-error-handler.js.map +1 -1
- package/dist/feature-flags/FeatureFlagsProvider.cjs.map +1 -1
- package/dist/feature-flags/FeatureFlagsProvider.js.map +1 -1
- package/dist/feature-flags/growthbook-adapter.cjs.map +1 -1
- package/dist/feature-flags/growthbook-adapter.js.map +1 -1
- package/dist/feature-flags/in-memory-adapter.cjs.map +1 -1
- package/dist/feature-flags/in-memory-adapter.js.map +1 -1
- package/dist/feature-flags/launchdarkly-adapter.cjs.map +1 -1
- package/dist/feature-flags/launchdarkly-adapter.js.map +1 -1
- package/dist/forms/FormField.cjs.map +1 -1
- package/dist/forms/FormField.js.map +1 -1
- package/dist/forms/br-validators.cjs.map +1 -1
- package/dist/forms/br-validators.js.map +1 -1
- package/dist/forms/masked-inputs.cjs.map +1 -1
- package/dist/forms/masked-inputs.js.map +1 -1
- package/dist/forms/use-viacep.cjs.map +1 -1
- package/dist/forms/use-viacep.js.map +1 -1
- package/dist/forms/use-zod-form.cjs.map +1 -1
- package/dist/forms/use-zod-form.js.map +1 -1
- package/dist/forms/validate-form.cjs.map +1 -1
- package/dist/forms/validate-form.js.map +1 -1
- package/dist/forms/zod-resolver.cjs.map +1 -1
- package/dist/forms/zod-resolver.js.map +1 -1
- package/dist/geo/TrajectoryMap.cjs.map +1 -1
- package/dist/geo/TrajectoryMap.js.map +1 -1
- package/dist/geo/TrajectoryMap.module.cjs.map +1 -1
- package/dist/geo/TrajectoryMap.module.js.map +1 -1
- package/dist/geo/bounds.cjs.map +1 -1
- package/dist/geo/bounds.js.map +1 -1
- package/dist/geo/create-position-tracker.cjs +1 -1
- package/dist/geo/create-position-tracker.cjs.map +1 -1
- package/dist/geo/create-position-tracker.js +1 -7
- package/dist/geo/create-position-tracker.js.map +1 -1
- package/dist/geo/distance.cjs.map +1 -1
- package/dist/geo/distance.js.map +1 -1
- package/dist/geo/estimate.cjs.map +1 -1
- package/dist/geo/estimate.js.map +1 -1
- package/dist/geo/leaflet-map.cjs.map +1 -1
- package/dist/geo/leaflet-map.js.map +1 -1
- package/dist/geo/projection.cjs.map +1 -1
- package/dist/geo/projection.js.map +1 -1
- package/dist/geo/routing.cjs.map +1 -1
- package/dist/geo/routing.js.map +1 -1
- package/dist/geo/types.cjs.map +1 -1
- package/dist/geo/types.js.map +1 -1
- package/dist/geo/use-position-tracker.cjs.map +1 -1
- package/dist/geo/use-position-tracker.js.map +1 -1
- package/dist/hooks/pwa-env.cjs.map +1 -1
- package/dist/hooks/pwa-env.js.map +1 -1
- package/dist/hooks/tab-sequence.cjs.map +1 -1
- package/dist/hooks/tab-sequence.js.map +1 -1
- package/dist/hooks/use-announce.cjs +1 -1
- package/dist/hooks/use-announce.cjs.map +1 -1
- package/dist/hooks/use-announce.js +2 -2
- package/dist/hooks/use-announce.js.map +1 -1
- package/dist/hooks/use-async.cjs.map +1 -1
- package/dist/hooks/use-async.js.map +1 -1
- package/dist/hooks/use-before-install-prompt.cjs.map +1 -1
- package/dist/hooks/use-before-install-prompt.js.map +1 -1
- package/dist/hooks/use-breakpoint.cjs.map +1 -1
- package/dist/hooks/use-breakpoint.js.map +1 -1
- package/dist/hooks/use-click-outside.cjs.map +1 -1
- package/dist/hooks/use-click-outside.js.map +1 -1
- package/dist/hooks/use-client-filter.cjs.map +1 -1
- package/dist/hooks/use-client-filter.js.map +1 -1
- package/dist/hooks/use-clipboard.cjs.map +1 -1
- package/dist/hooks/use-clipboard.js.map +1 -1
- package/dist/hooks/use-countdown.cjs.map +1 -1
- package/dist/hooks/use-countdown.js.map +1 -1
- package/dist/hooks/use-counter.cjs.map +1 -1
- package/dist/hooks/use-counter.js.map +1 -1
- package/dist/hooks/use-debounce.cjs.map +1 -1
- package/dist/hooks/use-debounce.js.map +1 -1
- package/dist/hooks/use-deep-memo.cjs.map +1 -1
- package/dist/hooks/use-deep-memo.js.map +1 -1
- package/dist/hooks/use-disclosure.cjs.map +1 -1
- package/dist/hooks/use-disclosure.js.map +1 -1
- package/dist/hooks/use-document-title.cjs.map +1 -1
- package/dist/hooks/use-document-title.js.map +1 -1
- package/dist/hooks/use-document-visibility.cjs.map +1 -1
- package/dist/hooks/use-document-visibility.js.map +1 -1
- package/dist/hooks/use-draft-filters.cjs.map +1 -1
- package/dist/hooks/use-draft-filters.js.map +1 -1
- package/dist/hooks/use-event-listener.cjs.map +1 -1
- package/dist/hooks/use-event-listener.js.map +1 -1
- package/dist/hooks/use-favicon.cjs.map +1 -1
- package/dist/hooks/use-favicon.js.map +1 -1
- package/dist/hooks/use-focus-trap.cjs.map +1 -1
- package/dist/hooks/use-focus-trap.js.map +1 -1
- package/dist/hooks/use-fullscreen-element.cjs.map +1 -1
- package/dist/hooks/use-fullscreen-element.js.map +1 -1
- package/dist/hooks/use-fullscreen.cjs +1 -1
- package/dist/hooks/use-fullscreen.cjs.map +1 -1
- package/dist/hooks/use-fullscreen.js +7 -23
- package/dist/hooks/use-fullscreen.js.map +1 -1
- package/dist/hooks/use-geolocation.cjs.map +1 -1
- package/dist/hooks/use-geolocation.js.map +1 -1
- package/dist/hooks/use-hover.cjs.map +1 -1
- package/dist/hooks/use-hover.js.map +1 -1
- package/dist/hooks/use-idle.cjs.map +1 -1
- package/dist/hooks/use-idle.js.map +1 -1
- package/dist/hooks/use-install-prompt.cjs +1 -1
- package/dist/hooks/use-install-prompt.cjs.map +1 -1
- package/dist/hooks/use-install-prompt.js +1 -1
- package/dist/hooks/use-install-prompt.js.map +1 -1
- package/dist/hooks/use-intersection-observer.cjs.map +1 -1
- package/dist/hooks/use-intersection-observer.js.map +1 -1
- package/dist/hooks/use-interval.cjs.map +1 -1
- package/dist/hooks/use-interval.js.map +1 -1
- package/dist/hooks/use-is-first-render.cjs.map +1 -1
- package/dist/hooks/use-is-first-render.js.map +1 -1
- package/dist/hooks/use-keyboard-shortcut.cjs.map +1 -1
- package/dist/hooks/use-keyboard-shortcut.js.map +1 -1
- package/dist/hooks/use-latest-ref.cjs.map +1 -1
- package/dist/hooks/use-latest-ref.js.map +1 -1
- package/dist/hooks/use-list-state.cjs.map +1 -1
- package/dist/hooks/use-list-state.js.map +1 -1
- package/dist/hooks/use-local-storage.cjs +1 -1
- package/dist/hooks/use-local-storage.cjs.map +1 -1
- package/dist/hooks/use-local-storage.js +2 -5
- package/dist/hooks/use-local-storage.js.map +1 -1
- package/dist/hooks/use-long-press-handlers.cjs.map +1 -1
- package/dist/hooks/use-long-press-handlers.js.map +1 -1
- package/dist/hooks/use-long-press.cjs.map +1 -1
- package/dist/hooks/use-long-press.js.map +1 -1
- package/dist/hooks/use-map.cjs.map +1 -1
- package/dist/hooks/use-map.js.map +1 -1
- package/dist/hooks/use-media-devices.cjs.map +1 -1
- package/dist/hooks/use-media-devices.js.map +1 -1
- package/dist/hooks/use-media-permission.cjs +1 -1
- package/dist/hooks/use-media-permission.cjs.map +1 -1
- package/dist/hooks/use-media-permission.js +2 -5
- package/dist/hooks/use-media-permission.js.map +1 -1
- package/dist/hooks/use-media-query.cjs.map +1 -1
- package/dist/hooks/use-media-query.js.map +1 -1
- package/dist/hooks/use-object-url.cjs.map +1 -1
- package/dist/hooks/use-object-url.js.map +1 -1
- package/dist/hooks/use-online.cjs.map +1 -1
- package/dist/hooks/use-online.js.map +1 -1
- package/dist/hooks/use-pagination.cjs.map +1 -1
- package/dist/hooks/use-pagination.js.map +1 -1
- package/dist/hooks/use-previous.cjs.map +1 -1
- package/dist/hooks/use-previous.js.map +1 -1
- package/dist/hooks/use-push-to-talk.cjs.map +1 -1
- package/dist/hooks/use-push-to-talk.js.map +1 -1
- package/dist/hooks/use-queue.cjs.map +1 -1
- package/dist/hooks/use-queue.js.map +1 -1
- package/dist/hooks/use-resize-observer.cjs.map +1 -1
- package/dist/hooks/use-resize-observer.js.map +1 -1
- package/dist/hooks/use-scroll-lock.cjs.map +1 -1
- package/dist/hooks/use-scroll-lock.js.map +1 -1
- package/dist/hooks/use-scroll-overflow.cjs.map +1 -1
- package/dist/hooks/use-scroll-overflow.js.map +1 -1
- package/dist/hooks/use-service-worker-update.cjs.map +1 -1
- package/dist/hooks/use-service-worker-update.js.map +1 -1
- package/dist/hooks/use-set.cjs.map +1 -1
- package/dist/hooks/use-set.js.map +1 -1
- package/dist/hooks/use-sortable.cjs.map +1 -1
- package/dist/hooks/use-sortable.js.map +1 -1
- package/dist/hooks/use-stable-callback.cjs.map +1 -1
- package/dist/hooks/use-stable-callback.js.map +1 -1
- package/dist/hooks/use-storage-estimate.cjs.map +1 -1
- package/dist/hooks/use-storage-estimate.js.map +1 -1
- package/dist/hooks/use-throttle.cjs.map +1 -1
- package/dist/hooks/use-throttle.js.map +1 -1
- package/dist/hooks/use-timeout.cjs.map +1 -1
- package/dist/hooks/use-timeout.js.map +1 -1
- package/dist/hooks/use-toggle.cjs.map +1 -1
- package/dist/hooks/use-toggle.js.map +1 -1
- package/dist/hooks/use-typewriter.cjs.map +1 -1
- package/dist/hooks/use-typewriter.js.map +1 -1
- package/dist/hooks/use-window-size.cjs.map +1 -1
- package/dist/hooks/use-window-size.js.map +1 -1
- package/dist/http/api-client.cjs.map +1 -1
- package/dist/http/api-client.js.map +1 -1
- package/dist/http/build-url.cjs.map +1 -1
- package/dist/http/build-url.js.map +1 -1
- package/dist/http/credential-scope.cjs.map +1 -1
- package/dist/http/credential-scope.js.map +1 -1
- package/dist/http/csrf.cjs.map +1 -1
- package/dist/http/csrf.js.map +1 -1
- package/dist/http/decode-response.cjs.map +1 -1
- package/dist/http/decode-response.js.map +1 -1
- package/dist/http/describe-api-error.cjs.map +1 -1
- package/dist/http/describe-api-error.js.map +1 -1
- package/dist/http/errors.cjs.map +1 -1
- package/dist/http/errors.js.map +1 -1
- package/dist/http/idempotency.cjs.map +1 -1
- package/dist/http/idempotency.js.map +1 -1
- package/dist/http/parse-response.cjs.map +1 -1
- package/dist/http/parse-response.js.map +1 -1
- package/dist/http/resumable-upload.cjs.map +1 -1
- package/dist/http/resumable-upload.js.map +1 -1
- package/dist/http/retry.cjs.map +1 -1
- package/dist/http/retry.js.map +1 -1
- package/dist/http/timeout.cjs.map +1 -1
- package/dist/http/timeout.js.map +1 -1
- package/dist/http/upload-with-progress.cjs +1 -1
- package/dist/http/upload-with-progress.cjs.map +1 -1
- package/dist/http/upload-with-progress.js +2 -7
- package/dist/http/upload-with-progress.js.map +1 -1
- package/dist/http/use-describe-api-error.cjs.map +1 -1
- package/dist/http/use-describe-api-error.js.map +1 -1
- package/dist/http/use-poll.cjs +1 -1
- package/dist/http/use-poll.cjs.map +1 -1
- package/dist/http/use-poll.js +2 -5
- package/dist/http/use-poll.js.map +1 -1
- package/dist/i18n/I18nProvider.cjs.map +1 -1
- package/dist/i18n/I18nProvider.js.map +1 -1
- package/dist/i18n/create-i18n.cjs.map +1 -1
- package/dist/i18n/create-i18n.js.map +1 -1
- package/dist/icons/Icon.cjs.map +1 -1
- package/dist/icons/Icon.js.map +1 -1
- package/dist/icons/IconPicker.cjs.map +1 -1
- package/dist/icons/IconPicker.js.map +1 -1
- package/dist/icons/IconPicker.module.cjs.map +1 -1
- package/dist/icons/IconPicker.module.js.map +1 -1
- package/dist/icons/IconProvider.cjs.map +1 -1
- package/dist/icons/IconProvider.js.map +1 -1
- package/dist/icons/alias.cjs.map +1 -1
- package/dist/icons/alias.js.map +1 -1
- package/dist/icons/generated/aliases.cjs.map +1 -1
- package/dist/icons/generated/aliases.js.map +1 -1
- package/dist/icons/generated/icon-names.cjs.map +1 -1
- package/dist/icons/generated/icon-names.js.map +1 -1
- package/dist/icons/generated/loaders.cjs.map +1 -1
- package/dist/icons/generated/loaders.js.map +1 -1
- package/dist/icons/generated/shard-00.cjs.map +1 -1
- package/dist/icons/generated/shard-00.js.map +1 -1
- package/dist/icons/generated/shard-01.cjs.map +1 -1
- package/dist/icons/generated/shard-01.js.map +1 -1
- package/dist/icons/generated/shard-02.cjs.map +1 -1
- package/dist/icons/generated/shard-02.js.map +1 -1
- package/dist/icons/generated/shard-03.cjs.map +1 -1
- package/dist/icons/generated/shard-03.js.map +1 -1
- package/dist/icons/generated/shard-04.cjs.map +1 -1
- package/dist/icons/generated/shard-04.js.map +1 -1
- package/dist/icons/generated/shard-05.cjs.map +1 -1
- package/dist/icons/generated/shard-05.js.map +1 -1
- package/dist/icons/generated/shard-06.cjs.map +1 -1
- package/dist/icons/generated/shard-06.js.map +1 -1
- package/dist/icons/generated/shard-07.cjs.map +1 -1
- package/dist/icons/generated/shard-07.js.map +1 -1
- package/dist/icons/generated/shard-08.cjs.map +1 -1
- package/dist/icons/generated/shard-08.js.map +1 -1
- package/dist/icons/generated/shard-09.cjs.map +1 -1
- package/dist/icons/generated/shard-09.js.map +1 -1
- package/dist/icons/generated/shard-10.cjs.map +1 -1
- package/dist/icons/generated/shard-10.js.map +1 -1
- package/dist/icons/generated/shard-11.cjs.map +1 -1
- package/dist/icons/generated/shard-11.js.map +1 -1
- package/dist/icons/generated/shard-12.cjs.map +1 -1
- package/dist/icons/generated/shard-12.js.map +1 -1
- package/dist/icons/generated/shard-13.cjs.map +1 -1
- package/dist/icons/generated/shard-13.js.map +1 -1
- package/dist/icons/generated/shard-14.cjs.map +1 -1
- package/dist/icons/generated/shard-14.js.map +1 -1
- package/dist/icons/generated/shard-15.cjs.map +1 -1
- package/dist/icons/generated/shard-15.js.map +1 -1
- package/dist/icons/generated/shard-16.cjs.map +1 -1
- package/dist/icons/generated/shard-16.js.map +1 -1
- package/dist/icons/generated/shard-17.cjs.map +1 -1
- package/dist/icons/generated/shard-17.js.map +1 -1
- package/dist/icons/generated/shard-18.cjs.map +1 -1
- package/dist/icons/generated/shard-18.js.map +1 -1
- package/dist/icons/generated/shard-19.cjs.map +1 -1
- package/dist/icons/generated/shard-19.js.map +1 -1
- package/dist/icons/generated/shard-20.cjs.map +1 -1
- package/dist/icons/generated/shard-20.js.map +1 -1
- package/dist/icons/generated/shard-21.cjs.map +1 -1
- package/dist/icons/generated/shard-21.js.map +1 -1
- package/dist/icons/generated/shard-22.cjs.map +1 -1
- package/dist/icons/generated/shard-22.js.map +1 -1
- package/dist/icons/generated/shard-23.cjs.map +1 -1
- package/dist/icons/generated/shard-23.js.map +1 -1
- package/dist/icons/generated/shard-24.cjs.map +1 -1
- package/dist/icons/generated/shard-24.js.map +1 -1
- package/dist/icons/generated/shard-25.cjs.map +1 -1
- package/dist/icons/generated/shard-25.js.map +1 -1
- package/dist/icons/generated/shard-26.cjs.map +1 -1
- package/dist/icons/generated/shard-26.js.map +1 -1
- package/dist/icons/generated/shard-27.cjs.map +1 -1
- package/dist/icons/generated/shard-27.js.map +1 -1
- package/dist/icons/generated/shard-28.cjs.map +1 -1
- package/dist/icons/generated/shard-28.js.map +1 -1
- package/dist/icons/generated/shard-29.cjs.map +1 -1
- package/dist/icons/generated/shard-29.js.map +1 -1
- package/dist/icons/generated/shard-30.cjs.map +1 -1
- package/dist/icons/generated/shard-30.js.map +1 -1
- package/dist/icons/generated/shard-31.cjs.map +1 -1
- package/dist/icons/generated/shard-31.js.map +1 -1
- package/dist/icons/generated/shard-32.cjs.map +1 -1
- package/dist/icons/generated/shard-32.js.map +1 -1
- package/dist/icons/generated/shard-33.cjs.map +1 -1
- package/dist/icons/generated/shard-33.js.map +1 -1
- package/dist/icons/generated/shard-34.cjs.map +1 -1
- package/dist/icons/generated/shard-34.js.map +1 -1
- package/dist/icons/generated/shard-35.cjs.map +1 -1
- package/dist/icons/generated/shard-35.js.map +1 -1
- package/dist/icons/generated/shard-36.cjs.map +1 -1
- package/dist/icons/generated/shard-36.js.map +1 -1
- package/dist/icons/generated/shard-37.cjs.map +1 -1
- package/dist/icons/generated/shard-37.js.map +1 -1
- package/dist/icons/generated/shard-38.cjs.map +1 -1
- package/dist/icons/generated/shard-38.js.map +1 -1
- package/dist/icons/generated/shard-39.cjs.map +1 -1
- package/dist/icons/generated/shard-39.js.map +1 -1
- package/dist/icons/generated/shard-40.cjs.map +1 -1
- package/dist/icons/generated/shard-40.js.map +1 -1
- package/dist/icons/generated/shard-41.cjs.map +1 -1
- package/dist/icons/generated/shard-41.js.map +1 -1
- package/dist/icons/generated/shard-42.cjs.map +1 -1
- package/dist/icons/generated/shard-42.js.map +1 -1
- package/dist/icons/generated/shard-43.cjs.map +1 -1
- package/dist/icons/generated/shard-43.js.map +1 -1
- package/dist/icons/generated/shard-44.cjs.map +1 -1
- package/dist/icons/generated/shard-44.js.map +1 -1
- package/dist/icons/generated/shard-45.cjs.map +1 -1
- package/dist/icons/generated/shard-45.js.map +1 -1
- package/dist/icons/icon-context.cjs.map +1 -1
- package/dist/icons/icon-context.js.map +1 -1
- package/dist/icons/is-icon-name.cjs.map +1 -1
- package/dist/icons/is-icon-name.js.map +1 -1
- package/dist/icons/material-symbols.cjs.map +1 -1
- package/dist/icons/material-symbols.js.map +1 -1
- package/dist/icons/normalize-icon-name.cjs.map +1 -1
- package/dist/icons/normalize-icon-name.js.map +1 -1
- package/dist/icons/shard-cache.cjs +1 -1
- package/dist/icons/shard-cache.cjs.map +1 -1
- package/dist/icons/shard-cache.js +2 -5
- package/dist/icons/shard-cache.js.map +1 -1
- package/dist/icons/use-icon.cjs.map +1 -1
- package/dist/icons/use-icon.js.map +1 -1
- package/dist/icons/validate-icon-name.cjs.map +1 -1
- package/dist/icons/validate-icon-name.js.map +1 -1
- package/dist/icons-virtual.cjs.map +1 -1
- package/dist/icons-virtual.js.map +1 -1
- package/dist/imaging/canvas.cjs.map +1 -1
- package/dist/imaging/canvas.js.map +1 -1
- package/dist/imaging/compress.cjs.map +1 -1
- package/dist/imaging/compress.js.map +1 -1
- package/dist/imaging/decode.cjs.map +1 -1
- package/dist/imaging/decode.js.map +1 -1
- package/dist/imaging/encode.cjs.map +1 -1
- package/dist/imaging/encode.js.map +1 -1
- package/dist/imaging/exceptions.cjs.map +1 -1
- package/dist/imaging/exceptions.js.map +1 -1
- package/dist/imaging/frame.cjs.map +1 -1
- package/dist/imaging/frame.js.map +1 -1
- package/dist/imaging/thumbnails.cjs.map +1 -1
- package/dist/imaging/thumbnails.js.map +1 -1
- package/dist/imaging/transform.cjs.map +1 -1
- package/dist/imaging/transform.js.map +1 -1
- package/dist/imaging/use-image-processing.cjs.map +1 -1
- package/dist/imaging/use-image-processing.js.map +1 -1
- package/dist/logger/logger.cjs.map +1 -1
- package/dist/logger/logger.js.map +1 -1
- package/dist/neural.cjs.map +1 -1
- package/dist/neural.js.map +1 -1
- package/dist/oauth/GoogleSignIn.cjs +1 -1
- package/dist/oauth/GoogleSignIn.cjs.map +1 -1
- package/dist/oauth/GoogleSignIn.js +6 -9
- package/dist/oauth/GoogleSignIn.js.map +1 -1
- package/dist/oauth/callback.cjs.map +1 -1
- package/dist/oauth/callback.js.map +1 -1
- package/dist/oauth/use-oauth-callback.cjs.map +1 -1
- package/dist/oauth/use-oauth-callback.js.map +1 -1
- package/dist/offline/conflict.cjs.map +1 -1
- package/dist/offline/conflict.js.map +1 -1
- package/dist/offline/create-offline-database.cjs.map +1 -1
- package/dist/offline/create-offline-database.js.map +1 -1
- package/dist/offline/create-offline-store.cjs +1 -1
- package/dist/offline/create-offline-store.cjs.map +1 -1
- package/dist/offline/create-offline-store.js +1 -5
- package/dist/offline/create-offline-store.js.map +1 -1
- package/dist/offline/create-offline-sync.cjs +1 -1
- package/dist/offline/create-offline-sync.cjs.map +1 -1
- package/dist/offline/create-offline-sync.js +9 -14
- package/dist/offline/create-offline-sync.js.map +1 -1
- package/dist/offline/use-offline-sync.cjs.map +1 -1
- package/dist/offline/use-offline-sync.js.map +1 -1
- package/dist/perf/cache-size.cjs.map +1 -1
- package/dist/perf/cache-size.js.map +1 -1
- package/dist/perf/device.cjs.map +1 -1
- package/dist/perf/device.js.map +1 -1
- package/dist/perf/format.cjs.map +1 -1
- package/dist/perf/format.js.map +1 -1
- package/dist/perf/profiler.cjs.map +1 -1
- package/dist/perf/profiler.js.map +1 -1
- package/dist/push/use-push-subscription.cjs.map +1 -1
- package/dist/push/use-push-subscription.js.map +1 -1
- package/dist/push/utils.cjs.map +1 -1
- package/dist/push/utils.js.map +1 -1
- package/dist/push/web-push-client.cjs.map +1 -1
- package/dist/push/web-push-client.js.map +1 -1
- package/dist/query/QueryProvider.cjs.map +1 -1
- package/dist/query/QueryProvider.js.map +1 -1
- package/dist/query/constants.cjs.map +1 -1
- package/dist/query/constants.js.map +1 -1
- package/dist/query/create-query-keys.cjs.map +1 -1
- package/dist/query/create-query-keys.js.map +1 -1
- package/dist/query/foreign-client-warning.cjs.map +1 -1
- package/dist/query/foreign-client-warning.js.map +1 -1
- package/dist/query/offline-persistence.cjs +1 -1
- package/dist/query/offline-persistence.cjs.map +1 -1
- package/dist/query/offline-persistence.js +2 -10
- package/dist/query/offline-persistence.js.map +1 -1
- package/dist/query/optimistic.cjs.map +1 -1
- package/dist/query/optimistic.js.map +1 -1
- package/dist/query/pagination.cjs.map +1 -1
- package/dist/query/pagination.js.map +1 -1
- package/dist/query/retry-policy.cjs.map +1 -1
- package/dist/query/retry-policy.js.map +1 -1
- package/dist/query/use-cursor-query.cjs.map +1 -1
- package/dist/query/use-cursor-query.js.map +1 -1
- package/dist/query/use-offline-mutation.cjs.map +1 -1
- package/dist/query/use-offline-mutation.js.map +1 -1
- package/dist/query/use-paginated-query.cjs.map +1 -1
- package/dist/query/use-paginated-query.js.map +1 -1
- package/dist/router/AppRouter.cjs.map +1 -1
- package/dist/router/AppRouter.js.map +1 -1
- package/dist/router/RouteGuard.cjs.map +1 -1
- package/dist/router/RouteGuard.js.map +1 -1
- package/dist/router/index.js +2 -2
- package/dist/share/share-or-download.cjs.map +1 -1
- package/dist/share/share-or-download.js.map +1 -1
- package/dist/share/share.cjs.map +1 -1
- package/dist/share/share.js.map +1 -1
- package/dist/sse/create-event-stream.cjs.map +1 -1
- package/dist/sse/create-event-stream.js.map +1 -1
- package/dist/sse/use-event-stream.cjs.map +1 -1
- package/dist/sse/use-event-stream.js.map +1 -1
- package/dist/store/create-selectors.cjs.map +1 -1
- package/dist/store/create-selectors.js.map +1 -1
- package/dist/store/create-store.cjs.map +1 -1
- package/dist/store/create-store.js.map +1 -1
- package/dist/sw/background-sync.cjs.map +1 -1
- package/dist/sw/background-sync.js.map +1 -1
- package/dist/sw/cache-inspect.cjs.map +1 -1
- package/dist/sw/cache-inspect.js.map +1 -1
- package/dist/sw/cache.cjs +1 -1
- package/dist/sw/cache.cjs.map +1 -1
- package/dist/sw/cache.js +2 -6
- package/dist/sw/cache.js.map +1 -1
- package/dist/sw/create-push-handler.cjs.map +1 -1
- package/dist/sw/create-push-handler.js.map +1 -1
- package/dist/sw/credential-headers.cjs.map +1 -1
- package/dist/sw/credential-headers.js.map +1 -1
- package/dist/sw/periodic-sync.cjs.map +1 -1
- package/dist/sw/periodic-sync.js.map +1 -1
- package/dist/sw/register-service-worker.cjs.map +1 -1
- package/dist/sw/register-service-worker.js.map +1 -1
- package/dist/sw/session-data.cjs.map +1 -1
- package/dist/sw/session-data.js.map +1 -1
- package/dist/tabular/assets.cjs.map +1 -1
- package/dist/tabular/assets.js.map +1 -1
- package/dist/tabular/cache.cjs.map +1 -1
- package/dist/tabular/cache.js.map +1 -1
- package/dist/tabular/compact.cjs.map +1 -1
- package/dist/tabular/compact.js.map +1 -1
- package/dist/tabular/exceptions.cjs.map +1 -1
- package/dist/tabular/exceptions.js.map +1 -1
- package/dist/tabular/manifest.cjs.map +1 -1
- package/dist/tabular/manifest.js.map +1 -1
- package/dist/tabular/predictor.cjs.map +1 -1
- package/dist/tabular/predictor.js.map +1 -1
- package/dist/tabular/use-tabular-predictor.cjs.map +1 -1
- package/dist/tabular/use-tabular-predictor.js.map +1 -1
- package/dist/telemetry/TelemetryProvider.cjs.map +1 -1
- package/dist/telemetry/TelemetryProvider.js.map +1 -1
- package/dist/telemetry/app-error-adapter.cjs.map +1 -1
- package/dist/telemetry/app-error-adapter.js.map +1 -1
- package/dist/telemetry/app-error-queue.cjs.map +1 -1
- package/dist/telemetry/app-error-queue.js.map +1 -1
- package/dist/telemetry/app-error-reporter.cjs.map +1 -1
- package/dist/telemetry/app-error-reporter.js.map +1 -1
- package/dist/telemetry/app-error-schema.cjs.map +1 -1
- package/dist/telemetry/app-error-schema.js.map +1 -1
- package/dist/telemetry/app-error-transport.cjs.map +1 -1
- package/dist/telemetry/app-error-transport.js.map +1 -1
- package/dist/telemetry/console-adapter.cjs.map +1 -1
- package/dist/telemetry/console-adapter.js.map +1 -1
- package/dist/telemetry/describe-app-error.cjs.map +1 -1
- package/dist/telemetry/describe-app-error.js.map +1 -1
- package/dist/telemetry/posthog-adapter.cjs +1 -1
- package/dist/telemetry/posthog-adapter.cjs.map +1 -1
- package/dist/telemetry/posthog-adapter.js +1 -5
- package/dist/telemetry/posthog-adapter.js.map +1 -1
- package/dist/telemetry/sentry-adapter.cjs.map +1 -1
- package/dist/telemetry/sentry-adapter.js.map +1 -1
- package/dist/tempest-react-sdk.cjs +1 -1
- package/dist/tempest-react-sdk.d.ts +234 -3
- package/dist/tempest-react-sdk.js +85 -85
- package/dist/testing/create-mock-handlers.cjs.map +1 -1
- package/dist/testing/create-mock-handlers.js.map +1 -1
- package/dist/testing.js +1 -2
- package/dist/theme/ThemeProvider.cjs.map +1 -1
- package/dist/theme/ThemeProvider.js.map +1 -1
- package/dist/theme/apply-theme.cjs.map +1 -1
- package/dist/theme/apply-theme.js.map +1 -1
- package/dist/theme/color.cjs.map +1 -1
- package/dist/theme/color.js.map +1 -1
- package/dist/theme/create-theme.cjs.map +1 -1
- package/dist/theme/create-theme.js.map +1 -1
- package/dist/theme/data-viz-ramps.cjs.map +1 -1
- package/dist/theme/data-viz-ramps.js.map +1 -1
- package/dist/theme/initial-theme.cjs.map +1 -1
- package/dist/theme/initial-theme.js.map +1 -1
- package/dist/theme/inverse-render.cjs.map +1 -1
- package/dist/theme/inverse-render.js.map +1 -1
- package/dist/theme/inverse-restore.cjs.map +1 -1
- package/dist/theme/inverse-restore.js.map +1 -1
- package/dist/theme/inverse-surface.cjs.map +1 -1
- package/dist/theme/inverse-surface.js.map +1 -1
- package/dist/theme/status-tokens.cjs.map +1 -1
- package/dist/theme/status-tokens.js.map +1 -1
- package/dist/theme/theme-presets.cjs.map +1 -1
- package/dist/theme/theme-presets.js.map +1 -1
- package/dist/utils/absent.cjs.map +1 -1
- package/dist/utils/absent.js.map +1 -1
- package/dist/utils/arrays.cjs.map +1 -1
- package/dist/utils/arrays.js.map +1 -1
- package/dist/utils/base64.cjs.map +1 -1
- package/dist/utils/base64.js.map +1 -1
- package/dist/utils/cn.cjs.map +1 -1
- package/dist/utils/cn.js.map +1 -1
- package/dist/utils/compare-values.cjs.map +1 -1
- package/dist/utils/compare-values.js.map +1 -1
- package/dist/utils/compressed-storage.cjs.map +1 -1
- package/dist/utils/compressed-storage.js.map +1 -1
- package/dist/utils/csv.cjs.map +1 -1
- package/dist/utils/csv.js.map +1 -1
- package/dist/utils/dev-mode.cjs.map +1 -1
- package/dist/utils/dev-mode.js.map +1 -1
- package/dist/utils/duplicate-instance.cjs.map +1 -1
- package/dist/utils/duplicate-instance.js.map +1 -1
- package/dist/utils/format.cjs.map +1 -1
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/functions.cjs +1 -1
- package/dist/utils/functions.cjs.map +1 -1
- package/dist/utils/functions.js +1 -1
- package/dist/utils/functions.js.map +1 -1
- package/dist/utils/guards.cjs.map +1 -1
- package/dist/utils/guards.js.map +1 -1
- package/dist/utils/ids.cjs.map +1 -1
- package/dist/utils/ids.js.map +1 -1
- package/dist/utils/intl-cache.cjs.map +1 -1
- package/dist/utils/intl-cache.js.map +1 -1
- package/dist/utils/json-frame.cjs.map +1 -1
- package/dist/utils/json-frame.js.map +1 -1
- package/dist/utils/numbers.cjs.map +1 -1
- package/dist/utils/numbers.js.map +1 -1
- package/dist/utils/objects.cjs.map +1 -1
- package/dist/utils/objects.js.map +1 -1
- package/dist/utils/owner-fingerprint.cjs.map +1 -1
- package/dist/utils/owner-fingerprint.js.map +1 -1
- package/dist/utils/promises.cjs.map +1 -1
- package/dist/utils/promises.js.map +1 -1
- package/dist/utils/relative-time.cjs.map +1 -1
- package/dist/utils/relative-time.js.map +1 -1
- package/dist/utils/safe-url.cjs.map +1 -1
- package/dist/utils/safe-url.js.map +1 -1
- package/dist/utils/schema-like.cjs.map +1 -1
- package/dist/utils/schema-like.js.map +1 -1
- package/dist/utils/storage.cjs +1 -1
- package/dist/utils/storage.cjs.map +1 -1
- package/dist/utils/storage.js +2 -2
- package/dist/utils/storage.js.map +1 -1
- package/dist/utils/strings.cjs.map +1 -1
- package/dist/utils/strings.js.map +1 -1
- package/dist/utils/xlsx.cjs.map +1 -1
- package/dist/utils/xlsx.js.map +1 -1
- package/dist/vision/core/canvas.cjs.map +1 -1
- package/dist/vision/core/canvas.js.map +1 -1
- package/dist/vision/core/dtypes.cjs.map +1 -1
- package/dist/vision/core/dtypes.js.map +1 -1
- package/dist/vision/core/exceptions.cjs.map +1 -1
- package/dist/vision/core/exceptions.js.map +1 -1
- package/dist/vision/core/graph.cjs.map +1 -1
- package/dist/vision/core/graph.js.map +1 -1
- package/dist/vision/core/metadata.cjs +1 -1
- package/dist/vision/core/metadata.cjs.map +1 -1
- package/dist/vision/core/metadata.js +9 -26
- package/dist/vision/core/metadata.js.map +1 -1
- package/dist/vision/core/providers.cjs.map +1 -1
- package/dist/vision/core/providers.js.map +1 -1
- package/dist/vision/core/session.cjs.map +1 -1
- package/dist/vision/core/session.js.map +1 -1
- package/dist/vision/core/timing.cjs.map +1 -1
- package/dist/vision/core/timing.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.map +1 -1
- package/dist/vision/index.js.map +1 -1
- package/dist/vision/io/image.cjs.map +1 -1
- package/dist/vision/io/image.js.map +1 -1
- package/dist/vision/labels.cjs.map +1 -1
- package/dist/vision/labels.js.map +1 -1
- package/dist/vision/luminance.cjs.map +1 -1
- package/dist/vision/luminance.js.map +1 -1
- package/dist/vision/normalization.cjs.map +1 -1
- package/dist/vision/normalization.js.map +1 -1
- package/dist/vision/postprocess/classification.cjs.map +1 -1
- package/dist/vision/postprocess/classification.js.map +1 -1
- package/dist/vision/postprocess/detection.cjs.map +1 -1
- package/dist/vision/postprocess/detection.js.map +1 -1
- package/dist/vision/postprocess/segmentation.cjs.map +1 -1
- package/dist/vision/postprocess/segmentation.js.map +1 -1
- package/dist/vision/preprocess/image.cjs.map +1 -1
- package/dist/vision/preprocess/image.js.map +1 -1
- package/dist/vision/preprocess/pipeline.cjs.map +1 -1
- package/dist/vision/preprocess/pipeline.js.map +1 -1
- package/dist/vision/results.cjs.map +1 -1
- package/dist/vision/results.js.map +1 -1
- package/dist/vision/tasks/base.cjs.map +1 -1
- package/dist/vision/tasks/base.js.map +1 -1
- package/dist/vision/tasks/classifier.cjs.map +1 -1
- package/dist/vision/tasks/classifier.js.map +1 -1
- package/dist/vision/tasks/detectClassify.cjs.map +1 -1
- package/dist/vision/tasks/detectClassify.js.map +1 -1
- package/dist/vision/tasks/detector.cjs.map +1 -1
- package/dist/vision/tasks/detector.js.map +1 -1
- package/dist/vision/tasks/segmenter.cjs.map +1 -1
- package/dist/vision/tasks/segmenter.js.map +1 -1
- package/dist/vision/types.cjs.map +1 -1
- package/dist/vision/types.js.map +1 -1
- package/dist/vision/use-camera-stream.cjs +1 -1
- package/dist/vision/use-camera-stream.cjs.map +1 -1
- package/dist/vision/use-camera-stream.js +3 -9
- package/dist/vision/use-camera-stream.js.map +1 -1
- package/dist/vision/use-live-luminance.cjs +1 -1
- package/dist/vision/use-live-luminance.cjs.map +1 -1
- package/dist/vision/use-live-luminance.js +1 -5
- package/dist/vision/use-live-luminance.js.map +1 -1
- package/dist/vite/base-url.cjs.map +1 -1
- package/dist/vite/base-url.js.map +1 -1
- package/dist/vite/create-vite-config.cjs.map +1 -1
- package/dist/vite/create-vite-config.js.map +1 -1
- package/dist/vite/narrow-tokens.cjs.map +1 -1
- package/dist/vite/narrow-tokens.js.map +1 -1
- package/dist/vite/tempest-csp.cjs +1 -1
- package/dist/vite/tempest-csp.cjs.map +1 -1
- package/dist/vite/tempest-csp.js +2 -10
- package/dist/vite/tempest-csp.js.map +1 -1
- package/dist/vite/tempest-icons.cjs.map +1 -1
- package/dist/vite/tempest-icons.js.map +1 -1
- package/dist/vite/tempest-pwa-dev-sw.cjs +1 -1
- package/dist/vite/tempest-pwa-dev-sw.cjs.map +1 -1
- package/dist/vite/tempest-pwa-dev-sw.js +9 -16
- package/dist/vite/tempest-pwa-dev-sw.js.map +1 -1
- package/dist/vite/tempest-pwa-icons.cjs.map +1 -1
- package/dist/vite/tempest-pwa-icons.js.map +1 -1
- package/dist/vite/tempest-pwa-manifest.cjs.map +1 -1
- package/dist/vite/tempest-pwa-manifest.js.map +1 -1
- package/dist/vite/tempest-styles.cjs.map +1 -1
- package/dist/vite/tempest-styles.js.map +1 -1
- package/dist/vite/tempest-vitest.cjs.map +1 -1
- package/dist/vite/tempest-vitest.js.map +1 -1
- package/dist/webrtc/link-stats.cjs.map +1 -1
- package/dist/webrtc/link-stats.js.map +1 -1
- package/dist/webrtc/mesh-quality.cjs.map +1 -1
- package/dist/webrtc/mesh-quality.js.map +1 -1
- package/dist/webrtc/opus-sdp.cjs.map +1 -1
- package/dist/webrtc/opus-sdp.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 +2 -5
- 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 +8 -24
- package/dist/webrtc/peer-mesh.js.map +1 -1
- package/dist/webrtc/sender-bitrate.cjs.map +1 -1
- package/dist/webrtc/sender-bitrate.js.map +1 -1
- package/dist/webrtc/use-link-stats.cjs.map +1 -1
- package/dist/webrtc/use-link-stats.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 +4 -22
- package/dist/ws/create-web-socket.js.map +1 -1
- package/dist/ws/resilience.cjs.map +1 -1
- package/dist/ws/resilience.js.map +1 -1
- package/dist/ws/use-web-socket.cjs.map +1 -1
- package/dist/ws/use-web-socket.js.map +1 -1
- package/package.json +9 -6
- package/template/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audio-bus.js","names":[],"sources":["../../src/audio/audio-bus.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — the mixing graph, the per-source handle and the\n * output route are one object's lifetime: the limiter only makes sense after the\n * sum, and the element that carries `setSinkId` is the same one the mix leaves\n * through. Splitting them would hand the caller two halves that are useless apart.\n */\nimport { isAudioOutputSelectionSupported, setAudioOutput } from \"./audio-output\";\n\n/** Default ceiling for a per-source or master gain, as a multiplier. */\nexport const DEFAULT_MAX_GAIN = 3;\n\n/** Shape of the master limiter. Matches `DynamicsCompressorNode`'s params. */\nexport interface LimiterSettings {\n /** dBFS above which the compressor starts working. */\n threshold: number;\n /** dB range over which the curve bends. `0` is a hard knee. */\n knee: number;\n /** Input/output ratio above the threshold. 20 is limiting, not compression. */\n ratio: number;\n /** Seconds to clamp a peak. */\n attack: number;\n /** Seconds to let go. */\n release: number;\n}\n\n/**\n * A limiter, not a compressor: a hard knee at a 20:1 ratio with a 3 ms attack\n * catches the sum before it clips without audibly ducking anything below it.\n */\nconst DEFAULT_LIMITER: LimiterSettings = {\n threshold: -8,\n knee: 0,\n ratio: 20,\n attack: 0.003,\n release: 0.25,\n};\n\n/** Options for {@link createAudioBus}. */\nexport interface AudioBusOptions {\n /** Ceiling for every gain on this bus. Default {@link DEFAULT_MAX_GAIN}. */\n maxGain?: number;\n /** Override the master limiter, or pass `false` to run without one. */\n limiter?: Partial<LimiterSettings> | false;\n /**\n * Reuse an existing `AudioContext` instead of creating one.\n *\n * Browsers cap the number of live contexts (Chrome allows around six), so a\n * page that already has one — a level meter, a player — should hand it over\n * rather than open a second.\n */\n context?: AudioContext;\n}\n\n/** One source attached to the bus. */\nexport interface AudioBusHandle {\n /**\n * Set this source's gain, where `1` is the level it arrived at.\n *\n * Values above `1` are the point of the whole graph: `element.volume` is\n * clamped at `1`, so a quiet talker could only ever be attenuated — the one\n * correction nobody needs.\n */\n setGain: (gain: number) => void;\n /** Current gain, after clamping. */\n readonly gain: number;\n /** Detach this source and release its nodes. The bus stays up. */\n stop: () => void;\n}\n\n/** A running mix. */\nexport interface AudioBus {\n /**\n * Play a stream through the shared mix.\n *\n * @param stream - The stream to play. Only its first audio track is used.\n * @param options - `gain` is the initial multiplier, default `1`.\n * @returns A handle to adjust or detach this source.\n */\n attach: (stream: MediaStream, options?: { gain?: number }) => AudioBusHandle;\n /** Scale every source, on top of its own gain. */\n setMasterGain: (gain: number) => void;\n /** Current master gain, after clamping. */\n readonly masterGain: number;\n /**\n * Route the whole mix to one output device.\n *\n * @param deviceId - Device id from `useMediaDevices().audioOutputs`, or `\"\"`\n * for the system default.\n * @returns `false` when the engine cannot route audio, or the device is gone.\n */\n setOutputDevice: (deviceId: string) => Promise<boolean>;\n /** Device id the mix is routed to. `\"\"` is the system default. */\n readonly outputDevice: string;\n /**\n * Resume a context the browser started suspended.\n *\n * Autoplay policy suspends a context created outside a user gesture, and a\n * suspended context is silent with no error anywhere. Call this from the\n * click that starts playback.\n */\n resume: () => Promise<void>;\n /**\n * Detach everything and close the context this bus created.\n *\n * Idempotent, and the bus stays callable afterwards: `attach` hands back an\n * inert handle instead of throwing. That is not politeness — creating a node\n * on a closed `AudioContext` throws `InvalidStateError`, and the stream that\n * arrives late is the normal case (a WebRTC `ontrack` firing after the\n * component that owned the bus went away).\n */\n close: () => void;\n /** Whether this browser gave us a Web Audio graph at all. */\n readonly supported: boolean;\n /** Whether this browser can route the mix to a chosen output device. */\n readonly canSelectOutput: boolean;\n}\n\n/**\n * Clamp a gain into `0..max`, treating a non-finite value as unity.\n *\n * `NaN` reaches here from an empty input or a failed parse, and assigning it to\n * an `AudioParam` throws — losing the audio for a typo in a number field.\n */\nfunction clampGain(gain: number, max: number): number {\n if (!Number.isFinite(gain)) return 1;\n return Math.min(max, Math.max(0, gain));\n}\n\n/** The `AudioContext` constructor this engine exposes, prefixed or not. */\nfunction audioContextConstructor(): typeof AudioContext | undefined {\n if (typeof AudioContext !== \"undefined\") return AudioContext;\n return (globalThis as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n}\n\n/** A media element that may support output routing. */\ntype SinkCapableElement = HTMLAudioElement & { setSinkId?: (sinkId: string) => Promise<void> };\n\n/**\n * The stream to feed the graph: just the audio track, when this engine can build\n * one.\n *\n * Isolating the track keeps a camera's video out of the source node. `MediaStream`\n * is missing outside a browser (jsdom, a worker), and there the original stream is\n * the right answer anyway — `createMediaStreamSource` reads its first audio track.\n */\nfunction audioOnly(stream: MediaStream, track: MediaStreamTrack): MediaStream {\n if (typeof MediaStream === \"undefined\") return stream;\n return new MediaStream([track]);\n}\n\n/** Start playback without letting an environment that has no media pipeline throw. */\nfunction playQuietly(element: HTMLAudioElement): void {\n try {\n void element.play?.()?.catch(() => undefined);\n } catch {\n /* jsdom and any engine without a media pipeline — nothing to play anyway */\n }\n}\n\n/**\n * Mix several streams into one output, with gain above 100% and a master limiter.\n *\n * Three things make this a graph instead of a few `<audio>` elements:\n *\n * 1. **`element.volume` is clamped at `1`.** A participant who speaks too quietly\n * can only be turned *down* — the one correction nobody needs. A `GainNode`\n * has no ceiling, so this bus takes one (`maxGain`, default 3).\n * 2. **Clipping is a property of the sum.** Three sources at 200% each are clean\n * alone and distort the instant they play together. A per-source limiter\n * cannot see that; the one after the mix can, which is where this puts it.\n * 3. **`setSinkId` lives on the element, not on the context.** Sending the mix to\n * a headset while the rest of the system keeps the speakers is only reachable\n * by leaving through a `MediaStreamAudioDestinationNode` into a real\n * `<audio>`. `AudioContext.setSinkId` has far thinner support.\n *\n * @param options - See {@link AudioBusOptions}.\n * @returns The bus. On an engine with no Web Audio it is inert but callable, and\n * `supported` is `false` — a page without sound beats a page that throws.\n *\n * @example\n * const bus = createAudioBus({ maxGain: 3 });\n * const handle = bus.attach(remoteStream, { gain: 1 });\n * handle.setGain(2.4); // above 1 — the point of the whole thing\n * await bus.setOutputDevice(headsetId);\n */\nexport function createAudioBus({\n maxGain = DEFAULT_MAX_GAIN,\n limiter: limiterOptions,\n context: injectedContext,\n}: AudioBusOptions = {}): AudioBus {\n const Ctor = audioContextConstructor();\n const context = injectedContext ?? (Ctor ? new Ctor() : null);\n\n if (!context) {\n return {\n attach: () => ({ setGain: () => undefined, gain: 1, stop: () => undefined }),\n setMasterGain: () => undefined,\n masterGain: 1,\n setOutputDevice: async () => false,\n outputDevice: \"\",\n resume: async () => undefined,\n close: () => undefined,\n supported: false,\n canSelectOutput: false,\n };\n }\n\n const graph = context;\n const ownsContext = !injectedContext;\n const master = graph.createGain();\n const destination = graph.createMediaStreamDestination();\n\n let limiterNode: DynamicsCompressorNode | null = null;\n if (limiterOptions === false) {\n master.connect(destination);\n } else {\n const limiter = graph.createDynamicsCompressor();\n limiterNode = limiter;\n const settings = { ...DEFAULT_LIMITER, ...limiterOptions };\n limiter.threshold.value = settings.threshold;\n limiter.knee.value = settings.knee;\n limiter.ratio.value = settings.ratio;\n limiter.attack.value = settings.attack;\n limiter.release.value = settings.release;\n master.connect(limiter);\n limiter.connect(destination);\n }\n\n const element = new Audio();\n element.autoplay = true;\n element.srcObject = destination.stream;\n playQuietly(element);\n\n let sinkId = \"\";\n let masterGain = 1;\n let closed = false;\n const handles = new Set<AudioBusHandle>();\n\n /** The handle a bus hands out when there is nothing to play through. */\n function inertHandle(): AudioBusHandle {\n return { setGain: () => undefined, gain: 1, stop: () => undefined };\n }\n\n /**\n * Play one stream through the mix.\n *\n * The muted `<audio>` anchor is not dead weight, and deleting it as unused is\n * the mistake this comment exists to prevent: Chrome will not pull samples\n * from a `MediaStreamAudioSourceNode` built over a **remote** WebRTC stream\n * unless that same stream is also attached to a media element\n * (crbug.com/687574). Without it the graph is visibly correct and completely\n * silent — a day of debugging for anyone who does not know the bug. It is\n * muted because the audible copy is the one leaving the bus.\n */\n function attach(stream: MediaStream, { gain = 1 }: { gain?: number } = {}): AudioBusHandle {\n const track = stream.getAudioTracks()[0];\n if (closed || !track) return inertHandle();\n\n const anchor = new Audio();\n anchor.muted = true;\n anchor.autoplay = true;\n anchor.srcObject = stream;\n playQuietly(anchor);\n\n const source = graph.createMediaStreamSource(audioOnly(stream, track));\n const node = graph.createGain();\n let current = clampGain(gain, maxGain);\n node.gain.value = current;\n source.connect(node);\n node.connect(master);\n\n const handle: AudioBusHandle = {\n setGain(next: number): void {\n current = clampGain(next, maxGain);\n node.gain.value = current;\n },\n get gain(): number {\n return current;\n },\n stop(): void {\n if (!handles.has(handle)) return;\n handles.delete(handle);\n source.disconnect();\n node.disconnect();\n anchor.srcObject = null;\n anchor.pause();\n },\n };\n handles.add(handle);\n return handle;\n }\n\n return {\n attach,\n setMasterGain(gain: number): void {\n if (closed) return;\n masterGain = clampGain(gain, maxGain);\n master.gain.value = masterGain;\n },\n get masterGain(): number {\n return masterGain;\n },\n async setOutputDevice(deviceId: string): Promise<boolean> {\n const applied = await setAudioOutput(element as SinkCapableElement, deviceId);\n if (applied) sinkId = deviceId;\n return applied;\n },\n get outputDevice(): string {\n return sinkId;\n },\n async resume(): Promise<void> {\n await graph.resume?.().catch(() => undefined);\n },\n close(): void {\n if (closed) return;\n closed = true;\n for (const handle of [...handles]) handle.stop();\n element.srcObject = null;\n element.pause();\n master.disconnect();\n limiterNode?.disconnect();\n if (ownsContext) void graph.close().catch(() => undefined);\n },\n supported: true,\n get canSelectOutput(): boolean {\n return isAudioOutputSelectionSupported();\n },\n };\n}\n"],"mappings":";;AASA,IAAa,IAAmB,GAoB1B,IAAmC;CACrC,WAAW;CACX,MAAM;CACN,OAAO;CACP,QAAQ;CACR,SAAS;AACb;AAwFA,SAAS,EAAU,GAAc,GAAqB;CAElD,OADK,OAAO,SAAS,CAAI,IAClB,KAAK,IAAI,GAAK,KAAK,IAAI,GAAG,CAAI,CAAC,IADH;AAEvC;AAGA,SAAS,IAA2D;CAEhE,OADI,OAAO,eAAiB,MAAoB,eACxC,WAA4D;AACxE;AAaA,SAAS,EAAU,GAAqB,GAAsC;CAE1E,OADI,OAAO,cAAgB,MAAoB,IACxC,IAAI,YAAY,CAAC,CAAK,CAAC;AAClC;AAGA,SAAS,EAAY,GAAiC;CAClD,IAAI;EACA,EAAa,OAAO,CAAC,EAAE,YAAY,KAAA,CAAS;CAChD,QAAQ,CAER;AACJ;AA4BA,SAAgB,EAAe,EAC3B,aAAA,GACA,SAAS,GACT,SAAS,MACQ,CAAC,GAAa;CAC/B,IAAM,IAAO,EAAwB,GAC/B,IAAU,MAAoB,IAAO,IAAI,EAAK,IAAI;CAExD,IAAI,CAAC,GACD,OAAO;EACH,eAAe;GAAE,eAAe,KAAA;GAAW,MAAM;GAAG,YAAY,KAAA;EAAU;EAC1E,qBAAqB,KAAA;EACrB,YAAY;EACZ,iBAAiB,YAAY;EAC7B,cAAc;EACd,QAAQ,YAAY,KAAA;EACpB,aAAa,KAAA;EACb,WAAW;EACX,iBAAiB;CACrB;CAGJ,IAAM,IAAQ,GACR,IAAc,CAAC,GACf,IAAS,EAAM,WAAW,GAC1B,IAAc,EAAM,6BAA6B,GAEnD,IAA6C;CACjD,IAAI,MAAmB,IACnB,EAAO,QAAQ,CAAW;MACvB;EACH,IAAM,IAAU,EAAM,yBAAyB;EAC/C,IAAc;EACd,IAAM,IAAW;GAAE,GAAG;GAAiB,GAAG;EAAe;EAOzD,AANA,EAAQ,UAAU,QAAQ,EAAS,WACnC,EAAQ,KAAK,QAAQ,EAAS,MAC9B,EAAQ,MAAM,QAAQ,EAAS,OAC/B,EAAQ,OAAO,QAAQ,EAAS,QAChC,EAAQ,QAAQ,QAAQ,EAAS,SACjC,EAAO,QAAQ,CAAO,GACtB,EAAQ,QAAQ,CAAW;CAC/B;CAEA,IAAM,IAAU,IAAI,MAAM;CAG1B,AAFA,EAAQ,WAAW,IACnB,EAAQ,YAAY,EAAY,QAChC,EAAY,CAAO;CAEnB,IAAI,IAAS,IACT,IAAa,GACb,IAAS,IACP,oBAAU,IAAI,IAAoB;CAGxC,SAAS,IAA8B;EACnC,OAAO;GAAE,eAAe,KAAA;GAAW,MAAM;GAAG,YAAY,KAAA;EAAU;CACtE;CAaA,SAAS,EAAO,GAAqB,EAAE,UAAO,MAAyB,CAAC,GAAmB;EACvF,IAAM,IAAQ,EAAO,eAAe,CAAC,CAAC;EACtC,IAAI,KAAU,CAAC,GAAO,OAAO,EAAY;EAEzC,IAAM,IAAS,IAAI,MAAM;EAIzB,AAHA,EAAO,QAAQ,IACf,EAAO,WAAW,IAClB,EAAO,YAAY,GACnB,EAAY,CAAM;EAElB,IAAM,IAAS,EAAM,wBAAwB,EAAU,GAAQ,CAAK,CAAC,GAC/D,IAAO,EAAM,WAAW,GAC1B,IAAU,EAAU,GAAM,CAAO;EAGrC,AAFA,EAAK,KAAK,QAAQ,GAClB,EAAO,QAAQ,CAAI,GACnB,EAAK,QAAQ,CAAM;EAEnB,IAAM,IAAyB;GAC3B,QAAQ,GAAoB;IAExB,AADA,IAAU,EAAU,GAAM,CAAO,GACjC,EAAK,KAAK,QAAQ;GACtB;GACA,IAAI,OAAe;IACf,OAAO;GACX;GACA,OAAa;IACJ,EAAQ,IAAI,CAAM,MACvB,EAAQ,OAAO,CAAM,GACrB,EAAO,WAAW,GAClB,EAAK,WAAW,GAChB,EAAO,YAAY,MACnB,EAAO,MAAM;GACjB;EACJ;EAEA,OADA,EAAQ,IAAI,CAAM,GACX;CACX;CAEA,OAAO;EACH;EACA,cAAc,GAAoB;GAC1B,MACJ,IAAa,EAAU,GAAM,CAAO,GACpC,EAAO,KAAK,QAAQ;EACxB;EACA,IAAI,aAAqB;GACrB,OAAO;EACX;EACA,MAAM,gBAAgB,GAAoC;GACtD,IAAM,IAAU,MAAM,EAAe,GAA+B,CAAQ;GAE5E,OADI,MAAS,IAAS,IACf;EACX;EACA,IAAI,eAAuB;GACvB,OAAO;EACX;EACA,MAAM,SAAwB;GAC1B,MAAM,EAAM,SAAS,CAAC,CAAC,YAAY,KAAA,CAAS;EAChD;EACA,QAAc;GACN,QACJ;QAAS;IACT,KAAK,IAAM,KAAU,CAAC,GAAG,CAAO,GAAG,EAAO,KAAK;IAK/C,AAJA,EAAQ,YAAY,MACpB,EAAQ,MAAM,GACd,EAAO,WAAW,GAClB,GAAa,WAAW,GACpB,KAAa,EAAW,MAAM,CAAC,CAAC,YAAY,KAAA,CAAS;GANhD;EAOb;EACA,WAAW;EACX,IAAI,kBAA2B;GAC3B,OAAO,EAAgC;EAC3C;CACJ;AACJ"}
|
|
1
|
+
{"version":3,"file":"audio-bus.js","names":["DEFAULT_MAX_GAIN","DEFAULT_LIMITER","clampGain","gain","max","audioContextConstructor","audioOnly","stream","track","playQuietly","createAudioBus","limiterOptions","injectedContext","Ctor","context","graph","ownsContext","master","destination","limiterNode","limiter","settings","element","sinkId","masterGain","closed","handles","inertHandle","attach","anchor","source","node","current","maxGain","handle","next","applied","setAudioOutput","deviceId","isAudioOutputSelectionSupported"],"sources":["../../src/audio/audio-bus.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — the mixing graph, the per-source handle and the\n * output route are one object's lifetime: the limiter only makes sense after the\n * sum, and the element that carries `setSinkId` is the same one the mix leaves\n * through. Splitting them would hand the caller two halves that are useless apart.\n */\nimport { isAudioOutputSelectionSupported, setAudioOutput } from \"./audio-output\";\n\n/** Default ceiling for a per-source or master gain, as a multiplier. */\nexport const DEFAULT_MAX_GAIN = 3;\n\n/** Shape of the master limiter. Matches `DynamicsCompressorNode`'s params. */\nexport interface LimiterSettings {\n /** dBFS above which the compressor starts working. */\n threshold: number;\n /** dB range over which the curve bends. `0` is a hard knee. */\n knee: number;\n /** Input/output ratio above the threshold. 20 is limiting, not compression. */\n ratio: number;\n /** Seconds to clamp a peak. */\n attack: number;\n /** Seconds to let go. */\n release: number;\n}\n\n/**\n * A limiter, not a compressor: a hard knee at a 20:1 ratio with a 3 ms attack\n * catches the sum before it clips without audibly ducking anything below it.\n */\nconst DEFAULT_LIMITER: LimiterSettings = {\n threshold: -8,\n knee: 0,\n ratio: 20,\n attack: 0.003,\n release: 0.25,\n};\n\n/** Options for {@link createAudioBus}. */\nexport interface AudioBusOptions {\n /** Ceiling for every gain on this bus. Default {@link DEFAULT_MAX_GAIN}. */\n maxGain?: number;\n /** Override the master limiter, or pass `false` to run without one. */\n limiter?: Partial<LimiterSettings> | false;\n /**\n * Reuse an existing `AudioContext` instead of creating one.\n *\n * Browsers cap the number of live contexts (Chrome allows around six), so a\n * page that already has one — a level meter, a player — should hand it over\n * rather than open a second.\n */\n context?: AudioContext;\n}\n\n/** One source attached to the bus. */\nexport interface AudioBusHandle {\n /**\n * Set this source's gain, where `1` is the level it arrived at.\n *\n * Values above `1` are the point of the whole graph: `element.volume` is\n * clamped at `1`, so a quiet talker could only ever be attenuated — the one\n * correction nobody needs.\n */\n setGain: (gain: number) => void;\n /** Current gain, after clamping. */\n readonly gain: number;\n /** Detach this source and release its nodes. The bus stays up. */\n stop: () => void;\n}\n\n/** A running mix. */\nexport interface AudioBus {\n /**\n * Play a stream through the shared mix.\n *\n * @param stream - The stream to play. Only its first audio track is used.\n * @param options - `gain` is the initial multiplier, default `1`.\n * @returns A handle to adjust or detach this source.\n */\n attach: (stream: MediaStream, options?: { gain?: number }) => AudioBusHandle;\n /** Scale every source, on top of its own gain. */\n setMasterGain: (gain: number) => void;\n /** Current master gain, after clamping. */\n readonly masterGain: number;\n /**\n * Route the whole mix to one output device.\n *\n * @param deviceId - Device id from `useMediaDevices().audioOutputs`, or `\"\"`\n * for the system default.\n * @returns `false` when the engine cannot route audio, or the device is gone.\n */\n setOutputDevice: (deviceId: string) => Promise<boolean>;\n /** Device id the mix is routed to. `\"\"` is the system default. */\n readonly outputDevice: string;\n /**\n * Resume a context the browser started suspended.\n *\n * Autoplay policy suspends a context created outside a user gesture, and a\n * suspended context is silent with no error anywhere. Call this from the\n * click that starts playback.\n */\n resume: () => Promise<void>;\n /**\n * Detach everything and close the context this bus created.\n *\n * Idempotent, and the bus stays callable afterwards: `attach` hands back an\n * inert handle instead of throwing. That is not politeness — creating a node\n * on a closed `AudioContext` throws `InvalidStateError`, and the stream that\n * arrives late is the normal case (a WebRTC `ontrack` firing after the\n * component that owned the bus went away).\n */\n close: () => void;\n /** Whether this browser gave us a Web Audio graph at all. */\n readonly supported: boolean;\n /** Whether this browser can route the mix to a chosen output device. */\n readonly canSelectOutput: boolean;\n}\n\n/**\n * Clamp a gain into `0..max`, treating a non-finite value as unity.\n *\n * `NaN` reaches here from an empty input or a failed parse, and assigning it to\n * an `AudioParam` throws — losing the audio for a typo in a number field.\n */\nfunction clampGain(gain: number, max: number): number {\n if (!Number.isFinite(gain)) return 1;\n return Math.min(max, Math.max(0, gain));\n}\n\n/** The `AudioContext` constructor this engine exposes, prefixed or not. */\nfunction audioContextConstructor(): typeof AudioContext | undefined {\n if (typeof AudioContext !== \"undefined\") return AudioContext;\n return (globalThis as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n}\n\n/** A media element that may support output routing. */\ntype SinkCapableElement = HTMLAudioElement & { setSinkId?: (sinkId: string) => Promise<void> };\n\n/**\n * The stream to feed the graph: just the audio track, when this engine can build\n * one.\n *\n * Isolating the track keeps a camera's video out of the source node. `MediaStream`\n * is missing outside a browser (jsdom, a worker), and there the original stream is\n * the right answer anyway — `createMediaStreamSource` reads its first audio track.\n */\nfunction audioOnly(stream: MediaStream, track: MediaStreamTrack): MediaStream {\n if (typeof MediaStream === \"undefined\") return stream;\n return new MediaStream([track]);\n}\n\n/** Start playback without letting an environment that has no media pipeline throw. */\nfunction playQuietly(element: HTMLAudioElement): void {\n try {\n void element.play?.()?.catch(() => undefined);\n } catch {\n /* jsdom and any engine without a media pipeline — nothing to play anyway */\n }\n}\n\n/**\n * Mix several streams into one output, with gain above 100% and a master limiter.\n *\n * Three things make this a graph instead of a few `<audio>` elements:\n *\n * 1. **`element.volume` is clamped at `1`.** A participant who speaks too quietly\n * can only be turned *down* — the one correction nobody needs. A `GainNode`\n * has no ceiling, so this bus takes one (`maxGain`, default 3).\n * 2. **Clipping is a property of the sum.** Three sources at 200% each are clean\n * alone and distort the instant they play together. A per-source limiter\n * cannot see that; the one after the mix can, which is where this puts it.\n * 3. **`setSinkId` lives on the element, not on the context.** Sending the mix to\n * a headset while the rest of the system keeps the speakers is only reachable\n * by leaving through a `MediaStreamAudioDestinationNode` into a real\n * `<audio>`. `AudioContext.setSinkId` has far thinner support.\n *\n * @param options - See {@link AudioBusOptions}.\n * @returns The bus. On an engine with no Web Audio it is inert but callable, and\n * `supported` is `false` — a page without sound beats a page that throws.\n *\n * @example\n * const bus = createAudioBus({ maxGain: 3 });\n * const handle = bus.attach(remoteStream, { gain: 1 });\n * handle.setGain(2.4); // above 1 — the point of the whole thing\n * await bus.setOutputDevice(headsetId);\n */\nexport function createAudioBus({\n maxGain = DEFAULT_MAX_GAIN,\n limiter: limiterOptions,\n context: injectedContext,\n}: AudioBusOptions = {}): AudioBus {\n const Ctor = audioContextConstructor();\n const context = injectedContext ?? (Ctor ? new Ctor() : null);\n\n if (!context) {\n return {\n attach: () => ({ setGain: () => undefined, gain: 1, stop: () => undefined }),\n setMasterGain: () => undefined,\n masterGain: 1,\n setOutputDevice: async () => false,\n outputDevice: \"\",\n resume: async () => undefined,\n close: () => undefined,\n supported: false,\n canSelectOutput: false,\n };\n }\n\n const graph = context;\n const ownsContext = !injectedContext;\n const master = graph.createGain();\n const destination = graph.createMediaStreamDestination();\n\n let limiterNode: DynamicsCompressorNode | null = null;\n if (limiterOptions === false) {\n master.connect(destination);\n } else {\n const limiter = graph.createDynamicsCompressor();\n limiterNode = limiter;\n const settings = { ...DEFAULT_LIMITER, ...limiterOptions };\n limiter.threshold.value = settings.threshold;\n limiter.knee.value = settings.knee;\n limiter.ratio.value = settings.ratio;\n limiter.attack.value = settings.attack;\n limiter.release.value = settings.release;\n master.connect(limiter);\n limiter.connect(destination);\n }\n\n const element = new Audio();\n element.autoplay = true;\n element.srcObject = destination.stream;\n playQuietly(element);\n\n let sinkId = \"\";\n let masterGain = 1;\n let closed = false;\n const handles = new Set<AudioBusHandle>();\n\n /** The handle a bus hands out when there is nothing to play through. */\n function inertHandle(): AudioBusHandle {\n return { setGain: () => undefined, gain: 1, stop: () => undefined };\n }\n\n /**\n * Play one stream through the mix.\n *\n * The muted `<audio>` anchor is not dead weight, and deleting it as unused is\n * the mistake this comment exists to prevent: Chrome will not pull samples\n * from a `MediaStreamAudioSourceNode` built over a **remote** WebRTC stream\n * unless that same stream is also attached to a media element\n * (crbug.com/687574). Without it the graph is visibly correct and completely\n * silent — a day of debugging for anyone who does not know the bug. It is\n * muted because the audible copy is the one leaving the bus.\n */\n function attach(stream: MediaStream, { gain = 1 }: { gain?: number } = {}): AudioBusHandle {\n const track = stream.getAudioTracks()[0];\n if (closed || !track) return inertHandle();\n\n const anchor = new Audio();\n anchor.muted = true;\n anchor.autoplay = true;\n anchor.srcObject = stream;\n playQuietly(anchor);\n\n const source = graph.createMediaStreamSource(audioOnly(stream, track));\n const node = graph.createGain();\n let current = clampGain(gain, maxGain);\n node.gain.value = current;\n source.connect(node);\n node.connect(master);\n\n const handle: AudioBusHandle = {\n setGain(next: number): void {\n current = clampGain(next, maxGain);\n node.gain.value = current;\n },\n get gain(): number {\n return current;\n },\n stop(): void {\n if (!handles.has(handle)) return;\n handles.delete(handle);\n source.disconnect();\n node.disconnect();\n anchor.srcObject = null;\n anchor.pause();\n },\n };\n handles.add(handle);\n return handle;\n }\n\n return {\n attach,\n setMasterGain(gain: number): void {\n if (closed) return;\n masterGain = clampGain(gain, maxGain);\n master.gain.value = masterGain;\n },\n get masterGain(): number {\n return masterGain;\n },\n async setOutputDevice(deviceId: string): Promise<boolean> {\n const applied = await setAudioOutput(element as SinkCapableElement, deviceId);\n if (applied) sinkId = deviceId;\n return applied;\n },\n get outputDevice(): string {\n return sinkId;\n },\n async resume(): Promise<void> {\n await graph.resume?.().catch(() => undefined);\n },\n close(): void {\n if (closed) return;\n closed = true;\n for (const handle of [...handles]) handle.stop();\n element.srcObject = null;\n element.pause();\n master.disconnect();\n limiterNode?.disconnect();\n if (ownsContext) void graph.close().catch(() => undefined);\n },\n supported: true,\n get canSelectOutput(): boolean {\n return isAudioOutputSelectionSupported();\n },\n };\n}\n"],"mappings":";;AASA,IAAaA,IAAmB,GAoB1BC,IAAmC;CACrC,WAAW;CACX,MAAM;CACN,OAAO;CACP,QAAQ;CACR,SAAS;AACb;AAwFA,SAASC,EAAU,GAAc,GAAqB;CAElD,OADK,OAAO,SAASC,CAAI,IAClB,KAAK,IAAIC,GAAK,KAAK,IAAI,GAAGD,CAAI,CAAC,IADH;AAEvC;AAGA,SAASE,IAA2D;CAEhE,OADI,OAAO,eAAiB,MAAoB,eACxC,WAA4D;AACxE;AAaA,SAASC,EAAU,GAAqB,GAAsC;CAE1E,OADI,OAAO,cAAgB,MAAoBC,IACxC,IAAI,YAAY,CAACC,CAAK,CAAC;AAClC;AAGA,SAASC,EAAY,GAAiC;CAClD,IAAI;EACA,EAAa,OAAO,CAAC,EAAE,YAAY,KAAA,CAAS;CAChD,QAAQ,CAER;AACJ;AA4BA,SAAgBC,EAAe,EAC3B,aAAA,GACA,SAASC,GACT,SAASC,MACQ,CAAC,GAAa;CAC/B,IAAMC,IAAOR,EAAwB,GAC/BS,IAAUF,MAAoBC,IAAO,IAAIA,EAAK,IAAI;CAExD,IAAI,CAACC,GACD,OAAO;EACH,eAAe;GAAE,eAAe,KAAA;GAAW,MAAM;GAAG,YAAY,KAAA;EAAU;EAC1E,qBAAqB,KAAA;EACrB,YAAY;EACZ,iBAAiB,YAAY;EAC7B,cAAc;EACd,QAAQ,YAAY,KAAA;EACpB,aAAa,KAAA;EACb,WAAW;EACX,iBAAiB;CACrB;CAGJ,IAAMC,IAAQD,GACRE,IAAc,CAACJ,GACfK,IAASF,EAAM,WAAW,GAC1BG,IAAcH,EAAM,6BAA6B,GAEnDI,IAA6C;CACjD,IAAIR,MAAmB,IACnB,EAAO,QAAQO,CAAW;MACvB;EACH,IAAME,IAAUL,EAAM,yBAAyB;EAC/C,IAAcK;EACd,IAAMC,IAAW;GAAE,GAAGpB;GAAiB,GAAGU;EAAe;EAOzD,AANA,EAAQ,UAAU,QAAQU,EAAS,WACnC,EAAQ,KAAK,QAAQA,EAAS,MAC9B,EAAQ,MAAM,QAAQA,EAAS,OAC/B,EAAQ,OAAO,QAAQA,EAAS,QAChC,EAAQ,QAAQ,QAAQA,EAAS,SACjCJ,EAAO,QAAQG,CAAO,GACtBA,EAAQ,QAAQF,CAAW;CAC/B;CAEA,IAAMI,IAAU,IAAI,MAAM;CAG1B,AAFA,EAAQ,WAAW,IACnB,EAAQ,YAAYJ,EAAY,QAChCT,EAAYa,CAAO;CAEnB,IAAIC,IAAS,IACTC,IAAa,GACbC,IAAS,IACPC,oBAAU,IAAI,IAAoB;CAGxC,SAASC,IAA8B;EACnC,OAAO;GAAE,eAAe,KAAA;GAAW,MAAM;GAAG,YAAY,KAAA;EAAU;CACtE;CAaA,SAASC,EAAO,GAAqB,EAAE,UAAO,MAAyB,CAAC,GAAmB;EACvF,IAAMpB,IAAQD,EAAO,eAAe,CAAC,CAAC;EACtC,IAAIkB,KAAU,CAACjB,GAAO,OAAOmB,EAAY;EAEzC,IAAME,IAAS,IAAI,MAAM;EAIzB,AAHA,EAAO,QAAQ,IACf,EAAO,WAAW,IAClB,EAAO,YAAYtB,GACnBE,EAAYoB,CAAM;EAElB,IAAMC,IAASf,EAAM,wBAAwBT,EAAUC,GAAQC,CAAK,CAAC,GAC/DuB,IAAOhB,EAAM,WAAW,GAC1BiB,IAAU9B,EAAUC,GAAM8B,CAAO;EAGrC,AAFA,EAAK,KAAK,QAAQD,GAClBF,EAAO,QAAQC,CAAI,GACnBA,EAAK,QAAQd,CAAM;EAEnB,IAAMiB,IAAyB;GAC3B,QAAQ,GAAoB;IAExB,AADA,IAAUhC,EAAUiC,GAAMF,CAAO,GACjC,EAAK,KAAK,QAAQD;GACtB;GACA,IAAI,OAAe;IACf,OAAOA;GACX;GACA,OAAa;IACT,AAAKN,EAAQ,IAAIQ,CAAM,MACvBR,EAAQ,OAAOQ,CAAM,GACrBJ,EAAO,WAAW,GAClBC,EAAK,WAAW,GAChB,EAAO,YAAY,MACnBF,EAAO,MAAM;GACjB;EACJ;EAEA,OADAH,EAAQ,IAAIQ,CAAM,GACXA;CACX;CAEA,OAAO;EACH;EACA,cAAc,GAAoB;GAC9B,AAAIT,MACJ,IAAavB,EAAUC,GAAM8B,CAAO,GACpC,EAAO,KAAK,QAAQT;EACxB;EACA,IAAI,aAAqB;GACrB,OAAOA;EACX;EACA,MAAM,gBAAgB,GAAoC;GACtD,IAAMY,IAAU,MAAMC,EAAef,GAA+BgB,CAAQ;GAE5E,OADIF,MAAS,IAASE,IACfF;EACX;EACA,IAAI,eAAuB;GACvB,OAAOb;EACX;EACA,MAAM,SAAwB;GAC1B,MAAMR,EAAM,SAAS,CAAC,CAAC,YAAY,KAAA,CAAS;EAChD;EACA,QAAc;GACV,IAAI,IACJ;QAAS;IACT,KAAK,IAAMmB,KAAU,CAAC,GAAGR,CAAO,GAAG,EAAO,KAAK;IAK/C,AAJA,EAAQ,YAAY,MACpBJ,EAAQ,MAAM,GACdL,EAAO,WAAW,GAClBE,GAAa,WAAW,GACpBH,KAAaD,EAAW,MAAM,CAAC,CAAC,YAAY,KAAA,CAAS;GANhD;EAOb;EACA,WAAW;EACX,IAAI,kBAA2B;GAC3B,OAAOwB,EAAgC;EAC3C;CACJ;AACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audio-output.cjs","names":[],"sources":["../../src/audio/audio-output.ts"],"sourcesContent":["/** A media element that may support output routing. */\ntype SinkCapableElement = HTMLMediaElement & {\n setSinkId?: (sinkId: string) => Promise<void>;\n sinkId?: string;\n};\n\n/**\n * Whether this browser can route audio to a chosen output device.\n *\n * Chromium-only at the time of writing: Firefox has `setSinkId` behind a preference\n * that is off by default, and Safari does not implement it at all. Check this before\n * rendering an output picker, or the control is a lie on two of three engines.\n */\nexport function isAudioOutputSelectionSupported(): boolean {\n return (\n typeof HTMLMediaElement !== \"undefined\" &&\n typeof (HTMLMediaElement.prototype as SinkCapableElement).setSinkId === \"function\"\n );\n}\n\n/**\n * Send an element's audio to a specific output device.\n *\n * The `sinkId` comes from `useMediaDevices().audioOutputs` — and, like every device\n * label, that list is anonymous until a capture permission has been granted, so an\n * output picker realistically only works after the microphone has been allowed once.\n *\n * Returns `false` instead of throwing when the browser has no `setSinkId`, because\n * \"this engine cannot route audio\" is the common case and not an error the caller can\n * act on: the sound still plays, on the system default device. A rejected\n * `setSinkId` — a device that was unplugged between enumeration and playback is the\n * usual cause — also resolves `false`, and playback continues on the default.\n *\n * @param element - The `<audio>` or `<video>` element to route.\n * @param sinkId - Device id, or `\"\"` for the system default.\n * @returns `true` when the route was applied.\n *\n * @example\n * const ok = await setAudioOutput(audioRef.current, selectedSpeakerId);\n * if (!ok) toast(\"Este navegador não permite escolher a saída de som.\");\n */\nexport async function setAudioOutput(\n element: HTMLMediaElement | null,\n sinkId: string,\n): Promise<boolean> {\n const target = element as SinkCapableElement | null;\n if (!target || typeof target.setSinkId !== \"function\") return false;\n try {\n await target.setSinkId(sinkId);\n return true;\n } catch {\n return false;\n }\n}\n"],"mappings":"AAaA,
|
|
1
|
+
{"version":3,"file":"audio-output.cjs","names":["isAudioOutputSelectionSupported","setAudioOutput","target","element","sinkId"],"sources":["../../src/audio/audio-output.ts"],"sourcesContent":["/** A media element that may support output routing. */\ntype SinkCapableElement = HTMLMediaElement & {\n setSinkId?: (sinkId: string) => Promise<void>;\n sinkId?: string;\n};\n\n/**\n * Whether this browser can route audio to a chosen output device.\n *\n * Chromium-only at the time of writing: Firefox has `setSinkId` behind a preference\n * that is off by default, and Safari does not implement it at all. Check this before\n * rendering an output picker, or the control is a lie on two of three engines.\n */\nexport function isAudioOutputSelectionSupported(): boolean {\n return (\n typeof HTMLMediaElement !== \"undefined\" &&\n typeof (HTMLMediaElement.prototype as SinkCapableElement).setSinkId === \"function\"\n );\n}\n\n/**\n * Send an element's audio to a specific output device.\n *\n * The `sinkId` comes from `useMediaDevices().audioOutputs` — and, like every device\n * label, that list is anonymous until a capture permission has been granted, so an\n * output picker realistically only works after the microphone has been allowed once.\n *\n * Returns `false` instead of throwing when the browser has no `setSinkId`, because\n * \"this engine cannot route audio\" is the common case and not an error the caller can\n * act on: the sound still plays, on the system default device. A rejected\n * `setSinkId` — a device that was unplugged between enumeration and playback is the\n * usual cause — also resolves `false`, and playback continues on the default.\n *\n * @param element - The `<audio>` or `<video>` element to route.\n * @param sinkId - Device id, or `\"\"` for the system default.\n * @returns `true` when the route was applied.\n *\n * @example\n * const ok = await setAudioOutput(audioRef.current, selectedSpeakerId);\n * if (!ok) toast(\"Este navegador não permite escolher a saída de som.\");\n */\nexport async function setAudioOutput(\n element: HTMLMediaElement | null,\n sinkId: string,\n): Promise<boolean> {\n const target = element as SinkCapableElement | null;\n if (!target || typeof target.setSinkId !== \"function\") return false;\n try {\n await target.setSinkId(sinkId);\n return true;\n } catch {\n return false;\n }\n}\n"],"mappings":"AAaA,SAAgBA,GAA2C,CACvD,OACI,OAAO,iBAAqB,KAC5B,OAAQ,iBAAiB,UAAiC,WAAc,UAEhF,CAuBA,eAAsBC,EAClB,EACA,EACgB,CAChB,IAAMC,EAASC,EACf,GAAI,CAACD,GAAU,OAAOA,EAAO,WAAc,WAAY,MAAO,GAC9D,GAAI,CAEA,OADA,MAAMA,EAAO,UAAUE,CAAM,EACtB,EACX,MAAQ,CACJ,MAAO,EACX,CACJ,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audio-output.js","names":[],"sources":["../../src/audio/audio-output.ts"],"sourcesContent":["/** A media element that may support output routing. */\ntype SinkCapableElement = HTMLMediaElement & {\n setSinkId?: (sinkId: string) => Promise<void>;\n sinkId?: string;\n};\n\n/**\n * Whether this browser can route audio to a chosen output device.\n *\n * Chromium-only at the time of writing: Firefox has `setSinkId` behind a preference\n * that is off by default, and Safari does not implement it at all. Check this before\n * rendering an output picker, or the control is a lie on two of three engines.\n */\nexport function isAudioOutputSelectionSupported(): boolean {\n return (\n typeof HTMLMediaElement !== \"undefined\" &&\n typeof (HTMLMediaElement.prototype as SinkCapableElement).setSinkId === \"function\"\n );\n}\n\n/**\n * Send an element's audio to a specific output device.\n *\n * The `sinkId` comes from `useMediaDevices().audioOutputs` — and, like every device\n * label, that list is anonymous until a capture permission has been granted, so an\n * output picker realistically only works after the microphone has been allowed once.\n *\n * Returns `false` instead of throwing when the browser has no `setSinkId`, because\n * \"this engine cannot route audio\" is the common case and not an error the caller can\n * act on: the sound still plays, on the system default device. A rejected\n * `setSinkId` — a device that was unplugged between enumeration and playback is the\n * usual cause — also resolves `false`, and playback continues on the default.\n *\n * @param element - The `<audio>` or `<video>` element to route.\n * @param sinkId - Device id, or `\"\"` for the system default.\n * @returns `true` when the route was applied.\n *\n * @example\n * const ok = await setAudioOutput(audioRef.current, selectedSpeakerId);\n * if (!ok) toast(\"Este navegador não permite escolher a saída de som.\");\n */\nexport async function setAudioOutput(\n element: HTMLMediaElement | null,\n sinkId: string,\n): Promise<boolean> {\n const target = element as SinkCapableElement | null;\n if (!target || typeof target.setSinkId !== \"function\") return false;\n try {\n await target.setSinkId(sinkId);\n return true;\n } catch {\n return false;\n }\n}\n"],"mappings":";AAaA,
|
|
1
|
+
{"version":3,"file":"audio-output.js","names":["isAudioOutputSelectionSupported","setAudioOutput","target","element","sinkId"],"sources":["../../src/audio/audio-output.ts"],"sourcesContent":["/** A media element that may support output routing. */\ntype SinkCapableElement = HTMLMediaElement & {\n setSinkId?: (sinkId: string) => Promise<void>;\n sinkId?: string;\n};\n\n/**\n * Whether this browser can route audio to a chosen output device.\n *\n * Chromium-only at the time of writing: Firefox has `setSinkId` behind a preference\n * that is off by default, and Safari does not implement it at all. Check this before\n * rendering an output picker, or the control is a lie on two of three engines.\n */\nexport function isAudioOutputSelectionSupported(): boolean {\n return (\n typeof HTMLMediaElement !== \"undefined\" &&\n typeof (HTMLMediaElement.prototype as SinkCapableElement).setSinkId === \"function\"\n );\n}\n\n/**\n * Send an element's audio to a specific output device.\n *\n * The `sinkId` comes from `useMediaDevices().audioOutputs` — and, like every device\n * label, that list is anonymous until a capture permission has been granted, so an\n * output picker realistically only works after the microphone has been allowed once.\n *\n * Returns `false` instead of throwing when the browser has no `setSinkId`, because\n * \"this engine cannot route audio\" is the common case and not an error the caller can\n * act on: the sound still plays, on the system default device. A rejected\n * `setSinkId` — a device that was unplugged between enumeration and playback is the\n * usual cause — also resolves `false`, and playback continues on the default.\n *\n * @param element - The `<audio>` or `<video>` element to route.\n * @param sinkId - Device id, or `\"\"` for the system default.\n * @returns `true` when the route was applied.\n *\n * @example\n * const ok = await setAudioOutput(audioRef.current, selectedSpeakerId);\n * if (!ok) toast(\"Este navegador não permite escolher a saída de som.\");\n */\nexport async function setAudioOutput(\n element: HTMLMediaElement | null,\n sinkId: string,\n): Promise<boolean> {\n const target = element as SinkCapableElement | null;\n if (!target || typeof target.setSinkId !== \"function\") return false;\n try {\n await target.setSinkId(sinkId);\n return true;\n } catch {\n return false;\n }\n}\n"],"mappings":";AAaA,SAAgBA,IAA2C;CACvD,OACI,OAAO,mBAAqB,OAC5B,OAAQ,iBAAiB,UAAiC,aAAc;AAEhF;AAuBA,eAAsBC,EAClB,GACA,GACgB;CAChB,IAAMC,IAASC;CACf,IAAI,CAACD,KAAU,OAAOA,EAAO,aAAc,YAAY,OAAO;CAC9D,IAAI;EAEA,OADA,MAAMA,EAAO,UAAUE,CAAM,GACtB;CACX,QAAQ;EACJ,OAAO;CACX;AACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audio-player.cjs","names":[],"sources":["../../src/audio/audio-player.ts"],"sourcesContent":["import { setAudioOutput } from \"./audio-output\";\n\nexport interface PlayAudioOptions {\n /** Volume between 0 and 1. Default: 1. */\n volume?: number;\n /** Loop the clip. Default: false. */\n loop?: boolean;\n /** Begin playback immediately. Default: true. */\n autoplay?: boolean;\n /** Stop the previous clip managed by this player. Default: false. */\n stopPrevious?: boolean;\n /**\n * Output device to play on, from `useMediaDevices().audioOutputs`.\n *\n * Ignored where the browser has no output routing (everything but Chromium) —\n * the clip still plays, on the system default. Useful for a chime that must land\n * on a headset while the call audio stays on the speakers.\n */\n sinkId?: string;\n /** Fired when playback ends naturally. */\n onEnded?: () => void;\n /** Fired on playback error. */\n onError?: (error: unknown) => void;\n}\n\n/**\n * Imperative handle over one \"current\" clip.\n *\n * Named `*Handle` like the SDK's other imperative handles (`ChatComposerHandle`,\n * `SignaturePadHandle`) — it is a control surface, not the `<AudioPlayer>` component.\n */\nexport interface AudioPlayerHandle {\n /** Play `src`. Returns the underlying element, or `null` when the browser blocked autoplay. */\n play: (src: string, options?: PlayAudioOptions) => Promise<HTMLAudioElement | null>;\n /** Stop the currently-playing clip and rewind it. */\n stop: () => void;\n /** Currently playing audio element, or `null`. */\n current: () => HTMLAudioElement | null;\n}\n\n/**\n * Create an isolated audio player that tracks a single \"current\" clip.\n * Multiple players coexist independently; use this when several layers of UI\n * need their own playback state.\n */\nexport function createAudioPlayer(): AudioPlayerHandle {\n let current: HTMLAudioElement | null = null;\n\n async function play(\n src: string,\n {\n volume = 1,\n loop = false,\n autoplay = true,\n stopPrevious = false,\n sinkId,\n onEnded,\n onError,\n }: PlayAudioOptions = {},\n ): Promise<HTMLAudioElement | null> {\n try {\n if (stopPrevious && current) {\n current.pause();\n current.currentTime = 0;\n }\n const audio = new Audio(src);\n audio.volume = Math.max(0, Math.min(1, volume));\n audio.loop = loop;\n audio.preload = \"auto\";\n if (onEnded) audio.onended = onEnded;\n if (onError) audio.onerror = (event) => onError(event);\n current = audio;\n // Routed before `play()`: applying a sink to an element that is already\n // playing restarts its audio pipeline and clips the first few ms.\n if (sinkId !== undefined) await setAudioOutput(audio, sinkId);\n if (autoplay) await audio.play();\n return audio;\n } catch (error) {\n onError?.(error);\n return null;\n }\n }\n\n function stop(): void {\n if (!current) return;\n current.pause();\n current.currentTime = 0;\n }\n\n return { play, stop, current: () => current };\n}\n\nlet defaultPlayer: AudioPlayerHandle | null = null;\n\nfunction getDefaultPlayer(): AudioPlayerHandle {\n if (!defaultPlayer) defaultPlayer = createAudioPlayer();\n return defaultPlayer;\n}\n\n/**\n * Convenience wrapper around a shared {@link AudioPlayerHandle}. Use this for\n * one-off notification sounds. For more complex flows (e.g. several\n * simultaneous channels), build a dedicated player with {@link createAudioPlayer}.\n */\nexport async function playAudio(\n src: string,\n options?: PlayAudioOptions,\n): Promise<HTMLAudioElement | null> {\n return getDefaultPlayer().play(src, options);\n}\n\n/** Stop the clip currently playing on the shared default player. */\nexport function stopAudio(): void {\n getDefaultPlayer().stop();\n}\n"],"mappings":"sCA6CA,
|
|
1
|
+
{"version":3,"file":"audio-player.cjs","names":["setAudioOutput","require_audio_output","createAudioPlayer","current","play","stopPrevious","audio","src","volume","loop","onEnded","onError","event","sinkId","autoplay","error","stop","defaultPlayer","getDefaultPlayer","playAudio","options","stopAudio"],"sources":["../../src/audio/audio-player.ts"],"sourcesContent":["import { setAudioOutput } from \"./audio-output\";\n\nexport interface PlayAudioOptions {\n /** Volume between 0 and 1. Default: 1. */\n volume?: number;\n /** Loop the clip. Default: false. */\n loop?: boolean;\n /** Begin playback immediately. Default: true. */\n autoplay?: boolean;\n /** Stop the previous clip managed by this player. Default: false. */\n stopPrevious?: boolean;\n /**\n * Output device to play on, from `useMediaDevices().audioOutputs`.\n *\n * Ignored where the browser has no output routing (everything but Chromium) —\n * the clip still plays, on the system default. Useful for a chime that must land\n * on a headset while the call audio stays on the speakers.\n */\n sinkId?: string;\n /** Fired when playback ends naturally. */\n onEnded?: () => void;\n /** Fired on playback error. */\n onError?: (error: unknown) => void;\n}\n\n/**\n * Imperative handle over one \"current\" clip.\n *\n * Named `*Handle` like the SDK's other imperative handles (`ChatComposerHandle`,\n * `SignaturePadHandle`) — it is a control surface, not the `<AudioPlayer>` component.\n */\nexport interface AudioPlayerHandle {\n /** Play `src`. Returns the underlying element, or `null` when the browser blocked autoplay. */\n play: (src: string, options?: PlayAudioOptions) => Promise<HTMLAudioElement | null>;\n /** Stop the currently-playing clip and rewind it. */\n stop: () => void;\n /** Currently playing audio element, or `null`. */\n current: () => HTMLAudioElement | null;\n}\n\n/**\n * Create an isolated audio player that tracks a single \"current\" clip.\n * Multiple players coexist independently; use this when several layers of UI\n * need their own playback state.\n */\nexport function createAudioPlayer(): AudioPlayerHandle {\n let current: HTMLAudioElement | null = null;\n\n async function play(\n src: string,\n {\n volume = 1,\n loop = false,\n autoplay = true,\n stopPrevious = false,\n sinkId,\n onEnded,\n onError,\n }: PlayAudioOptions = {},\n ): Promise<HTMLAudioElement | null> {\n try {\n if (stopPrevious && current) {\n current.pause();\n current.currentTime = 0;\n }\n const audio = new Audio(src);\n audio.volume = Math.max(0, Math.min(1, volume));\n audio.loop = loop;\n audio.preload = \"auto\";\n if (onEnded) audio.onended = onEnded;\n if (onError) audio.onerror = (event) => onError(event);\n current = audio;\n // Routed before `play()`: applying a sink to an element that is already\n // playing restarts its audio pipeline and clips the first few ms.\n if (sinkId !== undefined) await setAudioOutput(audio, sinkId);\n if (autoplay) await audio.play();\n return audio;\n } catch (error) {\n onError?.(error);\n return null;\n }\n }\n\n function stop(): void {\n if (!current) return;\n current.pause();\n current.currentTime = 0;\n }\n\n return { play, stop, current: () => current };\n}\n\nlet defaultPlayer: AudioPlayerHandle | null = null;\n\nfunction getDefaultPlayer(): AudioPlayerHandle {\n if (!defaultPlayer) defaultPlayer = createAudioPlayer();\n return defaultPlayer;\n}\n\n/**\n * Convenience wrapper around a shared {@link AudioPlayerHandle}. Use this for\n * one-off notification sounds. For more complex flows (e.g. several\n * simultaneous channels), build a dedicated player with {@link createAudioPlayer}.\n */\nexport async function playAudio(\n src: string,\n options?: PlayAudioOptions,\n): Promise<HTMLAudioElement | null> {\n return getDefaultPlayer().play(src, options);\n}\n\n/** Stop the clip currently playing on the shared default player. */\nexport function stopAudio(): void {\n getDefaultPlayer().stop();\n}\n"],"mappings":"A,sCA6CA,SAAgBE,GAAuC,CACnD,IAAIC,EAAmC,KAEvC,eAAeC,EACX,EACA,CACI,SAAS,EACT,OAAO,GACP,WAAW,GACX,eAAe,GACf,SACA,UACA,WACkB,CAAC,EACS,CAChC,GAAI,CACIC,GAAgBF,IAChBA,EAAQ,MAAM,EACd,EAAQ,YAAc,GAE1B,IAAMG,EAAQ,IAAI,MAAMC,CAAG,EAW3B,MAVA,GAAM,OAAS,KAAK,IAAI,EAAG,KAAK,IAAI,EAAGC,CAAM,CAAC,EAC9C,EAAM,KAAOC,EACb,EAAM,QAAU,OACZC,IAAS,EAAM,QAAUA,GACzBC,IAAS,EAAM,QAAW,GAAUA,EAAQC,CAAK,GACrD,EAAUN,EAGNO,IAAW,IAAA,IAAW,MAAMb,EAAAA,eAAeM,EAAOO,CAAM,EACxDC,GAAU,MAAMR,EAAM,KAAK,EACxBA,CACX,OAASS,EAAO,CAEZ,OADAJ,IAAUI,CAAK,EACR,IACX,CACJ,CAEA,SAASC,GAAa,CACbb,IACLA,EAAQ,MAAM,EACd,EAAQ,YAAc,EAC1B,CAEA,MAAO,CAAE,OAAM,OAAM,YAAeA,CAAQ,CAChD,CAEA,IAAIc,EAA0C,KAE9C,SAASC,GAAsC,CAE3C,MADA,CAAoBD,IAAgBf,EAAkB,EAC/Ce,CACX,CAOA,eAAsBE,EAClB,EACA,EACgC,CAChC,OAAOD,EAAiB,CAAC,CAAC,KAAKX,EAAKa,CAAO,CAC/C,CAGA,SAAgBC,GAAkB,CAC9BH,EAAiB,CAAC,CAAC,KAAK,CAC5B,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audio-player.js","names":[],"sources":["../../src/audio/audio-player.ts"],"sourcesContent":["import { setAudioOutput } from \"./audio-output\";\n\nexport interface PlayAudioOptions {\n /** Volume between 0 and 1. Default: 1. */\n volume?: number;\n /** Loop the clip. Default: false. */\n loop?: boolean;\n /** Begin playback immediately. Default: true. */\n autoplay?: boolean;\n /** Stop the previous clip managed by this player. Default: false. */\n stopPrevious?: boolean;\n /**\n * Output device to play on, from `useMediaDevices().audioOutputs`.\n *\n * Ignored where the browser has no output routing (everything but Chromium) —\n * the clip still plays, on the system default. Useful for a chime that must land\n * on a headset while the call audio stays on the speakers.\n */\n sinkId?: string;\n /** Fired when playback ends naturally. */\n onEnded?: () => void;\n /** Fired on playback error. */\n onError?: (error: unknown) => void;\n}\n\n/**\n * Imperative handle over one \"current\" clip.\n *\n * Named `*Handle` like the SDK's other imperative handles (`ChatComposerHandle`,\n * `SignaturePadHandle`) — it is a control surface, not the `<AudioPlayer>` component.\n */\nexport interface AudioPlayerHandle {\n /** Play `src`. Returns the underlying element, or `null` when the browser blocked autoplay. */\n play: (src: string, options?: PlayAudioOptions) => Promise<HTMLAudioElement | null>;\n /** Stop the currently-playing clip and rewind it. */\n stop: () => void;\n /** Currently playing audio element, or `null`. */\n current: () => HTMLAudioElement | null;\n}\n\n/**\n * Create an isolated audio player that tracks a single \"current\" clip.\n * Multiple players coexist independently; use this when several layers of UI\n * need their own playback state.\n */\nexport function createAudioPlayer(): AudioPlayerHandle {\n let current: HTMLAudioElement | null = null;\n\n async function play(\n src: string,\n {\n volume = 1,\n loop = false,\n autoplay = true,\n stopPrevious = false,\n sinkId,\n onEnded,\n onError,\n }: PlayAudioOptions = {},\n ): Promise<HTMLAudioElement | null> {\n try {\n if (stopPrevious && current) {\n current.pause();\n current.currentTime = 0;\n }\n const audio = new Audio(src);\n audio.volume = Math.max(0, Math.min(1, volume));\n audio.loop = loop;\n audio.preload = \"auto\";\n if (onEnded) audio.onended = onEnded;\n if (onError) audio.onerror = (event) => onError(event);\n current = audio;\n // Routed before `play()`: applying a sink to an element that is already\n // playing restarts its audio pipeline and clips the first few ms.\n if (sinkId !== undefined) await setAudioOutput(audio, sinkId);\n if (autoplay) await audio.play();\n return audio;\n } catch (error) {\n onError?.(error);\n return null;\n }\n }\n\n function stop(): void {\n if (!current) return;\n current.pause();\n current.currentTime = 0;\n }\n\n return { play, stop, current: () => current };\n}\n\nlet defaultPlayer: AudioPlayerHandle | null = null;\n\nfunction getDefaultPlayer(): AudioPlayerHandle {\n if (!defaultPlayer) defaultPlayer = createAudioPlayer();\n return defaultPlayer;\n}\n\n/**\n * Convenience wrapper around a shared {@link AudioPlayerHandle}. Use this for\n * one-off notification sounds. For more complex flows (e.g. several\n * simultaneous channels), build a dedicated player with {@link createAudioPlayer}.\n */\nexport async function playAudio(\n src: string,\n options?: PlayAudioOptions,\n): Promise<HTMLAudioElement | null> {\n return getDefaultPlayer().play(src, options);\n}\n\n/** Stop the clip currently playing on the shared default player. */\nexport function stopAudio(): void {\n getDefaultPlayer().stop();\n}\n"],"mappings":";;AA6CA,
|
|
1
|
+
{"version":3,"file":"audio-player.js","names":["createAudioPlayer","current","play","stopPrevious","audio","src","volume","loop","onEnded","onError","event","sinkId","setAudioOutput","autoplay","error","stop","defaultPlayer","getDefaultPlayer","playAudio","options","stopAudio"],"sources":["../../src/audio/audio-player.ts"],"sourcesContent":["import { setAudioOutput } from \"./audio-output\";\n\nexport interface PlayAudioOptions {\n /** Volume between 0 and 1. Default: 1. */\n volume?: number;\n /** Loop the clip. Default: false. */\n loop?: boolean;\n /** Begin playback immediately. Default: true. */\n autoplay?: boolean;\n /** Stop the previous clip managed by this player. Default: false. */\n stopPrevious?: boolean;\n /**\n * Output device to play on, from `useMediaDevices().audioOutputs`.\n *\n * Ignored where the browser has no output routing (everything but Chromium) —\n * the clip still plays, on the system default. Useful for a chime that must land\n * on a headset while the call audio stays on the speakers.\n */\n sinkId?: string;\n /** Fired when playback ends naturally. */\n onEnded?: () => void;\n /** Fired on playback error. */\n onError?: (error: unknown) => void;\n}\n\n/**\n * Imperative handle over one \"current\" clip.\n *\n * Named `*Handle` like the SDK's other imperative handles (`ChatComposerHandle`,\n * `SignaturePadHandle`) — it is a control surface, not the `<AudioPlayer>` component.\n */\nexport interface AudioPlayerHandle {\n /** Play `src`. Returns the underlying element, or `null` when the browser blocked autoplay. */\n play: (src: string, options?: PlayAudioOptions) => Promise<HTMLAudioElement | null>;\n /** Stop the currently-playing clip and rewind it. */\n stop: () => void;\n /** Currently playing audio element, or `null`. */\n current: () => HTMLAudioElement | null;\n}\n\n/**\n * Create an isolated audio player that tracks a single \"current\" clip.\n * Multiple players coexist independently; use this when several layers of UI\n * need their own playback state.\n */\nexport function createAudioPlayer(): AudioPlayerHandle {\n let current: HTMLAudioElement | null = null;\n\n async function play(\n src: string,\n {\n volume = 1,\n loop = false,\n autoplay = true,\n stopPrevious = false,\n sinkId,\n onEnded,\n onError,\n }: PlayAudioOptions = {},\n ): Promise<HTMLAudioElement | null> {\n try {\n if (stopPrevious && current) {\n current.pause();\n current.currentTime = 0;\n }\n const audio = new Audio(src);\n audio.volume = Math.max(0, Math.min(1, volume));\n audio.loop = loop;\n audio.preload = \"auto\";\n if (onEnded) audio.onended = onEnded;\n if (onError) audio.onerror = (event) => onError(event);\n current = audio;\n // Routed before `play()`: applying a sink to an element that is already\n // playing restarts its audio pipeline and clips the first few ms.\n if (sinkId !== undefined) await setAudioOutput(audio, sinkId);\n if (autoplay) await audio.play();\n return audio;\n } catch (error) {\n onError?.(error);\n return null;\n }\n }\n\n function stop(): void {\n if (!current) return;\n current.pause();\n current.currentTime = 0;\n }\n\n return { play, stop, current: () => current };\n}\n\nlet defaultPlayer: AudioPlayerHandle | null = null;\n\nfunction getDefaultPlayer(): AudioPlayerHandle {\n if (!defaultPlayer) defaultPlayer = createAudioPlayer();\n return defaultPlayer;\n}\n\n/**\n * Convenience wrapper around a shared {@link AudioPlayerHandle}. Use this for\n * one-off notification sounds. For more complex flows (e.g. several\n * simultaneous channels), build a dedicated player with {@link createAudioPlayer}.\n */\nexport async function playAudio(\n src: string,\n options?: PlayAudioOptions,\n): Promise<HTMLAudioElement | null> {\n return getDefaultPlayer().play(src, options);\n}\n\n/** Stop the clip currently playing on the shared default player. */\nexport function stopAudio(): void {\n getDefaultPlayer().stop();\n}\n"],"mappings":";;AA6CA,SAAgBA,IAAuC;CACnD,IAAIC,IAAmC;CAEvC,eAAeC,EACX,GACA,EACI,YAAS,GACT,UAAO,IACP,cAAW,IACX,kBAAe,IACf,WACA,YACA,eACkB,CAAC,GACS;EAChC,IAAI;GACA,AAAIC,KAAgBF,MAChBA,EAAQ,MAAM,GACd,EAAQ,cAAc;GAE1B,IAAMG,IAAQ,IAAI,MAAMC,CAAG;GAW3B,OAVA,EAAM,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,GAAGC,CAAM,CAAC,GAC9C,EAAM,OAAOC,GACb,EAAM,UAAU,QACZC,MAAS,EAAM,UAAUA,IACzBC,MAAS,EAAM,WAAW,MAAUA,EAAQC,CAAK,IACrD,IAAUN,GAGNO,MAAW,KAAA,KAAW,MAAMC,EAAeR,GAAOO,CAAM,GACxDE,KAAU,MAAMT,EAAM,KAAK,GACxBA;EACX,SAASU,GAAO;GAEZ,OADAL,IAAUK,CAAK,GACR;EACX;CACJ;CAEA,SAASC,IAAa;EAClB,AAAKd,MACLA,EAAQ,MAAM,GACd,EAAQ,cAAc;CAC1B;CAEA,OAAO;EAAE;EAAM;EAAM,eAAeA;CAAQ;AAChD;AAEA,IAAIe,IAA0C;AAE9C,SAASC,IAAsC;CAE3C,OADA,AAAoBD,MAAgBhB,EAAkB,GAC/CgB;AACX;AAOA,eAAsBE,EAClB,GACA,GACgC;CAChC,OAAOD,EAAiB,CAAC,CAAC,KAAKZ,GAAKc,CAAO;AAC/C;AAGA,SAAgBC,IAAkB;CAC9B,EAAiB,CAAC,CAAC,KAAK;AAC5B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audio-recorder.cjs","names":[],"sources":["../../src/audio/audio-recorder.ts"],"sourcesContent":["import {\n createMediaRecorder,\n pickRecordingMimeType,\n type MediaRecorderStatus,\n} from \"@/capture/media-recorder\";\n\n/** Lifecycle of a recording. Shared with the video recorder — the states are the same. */\nexport type AudioRecorderStatus = MediaRecorderStatus;\n\n/**\n * Container/codec candidates, best first.\n *\n * No browser supports all of these, and none supports MP3 or WAV from\n * `MediaRecorder` — see the note on {@link pickAudioMimeType}. Opus in WebM is the\n * first choice because it is the smallest at speech bitrates and is what Chromium\n * and Firefox produce natively; `audio/mp4` is here for Safari, which produces AAC\n * and nothing else.\n *\n * Ported from the intersection of what `MediaRecorder.isTypeSupported` accepts in\n * Chrome 120+, Firefox 115+ and Safari 17. Re-check against\n * <https://developer.mozilla.org/docs/Web/API/MediaRecorder/isTypeSupported> before\n * adding to the list.\n */\nexport const AUDIO_MIME_CANDIDATES: readonly string[] = [\n \"audio/webm;codecs=opus\",\n \"audio/webm\",\n \"audio/ogg;codecs=opus\",\n \"audio/mp4;codecs=mp4a.40.2\",\n \"audio/mp4\",\n];\n\n/** A finished recording. */\nexport interface AudioRecording {\n /** The audio. Wrap with `useObjectUrl` to play it, or POST it as-is. */\n blob: Blob;\n /** What the browser actually produced — not necessarily what you asked for. */\n mimeType: string;\n /** Recorded length, excluding time spent paused. */\n durationMs: number;\n}\n\n/** Options for {@link createAudioRecorder}. */\nexport interface AudioRecorderOptions {\n /**\n * Force a container. Throws when the browser cannot produce it.\n *\n * Leave it out. The default negotiates from {@link AUDIO_MIME_CANDIDATES}, which\n * is the only way one call site works on both Chromium and Safari.\n */\n mimeType?: string;\n /** Target bitrate. 32000–64000 is plenty for speech in Opus. */\n audioBitsPerSecond?: number;\n /**\n * Emit a chunk every N ms through `onChunk`, for streaming upload.\n *\n * Without it the whole recording is buffered in memory until `stop()` — fine for\n * a voice note, not fine for an hour-long meeting.\n */\n timesliceMs?: number;\n /** Receives each chunk when `timesliceMs` is set. Chunks are **not** independently playable. */\n onChunk?: (chunk: Blob) => void;\n /** Recorder-level failure (device unplugged mid-recording, encoder error). */\n onError?: (error: unknown) => void;\n}\n\n/** Imperative recorder. */\nexport interface AudioRecorderHandle {\n /** Begin recording. No-op when already recording or paused. */\n start: () => void;\n /** Pause. The clock stops; `durationMs` freezes. */\n pause: () => void;\n /** Resume after `pause()`. */\n resume: () => void;\n /** Stop and resolve with the assembled recording. */\n stop: () => Promise<AudioRecording>;\n /** Stop and throw the audio away. */\n cancel: () => void;\n status: () => AudioRecorderStatus;\n /** Recorded length so far, excluding paused time. */\n durationMs: () => number;\n /** The negotiated container. */\n mimeType: string;\n}\n\n/** Whether `MediaRecorder` exists and can produce at least one audio container. */\nexport function isAudioRecordingSupported(): boolean {\n return typeof MediaRecorder !== \"undefined\" && pickAudioMimeType() !== null;\n}\n\n/**\n * First container in `preferred` the browser can actually produce, or `null`.\n *\n * **There is no MP3 or WAV here, and that is not an omission.** `MediaRecorder`\n * emits Opus (in WebM or Ogg) on Chromium and Firefox and AAC (in MP4) on Safari —\n * no engine implements an MP3 or WAV encoder for it. If a backend needs WAV,\n * {@link blobToWav} converts one client-side with no dependency; if it needs MP3,\n * transcode on the server. Shipping an MP3 encoder would mean a WASM build of the\n * order of 150 KB in every consumer's bundle to serve one format, which is the\n * trade this SDK does not make.\n *\n * @param preferred - Candidates, best first. Defaults to {@link AUDIO_MIME_CANDIDATES}.\n * @returns A supported MIME type, or `null` when none is.\n */\nexport function pickAudioMimeType(\n preferred: readonly string[] = AUDIO_MIME_CANDIDATES,\n): string | null {\n return pickRecordingMimeType(preferred);\n}\n\n/**\n * Wrap a `MediaStream` in a recorder with a real state machine and an honest clock.\n *\n * The engine is shared with the video recorder (`createMediaRecorder`), because the\n * subtle parts are not audio-specific: `MediaRecorder` reports **no duration** (WebM\n * it writes carries none in its header, which is why `<audio>` shows `Infinity` for a\n * fresh recording) so the clock is kept by hand and subtracts paused time; and\n * `stop()` returns *before* the last `dataavailable` event, so the blob can only be\n * assembled in `onstop`. What stays here is the part that genuinely differs — the\n * container list.\n *\n * The stream is **not** owned here: `stop()` leaves the microphone open so a retake\n * does not need a second permission round-trip. Release it with the owning\n * `useMicrophone().stop()`.\n *\n * @param stream - A live audio stream, usually from {@link useMicrophone}.\n * @param options - See {@link AudioRecorderOptions}.\n * @returns The imperative recorder.\n * @throws When `MediaRecorder` is unavailable, or an explicit `mimeType` is unsupported.\n */\nexport function createAudioRecorder(\n stream: MediaStream,\n options: AudioRecorderOptions = {},\n): AudioRecorderHandle {\n return createMediaRecorder(stream, {\n candidates: AUDIO_MIME_CANDIDATES,\n kind: \"audio\",\n mimeType: options.mimeType,\n audioBitsPerSecond: options.audioBitsPerSecond,\n timesliceMs: options.timesliceMs,\n onChunk: options.onChunk,\n onError: options.onError,\n });\n}\n"],"mappings":"iDAuBA,
|
|
1
|
+
{"version":3,"file":"audio-recorder.cjs","names":["pickRecordingMimeType","createMediaRecorder","require_media_recorder","AUDIO_MIME_CANDIDATES","isAudioRecordingSupported","pickAudioMimeType","preferred","createAudioRecorder","stream","options"],"sources":["../../src/audio/audio-recorder.ts"],"sourcesContent":["import {\n createMediaRecorder,\n pickRecordingMimeType,\n type MediaRecorderStatus,\n} from \"@/capture/media-recorder\";\n\n/** Lifecycle of a recording. Shared with the video recorder — the states are the same. */\nexport type AudioRecorderStatus = MediaRecorderStatus;\n\n/**\n * Container/codec candidates, best first.\n *\n * No browser supports all of these, and none supports MP3 or WAV from\n * `MediaRecorder` — see the note on {@link pickAudioMimeType}. Opus in WebM is the\n * first choice because it is the smallest at speech bitrates and is what Chromium\n * and Firefox produce natively; `audio/mp4` is here for Safari, which produces AAC\n * and nothing else.\n *\n * Ported from the intersection of what `MediaRecorder.isTypeSupported` accepts in\n * Chrome 120+, Firefox 115+ and Safari 17. Re-check against\n * <https://developer.mozilla.org/docs/Web/API/MediaRecorder/isTypeSupported> before\n * adding to the list.\n */\nexport const AUDIO_MIME_CANDIDATES: readonly string[] = [\n \"audio/webm;codecs=opus\",\n \"audio/webm\",\n \"audio/ogg;codecs=opus\",\n \"audio/mp4;codecs=mp4a.40.2\",\n \"audio/mp4\",\n];\n\n/** A finished recording. */\nexport interface AudioRecording {\n /** The audio. Wrap with `useObjectUrl` to play it, or POST it as-is. */\n blob: Blob;\n /** What the browser actually produced — not necessarily what you asked for. */\n mimeType: string;\n /** Recorded length, excluding time spent paused. */\n durationMs: number;\n}\n\n/** Options for {@link createAudioRecorder}. */\nexport interface AudioRecorderOptions {\n /**\n * Force a container. Throws when the browser cannot produce it.\n *\n * Leave it out. The default negotiates from {@link AUDIO_MIME_CANDIDATES}, which\n * is the only way one call site works on both Chromium and Safari.\n */\n mimeType?: string;\n /** Target bitrate. 32000–64000 is plenty for speech in Opus. */\n audioBitsPerSecond?: number;\n /**\n * Emit a chunk every N ms through `onChunk`, for streaming upload.\n *\n * Without it the whole recording is buffered in memory until `stop()` — fine for\n * a voice note, not fine for an hour-long meeting.\n */\n timesliceMs?: number;\n /** Receives each chunk when `timesliceMs` is set. Chunks are **not** independently playable. */\n onChunk?: (chunk: Blob) => void;\n /** Recorder-level failure (device unplugged mid-recording, encoder error). */\n onError?: (error: unknown) => void;\n}\n\n/** Imperative recorder. */\nexport interface AudioRecorderHandle {\n /** Begin recording. No-op when already recording or paused. */\n start: () => void;\n /** Pause. The clock stops; `durationMs` freezes. */\n pause: () => void;\n /** Resume after `pause()`. */\n resume: () => void;\n /** Stop and resolve with the assembled recording. */\n stop: () => Promise<AudioRecording>;\n /** Stop and throw the audio away. */\n cancel: () => void;\n status: () => AudioRecorderStatus;\n /** Recorded length so far, excluding paused time. */\n durationMs: () => number;\n /** The negotiated container. */\n mimeType: string;\n}\n\n/** Whether `MediaRecorder` exists and can produce at least one audio container. */\nexport function isAudioRecordingSupported(): boolean {\n return typeof MediaRecorder !== \"undefined\" && pickAudioMimeType() !== null;\n}\n\n/**\n * First container in `preferred` the browser can actually produce, or `null`.\n *\n * **There is no MP3 or WAV here, and that is not an omission.** `MediaRecorder`\n * emits Opus (in WebM or Ogg) on Chromium and Firefox and AAC (in MP4) on Safari —\n * no engine implements an MP3 or WAV encoder for it. If a backend needs WAV,\n * {@link blobToWav} converts one client-side with no dependency; if it needs MP3,\n * transcode on the server. Shipping an MP3 encoder would mean a WASM build of the\n * order of 150 KB in every consumer's bundle to serve one format, which is the\n * trade this SDK does not make.\n *\n * @param preferred - Candidates, best first. Defaults to {@link AUDIO_MIME_CANDIDATES}.\n * @returns A supported MIME type, or `null` when none is.\n */\nexport function pickAudioMimeType(\n preferred: readonly string[] = AUDIO_MIME_CANDIDATES,\n): string | null {\n return pickRecordingMimeType(preferred);\n}\n\n/**\n * Wrap a `MediaStream` in a recorder with a real state machine and an honest clock.\n *\n * The engine is shared with the video recorder (`createMediaRecorder`), because the\n * subtle parts are not audio-specific: `MediaRecorder` reports **no duration** (WebM\n * it writes carries none in its header, which is why `<audio>` shows `Infinity` for a\n * fresh recording) so the clock is kept by hand and subtracts paused time; and\n * `stop()` returns *before* the last `dataavailable` event, so the blob can only be\n * assembled in `onstop`. What stays here is the part that genuinely differs — the\n * container list.\n *\n * The stream is **not** owned here: `stop()` leaves the microphone open so a retake\n * does not need a second permission round-trip. Release it with the owning\n * `useMicrophone().stop()`.\n *\n * @param stream - A live audio stream, usually from {@link useMicrophone}.\n * @param options - See {@link AudioRecorderOptions}.\n * @returns The imperative recorder.\n * @throws When `MediaRecorder` is unavailable, or an explicit `mimeType` is unsupported.\n */\nexport function createAudioRecorder(\n stream: MediaStream,\n options: AudioRecorderOptions = {},\n): AudioRecorderHandle {\n return createMediaRecorder(stream, {\n candidates: AUDIO_MIME_CANDIDATES,\n kind: \"audio\",\n mimeType: options.mimeType,\n audioBitsPerSecond: options.audioBitsPerSecond,\n timesliceMs: options.timesliceMs,\n onChunk: options.onChunk,\n onError: options.onError,\n });\n}\n"],"mappings":"A,iDAuBA,IAAaG,EAA2C,CACpD,yBACA,aACA,wBACA,6BACA,WACJ,EAwDA,SAAgBC,GAAqC,CACjD,OAAO,OAAO,cAAkB,KAAeC,EAAkB,IAAM,IAC3E,CAgBA,SAAgBA,EACZ,EAA+BF,EAClB,CACb,OAAOH,EAAAA,sBAAsBM,CAAS,CAC1C,CAsBA,SAAgBC,EACZ,EACA,EAAgC,CAAC,EACd,CACnB,OAAON,EAAAA,oBAAoBO,EAAQ,CAC/B,WAAYL,EACZ,KAAM,QACN,SAAUM,EAAQ,SAClB,mBAAoBA,EAAQ,mBAC5B,YAAaA,EAAQ,YACrB,QAASA,EAAQ,QACjB,QAASA,EAAQ,OACrB,CAAC,CACL,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audio-recorder.js","names":[],"sources":["../../src/audio/audio-recorder.ts"],"sourcesContent":["import {\n createMediaRecorder,\n pickRecordingMimeType,\n type MediaRecorderStatus,\n} from \"@/capture/media-recorder\";\n\n/** Lifecycle of a recording. Shared with the video recorder — the states are the same. */\nexport type AudioRecorderStatus = MediaRecorderStatus;\n\n/**\n * Container/codec candidates, best first.\n *\n * No browser supports all of these, and none supports MP3 or WAV from\n * `MediaRecorder` — see the note on {@link pickAudioMimeType}. Opus in WebM is the\n * first choice because it is the smallest at speech bitrates and is what Chromium\n * and Firefox produce natively; `audio/mp4` is here for Safari, which produces AAC\n * and nothing else.\n *\n * Ported from the intersection of what `MediaRecorder.isTypeSupported` accepts in\n * Chrome 120+, Firefox 115+ and Safari 17. Re-check against\n * <https://developer.mozilla.org/docs/Web/API/MediaRecorder/isTypeSupported> before\n * adding to the list.\n */\nexport const AUDIO_MIME_CANDIDATES: readonly string[] = [\n \"audio/webm;codecs=opus\",\n \"audio/webm\",\n \"audio/ogg;codecs=opus\",\n \"audio/mp4;codecs=mp4a.40.2\",\n \"audio/mp4\",\n];\n\n/** A finished recording. */\nexport interface AudioRecording {\n /** The audio. Wrap with `useObjectUrl` to play it, or POST it as-is. */\n blob: Blob;\n /** What the browser actually produced — not necessarily what you asked for. */\n mimeType: string;\n /** Recorded length, excluding time spent paused. */\n durationMs: number;\n}\n\n/** Options for {@link createAudioRecorder}. */\nexport interface AudioRecorderOptions {\n /**\n * Force a container. Throws when the browser cannot produce it.\n *\n * Leave it out. The default negotiates from {@link AUDIO_MIME_CANDIDATES}, which\n * is the only way one call site works on both Chromium and Safari.\n */\n mimeType?: string;\n /** Target bitrate. 32000–64000 is plenty for speech in Opus. */\n audioBitsPerSecond?: number;\n /**\n * Emit a chunk every N ms through `onChunk`, for streaming upload.\n *\n * Without it the whole recording is buffered in memory until `stop()` — fine for\n * a voice note, not fine for an hour-long meeting.\n */\n timesliceMs?: number;\n /** Receives each chunk when `timesliceMs` is set. Chunks are **not** independently playable. */\n onChunk?: (chunk: Blob) => void;\n /** Recorder-level failure (device unplugged mid-recording, encoder error). */\n onError?: (error: unknown) => void;\n}\n\n/** Imperative recorder. */\nexport interface AudioRecorderHandle {\n /** Begin recording. No-op when already recording or paused. */\n start: () => void;\n /** Pause. The clock stops; `durationMs` freezes. */\n pause: () => void;\n /** Resume after `pause()`. */\n resume: () => void;\n /** Stop and resolve with the assembled recording. */\n stop: () => Promise<AudioRecording>;\n /** Stop and throw the audio away. */\n cancel: () => void;\n status: () => AudioRecorderStatus;\n /** Recorded length so far, excluding paused time. */\n durationMs: () => number;\n /** The negotiated container. */\n mimeType: string;\n}\n\n/** Whether `MediaRecorder` exists and can produce at least one audio container. */\nexport function isAudioRecordingSupported(): boolean {\n return typeof MediaRecorder !== \"undefined\" && pickAudioMimeType() !== null;\n}\n\n/**\n * First container in `preferred` the browser can actually produce, or `null`.\n *\n * **There is no MP3 or WAV here, and that is not an omission.** `MediaRecorder`\n * emits Opus (in WebM or Ogg) on Chromium and Firefox and AAC (in MP4) on Safari —\n * no engine implements an MP3 or WAV encoder for it. If a backend needs WAV,\n * {@link blobToWav} converts one client-side with no dependency; if it needs MP3,\n * transcode on the server. Shipping an MP3 encoder would mean a WASM build of the\n * order of 150 KB in every consumer's bundle to serve one format, which is the\n * trade this SDK does not make.\n *\n * @param preferred - Candidates, best first. Defaults to {@link AUDIO_MIME_CANDIDATES}.\n * @returns A supported MIME type, or `null` when none is.\n */\nexport function pickAudioMimeType(\n preferred: readonly string[] = AUDIO_MIME_CANDIDATES,\n): string | null {\n return pickRecordingMimeType(preferred);\n}\n\n/**\n * Wrap a `MediaStream` in a recorder with a real state machine and an honest clock.\n *\n * The engine is shared with the video recorder (`createMediaRecorder`), because the\n * subtle parts are not audio-specific: `MediaRecorder` reports **no duration** (WebM\n * it writes carries none in its header, which is why `<audio>` shows `Infinity` for a\n * fresh recording) so the clock is kept by hand and subtracts paused time; and\n * `stop()` returns *before* the last `dataavailable` event, so the blob can only be\n * assembled in `onstop`. What stays here is the part that genuinely differs — the\n * container list.\n *\n * The stream is **not** owned here: `stop()` leaves the microphone open so a retake\n * does not need a second permission round-trip. Release it with the owning\n * `useMicrophone().stop()`.\n *\n * @param stream - A live audio stream, usually from {@link useMicrophone}.\n * @param options - See {@link AudioRecorderOptions}.\n * @returns The imperative recorder.\n * @throws When `MediaRecorder` is unavailable, or an explicit `mimeType` is unsupported.\n */\nexport function createAudioRecorder(\n stream: MediaStream,\n options: AudioRecorderOptions = {},\n): AudioRecorderHandle {\n return createMediaRecorder(stream, {\n candidates: AUDIO_MIME_CANDIDATES,\n kind: \"audio\",\n mimeType: options.mimeType,\n audioBitsPerSecond: options.audioBitsPerSecond,\n timesliceMs: options.timesliceMs,\n onChunk: options.onChunk,\n onError: options.onError,\n });\n}\n"],"mappings":";;AAuBA,
|
|
1
|
+
{"version":3,"file":"audio-recorder.js","names":["AUDIO_MIME_CANDIDATES","isAudioRecordingSupported","pickAudioMimeType","pickRecordingMimeType","preferred","createAudioRecorder","createMediaRecorder","stream","options"],"sources":["../../src/audio/audio-recorder.ts"],"sourcesContent":["import {\n createMediaRecorder,\n pickRecordingMimeType,\n type MediaRecorderStatus,\n} from \"@/capture/media-recorder\";\n\n/** Lifecycle of a recording. Shared with the video recorder — the states are the same. */\nexport type AudioRecorderStatus = MediaRecorderStatus;\n\n/**\n * Container/codec candidates, best first.\n *\n * No browser supports all of these, and none supports MP3 or WAV from\n * `MediaRecorder` — see the note on {@link pickAudioMimeType}. Opus in WebM is the\n * first choice because it is the smallest at speech bitrates and is what Chromium\n * and Firefox produce natively; `audio/mp4` is here for Safari, which produces AAC\n * and nothing else.\n *\n * Ported from the intersection of what `MediaRecorder.isTypeSupported` accepts in\n * Chrome 120+, Firefox 115+ and Safari 17. Re-check against\n * <https://developer.mozilla.org/docs/Web/API/MediaRecorder/isTypeSupported> before\n * adding to the list.\n */\nexport const AUDIO_MIME_CANDIDATES: readonly string[] = [\n \"audio/webm;codecs=opus\",\n \"audio/webm\",\n \"audio/ogg;codecs=opus\",\n \"audio/mp4;codecs=mp4a.40.2\",\n \"audio/mp4\",\n];\n\n/** A finished recording. */\nexport interface AudioRecording {\n /** The audio. Wrap with `useObjectUrl` to play it, or POST it as-is. */\n blob: Blob;\n /** What the browser actually produced — not necessarily what you asked for. */\n mimeType: string;\n /** Recorded length, excluding time spent paused. */\n durationMs: number;\n}\n\n/** Options for {@link createAudioRecorder}. */\nexport interface AudioRecorderOptions {\n /**\n * Force a container. Throws when the browser cannot produce it.\n *\n * Leave it out. The default negotiates from {@link AUDIO_MIME_CANDIDATES}, which\n * is the only way one call site works on both Chromium and Safari.\n */\n mimeType?: string;\n /** Target bitrate. 32000–64000 is plenty for speech in Opus. */\n audioBitsPerSecond?: number;\n /**\n * Emit a chunk every N ms through `onChunk`, for streaming upload.\n *\n * Without it the whole recording is buffered in memory until `stop()` — fine for\n * a voice note, not fine for an hour-long meeting.\n */\n timesliceMs?: number;\n /** Receives each chunk when `timesliceMs` is set. Chunks are **not** independently playable. */\n onChunk?: (chunk: Blob) => void;\n /** Recorder-level failure (device unplugged mid-recording, encoder error). */\n onError?: (error: unknown) => void;\n}\n\n/** Imperative recorder. */\nexport interface AudioRecorderHandle {\n /** Begin recording. No-op when already recording or paused. */\n start: () => void;\n /** Pause. The clock stops; `durationMs` freezes. */\n pause: () => void;\n /** Resume after `pause()`. */\n resume: () => void;\n /** Stop and resolve with the assembled recording. */\n stop: () => Promise<AudioRecording>;\n /** Stop and throw the audio away. */\n cancel: () => void;\n status: () => AudioRecorderStatus;\n /** Recorded length so far, excluding paused time. */\n durationMs: () => number;\n /** The negotiated container. */\n mimeType: string;\n}\n\n/** Whether `MediaRecorder` exists and can produce at least one audio container. */\nexport function isAudioRecordingSupported(): boolean {\n return typeof MediaRecorder !== \"undefined\" && pickAudioMimeType() !== null;\n}\n\n/**\n * First container in `preferred` the browser can actually produce, or `null`.\n *\n * **There is no MP3 or WAV here, and that is not an omission.** `MediaRecorder`\n * emits Opus (in WebM or Ogg) on Chromium and Firefox and AAC (in MP4) on Safari —\n * no engine implements an MP3 or WAV encoder for it. If a backend needs WAV,\n * {@link blobToWav} converts one client-side with no dependency; if it needs MP3,\n * transcode on the server. Shipping an MP3 encoder would mean a WASM build of the\n * order of 150 KB in every consumer's bundle to serve one format, which is the\n * trade this SDK does not make.\n *\n * @param preferred - Candidates, best first. Defaults to {@link AUDIO_MIME_CANDIDATES}.\n * @returns A supported MIME type, or `null` when none is.\n */\nexport function pickAudioMimeType(\n preferred: readonly string[] = AUDIO_MIME_CANDIDATES,\n): string | null {\n return pickRecordingMimeType(preferred);\n}\n\n/**\n * Wrap a `MediaStream` in a recorder with a real state machine and an honest clock.\n *\n * The engine is shared with the video recorder (`createMediaRecorder`), because the\n * subtle parts are not audio-specific: `MediaRecorder` reports **no duration** (WebM\n * it writes carries none in its header, which is why `<audio>` shows `Infinity` for a\n * fresh recording) so the clock is kept by hand and subtracts paused time; and\n * `stop()` returns *before* the last `dataavailable` event, so the blob can only be\n * assembled in `onstop`. What stays here is the part that genuinely differs — the\n * container list.\n *\n * The stream is **not** owned here: `stop()` leaves the microphone open so a retake\n * does not need a second permission round-trip. Release it with the owning\n * `useMicrophone().stop()`.\n *\n * @param stream - A live audio stream, usually from {@link useMicrophone}.\n * @param options - See {@link AudioRecorderOptions}.\n * @returns The imperative recorder.\n * @throws When `MediaRecorder` is unavailable, or an explicit `mimeType` is unsupported.\n */\nexport function createAudioRecorder(\n stream: MediaStream,\n options: AudioRecorderOptions = {},\n): AudioRecorderHandle {\n return createMediaRecorder(stream, {\n candidates: AUDIO_MIME_CANDIDATES,\n kind: \"audio\",\n mimeType: options.mimeType,\n audioBitsPerSecond: options.audioBitsPerSecond,\n timesliceMs: options.timesliceMs,\n onChunk: options.onChunk,\n onError: options.onError,\n });\n}\n"],"mappings":";;AAuBA,IAAaA,IAA2C;CACpD;CACA;CACA;CACA;CACA;AACJ;AAwDA,SAAgBC,IAAqC;CACjD,OAAO,OAAO,gBAAkB,OAAeC,EAAkB,MAAM;AAC3E;AAgBA,SAAgBA,EACZ,IAA+BF,GAClB;CACb,OAAOG,EAAsBC,CAAS;AAC1C;AAsBA,SAAgBC,EACZ,GACA,IAAgC,CAAC,GACd;CACnB,OAAOC,EAAoBC,GAAQ;EAC/B,YAAYP;EACZ,MAAM;EACN,UAAUQ,EAAQ;EAClB,oBAAoBA,EAAQ;EAC5B,aAAaA,EAAQ;EACrB,SAASA,EAAQ;EACjB,SAASA,EAAQ;CACrB,CAAC;AACL"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"duration.cjs","names":[],"sources":["../../src/audio/duration.ts"],"sourcesContent":["/**\n * Format a length in milliseconds as a clock: `0:07`, `2:41`, `1:03:12`.\n *\n * Returns `\"--:--\"` for anything not finite, which is the case that matters: a fresh\n * `MediaRecorder` WebM carries no duration in its header, so `<audio>.duration` reads\n * `Infinity` until the browser has been coaxed into resolving it. Rendering `NaN:aN`\n * there is the bug every home-made audio player ships with.\n *\n * The hour field appears only when there is one, so a voice note reads `0:07` rather\n * than `0:00:07`.\n *\n * @param ms - Length in milliseconds, or a non-finite value for \"unknown\".\n * @returns A clock string.\n */\nexport function formatDuration(ms: number): string {\n if (!Number.isFinite(ms) || ms < 0) return \"--:--\";\n const total = Math.floor(ms / 1000);\n const seconds = total % 60;\n const minutes = Math.floor(total / 60) % 60;\n const hours = Math.floor(total / 3600);\n const pad = (value: number): string => String(value).padStart(2, \"0\");\n return hours > 0 ? `${hours}:${pad(minutes)}:${pad(seconds)}` : `${minutes}:${pad(seconds)}`;\n}\n"],"mappings":"AAcA,
|
|
1
|
+
{"version":3,"file":"duration.cjs","names":["formatDuration","ms","total","seconds","minutes","hours","pad","value"],"sources":["../../src/audio/duration.ts"],"sourcesContent":["/**\n * Format a length in milliseconds as a clock: `0:07`, `2:41`, `1:03:12`.\n *\n * Returns `\"--:--\"` for anything not finite, which is the case that matters: a fresh\n * `MediaRecorder` WebM carries no duration in its header, so `<audio>.duration` reads\n * `Infinity` until the browser has been coaxed into resolving it. Rendering `NaN:aN`\n * there is the bug every home-made audio player ships with.\n *\n * The hour field appears only when there is one, so a voice note reads `0:07` rather\n * than `0:00:07`.\n *\n * @param ms - Length in milliseconds, or a non-finite value for \"unknown\".\n * @returns A clock string.\n */\nexport function formatDuration(ms: number): string {\n if (!Number.isFinite(ms) || ms < 0) return \"--:--\";\n const total = Math.floor(ms / 1000);\n const seconds = total % 60;\n const minutes = Math.floor(total / 60) % 60;\n const hours = Math.floor(total / 3600);\n const pad = (value: number): string => String(value).padStart(2, \"0\");\n return hours > 0 ? `${hours}:${pad(minutes)}:${pad(seconds)}` : `${minutes}:${pad(seconds)}`;\n}\n"],"mappings":"AAcA,SAAgBA,EAAe,EAAoB,CAC/C,GAAI,CAAC,OAAO,SAASC,CAAE,GAAKA,EAAK,EAAG,MAAO,QAC3C,IAAMC,EAAQ,KAAK,MAAMD,EAAK,GAAI,EAC5BE,EAAUD,EAAQ,GAClBE,EAAU,KAAK,MAAMF,EAAQ,EAAE,EAAI,GACnCG,EAAQ,KAAK,MAAMH,EAAQ,IAAI,EAC/BI,EAAO,GAA0B,OAAOC,CAAK,CAAC,CAAC,SAAS,EAAG,GAAG,EACpE,OAAOF,EAAQ,EAAI,GAAGA,EAAM,GAAGC,EAAIF,CAAO,EAAE,GAAGE,EAAIH,CAAO,IAAM,GAAGC,EAAQ,GAAGE,EAAIH,CAAO,GAC7F,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"duration.js","names":[],"sources":["../../src/audio/duration.ts"],"sourcesContent":["/**\n * Format a length in milliseconds as a clock: `0:07`, `2:41`, `1:03:12`.\n *\n * Returns `\"--:--\"` for anything not finite, which is the case that matters: a fresh\n * `MediaRecorder` WebM carries no duration in its header, so `<audio>.duration` reads\n * `Infinity` until the browser has been coaxed into resolving it. Rendering `NaN:aN`\n * there is the bug every home-made audio player ships with.\n *\n * The hour field appears only when there is one, so a voice note reads `0:07` rather\n * than `0:00:07`.\n *\n * @param ms - Length in milliseconds, or a non-finite value for \"unknown\".\n * @returns A clock string.\n */\nexport function formatDuration(ms: number): string {\n if (!Number.isFinite(ms) || ms < 0) return \"--:--\";\n const total = Math.floor(ms / 1000);\n const seconds = total % 60;\n const minutes = Math.floor(total / 60) % 60;\n const hours = Math.floor(total / 3600);\n const pad = (value: number): string => String(value).padStart(2, \"0\");\n return hours > 0 ? `${hours}:${pad(minutes)}:${pad(seconds)}` : `${minutes}:${pad(seconds)}`;\n}\n"],"mappings":";AAcA,
|
|
1
|
+
{"version":3,"file":"duration.js","names":["formatDuration","ms","total","seconds","minutes","hours","pad","value"],"sources":["../../src/audio/duration.ts"],"sourcesContent":["/**\n * Format a length in milliseconds as a clock: `0:07`, `2:41`, `1:03:12`.\n *\n * Returns `\"--:--\"` for anything not finite, which is the case that matters: a fresh\n * `MediaRecorder` WebM carries no duration in its header, so `<audio>.duration` reads\n * `Infinity` until the browser has been coaxed into resolving it. Rendering `NaN:aN`\n * there is the bug every home-made audio player ships with.\n *\n * The hour field appears only when there is one, so a voice note reads `0:07` rather\n * than `0:00:07`.\n *\n * @param ms - Length in milliseconds, or a non-finite value for \"unknown\".\n * @returns A clock string.\n */\nexport function formatDuration(ms: number): string {\n if (!Number.isFinite(ms) || ms < 0) return \"--:--\";\n const total = Math.floor(ms / 1000);\n const seconds = total % 60;\n const minutes = Math.floor(total / 60) % 60;\n const hours = Math.floor(total / 3600);\n const pad = (value: number): string => String(value).padStart(2, \"0\");\n return hours > 0 ? `${hours}:${pad(minutes)}:${pad(seconds)}` : `${minutes}:${pad(seconds)}`;\n}\n"],"mappings":";AAcA,SAAgBA,EAAe,GAAoB;CAC/C,IAAI,CAAC,OAAO,SAASC,CAAE,KAAKA,IAAK,GAAG,OAAO;CAC3C,IAAMC,IAAQ,KAAK,MAAMD,IAAK,GAAI,GAC5BE,IAAUD,IAAQ,IAClBE,IAAU,KAAK,MAAMF,IAAQ,EAAE,IAAI,IACnCG,IAAQ,KAAK,MAAMH,IAAQ,IAAI,GAC/BI,KAAO,MAA0B,OAAOC,CAAK,CAAC,CAAC,SAAS,GAAG,GAAG;CACpE,OAAOF,IAAQ,IAAI,GAAGA,EAAM,GAAGC,EAAIF,CAAO,EAAE,GAAGE,EAAIH,CAAO,MAAM,GAAGC,EAAQ,GAAGE,EAAIH,CAAO;AAC7F"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"level-meter.cjs","names":[],"sources":["../../src/audio/level-meter.ts"],"sourcesContent":["/** Options for {@link createLevelMeter}. */\nexport interface LevelMeterOptions {\n /**\n * FFT window. 1024 is a good default: ~21 ms at 48 kHz, long enough to be stable\n * and short enough to react to a syllable.\n */\n fftSize?: number;\n /**\n * Extra smoothing on the way down, 0–1. Default `0.7`.\n *\n * A raw RMS reading is jittery enough to make a meter look broken. Attack is left\n * instant — a meter that lags the voice going *up* reads as \"not recording\" —\n * while the decay is eased, which is how every hardware meter behaves.\n *\n * `0` turns the smoothing off and reports the window's RMS as measured, which is\n * what a detector wants: {@link monitorVoiceActivity} applies its own release,\n * and two of them stacked would hold the indicator open long past the speech.\n */\n decay?: number;\n /**\n * Reuse an existing `AudioContext` instead of creating one.\n *\n * Browsers cap live contexts (Chrome allows around six), and a meter per remote\n * participant reaches that in a five-person call. A caller measuring several\n * streams should open one context and hand it to every meter. `stop()` closes\n * only a context this meter created — an injected one belongs to the caller.\n */\n context?: AudioContext;\n}\n\n/** A running level meter. */\nexport interface LevelMeter {\n /** Latest level, 0–1. Read it on your own frame loop. */\n level: () => number;\n /** Stop sampling and release the Web Audio graph. */\n stop: () => void;\n}\n\n/**\n * Sample the loudness of a live stream, 0–1.\n *\n * This exists because a recorder with no visible level is indistinguishable from a\n * broken one. A muted OS input, a headset whose mic arm is switched off, the wrong\n * device selected — all three produce a perfectly successful recording of silence,\n * and the user only finds out after they finish talking.\n *\n * The value is RMS, not peak: peak reacts to a single sample and flickers, RMS tracks\n * perceived loudness. It is deliberately **not** React state — updating state per\n * frame would re-render the tree 60 times a second. Poll `level()` from a\n * `requestAnimationFrame` loop and write to the DOM, or read it inside an existing\n * animation.\n *\n * The `AudioContext` is created here and closed by `stop()`. Browsers cap the number\n * of live contexts (Chrome allows around six), so a meter left running on unmount\n * eventually breaks every later one on the page.\n *\n * `level()` applies instant attack and eased release: a value above the current one\n * is taken as is, a lower one decays by `decay`. A meter that fell as fast as it rose\n * reads as noise instead of as loudness.\n *\n * @tempest-limits empty-catch — `stop()` disconnects nodes whose context may already\n * be closed (the tab was backgrounded, the stream's track ended, `stop()` raced an\n * unmount), and a disconnect on a dead graph throws. There is nothing to report and\n * nothing to retry: the resource this call would have released is already gone, and\n * the `context.close()` right after it is what actually matters.\n *\n * @param stream - A live audio stream.\n * @param options - See {@link LevelMeterOptions}.\n * @returns A `level()` reader and a `stop()`.\n *\n * @example\n * const meter = createLevelMeter(stream);\n * const tick = () => { bar.style.transform = `scaleX(${meter.level()})`; raf = requestAnimationFrame(tick); };\n */\nexport function createLevelMeter(\n stream: MediaStream,\n { fftSize = 1024, decay = 0.7, context: injectedContext }: LevelMeterOptions = {},\n): LevelMeter {\n const Ctor: typeof AudioContext | undefined =\n typeof AudioContext !== \"undefined\"\n ? AudioContext\n : (globalThis as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n\n if (!injectedContext && !Ctor) {\n return { level: () => 0, stop: () => undefined };\n }\n\n const context = injectedContext ?? new (Ctor as typeof AudioContext)();\n const source = context.createMediaStreamSource(stream);\n const analyser = context.createAnalyser();\n analyser.fftSize = fftSize;\n source.connect(analyser);\n\n const samples = new Float32Array(analyser.fftSize);\n let smoothed = 0;\n let closed = false;\n\n const read = (): number => {\n if (closed) return 0;\n analyser.getFloatTimeDomainData(samples);\n let sum = 0;\n for (let index = 0; index < samples.length; index += 1) {\n sum += samples[index] * samples[index];\n }\n const rms = Math.sqrt(sum / samples.length);\n smoothed = rms > smoothed ? rms : smoothed * decay + rms * (1 - decay);\n return Math.min(1, smoothed);\n };\n\n return {\n level: read,\n stop: (): void => {\n if (closed) return;\n closed = true;\n try {\n source.disconnect();\n analyser.disconnect();\n } catch {\n /* empty */\n }\n if (!injectedContext) void context.close().catch(() => undefined);\n },\n };\n}\n"],"mappings":"AA0EA,
|
|
1
|
+
{"version":3,"file":"level-meter.cjs","names":["createLevelMeter","injectedContext","Ctor","context","source","stream","analyser","fftSize","samples","smoothed","closed","sum","index","rms","decay"],"sources":["../../src/audio/level-meter.ts"],"sourcesContent":["/** Options for {@link createLevelMeter}. */\nexport interface LevelMeterOptions {\n /**\n * FFT window. 1024 is a good default: ~21 ms at 48 kHz, long enough to be stable\n * and short enough to react to a syllable.\n */\n fftSize?: number;\n /**\n * Extra smoothing on the way down, 0–1. Default `0.7`.\n *\n * A raw RMS reading is jittery enough to make a meter look broken. Attack is left\n * instant — a meter that lags the voice going *up* reads as \"not recording\" —\n * while the decay is eased, which is how every hardware meter behaves.\n *\n * `0` turns the smoothing off and reports the window's RMS as measured, which is\n * what a detector wants: {@link monitorVoiceActivity} applies its own release,\n * and two of them stacked would hold the indicator open long past the speech.\n */\n decay?: number;\n /**\n * Reuse an existing `AudioContext` instead of creating one.\n *\n * Browsers cap live contexts (Chrome allows around six), and a meter per remote\n * participant reaches that in a five-person call. A caller measuring several\n * streams should open one context and hand it to every meter. `stop()` closes\n * only a context this meter created — an injected one belongs to the caller.\n */\n context?: AudioContext;\n}\n\n/** A running level meter. */\nexport interface LevelMeter {\n /** Latest level, 0–1. Read it on your own frame loop. */\n level: () => number;\n /** Stop sampling and release the Web Audio graph. */\n stop: () => void;\n}\n\n/**\n * Sample the loudness of a live stream, 0–1.\n *\n * This exists because a recorder with no visible level is indistinguishable from a\n * broken one. A muted OS input, a headset whose mic arm is switched off, the wrong\n * device selected — all three produce a perfectly successful recording of silence,\n * and the user only finds out after they finish talking.\n *\n * The value is RMS, not peak: peak reacts to a single sample and flickers, RMS tracks\n * perceived loudness. It is deliberately **not** React state — updating state per\n * frame would re-render the tree 60 times a second. Poll `level()` from a\n * `requestAnimationFrame` loop and write to the DOM, or read it inside an existing\n * animation.\n *\n * The `AudioContext` is created here and closed by `stop()`. Browsers cap the number\n * of live contexts (Chrome allows around six), so a meter left running on unmount\n * eventually breaks every later one on the page.\n *\n * `level()` applies instant attack and eased release: a value above the current one\n * is taken as is, a lower one decays by `decay`. A meter that fell as fast as it rose\n * reads as noise instead of as loudness.\n *\n * @tempest-limits empty-catch — `stop()` disconnects nodes whose context may already\n * be closed (the tab was backgrounded, the stream's track ended, `stop()` raced an\n * unmount), and a disconnect on a dead graph throws. There is nothing to report and\n * nothing to retry: the resource this call would have released is already gone, and\n * the `context.close()` right after it is what actually matters.\n *\n * @param stream - A live audio stream.\n * @param options - See {@link LevelMeterOptions}.\n * @returns A `level()` reader and a `stop()`.\n *\n * @example\n * const meter = createLevelMeter(stream);\n * const tick = () => { bar.style.transform = `scaleX(${meter.level()})`; raf = requestAnimationFrame(tick); };\n */\nexport function createLevelMeter(\n stream: MediaStream,\n { fftSize = 1024, decay = 0.7, context: injectedContext }: LevelMeterOptions = {},\n): LevelMeter {\n const Ctor: typeof AudioContext | undefined =\n typeof AudioContext !== \"undefined\"\n ? AudioContext\n : (globalThis as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n\n if (!injectedContext && !Ctor) {\n return { level: () => 0, stop: () => undefined };\n }\n\n const context = injectedContext ?? new (Ctor as typeof AudioContext)();\n const source = context.createMediaStreamSource(stream);\n const analyser = context.createAnalyser();\n analyser.fftSize = fftSize;\n source.connect(analyser);\n\n const samples = new Float32Array(analyser.fftSize);\n let smoothed = 0;\n let closed = false;\n\n const read = (): number => {\n if (closed) return 0;\n analyser.getFloatTimeDomainData(samples);\n let sum = 0;\n for (let index = 0; index < samples.length; index += 1) {\n sum += samples[index] * samples[index];\n }\n const rms = Math.sqrt(sum / samples.length);\n smoothed = rms > smoothed ? rms : smoothed * decay + rms * (1 - decay);\n return Math.min(1, smoothed);\n };\n\n return {\n level: read,\n stop: (): void => {\n if (closed) return;\n closed = true;\n try {\n source.disconnect();\n analyser.disconnect();\n } catch {\n /* empty */\n }\n if (!injectedContext) void context.close().catch(() => undefined);\n },\n };\n}\n"],"mappings":"AA0EA,SAAgBA,EACZ,EACA,CAAE,UAAU,KAAM,QAAQ,GAAK,QAASC,GAAuC,CAAC,EACtE,CACV,IAAMC,EACF,OAAO,aAAiB,IAClB,aACC,WAA4D,mBAEvE,GAAI,CAACD,GAAmB,CAACC,EACrB,MAAO,CAAE,UAAa,EAAG,SAAY,IAAA,EAAU,EAGnD,IAAMC,EAAUF,GAAmB,IAAKC,EAClCE,EAASD,EAAQ,wBAAwBE,CAAM,EAC/CC,EAAWH,EAAQ,eAAe,EACxC,EAAS,QAAUI,EACnBH,EAAO,QAAQE,CAAQ,EAEvB,IAAME,EAAU,IAAI,aAAaF,EAAS,OAAO,EAC7CG,EAAW,EACXC,EAAS,GAcb,MAAO,CACH,UAbuB,CACvB,GAAIA,EAAQ,MAAO,GACnBJ,EAAS,uBAAuBE,CAAO,EACvC,IAAIG,EAAM,EACV,IAAK,IAAIC,EAAQ,EAAGA,EAAQJ,EAAQ,OAAQ,GAAS,EACjD,GAAOA,EAAQI,GAASJ,EAAQI,GAEpC,IAAMC,EAAM,KAAK,KAAKF,EAAMH,EAAQ,MAAM,EAE1C,MADA,GAAWK,EAAMJ,EAAWI,EAAMJ,EAAWK,EAAQD,GAAO,EAAIC,GACzD,KAAK,IAAI,EAAGL,CAAQ,CAC/B,EAII,SAAkB,CACd,GAAI,GACJ,GAAS,GACT,GAAI,CACAL,EAAO,WAAW,EAClBE,EAAS,WAAW,CACxB,MAAQ,CAER,CACKL,GAAiBE,EAAa,MAAM,CAAC,CAAC,UAAY,IAAA,EAAS,CAPvD,CAQb,CACJ,CACJ,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"level-meter.js","names":[],"sources":["../../src/audio/level-meter.ts"],"sourcesContent":["/** Options for {@link createLevelMeter}. */\nexport interface LevelMeterOptions {\n /**\n * FFT window. 1024 is a good default: ~21 ms at 48 kHz, long enough to be stable\n * and short enough to react to a syllable.\n */\n fftSize?: number;\n /**\n * Extra smoothing on the way down, 0–1. Default `0.7`.\n *\n * A raw RMS reading is jittery enough to make a meter look broken. Attack is left\n * instant — a meter that lags the voice going *up* reads as \"not recording\" —\n * while the decay is eased, which is how every hardware meter behaves.\n *\n * `0` turns the smoothing off and reports the window's RMS as measured, which is\n * what a detector wants: {@link monitorVoiceActivity} applies its own release,\n * and two of them stacked would hold the indicator open long past the speech.\n */\n decay?: number;\n /**\n * Reuse an existing `AudioContext` instead of creating one.\n *\n * Browsers cap live contexts (Chrome allows around six), and a meter per remote\n * participant reaches that in a five-person call. A caller measuring several\n * streams should open one context and hand it to every meter. `stop()` closes\n * only a context this meter created — an injected one belongs to the caller.\n */\n context?: AudioContext;\n}\n\n/** A running level meter. */\nexport interface LevelMeter {\n /** Latest level, 0–1. Read it on your own frame loop. */\n level: () => number;\n /** Stop sampling and release the Web Audio graph. */\n stop: () => void;\n}\n\n/**\n * Sample the loudness of a live stream, 0–1.\n *\n * This exists because a recorder with no visible level is indistinguishable from a\n * broken one. A muted OS input, a headset whose mic arm is switched off, the wrong\n * device selected — all three produce a perfectly successful recording of silence,\n * and the user only finds out after they finish talking.\n *\n * The value is RMS, not peak: peak reacts to a single sample and flickers, RMS tracks\n * perceived loudness. It is deliberately **not** React state — updating state per\n * frame would re-render the tree 60 times a second. Poll `level()` from a\n * `requestAnimationFrame` loop and write to the DOM, or read it inside an existing\n * animation.\n *\n * The `AudioContext` is created here and closed by `stop()`. Browsers cap the number\n * of live contexts (Chrome allows around six), so a meter left running on unmount\n * eventually breaks every later one on the page.\n *\n * `level()` applies instant attack and eased release: a value above the current one\n * is taken as is, a lower one decays by `decay`. A meter that fell as fast as it rose\n * reads as noise instead of as loudness.\n *\n * @tempest-limits empty-catch — `stop()` disconnects nodes whose context may already\n * be closed (the tab was backgrounded, the stream's track ended, `stop()` raced an\n * unmount), and a disconnect on a dead graph throws. There is nothing to report and\n * nothing to retry: the resource this call would have released is already gone, and\n * the `context.close()` right after it is what actually matters.\n *\n * @param stream - A live audio stream.\n * @param options - See {@link LevelMeterOptions}.\n * @returns A `level()` reader and a `stop()`.\n *\n * @example\n * const meter = createLevelMeter(stream);\n * const tick = () => { bar.style.transform = `scaleX(${meter.level()})`; raf = requestAnimationFrame(tick); };\n */\nexport function createLevelMeter(\n stream: MediaStream,\n { fftSize = 1024, decay = 0.7, context: injectedContext }: LevelMeterOptions = {},\n): LevelMeter {\n const Ctor: typeof AudioContext | undefined =\n typeof AudioContext !== \"undefined\"\n ? AudioContext\n : (globalThis as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n\n if (!injectedContext && !Ctor) {\n return { level: () => 0, stop: () => undefined };\n }\n\n const context = injectedContext ?? new (Ctor as typeof AudioContext)();\n const source = context.createMediaStreamSource(stream);\n const analyser = context.createAnalyser();\n analyser.fftSize = fftSize;\n source.connect(analyser);\n\n const samples = new Float32Array(analyser.fftSize);\n let smoothed = 0;\n let closed = false;\n\n const read = (): number => {\n if (closed) return 0;\n analyser.getFloatTimeDomainData(samples);\n let sum = 0;\n for (let index = 0; index < samples.length; index += 1) {\n sum += samples[index] * samples[index];\n }\n const rms = Math.sqrt(sum / samples.length);\n smoothed = rms > smoothed ? rms : smoothed * decay + rms * (1 - decay);\n return Math.min(1, smoothed);\n };\n\n return {\n level: read,\n stop: (): void => {\n if (closed) return;\n closed = true;\n try {\n source.disconnect();\n analyser.disconnect();\n } catch {\n /* empty */\n }\n if (!injectedContext) void context.close().catch(() => undefined);\n },\n };\n}\n"],"mappings":";AA0EA,
|
|
1
|
+
{"version":3,"file":"level-meter.js","names":["createLevelMeter","injectedContext","Ctor","context","source","stream","analyser","fftSize","samples","smoothed","closed","sum","index","rms","decay"],"sources":["../../src/audio/level-meter.ts"],"sourcesContent":["/** Options for {@link createLevelMeter}. */\nexport interface LevelMeterOptions {\n /**\n * FFT window. 1024 is a good default: ~21 ms at 48 kHz, long enough to be stable\n * and short enough to react to a syllable.\n */\n fftSize?: number;\n /**\n * Extra smoothing on the way down, 0–1. Default `0.7`.\n *\n * A raw RMS reading is jittery enough to make a meter look broken. Attack is left\n * instant — a meter that lags the voice going *up* reads as \"not recording\" —\n * while the decay is eased, which is how every hardware meter behaves.\n *\n * `0` turns the smoothing off and reports the window's RMS as measured, which is\n * what a detector wants: {@link monitorVoiceActivity} applies its own release,\n * and two of them stacked would hold the indicator open long past the speech.\n */\n decay?: number;\n /**\n * Reuse an existing `AudioContext` instead of creating one.\n *\n * Browsers cap live contexts (Chrome allows around six), and a meter per remote\n * participant reaches that in a five-person call. A caller measuring several\n * streams should open one context and hand it to every meter. `stop()` closes\n * only a context this meter created — an injected one belongs to the caller.\n */\n context?: AudioContext;\n}\n\n/** A running level meter. */\nexport interface LevelMeter {\n /** Latest level, 0–1. Read it on your own frame loop. */\n level: () => number;\n /** Stop sampling and release the Web Audio graph. */\n stop: () => void;\n}\n\n/**\n * Sample the loudness of a live stream, 0–1.\n *\n * This exists because a recorder with no visible level is indistinguishable from a\n * broken one. A muted OS input, a headset whose mic arm is switched off, the wrong\n * device selected — all three produce a perfectly successful recording of silence,\n * and the user only finds out after they finish talking.\n *\n * The value is RMS, not peak: peak reacts to a single sample and flickers, RMS tracks\n * perceived loudness. It is deliberately **not** React state — updating state per\n * frame would re-render the tree 60 times a second. Poll `level()` from a\n * `requestAnimationFrame` loop and write to the DOM, or read it inside an existing\n * animation.\n *\n * The `AudioContext` is created here and closed by `stop()`. Browsers cap the number\n * of live contexts (Chrome allows around six), so a meter left running on unmount\n * eventually breaks every later one on the page.\n *\n * `level()` applies instant attack and eased release: a value above the current one\n * is taken as is, a lower one decays by `decay`. A meter that fell as fast as it rose\n * reads as noise instead of as loudness.\n *\n * @tempest-limits empty-catch — `stop()` disconnects nodes whose context may already\n * be closed (the tab was backgrounded, the stream's track ended, `stop()` raced an\n * unmount), and a disconnect on a dead graph throws. There is nothing to report and\n * nothing to retry: the resource this call would have released is already gone, and\n * the `context.close()` right after it is what actually matters.\n *\n * @param stream - A live audio stream.\n * @param options - See {@link LevelMeterOptions}.\n * @returns A `level()` reader and a `stop()`.\n *\n * @example\n * const meter = createLevelMeter(stream);\n * const tick = () => { bar.style.transform = `scaleX(${meter.level()})`; raf = requestAnimationFrame(tick); };\n */\nexport function createLevelMeter(\n stream: MediaStream,\n { fftSize = 1024, decay = 0.7, context: injectedContext }: LevelMeterOptions = {},\n): LevelMeter {\n const Ctor: typeof AudioContext | undefined =\n typeof AudioContext !== \"undefined\"\n ? AudioContext\n : (globalThis as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n\n if (!injectedContext && !Ctor) {\n return { level: () => 0, stop: () => undefined };\n }\n\n const context = injectedContext ?? new (Ctor as typeof AudioContext)();\n const source = context.createMediaStreamSource(stream);\n const analyser = context.createAnalyser();\n analyser.fftSize = fftSize;\n source.connect(analyser);\n\n const samples = new Float32Array(analyser.fftSize);\n let smoothed = 0;\n let closed = false;\n\n const read = (): number => {\n if (closed) return 0;\n analyser.getFloatTimeDomainData(samples);\n let sum = 0;\n for (let index = 0; index < samples.length; index += 1) {\n sum += samples[index] * samples[index];\n }\n const rms = Math.sqrt(sum / samples.length);\n smoothed = rms > smoothed ? rms : smoothed * decay + rms * (1 - decay);\n return Math.min(1, smoothed);\n };\n\n return {\n level: read,\n stop: (): void => {\n if (closed) return;\n closed = true;\n try {\n source.disconnect();\n analyser.disconnect();\n } catch {\n /* empty */\n }\n if (!injectedContext) void context.close().catch(() => undefined);\n },\n };\n}\n"],"mappings":";AA0EA,SAAgBA,EACZ,GACA,EAAE,aAAU,MAAM,WAAQ,IAAK,SAASC,MAAuC,CAAC,GACtE;CACV,IAAMC,IACF,OAAO,eAAiB,MAClB,eACC,WAA4D;CAEvE,IAAI,CAACD,KAAmB,CAACC,GACrB,OAAO;EAAE,aAAa;EAAG,YAAY,KAAA;CAAU;CAGnD,IAAMC,IAAUF,KAAmB,IAAKC,EAA6B,GAC/DE,IAASD,EAAQ,wBAAwBE,CAAM,GAC/CC,IAAWH,EAAQ,eAAe;CAExC,AADA,EAAS,UAAUI,GACnBH,EAAO,QAAQE,CAAQ;CAEvB,IAAME,IAAU,IAAI,aAAaF,EAAS,OAAO,GAC7CG,IAAW,GACXC,IAAS;CAcb,OAAO;EACH,aAbuB;GACvB,IAAIA,GAAQ,OAAO;GACnB,EAAS,uBAAuBF,CAAO;GACvC,IAAIG,IAAM;GACV,KAAK,IAAIC,IAAQ,GAAGA,IAAQJ,EAAQ,QAAQ,KAAS,GACjD,KAAOA,EAAQI,KAASJ,EAAQI;GAEpC,IAAMC,IAAM,KAAK,KAAKF,IAAMH,EAAQ,MAAM;GAE1C,OADA,IAAWK,IAAMJ,IAAWI,IAAMJ,IAAWK,IAAQD,KAAO,IAAIC,IACzD,KAAK,IAAI,GAAGL,CAAQ;EAC/B;EAII,YAAkB;GACd,IAAI,IACJ;QAAS;IACT,IAAI;KAEA,AADAL,EAAO,WAAW,GAClBE,EAAS,WAAW;IACxB,QAAQ,CAER;IACA,AAAKL,KAAiBE,EAAa,MAAM,CAAC,CAAC,YAAY,KAAA,CAAS;GAPvD;EAQb;CACJ;AACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media-access.cjs","names":[],"sources":["../../src/audio/media-access.ts"],"sourcesContent":["/**\n * What a media error is about.\n *\n * `\"screen\"` is not a device in the `getUserMedia` sense — it is what\n * `getDisplayMedia` captures — but it fails through the same `DOMException` names, so\n * it is classified by the same function rather than by a second copy of the table.\n */\nexport type MediaDeviceKindLabel = \"microphone\" | \"camera\" | \"screen\";\n\n/** Classified reason a capture device could not be acquired. */\nexport type MediaAccessErrorKind =\n \"unsupported\" | \"insecure\" | \"permission-denied\" | \"not-found\" | \"in-use\" | \"unknown\";\n\n/** A classified capture error with a human-readable, English message. */\nexport interface MediaAccessError {\n kind: MediaAccessErrorKind;\n message: string;\n}\n\n/** Sentence fragment naming the device, so one classifier serves both. */\nconst NOUN: Record<MediaDeviceKindLabel, string> = {\n microphone: \"Microphone\",\n camera: \"Camera\",\n screen: \"Screen\",\n};\n\n/**\n * Map an unknown `getUserMedia` failure into a {@link MediaAccessError}.\n *\n * The order matters. A missing `navigator.mediaDevices` is almost never \"this\n * browser cannot do audio\" — it is a page served over plain HTTP, where the whole\n * API is simply absent. Reporting `unsupported` there sends the developer looking\n * for a polyfill for a problem an `https://` URL fixes, so the secure-context check\n * runs first and wins.\n *\n * The `DOMException.name` values are then collapsed into kinds an app can actually\n * branch on, because the raw names do not group the way a UI needs them:\n * `NotFoundError` and `OverconstrainedError` both mean \"you will not get a device\n * with these constraints\", and `NotReadableError` and `AbortError` both mean \"the\n * hardware is busy\" — most often another tab of the same app.\n *\n * @param err - Whatever `getUserMedia` (or a device query) rejected with.\n * @param device - Which device was being opened, for the message.\n * @returns A stable kind plus a message safe to show a user.\n */\nexport function classifyMediaError(\n err: unknown,\n device: MediaDeviceKindLabel = \"microphone\",\n): MediaAccessError {\n const noun = NOUN[device];\n\n if (typeof window === \"undefined\") {\n return { kind: \"unsupported\", message: `${noun} is unavailable in this environment.` };\n }\n if (!window.isSecureContext) {\n return {\n kind: \"insecure\",\n message: `${noun} access requires a secure (HTTPS) connection.`,\n };\n }\n if (err instanceof DOMException) {\n switch (err.name) {\n case \"NotAllowedError\":\n case \"SecurityError\":\n return {\n kind: \"permission-denied\",\n message: `${noun} permission denied. Enable access in your browser settings.`,\n };\n case \"NotFoundError\":\n case \"OverconstrainedError\":\n return {\n kind: \"not-found\",\n message: `No ${device} available on this device.`,\n };\n case \"NotReadableError\":\n case \"AbortError\":\n return {\n kind: \"in-use\",\n message: `The ${device} is in use by another app. Close it and try again.`,\n };\n }\n }\n return {\n kind: \"unknown\",\n message:\n err instanceof Error ? err.message : `Unexpected error while accessing the ${device}.`,\n };\n}\n\n/**\n * Whether `getUserMedia` is reachable at all.\n *\n * Separate from the classifier because a page often wants to hide a \"record\" button\n * entirely rather than render it and fail on click.\n */\nexport function isMediaCaptureSupported(): boolean {\n return (\n typeof navigator !== \"undefined\" &&\n navigator.mediaDevices !== undefined &&\n typeof navigator.mediaDevices.getUserMedia === \"function\"\n );\n}\n\n/**\n * The error for \"the API is not here at all\", which is a different question from\n * \"the API rejected\".\n *\n * `classifyMediaError` takes a thrown value; a missing `navigator.mediaDevices` never\n * threw one, and handing it `null` would come back `unknown` — the least actionable\n * kind there is. The two real causes are an insecure page (the fix is a URL) and an\n * engine that genuinely cannot capture (the fix is another browser), and telling them\n * apart is the whole point.\n *\n * @param device - Which device was being opened, for the message.\n */\nexport function missingCaptureApiError(\n device: MediaDeviceKindLabel = \"microphone\",\n): MediaAccessError {\n if (typeof window !== \"undefined\" && !window.isSecureContext) {\n return classifyMediaError(null, device);\n }\n return {\n kind: \"unsupported\",\n message: `${NOUN[device]} capture is not supported in this browser.`,\n };\n}\n"],"mappings":"AAoBA,
|
|
1
|
+
{"version":3,"file":"media-access.cjs","names":["NOUN","classifyMediaError","noun","device","err","isMediaCaptureSupported","missingCaptureApiError"],"sources":["../../src/audio/media-access.ts"],"sourcesContent":["/**\n * What a media error is about.\n *\n * `\"screen\"` is not a device in the `getUserMedia` sense — it is what\n * `getDisplayMedia` captures — but it fails through the same `DOMException` names, so\n * it is classified by the same function rather than by a second copy of the table.\n */\nexport type MediaDeviceKindLabel = \"microphone\" | \"camera\" | \"screen\";\n\n/** Classified reason a capture device could not be acquired. */\nexport type MediaAccessErrorKind =\n \"unsupported\" | \"insecure\" | \"permission-denied\" | \"not-found\" | \"in-use\" | \"unknown\";\n\n/** A classified capture error with a human-readable, English message. */\nexport interface MediaAccessError {\n kind: MediaAccessErrorKind;\n message: string;\n}\n\n/** Sentence fragment naming the device, so one classifier serves both. */\nconst NOUN: Record<MediaDeviceKindLabel, string> = {\n microphone: \"Microphone\",\n camera: \"Camera\",\n screen: \"Screen\",\n};\n\n/**\n * Map an unknown `getUserMedia` failure into a {@link MediaAccessError}.\n *\n * The order matters. A missing `navigator.mediaDevices` is almost never \"this\n * browser cannot do audio\" — it is a page served over plain HTTP, where the whole\n * API is simply absent. Reporting `unsupported` there sends the developer looking\n * for a polyfill for a problem an `https://` URL fixes, so the secure-context check\n * runs first and wins.\n *\n * The `DOMException.name` values are then collapsed into kinds an app can actually\n * branch on, because the raw names do not group the way a UI needs them:\n * `NotFoundError` and `OverconstrainedError` both mean \"you will not get a device\n * with these constraints\", and `NotReadableError` and `AbortError` both mean \"the\n * hardware is busy\" — most often another tab of the same app.\n *\n * @param err - Whatever `getUserMedia` (or a device query) rejected with.\n * @param device - Which device was being opened, for the message.\n * @returns A stable kind plus a message safe to show a user.\n */\nexport function classifyMediaError(\n err: unknown,\n device: MediaDeviceKindLabel = \"microphone\",\n): MediaAccessError {\n const noun = NOUN[device];\n\n if (typeof window === \"undefined\") {\n return { kind: \"unsupported\", message: `${noun} is unavailable in this environment.` };\n }\n if (!window.isSecureContext) {\n return {\n kind: \"insecure\",\n message: `${noun} access requires a secure (HTTPS) connection.`,\n };\n }\n if (err instanceof DOMException) {\n switch (err.name) {\n case \"NotAllowedError\":\n case \"SecurityError\":\n return {\n kind: \"permission-denied\",\n message: `${noun} permission denied. Enable access in your browser settings.`,\n };\n case \"NotFoundError\":\n case \"OverconstrainedError\":\n return {\n kind: \"not-found\",\n message: `No ${device} available on this device.`,\n };\n case \"NotReadableError\":\n case \"AbortError\":\n return {\n kind: \"in-use\",\n message: `The ${device} is in use by another app. Close it and try again.`,\n };\n }\n }\n return {\n kind: \"unknown\",\n message:\n err instanceof Error ? err.message : `Unexpected error while accessing the ${device}.`,\n };\n}\n\n/**\n * Whether `getUserMedia` is reachable at all.\n *\n * Separate from the classifier because a page often wants to hide a \"record\" button\n * entirely rather than render it and fail on click.\n */\nexport function isMediaCaptureSupported(): boolean {\n return (\n typeof navigator !== \"undefined\" &&\n navigator.mediaDevices !== undefined &&\n typeof navigator.mediaDevices.getUserMedia === \"function\"\n );\n}\n\n/**\n * The error for \"the API is not here at all\", which is a different question from\n * \"the API rejected\".\n *\n * `classifyMediaError` takes a thrown value; a missing `navigator.mediaDevices` never\n * threw one, and handing it `null` would come back `unknown` — the least actionable\n * kind there is. The two real causes are an insecure page (the fix is a URL) and an\n * engine that genuinely cannot capture (the fix is another browser), and telling them\n * apart is the whole point.\n *\n * @param device - Which device was being opened, for the message.\n */\nexport function missingCaptureApiError(\n device: MediaDeviceKindLabel = \"microphone\",\n): MediaAccessError {\n if (typeof window !== \"undefined\" && !window.isSecureContext) {\n return classifyMediaError(null, device);\n }\n return {\n kind: \"unsupported\",\n message: `${NOUN[device]} capture is not supported in this browser.`,\n };\n}\n"],"mappings":"AAoBA,IAAMA,EAA6C,CAC/C,WAAY,aACZ,OAAQ,SACR,OAAQ,QACZ,EAqBA,SAAgBC,EACZ,EACA,EAA+B,aACf,CAChB,IAAMC,EAAOF,EAAKG,GAElB,GAAI,OAAO,OAAW,IAClB,MAAO,CAAE,KAAM,cAAe,QAAS,GAAGD,EAAK,qCAAsC,EAEzF,GAAI,CAAC,OAAO,gBACR,MAAO,CACH,KAAM,WACN,QAAS,GAAGA,EAAK,8CACrB,EAEJ,GAAIE,aAAe,aACf,OAAQA,EAAI,KAAZ,CACI,IAAK,kBACL,IAAK,gBACD,MAAO,CACH,KAAM,oBACN,QAAS,GAAGF,EAAK,4DACrB,EACJ,IAAK,gBACL,IAAK,uBACD,MAAO,CACH,KAAM,YACN,QAAS,MAAMC,EAAO,2BAC1B,EACJ,IAAK,mBACL,IAAK,aACD,MAAO,CACH,KAAM,SACN,QAAS,OAAOA,EAAO,mDAC3B,CACR,CAEJ,MAAO,CACH,KAAM,UACN,QACIC,aAAe,MAAQA,EAAI,QAAU,wCAAwCD,EAAO,EAC5F,CACJ,CAQA,SAAgBE,GAAmC,CAC/C,OACI,OAAO,UAAc,KACrB,UAAU,eAAiB,IAAA,IAC3B,OAAO,UAAU,aAAa,cAAiB,UAEvD,CAcA,SAAgBC,EACZ,EAA+B,aACf,CAIhB,OAHI,OAAO,OAAW,KAAe,CAAC,OAAO,gBAClCL,EAAmB,KAAME,CAAM,EAEnC,CACH,KAAM,cACN,QAAS,GAAGH,EAAKG,GAAQ,2CAC7B,CACJ,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media-access.js","names":[],"sources":["../../src/audio/media-access.ts"],"sourcesContent":["/**\n * What a media error is about.\n *\n * `\"screen\"` is not a device in the `getUserMedia` sense — it is what\n * `getDisplayMedia` captures — but it fails through the same `DOMException` names, so\n * it is classified by the same function rather than by a second copy of the table.\n */\nexport type MediaDeviceKindLabel = \"microphone\" | \"camera\" | \"screen\";\n\n/** Classified reason a capture device could not be acquired. */\nexport type MediaAccessErrorKind =\n \"unsupported\" | \"insecure\" | \"permission-denied\" | \"not-found\" | \"in-use\" | \"unknown\";\n\n/** A classified capture error with a human-readable, English message. */\nexport interface MediaAccessError {\n kind: MediaAccessErrorKind;\n message: string;\n}\n\n/** Sentence fragment naming the device, so one classifier serves both. */\nconst NOUN: Record<MediaDeviceKindLabel, string> = {\n microphone: \"Microphone\",\n camera: \"Camera\",\n screen: \"Screen\",\n};\n\n/**\n * Map an unknown `getUserMedia` failure into a {@link MediaAccessError}.\n *\n * The order matters. A missing `navigator.mediaDevices` is almost never \"this\n * browser cannot do audio\" — it is a page served over plain HTTP, where the whole\n * API is simply absent. Reporting `unsupported` there sends the developer looking\n * for a polyfill for a problem an `https://` URL fixes, so the secure-context check\n * runs first and wins.\n *\n * The `DOMException.name` values are then collapsed into kinds an app can actually\n * branch on, because the raw names do not group the way a UI needs them:\n * `NotFoundError` and `OverconstrainedError` both mean \"you will not get a device\n * with these constraints\", and `NotReadableError` and `AbortError` both mean \"the\n * hardware is busy\" — most often another tab of the same app.\n *\n * @param err - Whatever `getUserMedia` (or a device query) rejected with.\n * @param device - Which device was being opened, for the message.\n * @returns A stable kind plus a message safe to show a user.\n */\nexport function classifyMediaError(\n err: unknown,\n device: MediaDeviceKindLabel = \"microphone\",\n): MediaAccessError {\n const noun = NOUN[device];\n\n if (typeof window === \"undefined\") {\n return { kind: \"unsupported\", message: `${noun} is unavailable in this environment.` };\n }\n if (!window.isSecureContext) {\n return {\n kind: \"insecure\",\n message: `${noun} access requires a secure (HTTPS) connection.`,\n };\n }\n if (err instanceof DOMException) {\n switch (err.name) {\n case \"NotAllowedError\":\n case \"SecurityError\":\n return {\n kind: \"permission-denied\",\n message: `${noun} permission denied. Enable access in your browser settings.`,\n };\n case \"NotFoundError\":\n case \"OverconstrainedError\":\n return {\n kind: \"not-found\",\n message: `No ${device} available on this device.`,\n };\n case \"NotReadableError\":\n case \"AbortError\":\n return {\n kind: \"in-use\",\n message: `The ${device} is in use by another app. Close it and try again.`,\n };\n }\n }\n return {\n kind: \"unknown\",\n message:\n err instanceof Error ? err.message : `Unexpected error while accessing the ${device}.`,\n };\n}\n\n/**\n * Whether `getUserMedia` is reachable at all.\n *\n * Separate from the classifier because a page often wants to hide a \"record\" button\n * entirely rather than render it and fail on click.\n */\nexport function isMediaCaptureSupported(): boolean {\n return (\n typeof navigator !== \"undefined\" &&\n navigator.mediaDevices !== undefined &&\n typeof navigator.mediaDevices.getUserMedia === \"function\"\n );\n}\n\n/**\n * The error for \"the API is not here at all\", which is a different question from\n * \"the API rejected\".\n *\n * `classifyMediaError` takes a thrown value; a missing `navigator.mediaDevices` never\n * threw one, and handing it `null` would come back `unknown` — the least actionable\n * kind there is. The two real causes are an insecure page (the fix is a URL) and an\n * engine that genuinely cannot capture (the fix is another browser), and telling them\n * apart is the whole point.\n *\n * @param device - Which device was being opened, for the message.\n */\nexport function missingCaptureApiError(\n device: MediaDeviceKindLabel = \"microphone\",\n): MediaAccessError {\n if (typeof window !== \"undefined\" && !window.isSecureContext) {\n return classifyMediaError(null, device);\n }\n return {\n kind: \"unsupported\",\n message: `${NOUN[device]} capture is not supported in this browser.`,\n };\n}\n"],"mappings":";AAoBA,
|
|
1
|
+
{"version":3,"file":"media-access.js","names":["NOUN","classifyMediaError","noun","device","err","isMediaCaptureSupported","missingCaptureApiError"],"sources":["../../src/audio/media-access.ts"],"sourcesContent":["/**\n * What a media error is about.\n *\n * `\"screen\"` is not a device in the `getUserMedia` sense — it is what\n * `getDisplayMedia` captures — but it fails through the same `DOMException` names, so\n * it is classified by the same function rather than by a second copy of the table.\n */\nexport type MediaDeviceKindLabel = \"microphone\" | \"camera\" | \"screen\";\n\n/** Classified reason a capture device could not be acquired. */\nexport type MediaAccessErrorKind =\n \"unsupported\" | \"insecure\" | \"permission-denied\" | \"not-found\" | \"in-use\" | \"unknown\";\n\n/** A classified capture error with a human-readable, English message. */\nexport interface MediaAccessError {\n kind: MediaAccessErrorKind;\n message: string;\n}\n\n/** Sentence fragment naming the device, so one classifier serves both. */\nconst NOUN: Record<MediaDeviceKindLabel, string> = {\n microphone: \"Microphone\",\n camera: \"Camera\",\n screen: \"Screen\",\n};\n\n/**\n * Map an unknown `getUserMedia` failure into a {@link MediaAccessError}.\n *\n * The order matters. A missing `navigator.mediaDevices` is almost never \"this\n * browser cannot do audio\" — it is a page served over plain HTTP, where the whole\n * API is simply absent. Reporting `unsupported` there sends the developer looking\n * for a polyfill for a problem an `https://` URL fixes, so the secure-context check\n * runs first and wins.\n *\n * The `DOMException.name` values are then collapsed into kinds an app can actually\n * branch on, because the raw names do not group the way a UI needs them:\n * `NotFoundError` and `OverconstrainedError` both mean \"you will not get a device\n * with these constraints\", and `NotReadableError` and `AbortError` both mean \"the\n * hardware is busy\" — most often another tab of the same app.\n *\n * @param err - Whatever `getUserMedia` (or a device query) rejected with.\n * @param device - Which device was being opened, for the message.\n * @returns A stable kind plus a message safe to show a user.\n */\nexport function classifyMediaError(\n err: unknown,\n device: MediaDeviceKindLabel = \"microphone\",\n): MediaAccessError {\n const noun = NOUN[device];\n\n if (typeof window === \"undefined\") {\n return { kind: \"unsupported\", message: `${noun} is unavailable in this environment.` };\n }\n if (!window.isSecureContext) {\n return {\n kind: \"insecure\",\n message: `${noun} access requires a secure (HTTPS) connection.`,\n };\n }\n if (err instanceof DOMException) {\n switch (err.name) {\n case \"NotAllowedError\":\n case \"SecurityError\":\n return {\n kind: \"permission-denied\",\n message: `${noun} permission denied. Enable access in your browser settings.`,\n };\n case \"NotFoundError\":\n case \"OverconstrainedError\":\n return {\n kind: \"not-found\",\n message: `No ${device} available on this device.`,\n };\n case \"NotReadableError\":\n case \"AbortError\":\n return {\n kind: \"in-use\",\n message: `The ${device} is in use by another app. Close it and try again.`,\n };\n }\n }\n return {\n kind: \"unknown\",\n message:\n err instanceof Error ? err.message : `Unexpected error while accessing the ${device}.`,\n };\n}\n\n/**\n * Whether `getUserMedia` is reachable at all.\n *\n * Separate from the classifier because a page often wants to hide a \"record\" button\n * entirely rather than render it and fail on click.\n */\nexport function isMediaCaptureSupported(): boolean {\n return (\n typeof navigator !== \"undefined\" &&\n navigator.mediaDevices !== undefined &&\n typeof navigator.mediaDevices.getUserMedia === \"function\"\n );\n}\n\n/**\n * The error for \"the API is not here at all\", which is a different question from\n * \"the API rejected\".\n *\n * `classifyMediaError` takes a thrown value; a missing `navigator.mediaDevices` never\n * threw one, and handing it `null` would come back `unknown` — the least actionable\n * kind there is. The two real causes are an insecure page (the fix is a URL) and an\n * engine that genuinely cannot capture (the fix is another browser), and telling them\n * apart is the whole point.\n *\n * @param device - Which device was being opened, for the message.\n */\nexport function missingCaptureApiError(\n device: MediaDeviceKindLabel = \"microphone\",\n): MediaAccessError {\n if (typeof window !== \"undefined\" && !window.isSecureContext) {\n return classifyMediaError(null, device);\n }\n return {\n kind: \"unsupported\",\n message: `${NOUN[device]} capture is not supported in this browser.`,\n };\n}\n"],"mappings":";AAoBA,IAAMA,IAA6C;CAC/C,YAAY;CACZ,QAAQ;CACR,QAAQ;AACZ;AAqBA,SAAgBC,EACZ,GACA,IAA+B,cACf;CAChB,IAAMC,IAAOF,EAAKG;CAElB,IAAI,OAAO,SAAW,KAClB,OAAO;EAAE,MAAM;EAAe,SAAS,GAAGD,EAAK;CAAsC;CAEzF,IAAI,CAAC,OAAO,iBACR,OAAO;EACH,MAAM;EACN,SAAS,GAAGA,EAAK;CACrB;CAEJ,IAAIE,aAAe,cACf,QAAQA,EAAI,MAAZ;EACI,KAAK;EACL,KAAK,iBACD,OAAO;GACH,MAAM;GACN,SAAS,GAAGF,EAAK;EACrB;EACJ,KAAK;EACL,KAAK,wBACD,OAAO;GACH,MAAM;GACN,SAAS,MAAMC,EAAO;EAC1B;EACJ,KAAK;EACL,KAAK,cACD,OAAO;GACH,MAAM;GACN,SAAS,OAAOA,EAAO;EAC3B;CACR;CAEJ,OAAO;EACH,MAAM;EACN,SACIC,aAAe,QAAQA,EAAI,UAAU,wCAAwCD,EAAO;CAC5F;AACJ;AAQA,SAAgBE,IAAmC;CAC/C,OACI,OAAO,YAAc,OACrB,UAAU,iBAAiB,KAAA,KAC3B,OAAO,UAAU,aAAa,gBAAiB;AAEvD;AAcA,SAAgBC,EACZ,IAA+B,cACf;CAIhB,OAHI,OAAO,SAAW,OAAe,CAAC,OAAO,kBAClCL,EAAmB,MAAME,CAAM,IAEnC;EACH,MAAM;EACN,SAAS,GAAGH,EAAKG,GAAQ;CAC7B;AACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noise-floor.cjs","names":[],"sources":["../../src/audio/noise-floor.ts"],"sourcesContent":["import { windowRms } from \"./voice-chain-stages\";\n\n/** How long the measurement listens by default, in milliseconds. */\nconst DEFAULT_DURATION_MS = 3000;\n\n/** How often it samples the room, in milliseconds. */\nconst SAMPLE_MS = 50;\n\n/**\n * Headroom over the measured floor, so ordinary speech clears the gate.\n *\n * A gate set exactly at the noise level chatters, opening and closing on the\n * room's own variation. Ported from `tempest-mirror-screen`'s `voiceChain.ts`,\n * where it was arrived at by listening.\n */\nconst GATE_MARGIN = 2.4;\n\n/** The narrowest and widest thresholds worth suggesting. */\nconst GATE_MIN = 0.004;\nconst GATE_MAX = 0.12;\n\n/** Options for {@link measureNoiseFloor}. */\nexport interface NoiseFloorOptions {\n /** Called with `0..1` so a dialog can show the wait. */\n onProgress?: (fraction: number) => void;\n /** How long to listen. Default `3000`. */\n durationMs?: number;\n /** Reuse an existing `AudioContext` rather than opening one. */\n context?: AudioContext;\n}\n\n/** The `AudioContext` constructor this engine exposes, prefixed or not. */\nfunction audioContextConstructor(): typeof AudioContext | undefined {\n if (typeof AudioContext !== \"undefined\") return AudioContext;\n return (globalThis as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n}\n\n/**\n * Listen to a room at rest and report how loud its silence is.\n *\n * The number a person cannot guess. Setting a gate by ear means switching it on\n * and hearing what disappeared, which only works if you already know what should\n * have disappeared — so the usual outcome is leaving it at a default that is\n * wrong for that room. Measuring replaces the guess.\n *\n * The result is the **peak** RMS window observed, not the average: a threshold\n * under the loudest thing the quiet room did will be opened by that thing.\n *\n * @param stream - A live capture of the room while nobody speaks.\n * @param options - See {@link NoiseFloorOptions}.\n * @returns The peak RMS observed, `0..1`. `0` when this engine has no Web Audio\n * or the stream carries no audio track — which {@link suggestGateThreshold}\n * turns into its own floor rather than into a gate that never opens.\n *\n * @example\n * const floor = await measureNoiseFloor(stream, { onProgress: setProgress });\n * setThreshold(suggestGateThreshold(floor));\n */\nexport async function measureNoiseFloor(\n stream: MediaStream,\n {\n onProgress,\n durationMs = DEFAULT_DURATION_MS,\n context: injectedContext,\n }: NoiseFloorOptions = {},\n): Promise<number> {\n const Ctor = audioContextConstructor();\n const context = injectedContext ?? (Ctor ? new Ctor() : null);\n const track = stream.getAudioTracks()[0];\n if (!context || !track) return 0;\n\n const source = context.createMediaStreamSource(stream);\n const analyser = context.createAnalyser();\n analyser.fftSize = 2048;\n source.connect(analyser);\n\n const buffer = new Float32Array(analyser.fftSize);\n const started = performance.now();\n let peak = 0;\n\n await new Promise<void>((resolve) => {\n const timer = setInterval(() => {\n analyser.getFloatTimeDomainData(buffer);\n peak = Math.max(peak, windowRms(buffer));\n\n const elapsed = performance.now() - started;\n onProgress?.(Math.min(1, elapsed / durationMs));\n if (elapsed < durationMs) return;\n clearInterval(timer);\n resolve();\n }, SAMPLE_MS);\n });\n\n source.disconnect();\n analyser.disconnect();\n return peak;\n}\n\n/**\n * Turn a measured noise floor into a threshold worth using.\n *\n * Sits above the floor by a margin rather than on it, and is clamped at both\n * ends: a room measured as perfectly silent (or not measured at all) would\n * otherwise get a threshold of zero, which is a gate that never closes, and a\n * room measured while somebody talked would get one nothing opens.\n *\n * @param noiseFloor - Peak RMS measured while nobody spoke.\n * @returns A threshold for {@link VoiceChainSettings.gateThreshold}, `0.004..0.12`.\n */\nexport function suggestGateThreshold(noiseFloor: number): number {\n if (!Number.isFinite(noiseFloor)) return GATE_MIN;\n return Math.min(GATE_MAX, Math.max(GATE_MIN, noiseFloor * GATE_MARGIN));\n}\n"],"mappings":"4CAGA,
|
|
1
|
+
{"version":3,"file":"noise-floor.cjs","names":["windowRms","require_voice_chain_stages","DEFAULT_DURATION_MS","SAMPLE_MS","GATE_MARGIN","GATE_MIN","GATE_MAX","audioContextConstructor","measureNoiseFloor","injectedContext","Ctor","context","track","stream","source","analyser","buffer","started","peak","timer","elapsed","onProgress","durationMs","resolve","suggestGateThreshold","noiseFloor"],"sources":["../../src/audio/noise-floor.ts"],"sourcesContent":["import { windowRms } from \"./voice-chain-stages\";\n\n/** How long the measurement listens by default, in milliseconds. */\nconst DEFAULT_DURATION_MS = 3000;\n\n/** How often it samples the room, in milliseconds. */\nconst SAMPLE_MS = 50;\n\n/**\n * Headroom over the measured floor, so ordinary speech clears the gate.\n *\n * A gate set exactly at the noise level chatters, opening and closing on the\n * room's own variation. Ported from `tempest-mirror-screen`'s `voiceChain.ts`,\n * where it was arrived at by listening.\n */\nconst GATE_MARGIN = 2.4;\n\n/** The narrowest and widest thresholds worth suggesting. */\nconst GATE_MIN = 0.004;\nconst GATE_MAX = 0.12;\n\n/** Options for {@link measureNoiseFloor}. */\nexport interface NoiseFloorOptions {\n /** Called with `0..1` so a dialog can show the wait. */\n onProgress?: (fraction: number) => void;\n /** How long to listen. Default `3000`. */\n durationMs?: number;\n /** Reuse an existing `AudioContext` rather than opening one. */\n context?: AudioContext;\n}\n\n/** The `AudioContext` constructor this engine exposes, prefixed or not. */\nfunction audioContextConstructor(): typeof AudioContext | undefined {\n if (typeof AudioContext !== \"undefined\") return AudioContext;\n return (globalThis as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n}\n\n/**\n * Listen to a room at rest and report how loud its silence is.\n *\n * The number a person cannot guess. Setting a gate by ear means switching it on\n * and hearing what disappeared, which only works if you already know what should\n * have disappeared — so the usual outcome is leaving it at a default that is\n * wrong for that room. Measuring replaces the guess.\n *\n * The result is the **peak** RMS window observed, not the average: a threshold\n * under the loudest thing the quiet room did will be opened by that thing.\n *\n * @param stream - A live capture of the room while nobody speaks.\n * @param options - See {@link NoiseFloorOptions}.\n * @returns The peak RMS observed, `0..1`. `0` when this engine has no Web Audio\n * or the stream carries no audio track — which {@link suggestGateThreshold}\n * turns into its own floor rather than into a gate that never opens.\n *\n * @example\n * const floor = await measureNoiseFloor(stream, { onProgress: setProgress });\n * setThreshold(suggestGateThreshold(floor));\n */\nexport async function measureNoiseFloor(\n stream: MediaStream,\n {\n onProgress,\n durationMs = DEFAULT_DURATION_MS,\n context: injectedContext,\n }: NoiseFloorOptions = {},\n): Promise<number> {\n const Ctor = audioContextConstructor();\n const context = injectedContext ?? (Ctor ? new Ctor() : null);\n const track = stream.getAudioTracks()[0];\n if (!context || !track) return 0;\n\n const source = context.createMediaStreamSource(stream);\n const analyser = context.createAnalyser();\n analyser.fftSize = 2048;\n source.connect(analyser);\n\n const buffer = new Float32Array(analyser.fftSize);\n const started = performance.now();\n let peak = 0;\n\n await new Promise<void>((resolve) => {\n const timer = setInterval(() => {\n analyser.getFloatTimeDomainData(buffer);\n peak = Math.max(peak, windowRms(buffer));\n\n const elapsed = performance.now() - started;\n onProgress?.(Math.min(1, elapsed / durationMs));\n if (elapsed < durationMs) return;\n clearInterval(timer);\n resolve();\n }, SAMPLE_MS);\n });\n\n source.disconnect();\n analyser.disconnect();\n return peak;\n}\n\n/**\n * Turn a measured noise floor into a threshold worth using.\n *\n * Sits above the floor by a margin rather than on it, and is clamped at both\n * ends: a room measured as perfectly silent (or not measured at all) would\n * otherwise get a threshold of zero, which is a gate that never closes, and a\n * room measured while somebody talked would get one nothing opens.\n *\n * @param noiseFloor - Peak RMS measured while nobody spoke.\n * @returns A threshold for {@link VoiceChainSettings.gateThreshold}, `0.004..0.12`.\n */\nexport function suggestGateThreshold(noiseFloor: number): number {\n if (!Number.isFinite(noiseFloor)) return GATE_MIN;\n return Math.min(GATE_MAX, Math.max(GATE_MIN, noiseFloor * GATE_MARGIN));\n}\n"],"mappings":"A,4CAGA,IAAME,EAAsB,IAGtBC,EAAY,GASZC,EAAc,IAGdC,EAAW,KACXC,EAAW,IAajB,SAASC,GAA2D,CAEhE,OADI,OAAO,aAAiB,IAAoB,aACxC,WAA4D,kBACxE,CAuBA,eAAsBC,EAClB,EACA,CACI,aACA,aAAaN,EACb,QAASO,GACU,CAAC,EACT,CACf,IAAMC,EAAOH,EAAwB,EAC/BI,EAAUF,IAAoBC,EAAO,IAAIA,EAAS,MAClDE,EAAQC,EAAO,eAAe,CAAC,CAAC,GACtC,GAAI,CAACF,GAAW,CAACC,EAAO,MAAO,GAE/B,IAAME,EAASH,EAAQ,wBAAwBE,CAAM,EAC/CE,EAAWJ,EAAQ,eAAe,EACxC,EAAS,QAAU,KACnBG,EAAO,QAAQC,CAAQ,EAEvB,IAAMC,EAAS,IAAI,aAAaD,EAAS,OAAO,EAC1CE,EAAU,YAAY,IAAI,EAC5BC,EAAO,EAiBX,OAfA,MAAM,IAAI,QAAe,GAAY,CACjC,IAAMC,EAAQ,gBAAkB,CAC5BJ,EAAS,uBAAuBC,CAAM,EACtC,EAAO,KAAK,IAAIE,EAAMlB,EAAAA,UAAUgB,CAAM,CAAC,EAEvC,IAAMI,EAAU,YAAY,IAAI,EAAIH,EACpCI,IAAa,KAAK,IAAI,EAAGD,EAAUE,CAAU,CAAC,EAC1C,IAAUA,KACd,cAAcH,CAAK,EACnBI,EAAQ,EACZ,EAAGpB,CAAS,CAChB,CAAC,EAEDW,EAAO,WAAW,EAClBC,EAAS,WAAW,EACbG,CACX,CAaA,SAAgBM,EAAqB,EAA4B,CAE7D,OADK,OAAO,SAASC,CAAU,EACxB,KAAK,IAAInB,EAAU,KAAK,IAAID,EAAUoB,EAAarB,CAAW,CAAC,EAD7BC,CAE7C,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noise-floor.js","names":[],"sources":["../../src/audio/noise-floor.ts"],"sourcesContent":["import { windowRms } from \"./voice-chain-stages\";\n\n/** How long the measurement listens by default, in milliseconds. */\nconst DEFAULT_DURATION_MS = 3000;\n\n/** How often it samples the room, in milliseconds. */\nconst SAMPLE_MS = 50;\n\n/**\n * Headroom over the measured floor, so ordinary speech clears the gate.\n *\n * A gate set exactly at the noise level chatters, opening and closing on the\n * room's own variation. Ported from `tempest-mirror-screen`'s `voiceChain.ts`,\n * where it was arrived at by listening.\n */\nconst GATE_MARGIN = 2.4;\n\n/** The narrowest and widest thresholds worth suggesting. */\nconst GATE_MIN = 0.004;\nconst GATE_MAX = 0.12;\n\n/** Options for {@link measureNoiseFloor}. */\nexport interface NoiseFloorOptions {\n /** Called with `0..1` so a dialog can show the wait. */\n onProgress?: (fraction: number) => void;\n /** How long to listen. Default `3000`. */\n durationMs?: number;\n /** Reuse an existing `AudioContext` rather than opening one. */\n context?: AudioContext;\n}\n\n/** The `AudioContext` constructor this engine exposes, prefixed or not. */\nfunction audioContextConstructor(): typeof AudioContext | undefined {\n if (typeof AudioContext !== \"undefined\") return AudioContext;\n return (globalThis as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n}\n\n/**\n * Listen to a room at rest and report how loud its silence is.\n *\n * The number a person cannot guess. Setting a gate by ear means switching it on\n * and hearing what disappeared, which only works if you already know what should\n * have disappeared — so the usual outcome is leaving it at a default that is\n * wrong for that room. Measuring replaces the guess.\n *\n * The result is the **peak** RMS window observed, not the average: a threshold\n * under the loudest thing the quiet room did will be opened by that thing.\n *\n * @param stream - A live capture of the room while nobody speaks.\n * @param options - See {@link NoiseFloorOptions}.\n * @returns The peak RMS observed, `0..1`. `0` when this engine has no Web Audio\n * or the stream carries no audio track — which {@link suggestGateThreshold}\n * turns into its own floor rather than into a gate that never opens.\n *\n * @example\n * const floor = await measureNoiseFloor(stream, { onProgress: setProgress });\n * setThreshold(suggestGateThreshold(floor));\n */\nexport async function measureNoiseFloor(\n stream: MediaStream,\n {\n onProgress,\n durationMs = DEFAULT_DURATION_MS,\n context: injectedContext,\n }: NoiseFloorOptions = {},\n): Promise<number> {\n const Ctor = audioContextConstructor();\n const context = injectedContext ?? (Ctor ? new Ctor() : null);\n const track = stream.getAudioTracks()[0];\n if (!context || !track) return 0;\n\n const source = context.createMediaStreamSource(stream);\n const analyser = context.createAnalyser();\n analyser.fftSize = 2048;\n source.connect(analyser);\n\n const buffer = new Float32Array(analyser.fftSize);\n const started = performance.now();\n let peak = 0;\n\n await new Promise<void>((resolve) => {\n const timer = setInterval(() => {\n analyser.getFloatTimeDomainData(buffer);\n peak = Math.max(peak, windowRms(buffer));\n\n const elapsed = performance.now() - started;\n onProgress?.(Math.min(1, elapsed / durationMs));\n if (elapsed < durationMs) return;\n clearInterval(timer);\n resolve();\n }, SAMPLE_MS);\n });\n\n source.disconnect();\n analyser.disconnect();\n return peak;\n}\n\n/**\n * Turn a measured noise floor into a threshold worth using.\n *\n * Sits above the floor by a margin rather than on it, and is clamped at both\n * ends: a room measured as perfectly silent (or not measured at all) would\n * otherwise get a threshold of zero, which is a gate that never closes, and a\n * room measured while somebody talked would get one nothing opens.\n *\n * @param noiseFloor - Peak RMS measured while nobody spoke.\n * @returns A threshold for {@link VoiceChainSettings.gateThreshold}, `0.004..0.12`.\n */\nexport function suggestGateThreshold(noiseFloor: number): number {\n if (!Number.isFinite(noiseFloor)) return GATE_MIN;\n return Math.min(GATE_MAX, Math.max(GATE_MIN, noiseFloor * GATE_MARGIN));\n}\n"],"mappings":";;AAGA,
|
|
1
|
+
{"version":3,"file":"noise-floor.js","names":["windowRms","rms","DEFAULT_DURATION_MS","SAMPLE_MS","GATE_MARGIN","GATE_MIN","GATE_MAX","audioContextConstructor","measureNoiseFloor","injectedContext","Ctor","context","track","stream","source","analyser","buffer","started","peak","timer","elapsed","onProgress","durationMs","resolve","suggestGateThreshold","noiseFloor"],"sources":["../../src/audio/noise-floor.ts"],"sourcesContent":["import { windowRms } from \"./voice-chain-stages\";\n\n/** How long the measurement listens by default, in milliseconds. */\nconst DEFAULT_DURATION_MS = 3000;\n\n/** How often it samples the room, in milliseconds. */\nconst SAMPLE_MS = 50;\n\n/**\n * Headroom over the measured floor, so ordinary speech clears the gate.\n *\n * A gate set exactly at the noise level chatters, opening and closing on the\n * room's own variation. Ported from `tempest-mirror-screen`'s `voiceChain.ts`,\n * where it was arrived at by listening.\n */\nconst GATE_MARGIN = 2.4;\n\n/** The narrowest and widest thresholds worth suggesting. */\nconst GATE_MIN = 0.004;\nconst GATE_MAX = 0.12;\n\n/** Options for {@link measureNoiseFloor}. */\nexport interface NoiseFloorOptions {\n /** Called with `0..1` so a dialog can show the wait. */\n onProgress?: (fraction: number) => void;\n /** How long to listen. Default `3000`. */\n durationMs?: number;\n /** Reuse an existing `AudioContext` rather than opening one. */\n context?: AudioContext;\n}\n\n/** The `AudioContext` constructor this engine exposes, prefixed or not. */\nfunction audioContextConstructor(): typeof AudioContext | undefined {\n if (typeof AudioContext !== \"undefined\") return AudioContext;\n return (globalThis as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n}\n\n/**\n * Listen to a room at rest and report how loud its silence is.\n *\n * The number a person cannot guess. Setting a gate by ear means switching it on\n * and hearing what disappeared, which only works if you already know what should\n * have disappeared — so the usual outcome is leaving it at a default that is\n * wrong for that room. Measuring replaces the guess.\n *\n * The result is the **peak** RMS window observed, not the average: a threshold\n * under the loudest thing the quiet room did will be opened by that thing.\n *\n * @param stream - A live capture of the room while nobody speaks.\n * @param options - See {@link NoiseFloorOptions}.\n * @returns The peak RMS observed, `0..1`. `0` when this engine has no Web Audio\n * or the stream carries no audio track — which {@link suggestGateThreshold}\n * turns into its own floor rather than into a gate that never opens.\n *\n * @example\n * const floor = await measureNoiseFloor(stream, { onProgress: setProgress });\n * setThreshold(suggestGateThreshold(floor));\n */\nexport async function measureNoiseFloor(\n stream: MediaStream,\n {\n onProgress,\n durationMs = DEFAULT_DURATION_MS,\n context: injectedContext,\n }: NoiseFloorOptions = {},\n): Promise<number> {\n const Ctor = audioContextConstructor();\n const context = injectedContext ?? (Ctor ? new Ctor() : null);\n const track = stream.getAudioTracks()[0];\n if (!context || !track) return 0;\n\n const source = context.createMediaStreamSource(stream);\n const analyser = context.createAnalyser();\n analyser.fftSize = 2048;\n source.connect(analyser);\n\n const buffer = new Float32Array(analyser.fftSize);\n const started = performance.now();\n let peak = 0;\n\n await new Promise<void>((resolve) => {\n const timer = setInterval(() => {\n analyser.getFloatTimeDomainData(buffer);\n peak = Math.max(peak, windowRms(buffer));\n\n const elapsed = performance.now() - started;\n onProgress?.(Math.min(1, elapsed / durationMs));\n if (elapsed < durationMs) return;\n clearInterval(timer);\n resolve();\n }, SAMPLE_MS);\n });\n\n source.disconnect();\n analyser.disconnect();\n return peak;\n}\n\n/**\n * Turn a measured noise floor into a threshold worth using.\n *\n * Sits above the floor by a margin rather than on it, and is clamped at both\n * ends: a room measured as perfectly silent (or not measured at all) would\n * otherwise get a threshold of zero, which is a gate that never closes, and a\n * room measured while somebody talked would get one nothing opens.\n *\n * @param noiseFloor - Peak RMS measured while nobody spoke.\n * @returns A threshold for {@link VoiceChainSettings.gateThreshold}, `0.004..0.12`.\n */\nexport function suggestGateThreshold(noiseFloor: number): number {\n if (!Number.isFinite(noiseFloor)) return GATE_MIN;\n return Math.min(GATE_MAX, Math.max(GATE_MIN, noiseFloor * GATE_MARGIN));\n}\n"],"mappings":";;AAGA,IAAME,IAAsB,KAGtBC,IAAY,IASZC,IAAc,KAGdC,IAAW,MACXC,IAAW;AAajB,SAASC,IAA2D;CAEhE,OADI,OAAO,eAAiB,MAAoB,eACxC,WAA4D;AACxE;AAuBA,eAAsBC,EAClB,GACA,EACI,eACA,gBAAaN,GACb,SAASO,MACU,CAAC,GACT;CACf,IAAMC,IAAOH,EAAwB,GAC/BI,IAAUF,MAAoBC,IAAO,IAAIA,EAAK,IAAI,OAClDE,IAAQC,EAAO,eAAe,CAAC,CAAC;CACtC,IAAI,CAACF,KAAW,CAACC,GAAO,OAAO;CAE/B,IAAME,IAASH,EAAQ,wBAAwBE,CAAM,GAC/CE,IAAWJ,EAAQ,eAAe;CAExC,AADA,EAAS,UAAU,MACnBG,EAAO,QAAQC,CAAQ;CAEvB,IAAMC,IAAS,IAAI,aAAaD,EAAS,OAAO,GAC1CE,IAAU,YAAY,IAAI,GAC5BC,IAAO;CAiBX,OAfA,MAAM,IAAI,SAAe,MAAY;EACjC,IAAMC,IAAQ,kBAAkB;GAE5B,AADAJ,EAAS,uBAAuBC,CAAM,GACtC,IAAO,KAAK,IAAIE,GAAMlB,EAAUgB,CAAM,CAAC;GAEvC,IAAMI,IAAU,YAAY,IAAI,IAAIH;GAEpC,AADAI,IAAa,KAAK,IAAI,GAAGD,IAAUE,CAAU,CAAC,GAC1C,MAAUA,OACd,cAAcH,CAAK,GACnBI,EAAQ;EACZ,GAAGpB,CAAS;CAChB,CAAC,GAEDW,EAAO,WAAW,GAClBC,EAAS,WAAW,GACbG;AACX;AAaA,SAAgBM,EAAqB,GAA4B;CAE7D,OADK,OAAO,SAASC,CAAU,IACxB,KAAK,IAAInB,GAAU,KAAK,IAAID,GAAUoB,IAAarB,CAAW,CAAC,IAD7BC;AAE7C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sfx-pool.cjs","names":[],"sources":["../../src/audio/sfx-pool.ts"],"sourcesContent":["/** Options for {@link createSfxPool}. */\nexport interface SfxPoolOptions {\n /**\n * Master volume, `0`–`1`, multiplied into every per-play volume. Default\n * `1`. Wire it to the app's sound setting so one value governs the lot.\n */\n volume?: number;\n /**\n * Prefix applied to sources that are not absolute URLs — typically Vite's\n * `import.meta.env.BASE_URL`, so a build served from a subpath resolves.\n * Default `\"\"`.\n */\n baseUrl?: string;\n /**\n * Elements kept per source. `1` (the default) restarts the clip on every\n * play, which is what a menu blip wants. Raise it to let a sound overlap\n * itself — a hit landing while the previous one is still ringing.\n */\n voices?: number;\n /**\n * Maximum number of distinct sources held. When exceeded, the least\n * recently played source is released. Default `48`.\n */\n maxSources?: number;\n}\n\n/** Per-play overrides. */\nexport interface PlaySfxOptions {\n /** Volume for this play, `0`–`1`, multiplied by the pool's master. Default `1`. */\n volume?: number;\n}\n\n/** Imperative handle over a pool of short sound effects. */\nexport interface SfxPool {\n /** Play a clip, allocating and caching its element on first use. */\n play: (src: string, options?: PlaySfxOptions) => void;\n /** Fetch clips ahead of the first play, so it is not silent while the file downloads. */\n preload: (src: string | string[]) => void;\n /** Set the master volume, applying it to anything already sounding. */\n setVolume: (volume: number) => void;\n /** Stop one source, or every source when called with no argument. */\n stop: (src?: string) => void;\n /** Release every element. Call on unmount. */\n dispose: () => void;\n}\n\n/** Clamp to the range `HTMLMediaElement.volume` accepts, rejecting `NaN`. */\nfunction clampVolume(value: number): number {\n if (!Number.isFinite(value)) return 1;\n return Math.min(1, Math.max(0, value));\n}\n\n/**\n * A pool of preallocated `<audio>` elements for short sound effects.\n *\n * `new Audio(src)` on every play allocates an element and re-enters the network\n * stack for a file the browser already has, which is the wrong shape for a\n * sound that fires dozens of times a minute — a UI blip, a hit, a pickup. The\n * pool allocates once per source and replays.\n *\n * This is deliberately not {@link createAudioPlayer}: that handle tracks a\n * single \"current\" clip with loop, sink routing and lifecycle callbacks, which\n * is what background music needs. Effects are the opposite case — many\n * sources, all short, fire-and-forget, and the only thing that matters is that\n * firing one is cheap.\n *\n * A blocked `play()` is swallowed. Browsers reject playback until the user has\n * interacted with the page, and a sound effect is by definition not worth\n * interrupting anything over; call {@link SfxPool.preload} after the first\n * interaction if you want the pool warm.\n *\n * @param options - Master volume, base URL, voices per source and pool size.\n * @returns The pool handle.\n *\n * @example\n * const sfx = createSfxPool({ volume: 0.6, baseUrl: import.meta.env.BASE_URL });\n * sfx.preload([\"sfx/select.mp3\", \"sfx/back.mp3\"]);\n *\n * <button onClick={() => sfx.play(\"sfx/select.mp3\")}>Confirmar</button>\n */\n/** One source's voices plus the round-robin cursor over them. */\ninterface SourceEntry {\n /** The audio elements sharing this source. */\n elements: HTMLAudioElement[];\n /** Index of the element the next play claims. */\n next: number;\n}\n\n/**\n * Resolve a source against the pool's base URL.\n *\n * An absolute URL, a protocol-relative one and a `data:` URI are already\n * addresses — prefixing them would produce a path that resolves to nothing.\n *\n * @param baseUrl - Pool base, possibly empty.\n * @param src - Source as the caller wrote it.\n * @returns The URL to load.\n */\nfunction resolveSource(baseUrl: string, src: string): string {\n if (!baseUrl || /^(https?:)?\\/\\//.test(src) || src.startsWith(\"data:\")) return src;\n return `${baseUrl.replace(/\\/$/, \"\")}/${src.replace(/^\\//, \"\")}`;\n}\n\n/**\n * Stop every voice of an entry and let the browser drop its buffer.\n *\n * Removing `src` before `load()` is what frees the decoded audio: `load()` on an\n * element that still has a source re-fetches it instead.\n *\n * @param entry - The entry being evicted.\n */\nfunction releaseEntry(entry: { elements: HTMLAudioElement[] }): void {\n for (const element of entry.elements) {\n element.pause();\n element.removeAttribute(\"src\");\n element.load();\n }\n}\n\n/**\n * Drop the least recently played source once the pool is over its cap.\n *\n * The map is insertion-ordered by last play, so the first key is the coldest.\n * The source that was just admitted is never the one evicted, which would\n * otherwise happen with a cap of one.\n *\n * @param sources - The live pool, mutated in place.\n * @param keepUrl - The source that must survive this eviction.\n * @param maxSources - How many sources the pool may hold.\n */\nfunction evictLeastRecent(\n sources: Map<string, SourceEntry>,\n keepUrl: string,\n maxSources: number,\n): void {\n if (sources.size <= maxSources) return;\n const oldest = sources.keys().next();\n if (oldest.done || oldest.value === keepUrl) return;\n const evicted = sources.get(oldest.value);\n if (evicted) releaseEntry(evicted);\n sources.delete(oldest.value);\n}\n\nexport function createSfxPool(options: SfxPoolOptions = {}): SfxPool {\n const { baseUrl = \"\", voices = 1, maxSources = 48 } = options;\n\n let master = clampVolume(options.volume ?? 1);\n const voiceCount = Math.max(1, Math.floor(voices));\n\n /**\n * Insertion-ordered by last play, so evicting the first key drops the\n * least recently used source.\n */\n const sources = new Map<string, SourceEntry>();\n\n /**\n * Per-play gain of whatever each element last played at.\n *\n * `setVolume` has to rescale live playback by the same factor it was\n * started with; assigning the master directly would yank a clip that\n * started at half volume up to full.\n */\n const gains = new WeakMap<HTMLAudioElement, number>();\n\n /**\n * The pool entry for a source, creating and admitting it when it is new.\n *\n * Re-inserts an existing entry so the map order stays \"least recently used\n * first\", which is what makes evicting the first key correct.\n *\n * `created` is reported because assigning `src` on an element whose `preload`\n * is `\"auto\"` already starts the fetch: calling `load()` on an entry that was\n * merely looked up would abort that fetch and discard whatever is already\n * buffered, per the media element load algorithm.\n *\n * @param src - Raw source, resolved against `baseUrl`.\n * @returns The entry and whether this call created it, or `null` where\n * `Audio` does not exist.\n */\n function acquire(src: string): { entry: SourceEntry; created: boolean } | null {\n if (typeof Audio === \"undefined\") return null;\n\n const url = resolveSource(baseUrl, src);\n const existing = sources.get(url);\n if (existing) {\n sources.delete(url);\n sources.set(url, existing);\n return { entry: existing, created: false };\n }\n\n const entry: SourceEntry = {\n elements: Array.from({ length: voiceCount }, () => {\n const element = new Audio(url);\n element.preload = \"auto\";\n return element;\n }),\n next: 0,\n };\n sources.set(url, entry);\n\n evictLeastRecent(sources, url, maxSources);\n\n return { entry, created: true };\n }\n\n return {\n play(src, playOptions = {}) {\n const acquired = acquire(src);\n if (!acquired) return;\n\n const entry = acquired.entry;\n const element = entry.elements[entry.next];\n entry.next = (entry.next + 1) % entry.elements.length;\n\n const gain = clampVolume(playOptions.volume ?? 1);\n gains.set(element, gain);\n\n element.pause();\n element.currentTime = 0;\n element.volume = clampVolume(gain * master);\n void element.play().catch(() => {});\n },\n\n preload(src) {\n for (const one of Array.isArray(src) ? src : [src]) {\n const acquired = acquire(one);\n if (!acquired?.created) continue;\n for (const element of acquired.entry.elements) element.load();\n }\n },\n\n setVolume(volume) {\n master = clampVolume(volume);\n for (const entry of sources.values()) {\n for (const element of entry.elements) {\n if (element.paused) continue;\n element.volume = clampVolume((gains.get(element) ?? 1) * master);\n }\n }\n },\n\n stop(src) {\n const targets = src\n ? [sources.get(resolveSource(baseUrl, src))]\n : [...sources.values()];\n for (const entry of targets) {\n if (!entry) continue;\n for (const element of entry.elements) {\n element.pause();\n element.currentTime = 0;\n }\n }\n },\n\n dispose() {\n for (const entry of sources.values()) releaseEntry(entry);\n sources.clear();\n },\n };\n}\n"],"mappings":"AA+CA,SAAS,EAAY,EAAuB,CAExC,OADK,OAAO,SAAS,CAAK,EACnB,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG,CAAK,CAAC,EADD,CAExC,CAgDA,SAAS,EAAc,EAAiB,EAAqB,CAEzD,MADI,CAAC,GAAW,kBAAkB,KAAK,CAAG,GAAK,EAAI,WAAW,OAAO,EAAU,EACxE,GAAG,EAAQ,QAAQ,MAAO,EAAE,EAAE,GAAG,EAAI,QAAQ,MAAO,EAAE,GACjE,CAUA,SAAS,EAAa,EAA+C,CACjE,IAAK,IAAM,KAAW,EAAM,SACxB,EAAQ,MAAM,EACd,EAAQ,gBAAgB,KAAK,EAC7B,EAAQ,KAAK,CAErB,CAaA,SAAS,EACL,EACA,EACA,EACI,CACJ,GAAI,EAAQ,MAAQ,EAAY,OAChC,IAAM,EAAS,EAAQ,KAAK,CAAC,CAAC,KAAK,EACnC,GAAI,EAAO,MAAQ,EAAO,QAAU,EAAS,OAC7C,IAAM,EAAU,EAAQ,IAAI,EAAO,KAAK,EACpC,GAAS,EAAa,CAAO,EACjC,EAAQ,OAAO,EAAO,KAAK,CAC/B,CAEA,SAAgB,EAAc,EAA0B,CAAC,EAAY,CACjE,GAAM,CAAE,UAAU,GAAI,SAAS,EAAG,aAAa,IAAO,EAElD,EAAS,EAAY,EAAQ,QAAU,CAAC,EACtC,EAAa,KAAK,IAAI,EAAG,KAAK,MAAM,CAAM,CAAC,EAM3C,EAAU,IAAI,IASd,EAAQ,IAAI,QAiBlB,SAAS,EAAQ,EAA8D,CAC3E,GAAI,OAAO,MAAU,IAAa,OAAO,KAEzC,IAAM,EAAM,EAAc,EAAS,CAAG,EAChC,EAAW,EAAQ,IAAI,CAAG,EAChC,GAAI,EAGA,OAFA,EAAQ,OAAO,CAAG,EAClB,EAAQ,IAAI,EAAK,CAAQ,EAClB,CAAE,MAAO,EAAU,QAAS,EAAM,EAG7C,IAAM,EAAqB,CACvB,SAAU,MAAM,KAAK,CAAE,OAAQ,CAAW,MAAS,CAC/C,IAAM,EAAU,IAAI,MAAM,CAAG,EAE7B,MADA,GAAQ,QAAU,OACX,CACX,CAAC,EACD,KAAM,CACV,EAKA,OAJA,EAAQ,IAAI,EAAK,CAAK,EAEtB,EAAiB,EAAS,EAAK,CAAU,EAElC,CAAE,QAAO,QAAS,EAAK,CAClC,CAEA,MAAO,CACH,KAAK,EAAK,EAAc,CAAC,EAAG,CACxB,IAAM,EAAW,EAAQ,CAAG,EAC5B,GAAI,CAAC,EAAU,OAEf,IAAM,EAAQ,EAAS,MACjB,EAAU,EAAM,SAAS,EAAM,MACrC,EAAM,MAAQ,EAAM,KAAO,GAAK,EAAM,SAAS,OAE/C,IAAM,EAAO,EAAY,EAAY,QAAU,CAAC,EAChD,EAAM,IAAI,EAAS,CAAI,EAEvB,EAAQ,MAAM,EACd,EAAQ,YAAc,EACtB,EAAQ,OAAS,EAAY,EAAO,CAAM,EAC1C,EAAa,KAAK,CAAC,CAAC,UAAY,CAAC,CAAC,CACtC,EAEA,QAAQ,EAAK,CACT,IAAK,IAAM,KAAO,MAAM,QAAQ,CAAG,EAAI,EAAM,CAAC,CAAG,EAAG,CAChD,IAAM,EAAW,EAAQ,CAAG,EACvB,MAAU,QACf,IAAK,IAAM,KAAW,EAAS,MAAM,SAAU,EAAQ,KAAK,CAChE,CACJ,EAEA,UAAU,EAAQ,CACd,EAAS,EAAY,CAAM,EAC3B,IAAK,IAAM,KAAS,EAAQ,OAAO,EAC/B,IAAK,IAAM,KAAW,EAAM,SACpB,EAAQ,SACZ,EAAQ,OAAS,GAAa,EAAM,IAAI,CAAO,GAAK,GAAK,CAAM,EAG3E,EAEA,KAAK,EAAK,CACN,IAAM,EAAU,EACV,CAAC,EAAQ,IAAI,EAAc,EAAS,CAAG,CAAC,CAAC,EACzC,CAAC,GAAG,EAAQ,OAAO,CAAC,EAC1B,IAAK,IAAM,KAAS,EACX,KACL,IAAK,IAAM,KAAW,EAAM,SACxB,EAAQ,MAAM,EACd,EAAQ,YAAc,CAGlC,EAEA,SAAU,CACN,IAAK,IAAM,KAAS,EAAQ,OAAO,EAAG,EAAa,CAAK,EACxD,EAAQ,MAAM,CAClB,CACJ,CACJ"}
|
|
1
|
+
{"version":3,"file":"sfx-pool.cjs","names":["clampVolume","value","resolveSource","baseUrl","src","releaseEntry","element","entry","evictLeastRecent","sources","maxSources","oldest","keepUrl","evicted","createSfxPool","options","master","voiceCount","voices","gains","acquire","url","existing","acquired","gain","playOptions","one","volume","targets"],"sources":["../../src/audio/sfx-pool.ts"],"sourcesContent":["/** Options for {@link createSfxPool}. */\nexport interface SfxPoolOptions {\n /**\n * Master volume, `0`–`1`, multiplied into every per-play volume. Default\n * `1`. Wire it to the app's sound setting so one value governs the lot.\n */\n volume?: number;\n /**\n * Prefix applied to sources that are not absolute URLs — typically Vite's\n * `import.meta.env.BASE_URL`, so a build served from a subpath resolves.\n * Default `\"\"`.\n */\n baseUrl?: string;\n /**\n * Elements kept per source. `1` (the default) restarts the clip on every\n * play, which is what a menu blip wants. Raise it to let a sound overlap\n * itself — a hit landing while the previous one is still ringing.\n */\n voices?: number;\n /**\n * Maximum number of distinct sources held. When exceeded, the least\n * recently played source is released. Default `48`.\n */\n maxSources?: number;\n}\n\n/** Per-play overrides. */\nexport interface PlaySfxOptions {\n /** Volume for this play, `0`–`1`, multiplied by the pool's master. Default `1`. */\n volume?: number;\n}\n\n/** Imperative handle over a pool of short sound effects. */\nexport interface SfxPool {\n /** Play a clip, allocating and caching its element on first use. */\n play: (src: string, options?: PlaySfxOptions) => void;\n /** Fetch clips ahead of the first play, so it is not silent while the file downloads. */\n preload: (src: string | string[]) => void;\n /** Set the master volume, applying it to anything already sounding. */\n setVolume: (volume: number) => void;\n /** Stop one source, or every source when called with no argument. */\n stop: (src?: string) => void;\n /** Release every element. Call on unmount. */\n dispose: () => void;\n}\n\n/** Clamp to the range `HTMLMediaElement.volume` accepts, rejecting `NaN`. */\nfunction clampVolume(value: number): number {\n if (!Number.isFinite(value)) return 1;\n return Math.min(1, Math.max(0, value));\n}\n\n/**\n * A pool of preallocated `<audio>` elements for short sound effects.\n *\n * `new Audio(src)` on every play allocates an element and re-enters the network\n * stack for a file the browser already has, which is the wrong shape for a\n * sound that fires dozens of times a minute — a UI blip, a hit, a pickup. The\n * pool allocates once per source and replays.\n *\n * This is deliberately not {@link createAudioPlayer}: that handle tracks a\n * single \"current\" clip with loop, sink routing and lifecycle callbacks, which\n * is what background music needs. Effects are the opposite case — many\n * sources, all short, fire-and-forget, and the only thing that matters is that\n * firing one is cheap.\n *\n * A blocked `play()` is swallowed. Browsers reject playback until the user has\n * interacted with the page, and a sound effect is by definition not worth\n * interrupting anything over; call {@link SfxPool.preload} after the first\n * interaction if you want the pool warm.\n *\n * @param options - Master volume, base URL, voices per source and pool size.\n * @returns The pool handle.\n *\n * @example\n * const sfx = createSfxPool({ volume: 0.6, baseUrl: import.meta.env.BASE_URL });\n * sfx.preload([\"sfx/select.mp3\", \"sfx/back.mp3\"]);\n *\n * <button onClick={() => sfx.play(\"sfx/select.mp3\")}>Confirmar</button>\n */\n/** One source's voices plus the round-robin cursor over them. */\ninterface SourceEntry {\n /** The audio elements sharing this source. */\n elements: HTMLAudioElement[];\n /** Index of the element the next play claims. */\n next: number;\n}\n\n/**\n * Resolve a source against the pool's base URL.\n *\n * An absolute URL, a protocol-relative one and a `data:` URI are already\n * addresses — prefixing them would produce a path that resolves to nothing.\n *\n * @param baseUrl - Pool base, possibly empty.\n * @param src - Source as the caller wrote it.\n * @returns The URL to load.\n */\nfunction resolveSource(baseUrl: string, src: string): string {\n if (!baseUrl || /^(https?:)?\\/\\//.test(src) || src.startsWith(\"data:\")) return src;\n return `${baseUrl.replace(/\\/$/, \"\")}/${src.replace(/^\\//, \"\")}`;\n}\n\n/**\n * Stop every voice of an entry and let the browser drop its buffer.\n *\n * Removing `src` before `load()` is what frees the decoded audio: `load()` on an\n * element that still has a source re-fetches it instead.\n *\n * @param entry - The entry being evicted.\n */\nfunction releaseEntry(entry: { elements: HTMLAudioElement[] }): void {\n for (const element of entry.elements) {\n element.pause();\n element.removeAttribute(\"src\");\n element.load();\n }\n}\n\n/**\n * Drop the least recently played source once the pool is over its cap.\n *\n * The map is insertion-ordered by last play, so the first key is the coldest.\n * The source that was just admitted is never the one evicted, which would\n * otherwise happen with a cap of one.\n *\n * @param sources - The live pool, mutated in place.\n * @param keepUrl - The source that must survive this eviction.\n * @param maxSources - How many sources the pool may hold.\n */\nfunction evictLeastRecent(\n sources: Map<string, SourceEntry>,\n keepUrl: string,\n maxSources: number,\n): void {\n if (sources.size <= maxSources) return;\n const oldest = sources.keys().next();\n if (oldest.done || oldest.value === keepUrl) return;\n const evicted = sources.get(oldest.value);\n if (evicted) releaseEntry(evicted);\n sources.delete(oldest.value);\n}\n\nexport function createSfxPool(options: SfxPoolOptions = {}): SfxPool {\n const { baseUrl = \"\", voices = 1, maxSources = 48 } = options;\n\n let master = clampVolume(options.volume ?? 1);\n const voiceCount = Math.max(1, Math.floor(voices));\n\n /**\n * Insertion-ordered by last play, so evicting the first key drops the\n * least recently used source.\n */\n const sources = new Map<string, SourceEntry>();\n\n /**\n * Per-play gain of whatever each element last played at.\n *\n * `setVolume` has to rescale live playback by the same factor it was\n * started with; assigning the master directly would yank a clip that\n * started at half volume up to full.\n */\n const gains = new WeakMap<HTMLAudioElement, number>();\n\n /**\n * The pool entry for a source, creating and admitting it when it is new.\n *\n * Re-inserts an existing entry so the map order stays \"least recently used\n * first\", which is what makes evicting the first key correct.\n *\n * `created` is reported because assigning `src` on an element whose `preload`\n * is `\"auto\"` already starts the fetch: calling `load()` on an entry that was\n * merely looked up would abort that fetch and discard whatever is already\n * buffered, per the media element load algorithm.\n *\n * @param src - Raw source, resolved against `baseUrl`.\n * @returns The entry and whether this call created it, or `null` where\n * `Audio` does not exist.\n */\n function acquire(src: string): { entry: SourceEntry; created: boolean } | null {\n if (typeof Audio === \"undefined\") return null;\n\n const url = resolveSource(baseUrl, src);\n const existing = sources.get(url);\n if (existing) {\n sources.delete(url);\n sources.set(url, existing);\n return { entry: existing, created: false };\n }\n\n const entry: SourceEntry = {\n elements: Array.from({ length: voiceCount }, () => {\n const element = new Audio(url);\n element.preload = \"auto\";\n return element;\n }),\n next: 0,\n };\n sources.set(url, entry);\n\n evictLeastRecent(sources, url, maxSources);\n\n return { entry, created: true };\n }\n\n return {\n play(src, playOptions = {}) {\n const acquired = acquire(src);\n if (!acquired) return;\n\n const entry = acquired.entry;\n const element = entry.elements[entry.next];\n entry.next = (entry.next + 1) % entry.elements.length;\n\n const gain = clampVolume(playOptions.volume ?? 1);\n gains.set(element, gain);\n\n element.pause();\n element.currentTime = 0;\n element.volume = clampVolume(gain * master);\n void element.play().catch(() => {});\n },\n\n preload(src) {\n for (const one of Array.isArray(src) ? src : [src]) {\n const acquired = acquire(one);\n if (!acquired?.created) continue;\n for (const element of acquired.entry.elements) element.load();\n }\n },\n\n setVolume(volume) {\n master = clampVolume(volume);\n for (const entry of sources.values()) {\n for (const element of entry.elements) {\n if (element.paused) continue;\n element.volume = clampVolume((gains.get(element) ?? 1) * master);\n }\n }\n },\n\n stop(src) {\n const targets = src\n ? [sources.get(resolveSource(baseUrl, src))]\n : [...sources.values()];\n for (const entry of targets) {\n if (!entry) continue;\n for (const element of entry.elements) {\n element.pause();\n element.currentTime = 0;\n }\n }\n },\n\n dispose() {\n for (const entry of sources.values()) releaseEntry(entry);\n sources.clear();\n },\n };\n}\n"],"mappings":"AA+CA,SAASA,EAAY,EAAuB,CAExC,OADK,OAAO,SAASC,CAAK,EACnB,KAAK,IAAI,EAAG,KAAK,IAAI,EAAGA,CAAK,CAAC,EADD,CAExC,CAgDA,SAASC,EAAc,EAAiB,EAAqB,CAEzD,MADI,CAACC,GAAW,kBAAkB,KAAKC,CAAG,GAAKA,EAAI,WAAW,OAAO,EAAUA,EACxE,GAAGD,EAAQ,QAAQ,MAAO,EAAE,EAAE,GAAGC,EAAI,QAAQ,MAAO,EAAE,GACjE,CAUA,SAASC,EAAa,EAA+C,CACjE,IAAK,IAAMC,KAAWC,EAAM,SACxBD,EAAQ,MAAM,EACdA,EAAQ,gBAAgB,KAAK,EAC7BA,EAAQ,KAAK,CAErB,CAaA,SAASE,EACL,EACA,EACA,EACI,CACJ,GAAIC,EAAQ,MAAQC,EAAY,OAChC,IAAMC,EAASF,EAAQ,KAAK,CAAC,CAAC,KAAK,EACnC,GAAIE,EAAO,MAAQA,EAAO,QAAUC,EAAS,OAC7C,IAAMC,EAAUJ,EAAQ,IAAIE,EAAO,KAAK,EACpCE,GAASR,EAAaQ,CAAO,EACjCJ,EAAQ,OAAOE,EAAO,KAAK,CAC/B,CAEA,SAAgBG,EAAc,EAA0B,CAAC,EAAY,CACjE,GAAM,CAAE,UAAU,GAAI,SAAS,EAAG,aAAa,IAAOC,EAElDC,EAAShB,EAAYe,EAAQ,QAAU,CAAC,EACtCE,EAAa,KAAK,IAAI,EAAG,KAAK,MAAMC,CAAM,CAAC,EAM3CT,EAAU,IAAI,IASdU,EAAQ,IAAI,QAiBlB,SAASC,EAAQ,EAA8D,CAC3E,GAAI,OAAO,MAAU,IAAa,OAAO,KAEzC,IAAMC,EAAMnB,EAAcC,EAASC,CAAG,EAChCkB,EAAWb,EAAQ,IAAIY,CAAG,EAChC,GAAIC,EAGA,OAFAb,EAAQ,OAAOY,CAAG,EAClBZ,EAAQ,IAAIY,EAAKC,CAAQ,EAClB,CAAE,MAAOA,EAAU,QAAS,EAAM,EAG7C,IAAMf,EAAqB,CACvB,SAAU,MAAM,KAAK,CAAE,OAAQU,CAAW,MAAS,CAC/C,IAAMX,EAAU,IAAI,MAAMe,CAAG,EAE7B,MADA,GAAQ,QAAU,OACXf,CACX,CAAC,EACD,KAAM,CACV,EAKA,OAJAG,EAAQ,IAAIY,EAAKd,CAAK,EAEtBC,EAAiBC,EAASY,EAAKX,CAAU,EAElC,CAAE,QAAO,QAAS,EAAK,CAClC,CAEA,MAAO,CACH,KAAK,EAAK,EAAc,CAAC,EAAG,CACxB,IAAMa,EAAWH,EAAQhB,CAAG,EAC5B,GAAI,CAACmB,EAAU,OAEf,IAAMhB,EAAQgB,EAAS,MACjBjB,EAAUC,EAAM,SAASA,EAAM,MACrC,EAAM,MAAQA,EAAM,KAAO,GAAKA,EAAM,SAAS,OAE/C,IAAMiB,EAAOxB,EAAYyB,EAAY,QAAU,CAAC,EAChDN,EAAM,IAAIb,EAASkB,CAAI,EAEvBlB,EAAQ,MAAM,EACd,EAAQ,YAAc,EACtB,EAAQ,OAASN,EAAYwB,EAAOR,CAAM,EAC1CV,EAAa,KAAK,CAAC,CAAC,UAAY,CAAC,CAAC,CACtC,EAEA,QAAQ,EAAK,CACT,IAAK,IAAMoB,KAAO,MAAM,QAAQtB,CAAG,EAAIA,EAAM,CAACA,CAAG,EAAG,CAChD,IAAMmB,EAAWH,EAAQM,CAAG,EAC5B,GAAKH,GAAU,QACf,IAAK,IAAMjB,KAAWiB,EAAS,MAAM,SAAUjB,EAAQ,KAAK,CAChE,CACJ,EAEA,UAAU,EAAQ,CACd,EAASN,EAAY2B,CAAM,EAC3B,IAAK,IAAMpB,KAASE,EAAQ,OAAO,EAC/B,IAAK,IAAMH,KAAWC,EAAM,SACpBD,EAAQ,SACZ,EAAQ,OAASN,GAAamB,EAAM,IAAIb,CAAO,GAAK,GAAKU,CAAM,EAG3E,EAEA,KAAK,EAAK,CACN,IAAMY,EAAUxB,EACV,CAACK,EAAQ,IAAIP,EAAcC,EAASC,CAAG,CAAC,CAAC,EACzC,CAAC,GAAGK,EAAQ,OAAO,CAAC,EAC1B,IAAK,IAAMF,KAASqB,EAChB,GAAKrB,EACL,IAAK,IAAMD,KAAWC,EAAM,SACxBD,EAAQ,MAAM,EACd,EAAQ,YAAc,CAGlC,EAEA,SAAU,CACN,IAAK,IAAMC,KAASE,EAAQ,OAAO,EAAGJ,EAAaE,CAAK,EACxDE,EAAQ,MAAM,CAClB,CACJ,CACJ,C"}
|