tempest-react-sdk 0.78.0 → 0.80.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.hostile.test.mjs +45 -4
- package/bin/lib/openapi/generate.mjs +303 -88
- package/bin/lib/openapi/generate.pagination.test.mjs +3 -2
- package/bin/lib/openapi/generate.test.mjs +462 -1
- package/bin/lib/openapi/schema-to-zod.mjs +4 -3
- 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 +1 -1
- package/dist/http/api-client.cjs.map +1 -1
- package/dist/http/api-client.js +5 -1
- package/dist/http/api-client.js.map +1 -1
- package/dist/http/build-url.cjs +1 -1
- package/dist/http/build-url.cjs.map +1 -1
- package/dist/http/build-url.js +3 -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/presigned-post.cjs +2 -0
- package/dist/http/presigned-post.cjs.map +1 -0
- package/dist/http/presigned-post.js +73 -0
- package/dist/http/presigned-post.js.map +1 -0
- 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 +1 -1
- package/dist/sse/create-event-stream.cjs.map +1 -1
- package/dist/sse/create-event-stream.js +44 -30
- package/dist/sse/create-event-stream.js.map +1 -1
- package/dist/sse/ticket-event-stream.cjs +2 -0
- package/dist/sse/ticket-event-stream.cjs.map +1 -0
- package/dist/sse/ticket-event-stream.js +41 -0
- package/dist/sse/ticket-event-stream.js.map +1 -0
- package/dist/sse/use-event-stream.cjs +1 -1
- package/dist/sse/use-event-stream.cjs.map +1 -1
- package/dist/sse/use-event-stream.js +7 -4
- 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 +440 -7
- package/dist/tempest-react-sdk.js +122 -120
- 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":"voice-chain-stages.cjs","names":[],"sources":["../../src/audio/voice-chain-stages.ts"],"sourcesContent":["/**\n * The individual stages a voice chain is built from, and the two side-chains\n * Web Audio cannot express declaratively.\n *\n * Split out of `voice-chain.ts` because every number here is a tuning decision\n * with a reason attached, and the file that assembles them should read as the\n * signal path rather than as a wall of constants.\n */\n\n/** Everything below this is rumble, not speech. */\nconst HIGH_PASS_HZ = 85;\n\n/** Where consonants live — the band that decides whether a word is understood. */\nconst PRESENCE_HZ = 3000;\nconst PRESENCE_GAIN_DB = 3;\nconst PRESENCE_Q = 1;\n\n/** Where microphone hiss lives, above anything speech needs. */\nconst HISS_HZ = 9000;\n\n/** The sibilance band a de-esser rides. */\nconst SIBILANCE_HZ = 7000;\nconst SIBILANCE_Q = 2;\n\n/** Deepest cut the de-esser applies, in dB. */\nconst DEESSER_MAX_CUT_DB = 10;\n\n/** Band energy above which the cut starts, as RMS. */\nconst DEESSER_THRESHOLD = 0.02;\n\n/** How steeply the cut follows the band's energy above the threshold. */\nconst DEESSER_SLOPE_DB_PER_RMS = 200;\n\n/** Seconds the de-esser takes to reach a new cut. */\nconst DEESSER_SMOOTHING = 0.02;\n\n/**\n * A leveller, not a limiter: 3:1 with a soft knee evens out the distance between\n * a whisper and a shout without audibly pumping.\n */\nconst COMPRESSOR = {\n threshold: -24,\n knee: 30,\n ratio: 3,\n attack: 0.003,\n release: 0.25,\n} as const;\n\n/**\n * The ceiling the limiter holds, in dB relative to full scale.\n *\n * Just under zero, because digital clipping is not a degradation the other end\n * can recover from — it arrives as squared-off samples that no amount of\n * processing undoes.\n */\nconst LIMITER = {\n threshold: -1,\n knee: 0,\n ratio: 20,\n attack: 0.001,\n release: 0.1,\n} as const;\n\n/** How often the gate and the de-esser look at the signal, in milliseconds. */\nexport const DETECTOR_POLL_MS = 20;\n\n/** Time constant for opening the gate. Short, so a first syllable survives. */\nconst GATE_ATTACK = 0.005;\n\n/** Time constant for closing it. Long, so a word does not end abruptly. */\nconst GATE_RELEASE = 0.12;\n\n/**\n * How long the gate stays open after the level drops.\n *\n * RMS falls to nothing between syllables, so a gate without hold chops speech\n * into pieces — it closes inside a word and reopens on the next one. This is the\n * difference between a gate that works and one everybody turns off again.\n */\nexport const GATE_HOLD_MS = 220;\n\n/** The window each detector reads. */\nconst DETECTOR_FFT_SIZE = 1024;\n\n/**\n * Root-mean-square of a time-domain window.\n *\n * RMS rather than peak because both detectors here answer \"how much energy is\n * there\", not \"did one sample spike\": a peak reading opens a gate on a keyboard\n * click and drives a de-esser off a single transient.\n *\n * @param buffer - Time-domain samples, -1..1.\n * @returns The window's RMS, 0..1.\n */\nfunction rms(buffer: Float32Array): number {\n let sum = 0;\n for (const sample of buffer) sum += sample * sample;\n return Math.sqrt(sum / buffer.length);\n}\n\n/** Build the analyser both detectors read through. */\nfunction detectorFor(context: AudioContext): AnalyserNode {\n const analyser = context.createAnalyser();\n analyser.fftSize = DETECTOR_FFT_SIZE;\n return analyser;\n}\n\n/** A high-pass at 85 Hz: fans, traffic, desk knocks, plosives. */\nexport function highPassStage(context: AudioContext): BiquadFilterNode {\n const filter = context.createBiquadFilter();\n filter.type = \"highpass\";\n filter.frequency.value = HIGH_PASS_HZ;\n return filter;\n}\n\n/** A 3:1 leveller with a soft knee. */\nexport function compressorStage(context: AudioContext): DynamicsCompressorNode {\n const comp = context.createDynamicsCompressor();\n comp.threshold.value = COMPRESSOR.threshold;\n comp.knee.value = COMPRESSOR.knee;\n comp.ratio.value = COMPRESSOR.ratio;\n comp.attack.value = COMPRESSOR.attack;\n comp.release.value = COMPRESSOR.release;\n return comp;\n}\n\n/** A +3 dB peak at 3 kHz: speech that reads without getting louder. */\nexport function presenceStage(context: AudioContext): BiquadFilterNode {\n const eq = context.createBiquadFilter();\n eq.type = \"peaking\";\n eq.frequency.value = PRESENCE_HZ;\n eq.Q.value = PRESENCE_Q;\n eq.gain.value = PRESENCE_GAIN_DB;\n return eq;\n}\n\n/** A low-pass at 9 kHz: the hiss of a cheap microphone. */\nexport function hissCutStage(context: AudioContext): BiquadFilterNode {\n const filter = context.createBiquadFilter();\n filter.type = \"lowpass\";\n filter.frequency.value = HISS_HZ;\n return filter;\n}\n\n/** A hard 20:1 ceiling at -1 dBFS, placed after the output gain. */\nexport function limiterStage(context: AudioContext): DynamicsCompressorNode {\n const limiter = context.createDynamicsCompressor();\n limiter.threshold.value = LIMITER.threshold;\n limiter.knee.value = LIMITER.knee;\n limiter.ratio.value = LIMITER.ratio;\n limiter.attack.value = LIMITER.attack;\n limiter.release.value = LIMITER.release;\n return limiter;\n}\n\n/** The nodes a gate stage owns. */\nexport interface GateStage {\n /** Reads the signal entering the gate. */\n detector: AnalyserNode;\n /** The gain the detector drives, 0 when closed. */\n gain: GainNode;\n /** Stop the detector's timer. */\n stop: () => void;\n}\n\n/**\n * Silence the line between phrases, without cutting inside a word.\n *\n * Measured on a timer rather than in an `AudioWorklet`. A worklet would gate\n * sample-accurately at the cost of a separate module file the consumer has to\n * serve and a second graph to keep in sync; at 20 ms the difference is inaudible\n * for speech, because the hold and the release are an order of magnitude longer\n * than the polling interval and are what actually shape how a gate sounds.\n *\n * The gate starts closed and opens on the first window over the threshold, so a\n * chain built while the room is quiet does not leak the first 20 ms of it.\n *\n * @param context - The graph's context.\n * @param threshold - Read on every tick, so the caller can move a slider while\n * the chain is live rather than rebuild it.\n * @returns The stage's nodes and its teardown.\n */\nexport function gateStage(context: AudioContext, threshold: () => number): GateStage {\n const detector = detectorFor(context);\n const gain = context.createGain();\n gain.gain.value = 0;\n\n const buffer = new Float32Array(detector.fftSize);\n let lastLoudAt = 0;\n\n const timer = setInterval(() => {\n detector.getFloatTimeDomainData(buffer);\n const now = performance.now();\n if (rms(buffer) >= threshold()) lastLoudAt = now;\n const open = lastLoudAt > 0 && now - lastLoudAt < GATE_HOLD_MS;\n gain.gain.setTargetAtTime(\n open ? 1 : 0,\n context.currentTime,\n open ? GATE_ATTACK : GATE_RELEASE,\n );\n }, DETECTOR_POLL_MS);\n\n return { detector, gain, stop: () => clearInterval(timer) };\n}\n\n/** The nodes a de-esser stage owns. */\nexport interface DeEsserStage {\n /** Band-pass feeding the detector — the side-chain's input. */\n band: BiquadFilterNode;\n /** Reads 6-8 kHz only. */\n detector: AnalyserNode;\n /** The peaking filter in the signal path, whose gain rides the band. */\n shaper: BiquadFilterNode;\n /** Stop the detector's timer. */\n stop: () => void;\n}\n\n/**\n * Pull the sibilance band down while it is loud, and let go when it is not.\n *\n * Web Audio has no side-chain, so the detector is built by hand: a band-pass\n * feeds an analyser watching only 6-8 kHz, and that analyser's energy drives the\n * gain of a peaking filter sitting in the main path. The distinction is the whole\n * stage — the cut has to answer to the *band*, not to how loud the person is. A\n * static cut at the same frequency would dull every consonant instead of the\n * syllables that actually hiss.\n *\n * @param context - The graph's context.\n * @returns The stage's nodes and its teardown.\n */\nexport function deEsserStage(context: AudioContext): DeEsserStage {\n const band = context.createBiquadFilter();\n band.type = \"bandpass\";\n band.frequency.value = SIBILANCE_HZ;\n band.Q.value = SIBILANCE_Q;\n\n const detector = detectorFor(context);\n band.connect(detector);\n\n const shaper = context.createBiquadFilter();\n shaper.type = \"peaking\";\n shaper.frequency.value = SIBILANCE_HZ;\n shaper.Q.value = SIBILANCE_Q;\n shaper.gain.value = 0;\n\n const buffer = new Float32Array(detector.fftSize);\n const timer = setInterval(() => {\n detector.getFloatTimeDomainData(buffer);\n const over = Math.max(0, rms(buffer) - DEESSER_THRESHOLD);\n const cut = Math.min(DEESSER_MAX_CUT_DB, over * DEESSER_SLOPE_DB_PER_RMS);\n shaper.gain.setTargetAtTime(-cut, context.currentTime, DEESSER_SMOOTHING);\n }, DETECTOR_POLL_MS);\n\n return { band, detector, shaper, stop: () => clearInterval(timer) };\n}\n\nexport { rms as windowRms };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"voice-chain-stages.cjs","names":["SIBILANCE_HZ","COMPRESSOR","LIMITER","GATE_ATTACK","GATE_RELEASE","DETECTOR_FFT_SIZE","rms","sum","sample","buffer","detectorFor","analyser","context","highPassStage","filter","compressorStage","comp","presenceStage","eq","hissCutStage","limiterStage","limiter","gateStage","detector","gain","lastLoudAt","timer","now","threshold","open","deEsserStage","band","shaper","over","cut"],"sources":["../../src/audio/voice-chain-stages.ts"],"sourcesContent":["/**\n * The individual stages a voice chain is built from, and the two side-chains\n * Web Audio cannot express declaratively.\n *\n * Split out of `voice-chain.ts` because every number here is a tuning decision\n * with a reason attached, and the file that assembles them should read as the\n * signal path rather than as a wall of constants.\n */\n\n/** Everything below this is rumble, not speech. */\nconst HIGH_PASS_HZ = 85;\n\n/** Where consonants live — the band that decides whether a word is understood. */\nconst PRESENCE_HZ = 3000;\nconst PRESENCE_GAIN_DB = 3;\nconst PRESENCE_Q = 1;\n\n/** Where microphone hiss lives, above anything speech needs. */\nconst HISS_HZ = 9000;\n\n/** The sibilance band a de-esser rides. */\nconst SIBILANCE_HZ = 7000;\nconst SIBILANCE_Q = 2;\n\n/** Deepest cut the de-esser applies, in dB. */\nconst DEESSER_MAX_CUT_DB = 10;\n\n/** Band energy above which the cut starts, as RMS. */\nconst DEESSER_THRESHOLD = 0.02;\n\n/** How steeply the cut follows the band's energy above the threshold. */\nconst DEESSER_SLOPE_DB_PER_RMS = 200;\n\n/** Seconds the de-esser takes to reach a new cut. */\nconst DEESSER_SMOOTHING = 0.02;\n\n/**\n * A leveller, not a limiter: 3:1 with a soft knee evens out the distance between\n * a whisper and a shout without audibly pumping.\n */\nconst COMPRESSOR = {\n threshold: -24,\n knee: 30,\n ratio: 3,\n attack: 0.003,\n release: 0.25,\n} as const;\n\n/**\n * The ceiling the limiter holds, in dB relative to full scale.\n *\n * Just under zero, because digital clipping is not a degradation the other end\n * can recover from — it arrives as squared-off samples that no amount of\n * processing undoes.\n */\nconst LIMITER = {\n threshold: -1,\n knee: 0,\n ratio: 20,\n attack: 0.001,\n release: 0.1,\n} as const;\n\n/** How often the gate and the de-esser look at the signal, in milliseconds. */\nexport const DETECTOR_POLL_MS = 20;\n\n/** Time constant for opening the gate. Short, so a first syllable survives. */\nconst GATE_ATTACK = 0.005;\n\n/** Time constant for closing it. Long, so a word does not end abruptly. */\nconst GATE_RELEASE = 0.12;\n\n/**\n * How long the gate stays open after the level drops.\n *\n * RMS falls to nothing between syllables, so a gate without hold chops speech\n * into pieces — it closes inside a word and reopens on the next one. This is the\n * difference between a gate that works and one everybody turns off again.\n */\nexport const GATE_HOLD_MS = 220;\n\n/** The window each detector reads. */\nconst DETECTOR_FFT_SIZE = 1024;\n\n/**\n * Root-mean-square of a time-domain window.\n *\n * RMS rather than peak because both detectors here answer \"how much energy is\n * there\", not \"did one sample spike\": a peak reading opens a gate on a keyboard\n * click and drives a de-esser off a single transient.\n *\n * @param buffer - Time-domain samples, -1..1.\n * @returns The window's RMS, 0..1.\n */\nfunction rms(buffer: Float32Array): number {\n let sum = 0;\n for (const sample of buffer) sum += sample * sample;\n return Math.sqrt(sum / buffer.length);\n}\n\n/** Build the analyser both detectors read through. */\nfunction detectorFor(context: AudioContext): AnalyserNode {\n const analyser = context.createAnalyser();\n analyser.fftSize = DETECTOR_FFT_SIZE;\n return analyser;\n}\n\n/** A high-pass at 85 Hz: fans, traffic, desk knocks, plosives. */\nexport function highPassStage(context: AudioContext): BiquadFilterNode {\n const filter = context.createBiquadFilter();\n filter.type = \"highpass\";\n filter.frequency.value = HIGH_PASS_HZ;\n return filter;\n}\n\n/** A 3:1 leveller with a soft knee. */\nexport function compressorStage(context: AudioContext): DynamicsCompressorNode {\n const comp = context.createDynamicsCompressor();\n comp.threshold.value = COMPRESSOR.threshold;\n comp.knee.value = COMPRESSOR.knee;\n comp.ratio.value = COMPRESSOR.ratio;\n comp.attack.value = COMPRESSOR.attack;\n comp.release.value = COMPRESSOR.release;\n return comp;\n}\n\n/** A +3 dB peak at 3 kHz: speech that reads without getting louder. */\nexport function presenceStage(context: AudioContext): BiquadFilterNode {\n const eq = context.createBiquadFilter();\n eq.type = \"peaking\";\n eq.frequency.value = PRESENCE_HZ;\n eq.Q.value = PRESENCE_Q;\n eq.gain.value = PRESENCE_GAIN_DB;\n return eq;\n}\n\n/** A low-pass at 9 kHz: the hiss of a cheap microphone. */\nexport function hissCutStage(context: AudioContext): BiquadFilterNode {\n const filter = context.createBiquadFilter();\n filter.type = \"lowpass\";\n filter.frequency.value = HISS_HZ;\n return filter;\n}\n\n/** A hard 20:1 ceiling at -1 dBFS, placed after the output gain. */\nexport function limiterStage(context: AudioContext): DynamicsCompressorNode {\n const limiter = context.createDynamicsCompressor();\n limiter.threshold.value = LIMITER.threshold;\n limiter.knee.value = LIMITER.knee;\n limiter.ratio.value = LIMITER.ratio;\n limiter.attack.value = LIMITER.attack;\n limiter.release.value = LIMITER.release;\n return limiter;\n}\n\n/** The nodes a gate stage owns. */\nexport interface GateStage {\n /** Reads the signal entering the gate. */\n detector: AnalyserNode;\n /** The gain the detector drives, 0 when closed. */\n gain: GainNode;\n /** Stop the detector's timer. */\n stop: () => void;\n}\n\n/**\n * Silence the line between phrases, without cutting inside a word.\n *\n * Measured on a timer rather than in an `AudioWorklet`. A worklet would gate\n * sample-accurately at the cost of a separate module file the consumer has to\n * serve and a second graph to keep in sync; at 20 ms the difference is inaudible\n * for speech, because the hold and the release are an order of magnitude longer\n * than the polling interval and are what actually shape how a gate sounds.\n *\n * The gate starts closed and opens on the first window over the threshold, so a\n * chain built while the room is quiet does not leak the first 20 ms of it.\n *\n * @param context - The graph's context.\n * @param threshold - Read on every tick, so the caller can move a slider while\n * the chain is live rather than rebuild it.\n * @returns The stage's nodes and its teardown.\n */\nexport function gateStage(context: AudioContext, threshold: () => number): GateStage {\n const detector = detectorFor(context);\n const gain = context.createGain();\n gain.gain.value = 0;\n\n const buffer = new Float32Array(detector.fftSize);\n let lastLoudAt = 0;\n\n const timer = setInterval(() => {\n detector.getFloatTimeDomainData(buffer);\n const now = performance.now();\n if (rms(buffer) >= threshold()) lastLoudAt = now;\n const open = lastLoudAt > 0 && now - lastLoudAt < GATE_HOLD_MS;\n gain.gain.setTargetAtTime(\n open ? 1 : 0,\n context.currentTime,\n open ? GATE_ATTACK : GATE_RELEASE,\n );\n }, DETECTOR_POLL_MS);\n\n return { detector, gain, stop: () => clearInterval(timer) };\n}\n\n/** The nodes a de-esser stage owns. */\nexport interface DeEsserStage {\n /** Band-pass feeding the detector — the side-chain's input. */\n band: BiquadFilterNode;\n /** Reads 6-8 kHz only. */\n detector: AnalyserNode;\n /** The peaking filter in the signal path, whose gain rides the band. */\n shaper: BiquadFilterNode;\n /** Stop the detector's timer. */\n stop: () => void;\n}\n\n/**\n * Pull the sibilance band down while it is loud, and let go when it is not.\n *\n * Web Audio has no side-chain, so the detector is built by hand: a band-pass\n * feeds an analyser watching only 6-8 kHz, and that analyser's energy drives the\n * gain of a peaking filter sitting in the main path. The distinction is the whole\n * stage — the cut has to answer to the *band*, not to how loud the person is. A\n * static cut at the same frequency would dull every consonant instead of the\n * syllables that actually hiss.\n *\n * @param context - The graph's context.\n * @returns The stage's nodes and its teardown.\n */\nexport function deEsserStage(context: AudioContext): DeEsserStage {\n const band = context.createBiquadFilter();\n band.type = \"bandpass\";\n band.frequency.value = SIBILANCE_HZ;\n band.Q.value = SIBILANCE_Q;\n\n const detector = detectorFor(context);\n band.connect(detector);\n\n const shaper = context.createBiquadFilter();\n shaper.type = \"peaking\";\n shaper.frequency.value = SIBILANCE_HZ;\n shaper.Q.value = SIBILANCE_Q;\n shaper.gain.value = 0;\n\n const buffer = new Float32Array(detector.fftSize);\n const timer = setInterval(() => {\n detector.getFloatTimeDomainData(buffer);\n const over = Math.max(0, rms(buffer) - DEESSER_THRESHOLD);\n const cut = Math.min(DEESSER_MAX_CUT_DB, over * DEESSER_SLOPE_DB_PER_RMS);\n shaper.gain.setTargetAtTime(-cut, context.currentTime, DEESSER_SMOOTHING);\n }, DETECTOR_POLL_MS);\n\n return { band, detector, shaper, stop: () => clearInterval(timer) };\n}\n\nexport { rms as windowRms };\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voice-chain-stages.js","names":[],"sources":["../../src/audio/voice-chain-stages.ts"],"sourcesContent":["/**\n * The individual stages a voice chain is built from, and the two side-chains\n * Web Audio cannot express declaratively.\n *\n * Split out of `voice-chain.ts` because every number here is a tuning decision\n * with a reason attached, and the file that assembles them should read as the\n * signal path rather than as a wall of constants.\n */\n\n/** Everything below this is rumble, not speech. */\nconst HIGH_PASS_HZ = 85;\n\n/** Where consonants live — the band that decides whether a word is understood. */\nconst PRESENCE_HZ = 3000;\nconst PRESENCE_GAIN_DB = 3;\nconst PRESENCE_Q = 1;\n\n/** Where microphone hiss lives, above anything speech needs. */\nconst HISS_HZ = 9000;\n\n/** The sibilance band a de-esser rides. */\nconst SIBILANCE_HZ = 7000;\nconst SIBILANCE_Q = 2;\n\n/** Deepest cut the de-esser applies, in dB. */\nconst DEESSER_MAX_CUT_DB = 10;\n\n/** Band energy above which the cut starts, as RMS. */\nconst DEESSER_THRESHOLD = 0.02;\n\n/** How steeply the cut follows the band's energy above the threshold. */\nconst DEESSER_SLOPE_DB_PER_RMS = 200;\n\n/** Seconds the de-esser takes to reach a new cut. */\nconst DEESSER_SMOOTHING = 0.02;\n\n/**\n * A leveller, not a limiter: 3:1 with a soft knee evens out the distance between\n * a whisper and a shout without audibly pumping.\n */\nconst COMPRESSOR = {\n threshold: -24,\n knee: 30,\n ratio: 3,\n attack: 0.003,\n release: 0.25,\n} as const;\n\n/**\n * The ceiling the limiter holds, in dB relative to full scale.\n *\n * Just under zero, because digital clipping is not a degradation the other end\n * can recover from — it arrives as squared-off samples that no amount of\n * processing undoes.\n */\nconst LIMITER = {\n threshold: -1,\n knee: 0,\n ratio: 20,\n attack: 0.001,\n release: 0.1,\n} as const;\n\n/** How often the gate and the de-esser look at the signal, in milliseconds. */\nexport const DETECTOR_POLL_MS = 20;\n\n/** Time constant for opening the gate. Short, so a first syllable survives. */\nconst GATE_ATTACK = 0.005;\n\n/** Time constant for closing it. Long, so a word does not end abruptly. */\nconst GATE_RELEASE = 0.12;\n\n/**\n * How long the gate stays open after the level drops.\n *\n * RMS falls to nothing between syllables, so a gate without hold chops speech\n * into pieces — it closes inside a word and reopens on the next one. This is the\n * difference between a gate that works and one everybody turns off again.\n */\nexport const GATE_HOLD_MS = 220;\n\n/** The window each detector reads. */\nconst DETECTOR_FFT_SIZE = 1024;\n\n/**\n * Root-mean-square of a time-domain window.\n *\n * RMS rather than peak because both detectors here answer \"how much energy is\n * there\", not \"did one sample spike\": a peak reading opens a gate on a keyboard\n * click and drives a de-esser off a single transient.\n *\n * @param buffer - Time-domain samples, -1..1.\n * @returns The window's RMS, 0..1.\n */\nfunction rms(buffer: Float32Array): number {\n let sum = 0;\n for (const sample of buffer) sum += sample * sample;\n return Math.sqrt(sum / buffer.length);\n}\n\n/** Build the analyser both detectors read through. */\nfunction detectorFor(context: AudioContext): AnalyserNode {\n const analyser = context.createAnalyser();\n analyser.fftSize = DETECTOR_FFT_SIZE;\n return analyser;\n}\n\n/** A high-pass at 85 Hz: fans, traffic, desk knocks, plosives. */\nexport function highPassStage(context: AudioContext): BiquadFilterNode {\n const filter = context.createBiquadFilter();\n filter.type = \"highpass\";\n filter.frequency.value = HIGH_PASS_HZ;\n return filter;\n}\n\n/** A 3:1 leveller with a soft knee. */\nexport function compressorStage(context: AudioContext): DynamicsCompressorNode {\n const comp = context.createDynamicsCompressor();\n comp.threshold.value = COMPRESSOR.threshold;\n comp.knee.value = COMPRESSOR.knee;\n comp.ratio.value = COMPRESSOR.ratio;\n comp.attack.value = COMPRESSOR.attack;\n comp.release.value = COMPRESSOR.release;\n return comp;\n}\n\n/** A +3 dB peak at 3 kHz: speech that reads without getting louder. */\nexport function presenceStage(context: AudioContext): BiquadFilterNode {\n const eq = context.createBiquadFilter();\n eq.type = \"peaking\";\n eq.frequency.value = PRESENCE_HZ;\n eq.Q.value = PRESENCE_Q;\n eq.gain.value = PRESENCE_GAIN_DB;\n return eq;\n}\n\n/** A low-pass at 9 kHz: the hiss of a cheap microphone. */\nexport function hissCutStage(context: AudioContext): BiquadFilterNode {\n const filter = context.createBiquadFilter();\n filter.type = \"lowpass\";\n filter.frequency.value = HISS_HZ;\n return filter;\n}\n\n/** A hard 20:1 ceiling at -1 dBFS, placed after the output gain. */\nexport function limiterStage(context: AudioContext): DynamicsCompressorNode {\n const limiter = context.createDynamicsCompressor();\n limiter.threshold.value = LIMITER.threshold;\n limiter.knee.value = LIMITER.knee;\n limiter.ratio.value = LIMITER.ratio;\n limiter.attack.value = LIMITER.attack;\n limiter.release.value = LIMITER.release;\n return limiter;\n}\n\n/** The nodes a gate stage owns. */\nexport interface GateStage {\n /** Reads the signal entering the gate. */\n detector: AnalyserNode;\n /** The gain the detector drives, 0 when closed. */\n gain: GainNode;\n /** Stop the detector's timer. */\n stop: () => void;\n}\n\n/**\n * Silence the line between phrases, without cutting inside a word.\n *\n * Measured on a timer rather than in an `AudioWorklet`. A worklet would gate\n * sample-accurately at the cost of a separate module file the consumer has to\n * serve and a second graph to keep in sync; at 20 ms the difference is inaudible\n * for speech, because the hold and the release are an order of magnitude longer\n * than the polling interval and are what actually shape how a gate sounds.\n *\n * The gate starts closed and opens on the first window over the threshold, so a\n * chain built while the room is quiet does not leak the first 20 ms of it.\n *\n * @param context - The graph's context.\n * @param threshold - Read on every tick, so the caller can move a slider while\n * the chain is live rather than rebuild it.\n * @returns The stage's nodes and its teardown.\n */\nexport function gateStage(context: AudioContext, threshold: () => number): GateStage {\n const detector = detectorFor(context);\n const gain = context.createGain();\n gain.gain.value = 0;\n\n const buffer = new Float32Array(detector.fftSize);\n let lastLoudAt = 0;\n\n const timer = setInterval(() => {\n detector.getFloatTimeDomainData(buffer);\n const now = performance.now();\n if (rms(buffer) >= threshold()) lastLoudAt = now;\n const open = lastLoudAt > 0 && now - lastLoudAt < GATE_HOLD_MS;\n gain.gain.setTargetAtTime(\n open ? 1 : 0,\n context.currentTime,\n open ? GATE_ATTACK : GATE_RELEASE,\n );\n }, DETECTOR_POLL_MS);\n\n return { detector, gain, stop: () => clearInterval(timer) };\n}\n\n/** The nodes a de-esser stage owns. */\nexport interface DeEsserStage {\n /** Band-pass feeding the detector — the side-chain's input. */\n band: BiquadFilterNode;\n /** Reads 6-8 kHz only. */\n detector: AnalyserNode;\n /** The peaking filter in the signal path, whose gain rides the band. */\n shaper: BiquadFilterNode;\n /** Stop the detector's timer. */\n stop: () => void;\n}\n\n/**\n * Pull the sibilance band down while it is loud, and let go when it is not.\n *\n * Web Audio has no side-chain, so the detector is built by hand: a band-pass\n * feeds an analyser watching only 6-8 kHz, and that analyser's energy drives the\n * gain of a peaking filter sitting in the main path. The distinction is the whole\n * stage — the cut has to answer to the *band*, not to how loud the person is. A\n * static cut at the same frequency would dull every consonant instead of the\n * syllables that actually hiss.\n *\n * @param context - The graph's context.\n * @returns The stage's nodes and its teardown.\n */\nexport function deEsserStage(context: AudioContext): DeEsserStage {\n const band = context.createBiquadFilter();\n band.type = \"bandpass\";\n band.frequency.value = SIBILANCE_HZ;\n band.Q.value = SIBILANCE_Q;\n\n const detector = detectorFor(context);\n band.connect(detector);\n\n const shaper = context.createBiquadFilter();\n shaper.type = \"peaking\";\n shaper.frequency.value = SIBILANCE_HZ;\n shaper.Q.value = SIBILANCE_Q;\n shaper.gain.value = 0;\n\n const buffer = new Float32Array(detector.fftSize);\n const timer = setInterval(() => {\n detector.getFloatTimeDomainData(buffer);\n const over = Math.max(0, rms(buffer) - DEESSER_THRESHOLD);\n const cut = Math.min(DEESSER_MAX_CUT_DB, over * DEESSER_SLOPE_DB_PER_RMS);\n shaper.gain.setTargetAtTime(-cut, context.currentTime, DEESSER_SMOOTHING);\n }, DETECTOR_POLL_MS);\n\n return { band, detector, shaper, stop: () => clearInterval(timer) };\n}\n\nexport { rms as windowRms };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"voice-chain-stages.js","names":["SIBILANCE_HZ","COMPRESSOR","LIMITER","GATE_ATTACK","GATE_RELEASE","DETECTOR_FFT_SIZE","rms","sum","sample","buffer","detectorFor","analyser","context","highPassStage","filter","compressorStage","comp","presenceStage","eq","hissCutStage","limiterStage","limiter","gateStage","detector","gain","lastLoudAt","timer","now","threshold","open","deEsserStage","band","shaper","over","cut"],"sources":["../../src/audio/voice-chain-stages.ts"],"sourcesContent":["/**\n * The individual stages a voice chain is built from, and the two side-chains\n * Web Audio cannot express declaratively.\n *\n * Split out of `voice-chain.ts` because every number here is a tuning decision\n * with a reason attached, and the file that assembles them should read as the\n * signal path rather than as a wall of constants.\n */\n\n/** Everything below this is rumble, not speech. */\nconst HIGH_PASS_HZ = 85;\n\n/** Where consonants live — the band that decides whether a word is understood. */\nconst PRESENCE_HZ = 3000;\nconst PRESENCE_GAIN_DB = 3;\nconst PRESENCE_Q = 1;\n\n/** Where microphone hiss lives, above anything speech needs. */\nconst HISS_HZ = 9000;\n\n/** The sibilance band a de-esser rides. */\nconst SIBILANCE_HZ = 7000;\nconst SIBILANCE_Q = 2;\n\n/** Deepest cut the de-esser applies, in dB. */\nconst DEESSER_MAX_CUT_DB = 10;\n\n/** Band energy above which the cut starts, as RMS. */\nconst DEESSER_THRESHOLD = 0.02;\n\n/** How steeply the cut follows the band's energy above the threshold. */\nconst DEESSER_SLOPE_DB_PER_RMS = 200;\n\n/** Seconds the de-esser takes to reach a new cut. */\nconst DEESSER_SMOOTHING = 0.02;\n\n/**\n * A leveller, not a limiter: 3:1 with a soft knee evens out the distance between\n * a whisper and a shout without audibly pumping.\n */\nconst COMPRESSOR = {\n threshold: -24,\n knee: 30,\n ratio: 3,\n attack: 0.003,\n release: 0.25,\n} as const;\n\n/**\n * The ceiling the limiter holds, in dB relative to full scale.\n *\n * Just under zero, because digital clipping is not a degradation the other end\n * can recover from — it arrives as squared-off samples that no amount of\n * processing undoes.\n */\nconst LIMITER = {\n threshold: -1,\n knee: 0,\n ratio: 20,\n attack: 0.001,\n release: 0.1,\n} as const;\n\n/** How often the gate and the de-esser look at the signal, in milliseconds. */\nexport const DETECTOR_POLL_MS = 20;\n\n/** Time constant for opening the gate. Short, so a first syllable survives. */\nconst GATE_ATTACK = 0.005;\n\n/** Time constant for closing it. Long, so a word does not end abruptly. */\nconst GATE_RELEASE = 0.12;\n\n/**\n * How long the gate stays open after the level drops.\n *\n * RMS falls to nothing between syllables, so a gate without hold chops speech\n * into pieces — it closes inside a word and reopens on the next one. This is the\n * difference between a gate that works and one everybody turns off again.\n */\nexport const GATE_HOLD_MS = 220;\n\n/** The window each detector reads. */\nconst DETECTOR_FFT_SIZE = 1024;\n\n/**\n * Root-mean-square of a time-domain window.\n *\n * RMS rather than peak because both detectors here answer \"how much energy is\n * there\", not \"did one sample spike\": a peak reading opens a gate on a keyboard\n * click and drives a de-esser off a single transient.\n *\n * @param buffer - Time-domain samples, -1..1.\n * @returns The window's RMS, 0..1.\n */\nfunction rms(buffer: Float32Array): number {\n let sum = 0;\n for (const sample of buffer) sum += sample * sample;\n return Math.sqrt(sum / buffer.length);\n}\n\n/** Build the analyser both detectors read through. */\nfunction detectorFor(context: AudioContext): AnalyserNode {\n const analyser = context.createAnalyser();\n analyser.fftSize = DETECTOR_FFT_SIZE;\n return analyser;\n}\n\n/** A high-pass at 85 Hz: fans, traffic, desk knocks, plosives. */\nexport function highPassStage(context: AudioContext): BiquadFilterNode {\n const filter = context.createBiquadFilter();\n filter.type = \"highpass\";\n filter.frequency.value = HIGH_PASS_HZ;\n return filter;\n}\n\n/** A 3:1 leveller with a soft knee. */\nexport function compressorStage(context: AudioContext): DynamicsCompressorNode {\n const comp = context.createDynamicsCompressor();\n comp.threshold.value = COMPRESSOR.threshold;\n comp.knee.value = COMPRESSOR.knee;\n comp.ratio.value = COMPRESSOR.ratio;\n comp.attack.value = COMPRESSOR.attack;\n comp.release.value = COMPRESSOR.release;\n return comp;\n}\n\n/** A +3 dB peak at 3 kHz: speech that reads without getting louder. */\nexport function presenceStage(context: AudioContext): BiquadFilterNode {\n const eq = context.createBiquadFilter();\n eq.type = \"peaking\";\n eq.frequency.value = PRESENCE_HZ;\n eq.Q.value = PRESENCE_Q;\n eq.gain.value = PRESENCE_GAIN_DB;\n return eq;\n}\n\n/** A low-pass at 9 kHz: the hiss of a cheap microphone. */\nexport function hissCutStage(context: AudioContext): BiquadFilterNode {\n const filter = context.createBiquadFilter();\n filter.type = \"lowpass\";\n filter.frequency.value = HISS_HZ;\n return filter;\n}\n\n/** A hard 20:1 ceiling at -1 dBFS, placed after the output gain. */\nexport function limiterStage(context: AudioContext): DynamicsCompressorNode {\n const limiter = context.createDynamicsCompressor();\n limiter.threshold.value = LIMITER.threshold;\n limiter.knee.value = LIMITER.knee;\n limiter.ratio.value = LIMITER.ratio;\n limiter.attack.value = LIMITER.attack;\n limiter.release.value = LIMITER.release;\n return limiter;\n}\n\n/** The nodes a gate stage owns. */\nexport interface GateStage {\n /** Reads the signal entering the gate. */\n detector: AnalyserNode;\n /** The gain the detector drives, 0 when closed. */\n gain: GainNode;\n /** Stop the detector's timer. */\n stop: () => void;\n}\n\n/**\n * Silence the line between phrases, without cutting inside a word.\n *\n * Measured on a timer rather than in an `AudioWorklet`. A worklet would gate\n * sample-accurately at the cost of a separate module file the consumer has to\n * serve and a second graph to keep in sync; at 20 ms the difference is inaudible\n * for speech, because the hold and the release are an order of magnitude longer\n * than the polling interval and are what actually shape how a gate sounds.\n *\n * The gate starts closed and opens on the first window over the threshold, so a\n * chain built while the room is quiet does not leak the first 20 ms of it.\n *\n * @param context - The graph's context.\n * @param threshold - Read on every tick, so the caller can move a slider while\n * the chain is live rather than rebuild it.\n * @returns The stage's nodes and its teardown.\n */\nexport function gateStage(context: AudioContext, threshold: () => number): GateStage {\n const detector = detectorFor(context);\n const gain = context.createGain();\n gain.gain.value = 0;\n\n const buffer = new Float32Array(detector.fftSize);\n let lastLoudAt = 0;\n\n const timer = setInterval(() => {\n detector.getFloatTimeDomainData(buffer);\n const now = performance.now();\n if (rms(buffer) >= threshold()) lastLoudAt = now;\n const open = lastLoudAt > 0 && now - lastLoudAt < GATE_HOLD_MS;\n gain.gain.setTargetAtTime(\n open ? 1 : 0,\n context.currentTime,\n open ? GATE_ATTACK : GATE_RELEASE,\n );\n }, DETECTOR_POLL_MS);\n\n return { detector, gain, stop: () => clearInterval(timer) };\n}\n\n/** The nodes a de-esser stage owns. */\nexport interface DeEsserStage {\n /** Band-pass feeding the detector — the side-chain's input. */\n band: BiquadFilterNode;\n /** Reads 6-8 kHz only. */\n detector: AnalyserNode;\n /** The peaking filter in the signal path, whose gain rides the band. */\n shaper: BiquadFilterNode;\n /** Stop the detector's timer. */\n stop: () => void;\n}\n\n/**\n * Pull the sibilance band down while it is loud, and let go when it is not.\n *\n * Web Audio has no side-chain, so the detector is built by hand: a band-pass\n * feeds an analyser watching only 6-8 kHz, and that analyser's energy drives the\n * gain of a peaking filter sitting in the main path. The distinction is the whole\n * stage — the cut has to answer to the *band*, not to how loud the person is. A\n * static cut at the same frequency would dull every consonant instead of the\n * syllables that actually hiss.\n *\n * @param context - The graph's context.\n * @returns The stage's nodes and its teardown.\n */\nexport function deEsserStage(context: AudioContext): DeEsserStage {\n const band = context.createBiquadFilter();\n band.type = \"bandpass\";\n band.frequency.value = SIBILANCE_HZ;\n band.Q.value = SIBILANCE_Q;\n\n const detector = detectorFor(context);\n band.connect(detector);\n\n const shaper = context.createBiquadFilter();\n shaper.type = \"peaking\";\n shaper.frequency.value = SIBILANCE_HZ;\n shaper.Q.value = SIBILANCE_Q;\n shaper.gain.value = 0;\n\n const buffer = new Float32Array(detector.fftSize);\n const timer = setInterval(() => {\n detector.getFloatTimeDomainData(buffer);\n const over = Math.max(0, rms(buffer) - DEESSER_THRESHOLD);\n const cut = Math.min(DEESSER_MAX_CUT_DB, over * DEESSER_SLOPE_DB_PER_RMS);\n shaper.gain.setTargetAtTime(-cut, context.currentTime, DEESSER_SMOOTHING);\n }, DETECTOR_POLL_MS);\n\n return { band, detector, shaper, stop: () => clearInterval(timer) };\n}\n\nexport { rms as windowRms };\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voice-chain.cjs","names":[],"sources":["../../src/audio/voice-chain.ts"],"sourcesContent":["import {\n compressorStage,\n deEsserStage,\n gateStage,\n highPassStage,\n hissCutStage,\n limiterStage,\n presenceStage,\n} from \"./voice-chain-stages\";\n\n/** Which stages a voice chain builds. */\nexport interface VoiceChainSettings {\n /** Cut everything below speech: fans, traffic rumble, desk knocks, plosives. */\n highPass: boolean;\n /** Silence the line when nobody is talking. */\n gate: boolean;\n /** RMS below which the gate closes, 0..1. See {@link suggestGateThreshold}. */\n gateThreshold: number;\n /** Even out the distance between a whisper and a shout. */\n compressor: boolean;\n /** Lift the consonant band so speech reads without getting louder. */\n presence: boolean;\n /** Roll off hiss above what speech uses. */\n hissCut: boolean;\n /** Ride down harsh S and CH sounds. */\n deEsser: boolean;\n /**\n * Hard ceiling before the signal leaves.\n *\n * On by default and worth leaving on: the leveller is 3:1, which controls the\n * average and lets a peak through, and `gain` can reach well above 1.\n */\n limiter: boolean;\n}\n\n/**\n * What a call wants before anybody touches a slider.\n *\n * High-pass, leveller and limiter only. Gate, presence, hiss cut and de-esser are\n * off because each has an audible cost when it is not needed — a gate set for the\n * wrong room clips words, presence on a bright microphone is harsh, and a de-esser\n * on a voice that does not hiss just dulls it.\n */\nexport const DEFAULT_VOICE_CHAIN: VoiceChainSettings = {\n highPass: true,\n gate: false,\n gateThreshold: 0.02,\n compressor: true,\n presence: false,\n hissCut: false,\n deEsser: false,\n limiter: true,\n};\n\n/** Options for {@link createVoiceChain}. */\nexport interface VoiceChainOptions {\n /** Output multiplier, applied after every stage and before the limiter. Default `1`. */\n gain?: number;\n /**\n * Reuse an existing `AudioContext` instead of creating one.\n *\n * Browsers cap live contexts (Chrome allows around six), so a page that already\n * has one — a level meter, an audio bus — should hand it over.\n */\n context?: AudioContext;\n /**\n * Whether `release()` also stops `source`. Default `true`.\n *\n * Pass `false` when the track belongs to somebody else: a settings dialog\n * building a second chain over its live preview would otherwise kill the meter\n * the person is watching while they listen.\n */\n ownsSource?: boolean;\n}\n\n/** A running voice chain. */\nexport interface VoiceChain {\n /** The processed track to publish. */\n track: MediaStreamTrack;\n /** Stop the detectors, disconnect the graph, and release the track. */\n release: () => void;\n /**\n * Whether a graph was actually built.\n *\n * `false` when this engine has no Web Audio, and also when the settings asked\n * for nothing — in both cases `track` is `source`, untouched.\n */\n readonly supported: boolean;\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 * Whether any of this would change the signal.\n *\n * A chain that only passes audio through still costs a re-encode and a handful of\n * nodes, so a caller that rebuilds on every settings change should ask first —\n * and {@link createVoiceChain} asks too, handing back `source` rather than\n * building a graph that does nothing.\n *\n * @param settings - The stages under consideration.\n * @param gain - The output multiplier that would be applied. Default `1`.\n * @returns `true` when the chain would be audibly transparent.\n */\nexport function isVoiceChainIdle(settings: VoiceChainSettings, gain = 1): boolean {\n return (\n !settings.highPass &&\n !settings.gate &&\n !settings.compressor &&\n !settings.presence &&\n !settings.hissCut &&\n !settings.deEsser &&\n !settings.limiter &&\n gain === 1\n );\n}\n\n/** A chain that owns nothing, for an engine or a settings object with no work to do. */\nfunction passThrough(source: MediaStreamTrack, ownsSource: boolean): VoiceChain {\n return {\n track: source,\n release: () => {\n if (ownsSource) source.stop();\n },\n supported: false,\n };\n}\n\n/**\n * Build the processing a microphone is published through.\n *\n * Ordered the way a console is: cut what is not speech, gate what is left, level\n * it, shape it, set how loud it goes out, then hold a ceiling. **The order is not\n * cosmetic.** Gating before the high-pass lets a rumble hold the gate open;\n * compressing before the gate lifts the noise floor up to meet the threshold; and\n * a limiter placed before the output gain is a ceiling the gain then walks\n * straight through.\n *\n * This sits *after* the browser's own echo cancellation and noise suppression,\n * which stay on: the two solve different problems. The browser's is trained on\n * stationary noise inside the capture pipeline; this cuts what it leaves behind\n * and decides when the line should be silent at all.\n *\n * @param source - The captured microphone track.\n * @param settings - Which stages to build. Default {@link DEFAULT_VOICE_CHAIN}.\n * @param options - See {@link VoiceChainOptions}.\n * @returns The track to publish plus its teardown. On an engine with no Web Audio,\n * and when every stage is off, the source track is handed back untouched and\n * `supported` is `false` — a call without processing beats a call that throws.\n * The idle case is decided **before** a context is opened, because browsers cap\n * how many can be live and one built for a chain that does nothing still counts.\n *\n * @example\n * const floor = await measureNoiseFloor(stream);\n * const chain = createVoiceChain(micTrack, {\n * ...DEFAULT_VOICE_CHAIN,\n * gate: true,\n * gateThreshold: suggestGateThreshold(floor),\n * }, { gain: 1.4 });\n * await mesh.setLocalTrack(\"mic\", chain.track);\n */\nexport function createVoiceChain(\n source: MediaStreamTrack,\n settings: VoiceChainSettings = DEFAULT_VOICE_CHAIN,\n { gain = 1, context: injectedContext, ownsSource = true }: VoiceChainOptions = {},\n): VoiceChain {\n if (isVoiceChainIdle(settings, gain)) return passThrough(source, ownsSource);\n\n const Ctor = audioContextConstructor();\n const context = injectedContext ?? (Ctor ? new Ctor() : null);\n if (!context) return passThrough(source, ownsSource);\n\n const input = context.createMediaStreamSource(\n typeof MediaStream === \"undefined\"\n ? (source as unknown as MediaStream)\n : new MediaStream([source]),\n );\n const built: AudioNode[] = [input];\n const stops: (() => void)[] = [];\n let node: AudioNode = input;\n\n const chain = (next: AudioNode): void => {\n node.connect(next);\n node = next;\n built.push(next);\n };\n\n if (settings.highPass) chain(highPassStage(context));\n\n if (settings.gate) {\n const stage = gateStage(context, () => settings.gateThreshold);\n node.connect(stage.detector);\n built.push(stage.detector);\n stops.push(stage.stop);\n chain(stage.gain);\n }\n\n if (settings.compressor) chain(compressorStage(context));\n if (settings.presence) chain(presenceStage(context));\n if (settings.hissCut) chain(hissCutStage(context));\n\n if (settings.deEsser) {\n const stage = deEsserStage(context);\n node.connect(stage.band);\n built.push(stage.band, stage.detector);\n stops.push(stage.stop);\n chain(stage.shaper);\n }\n\n const output = context.createGain();\n output.gain.value = gain;\n chain(output);\n\n if (settings.limiter) chain(limiterStage(context));\n\n const destination = context.createMediaStreamDestination();\n node.connect(destination);\n built.push(destination);\n const track = destination.stream.getAudioTracks()[0];\n\n const teardown = (): void => {\n for (const stop of stops) stop();\n for (const built_ of built) built_.disconnect();\n };\n\n if (!track) {\n teardown();\n return passThrough(source, ownsSource);\n }\n\n return {\n track,\n release: (): void => {\n teardown();\n track.stop();\n if (ownsSource) source.stop();\n },\n supported: true,\n };\n}\n\n/** A running monitor. */\nexport interface VoiceMonitor {\n /** Stop listening and release the graph. Does **not** stop the source track. */\n stop: () => void;\n}\n\n/**\n * Play your own processed microphone back to you.\n *\n * The only way to hear what these filters do without a second person on the call.\n * Every number the chain is tuned by — how deep the de-esser cuts, where the gate\n * sits, how much presence is too much — is a judgement made by ear, and without\n * this the only available ear belongs to somebody else.\n *\n * **Feedback is the hazard, and the reason this is a held, explicit action rather\n * than a setting:** without headphones the speakers feed the microphone that feeds\n * the speakers. Say so in the UI that offers it.\n *\n * @param source - The raw captured track to listen to. It is never stopped here.\n * @param settings - The stages to hear it through. Default {@link DEFAULT_VOICE_CHAIN}.\n * @param options - See {@link VoiceChainOptions}; `ownsSource` is forced to `false`.\n * @returns A handle that stops the monitor.\n */\nexport function monitorVoiceChain(\n source: MediaStreamTrack,\n settings: VoiceChainSettings = DEFAULT_VOICE_CHAIN,\n options: Omit<VoiceChainOptions, \"ownsSource\"> = {},\n): VoiceMonitor {\n const Ctor = audioContextConstructor();\n const context = options.context ?? (Ctor ? new Ctor() : null);\n if (!context) return { stop: () => undefined };\n\n const chain = createVoiceChain(source, settings, { ...options, context, ownsSource: false });\n const playback = context.createMediaStreamSource(\n typeof MediaStream === \"undefined\"\n ? (chain.track as unknown as MediaStream)\n : new MediaStream([chain.track]),\n );\n playback.connect(context.destination);\n\n return {\n stop: (): void => {\n playback.disconnect();\n chain.release();\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"voice-chain.cjs","names":["highPassStage","gateStage","compressorStage","presenceStage","hissCutStage","deEsserStage","limiterStage","require_voice_chain_stages","DEFAULT_VOICE_CHAIN","audioContextConstructor","isVoiceChainIdle","settings","gain","passThrough","source","ownsSource","createVoiceChain","injectedContext","Ctor","context","input","built","stops","node","chain","next","stage","output","destination","track","teardown","stop","built_","monitorVoiceChain","options","playback"],"sources":["../../src/audio/voice-chain.ts"],"sourcesContent":["import {\n compressorStage,\n deEsserStage,\n gateStage,\n highPassStage,\n hissCutStage,\n limiterStage,\n presenceStage,\n} from \"./voice-chain-stages\";\n\n/** Which stages a voice chain builds. */\nexport interface VoiceChainSettings {\n /** Cut everything below speech: fans, traffic rumble, desk knocks, plosives. */\n highPass: boolean;\n /** Silence the line when nobody is talking. */\n gate: boolean;\n /** RMS below which the gate closes, 0..1. See {@link suggestGateThreshold}. */\n gateThreshold: number;\n /** Even out the distance between a whisper and a shout. */\n compressor: boolean;\n /** Lift the consonant band so speech reads without getting louder. */\n presence: boolean;\n /** Roll off hiss above what speech uses. */\n hissCut: boolean;\n /** Ride down harsh S and CH sounds. */\n deEsser: boolean;\n /**\n * Hard ceiling before the signal leaves.\n *\n * On by default and worth leaving on: the leveller is 3:1, which controls the\n * average and lets a peak through, and `gain` can reach well above 1.\n */\n limiter: boolean;\n}\n\n/**\n * What a call wants before anybody touches a slider.\n *\n * High-pass, leveller and limiter only. Gate, presence, hiss cut and de-esser are\n * off because each has an audible cost when it is not needed — a gate set for the\n * wrong room clips words, presence on a bright microphone is harsh, and a de-esser\n * on a voice that does not hiss just dulls it.\n */\nexport const DEFAULT_VOICE_CHAIN: VoiceChainSettings = {\n highPass: true,\n gate: false,\n gateThreshold: 0.02,\n compressor: true,\n presence: false,\n hissCut: false,\n deEsser: false,\n limiter: true,\n};\n\n/** Options for {@link createVoiceChain}. */\nexport interface VoiceChainOptions {\n /** Output multiplier, applied after every stage and before the limiter. Default `1`. */\n gain?: number;\n /**\n * Reuse an existing `AudioContext` instead of creating one.\n *\n * Browsers cap live contexts (Chrome allows around six), so a page that already\n * has one — a level meter, an audio bus — should hand it over.\n */\n context?: AudioContext;\n /**\n * Whether `release()` also stops `source`. Default `true`.\n *\n * Pass `false` when the track belongs to somebody else: a settings dialog\n * building a second chain over its live preview would otherwise kill the meter\n * the person is watching while they listen.\n */\n ownsSource?: boolean;\n}\n\n/** A running voice chain. */\nexport interface VoiceChain {\n /** The processed track to publish. */\n track: MediaStreamTrack;\n /** Stop the detectors, disconnect the graph, and release the track. */\n release: () => void;\n /**\n * Whether a graph was actually built.\n *\n * `false` when this engine has no Web Audio, and also when the settings asked\n * for nothing — in both cases `track` is `source`, untouched.\n */\n readonly supported: boolean;\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 * Whether any of this would change the signal.\n *\n * A chain that only passes audio through still costs a re-encode and a handful of\n * nodes, so a caller that rebuilds on every settings change should ask first —\n * and {@link createVoiceChain} asks too, handing back `source` rather than\n * building a graph that does nothing.\n *\n * @param settings - The stages under consideration.\n * @param gain - The output multiplier that would be applied. Default `1`.\n * @returns `true` when the chain would be audibly transparent.\n */\nexport function isVoiceChainIdle(settings: VoiceChainSettings, gain = 1): boolean {\n return (\n !settings.highPass &&\n !settings.gate &&\n !settings.compressor &&\n !settings.presence &&\n !settings.hissCut &&\n !settings.deEsser &&\n !settings.limiter &&\n gain === 1\n );\n}\n\n/** A chain that owns nothing, for an engine or a settings object with no work to do. */\nfunction passThrough(source: MediaStreamTrack, ownsSource: boolean): VoiceChain {\n return {\n track: source,\n release: () => {\n if (ownsSource) source.stop();\n },\n supported: false,\n };\n}\n\n/**\n * Build the processing a microphone is published through.\n *\n * Ordered the way a console is: cut what is not speech, gate what is left, level\n * it, shape it, set how loud it goes out, then hold a ceiling. **The order is not\n * cosmetic.** Gating before the high-pass lets a rumble hold the gate open;\n * compressing before the gate lifts the noise floor up to meet the threshold; and\n * a limiter placed before the output gain is a ceiling the gain then walks\n * straight through.\n *\n * This sits *after* the browser's own echo cancellation and noise suppression,\n * which stay on: the two solve different problems. The browser's is trained on\n * stationary noise inside the capture pipeline; this cuts what it leaves behind\n * and decides when the line should be silent at all.\n *\n * @param source - The captured microphone track.\n * @param settings - Which stages to build. Default {@link DEFAULT_VOICE_CHAIN}.\n * @param options - See {@link VoiceChainOptions}.\n * @returns The track to publish plus its teardown. On an engine with no Web Audio,\n * and when every stage is off, the source track is handed back untouched and\n * `supported` is `false` — a call without processing beats a call that throws.\n * The idle case is decided **before** a context is opened, because browsers cap\n * how many can be live and one built for a chain that does nothing still counts.\n *\n * @example\n * const floor = await measureNoiseFloor(stream);\n * const chain = createVoiceChain(micTrack, {\n * ...DEFAULT_VOICE_CHAIN,\n * gate: true,\n * gateThreshold: suggestGateThreshold(floor),\n * }, { gain: 1.4 });\n * await mesh.setLocalTrack(\"mic\", chain.track);\n */\nexport function createVoiceChain(\n source: MediaStreamTrack,\n settings: VoiceChainSettings = DEFAULT_VOICE_CHAIN,\n { gain = 1, context: injectedContext, ownsSource = true }: VoiceChainOptions = {},\n): VoiceChain {\n if (isVoiceChainIdle(settings, gain)) return passThrough(source, ownsSource);\n\n const Ctor = audioContextConstructor();\n const context = injectedContext ?? (Ctor ? new Ctor() : null);\n if (!context) return passThrough(source, ownsSource);\n\n const input = context.createMediaStreamSource(\n typeof MediaStream === \"undefined\"\n ? (source as unknown as MediaStream)\n : new MediaStream([source]),\n );\n const built: AudioNode[] = [input];\n const stops: (() => void)[] = [];\n let node: AudioNode = input;\n\n const chain = (next: AudioNode): void => {\n node.connect(next);\n node = next;\n built.push(next);\n };\n\n if (settings.highPass) chain(highPassStage(context));\n\n if (settings.gate) {\n const stage = gateStage(context, () => settings.gateThreshold);\n node.connect(stage.detector);\n built.push(stage.detector);\n stops.push(stage.stop);\n chain(stage.gain);\n }\n\n if (settings.compressor) chain(compressorStage(context));\n if (settings.presence) chain(presenceStage(context));\n if (settings.hissCut) chain(hissCutStage(context));\n\n if (settings.deEsser) {\n const stage = deEsserStage(context);\n node.connect(stage.band);\n built.push(stage.band, stage.detector);\n stops.push(stage.stop);\n chain(stage.shaper);\n }\n\n const output = context.createGain();\n output.gain.value = gain;\n chain(output);\n\n if (settings.limiter) chain(limiterStage(context));\n\n const destination = context.createMediaStreamDestination();\n node.connect(destination);\n built.push(destination);\n const track = destination.stream.getAudioTracks()[0];\n\n const teardown = (): void => {\n for (const stop of stops) stop();\n for (const built_ of built) built_.disconnect();\n };\n\n if (!track) {\n teardown();\n return passThrough(source, ownsSource);\n }\n\n return {\n track,\n release: (): void => {\n teardown();\n track.stop();\n if (ownsSource) source.stop();\n },\n supported: true,\n };\n}\n\n/** A running monitor. */\nexport interface VoiceMonitor {\n /** Stop listening and release the graph. Does **not** stop the source track. */\n stop: () => void;\n}\n\n/**\n * Play your own processed microphone back to you.\n *\n * The only way to hear what these filters do without a second person on the call.\n * Every number the chain is tuned by — how deep the de-esser cuts, where the gate\n * sits, how much presence is too much — is a judgement made by ear, and without\n * this the only available ear belongs to somebody else.\n *\n * **Feedback is the hazard, and the reason this is a held, explicit action rather\n * than a setting:** without headphones the speakers feed the microphone that feeds\n * the speakers. Say so in the UI that offers it.\n *\n * @param source - The raw captured track to listen to. It is never stopped here.\n * @param settings - The stages to hear it through. Default {@link DEFAULT_VOICE_CHAIN}.\n * @param options - See {@link VoiceChainOptions}; `ownsSource` is forced to `false`.\n * @returns A handle that stops the monitor.\n */\nexport function monitorVoiceChain(\n source: MediaStreamTrack,\n settings: VoiceChainSettings = DEFAULT_VOICE_CHAIN,\n options: Omit<VoiceChainOptions, \"ownsSource\"> = {},\n): VoiceMonitor {\n const Ctor = audioContextConstructor();\n const context = options.context ?? (Ctor ? new Ctor() : null);\n if (!context) return { stop: () => undefined };\n\n const chain = createVoiceChain(source, settings, { ...options, context, ownsSource: false });\n const playback = context.createMediaStreamSource(\n typeof MediaStream === \"undefined\"\n ? (chain.track as unknown as MediaStream)\n : new MediaStream([chain.track]),\n );\n playback.connect(context.destination);\n\n return {\n stop: (): void => {\n playback.disconnect();\n chain.release();\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voice-chain.js","names":[],"sources":["../../src/audio/voice-chain.ts"],"sourcesContent":["import {\n compressorStage,\n deEsserStage,\n gateStage,\n highPassStage,\n hissCutStage,\n limiterStage,\n presenceStage,\n} from \"./voice-chain-stages\";\n\n/** Which stages a voice chain builds. */\nexport interface VoiceChainSettings {\n /** Cut everything below speech: fans, traffic rumble, desk knocks, plosives. */\n highPass: boolean;\n /** Silence the line when nobody is talking. */\n gate: boolean;\n /** RMS below which the gate closes, 0..1. See {@link suggestGateThreshold}. */\n gateThreshold: number;\n /** Even out the distance between a whisper and a shout. */\n compressor: boolean;\n /** Lift the consonant band so speech reads without getting louder. */\n presence: boolean;\n /** Roll off hiss above what speech uses. */\n hissCut: boolean;\n /** Ride down harsh S and CH sounds. */\n deEsser: boolean;\n /**\n * Hard ceiling before the signal leaves.\n *\n * On by default and worth leaving on: the leveller is 3:1, which controls the\n * average and lets a peak through, and `gain` can reach well above 1.\n */\n limiter: boolean;\n}\n\n/**\n * What a call wants before anybody touches a slider.\n *\n * High-pass, leveller and limiter only. Gate, presence, hiss cut and de-esser are\n * off because each has an audible cost when it is not needed — a gate set for the\n * wrong room clips words, presence on a bright microphone is harsh, and a de-esser\n * on a voice that does not hiss just dulls it.\n */\nexport const DEFAULT_VOICE_CHAIN: VoiceChainSettings = {\n highPass: true,\n gate: false,\n gateThreshold: 0.02,\n compressor: true,\n presence: false,\n hissCut: false,\n deEsser: false,\n limiter: true,\n};\n\n/** Options for {@link createVoiceChain}. */\nexport interface VoiceChainOptions {\n /** Output multiplier, applied after every stage and before the limiter. Default `1`. */\n gain?: number;\n /**\n * Reuse an existing `AudioContext` instead of creating one.\n *\n * Browsers cap live contexts (Chrome allows around six), so a page that already\n * has one — a level meter, an audio bus — should hand it over.\n */\n context?: AudioContext;\n /**\n * Whether `release()` also stops `source`. Default `true`.\n *\n * Pass `false` when the track belongs to somebody else: a settings dialog\n * building a second chain over its live preview would otherwise kill the meter\n * the person is watching while they listen.\n */\n ownsSource?: boolean;\n}\n\n/** A running voice chain. */\nexport interface VoiceChain {\n /** The processed track to publish. */\n track: MediaStreamTrack;\n /** Stop the detectors, disconnect the graph, and release the track. */\n release: () => void;\n /**\n * Whether a graph was actually built.\n *\n * `false` when this engine has no Web Audio, and also when the settings asked\n * for nothing — in both cases `track` is `source`, untouched.\n */\n readonly supported: boolean;\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 * Whether any of this would change the signal.\n *\n * A chain that only passes audio through still costs a re-encode and a handful of\n * nodes, so a caller that rebuilds on every settings change should ask first —\n * and {@link createVoiceChain} asks too, handing back `source` rather than\n * building a graph that does nothing.\n *\n * @param settings - The stages under consideration.\n * @param gain - The output multiplier that would be applied. Default `1`.\n * @returns `true` when the chain would be audibly transparent.\n */\nexport function isVoiceChainIdle(settings: VoiceChainSettings, gain = 1): boolean {\n return (\n !settings.highPass &&\n !settings.gate &&\n !settings.compressor &&\n !settings.presence &&\n !settings.hissCut &&\n !settings.deEsser &&\n !settings.limiter &&\n gain === 1\n );\n}\n\n/** A chain that owns nothing, for an engine or a settings object with no work to do. */\nfunction passThrough(source: MediaStreamTrack, ownsSource: boolean): VoiceChain {\n return {\n track: source,\n release: () => {\n if (ownsSource) source.stop();\n },\n supported: false,\n };\n}\n\n/**\n * Build the processing a microphone is published through.\n *\n * Ordered the way a console is: cut what is not speech, gate what is left, level\n * it, shape it, set how loud it goes out, then hold a ceiling. **The order is not\n * cosmetic.** Gating before the high-pass lets a rumble hold the gate open;\n * compressing before the gate lifts the noise floor up to meet the threshold; and\n * a limiter placed before the output gain is a ceiling the gain then walks\n * straight through.\n *\n * This sits *after* the browser's own echo cancellation and noise suppression,\n * which stay on: the two solve different problems. The browser's is trained on\n * stationary noise inside the capture pipeline; this cuts what it leaves behind\n * and decides when the line should be silent at all.\n *\n * @param source - The captured microphone track.\n * @param settings - Which stages to build. Default {@link DEFAULT_VOICE_CHAIN}.\n * @param options - See {@link VoiceChainOptions}.\n * @returns The track to publish plus its teardown. On an engine with no Web Audio,\n * and when every stage is off, the source track is handed back untouched and\n * `supported` is `false` — a call without processing beats a call that throws.\n * The idle case is decided **before** a context is opened, because browsers cap\n * how many can be live and one built for a chain that does nothing still counts.\n *\n * @example\n * const floor = await measureNoiseFloor(stream);\n * const chain = createVoiceChain(micTrack, {\n * ...DEFAULT_VOICE_CHAIN,\n * gate: true,\n * gateThreshold: suggestGateThreshold(floor),\n * }, { gain: 1.4 });\n * await mesh.setLocalTrack(\"mic\", chain.track);\n */\nexport function createVoiceChain(\n source: MediaStreamTrack,\n settings: VoiceChainSettings = DEFAULT_VOICE_CHAIN,\n { gain = 1, context: injectedContext, ownsSource = true }: VoiceChainOptions = {},\n): VoiceChain {\n if (isVoiceChainIdle(settings, gain)) return passThrough(source, ownsSource);\n\n const Ctor = audioContextConstructor();\n const context = injectedContext ?? (Ctor ? new Ctor() : null);\n if (!context) return passThrough(source, ownsSource);\n\n const input = context.createMediaStreamSource(\n typeof MediaStream === \"undefined\"\n ? (source as unknown as MediaStream)\n : new MediaStream([source]),\n );\n const built: AudioNode[] = [input];\n const stops: (() => void)[] = [];\n let node: AudioNode = input;\n\n const chain = (next: AudioNode): void => {\n node.connect(next);\n node = next;\n built.push(next);\n };\n\n if (settings.highPass) chain(highPassStage(context));\n\n if (settings.gate) {\n const stage = gateStage(context, () => settings.gateThreshold);\n node.connect(stage.detector);\n built.push(stage.detector);\n stops.push(stage.stop);\n chain(stage.gain);\n }\n\n if (settings.compressor) chain(compressorStage(context));\n if (settings.presence) chain(presenceStage(context));\n if (settings.hissCut) chain(hissCutStage(context));\n\n if (settings.deEsser) {\n const stage = deEsserStage(context);\n node.connect(stage.band);\n built.push(stage.band, stage.detector);\n stops.push(stage.stop);\n chain(stage.shaper);\n }\n\n const output = context.createGain();\n output.gain.value = gain;\n chain(output);\n\n if (settings.limiter) chain(limiterStage(context));\n\n const destination = context.createMediaStreamDestination();\n node.connect(destination);\n built.push(destination);\n const track = destination.stream.getAudioTracks()[0];\n\n const teardown = (): void => {\n for (const stop of stops) stop();\n for (const built_ of built) built_.disconnect();\n };\n\n if (!track) {\n teardown();\n return passThrough(source, ownsSource);\n }\n\n return {\n track,\n release: (): void => {\n teardown();\n track.stop();\n if (ownsSource) source.stop();\n },\n supported: true,\n };\n}\n\n/** A running monitor. */\nexport interface VoiceMonitor {\n /** Stop listening and release the graph. Does **not** stop the source track. */\n stop: () => void;\n}\n\n/**\n * Play your own processed microphone back to you.\n *\n * The only way to hear what these filters do without a second person on the call.\n * Every number the chain is tuned by — how deep the de-esser cuts, where the gate\n * sits, how much presence is too much — is a judgement made by ear, and without\n * this the only available ear belongs to somebody else.\n *\n * **Feedback is the hazard, and the reason this is a held, explicit action rather\n * than a setting:** without headphones the speakers feed the microphone that feeds\n * the speakers. Say so in the UI that offers it.\n *\n * @param source - The raw captured track to listen to. It is never stopped here.\n * @param settings - The stages to hear it through. Default {@link DEFAULT_VOICE_CHAIN}.\n * @param options - See {@link VoiceChainOptions}; `ownsSource` is forced to `false`.\n * @returns A handle that stops the monitor.\n */\nexport function monitorVoiceChain(\n source: MediaStreamTrack,\n settings: VoiceChainSettings = DEFAULT_VOICE_CHAIN,\n options: Omit<VoiceChainOptions, \"ownsSource\"> = {},\n): VoiceMonitor {\n const Ctor = audioContextConstructor();\n const context = options.context ?? (Ctor ? new Ctor() : null);\n if (!context) return { stop: () => undefined };\n\n const chain = createVoiceChain(source, settings, { ...options, context, ownsSource: false });\n const playback = context.createMediaStreamSource(\n typeof MediaStream === \"undefined\"\n ? (chain.track as unknown as MediaStream)\n : new MediaStream([chain.track]),\n );\n playback.connect(context.destination);\n\n return {\n stop: (): void => {\n playback.disconnect();\n chain.release();\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"voice-chain.js","names":["DEFAULT_VOICE_CHAIN","audioContextConstructor","isVoiceChainIdle","settings","gain","passThrough","source","ownsSource","createVoiceChain","injectedContext","Ctor","context","input","built","stops","node","chain","next","highPassStage","stage","gateStage","compressorStage","presenceStage","hissCutStage","deEsserStage","output","limiterStage","destination","track","teardown","stop","built_","monitorVoiceChain","options","playback"],"sources":["../../src/audio/voice-chain.ts"],"sourcesContent":["import {\n compressorStage,\n deEsserStage,\n gateStage,\n highPassStage,\n hissCutStage,\n limiterStage,\n presenceStage,\n} from \"./voice-chain-stages\";\n\n/** Which stages a voice chain builds. */\nexport interface VoiceChainSettings {\n /** Cut everything below speech: fans, traffic rumble, desk knocks, plosives. */\n highPass: boolean;\n /** Silence the line when nobody is talking. */\n gate: boolean;\n /** RMS below which the gate closes, 0..1. See {@link suggestGateThreshold}. */\n gateThreshold: number;\n /** Even out the distance between a whisper and a shout. */\n compressor: boolean;\n /** Lift the consonant band so speech reads without getting louder. */\n presence: boolean;\n /** Roll off hiss above what speech uses. */\n hissCut: boolean;\n /** Ride down harsh S and CH sounds. */\n deEsser: boolean;\n /**\n * Hard ceiling before the signal leaves.\n *\n * On by default and worth leaving on: the leveller is 3:1, which controls the\n * average and lets a peak through, and `gain` can reach well above 1.\n */\n limiter: boolean;\n}\n\n/**\n * What a call wants before anybody touches a slider.\n *\n * High-pass, leveller and limiter only. Gate, presence, hiss cut and de-esser are\n * off because each has an audible cost when it is not needed — a gate set for the\n * wrong room clips words, presence on a bright microphone is harsh, and a de-esser\n * on a voice that does not hiss just dulls it.\n */\nexport const DEFAULT_VOICE_CHAIN: VoiceChainSettings = {\n highPass: true,\n gate: false,\n gateThreshold: 0.02,\n compressor: true,\n presence: false,\n hissCut: false,\n deEsser: false,\n limiter: true,\n};\n\n/** Options for {@link createVoiceChain}. */\nexport interface VoiceChainOptions {\n /** Output multiplier, applied after every stage and before the limiter. Default `1`. */\n gain?: number;\n /**\n * Reuse an existing `AudioContext` instead of creating one.\n *\n * Browsers cap live contexts (Chrome allows around six), so a page that already\n * has one — a level meter, an audio bus — should hand it over.\n */\n context?: AudioContext;\n /**\n * Whether `release()` also stops `source`. Default `true`.\n *\n * Pass `false` when the track belongs to somebody else: a settings dialog\n * building a second chain over its live preview would otherwise kill the meter\n * the person is watching while they listen.\n */\n ownsSource?: boolean;\n}\n\n/** A running voice chain. */\nexport interface VoiceChain {\n /** The processed track to publish. */\n track: MediaStreamTrack;\n /** Stop the detectors, disconnect the graph, and release the track. */\n release: () => void;\n /**\n * Whether a graph was actually built.\n *\n * `false` when this engine has no Web Audio, and also when the settings asked\n * for nothing — in both cases `track` is `source`, untouched.\n */\n readonly supported: boolean;\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 * Whether any of this would change the signal.\n *\n * A chain that only passes audio through still costs a re-encode and a handful of\n * nodes, so a caller that rebuilds on every settings change should ask first —\n * and {@link createVoiceChain} asks too, handing back `source` rather than\n * building a graph that does nothing.\n *\n * @param settings - The stages under consideration.\n * @param gain - The output multiplier that would be applied. Default `1`.\n * @returns `true` when the chain would be audibly transparent.\n */\nexport function isVoiceChainIdle(settings: VoiceChainSettings, gain = 1): boolean {\n return (\n !settings.highPass &&\n !settings.gate &&\n !settings.compressor &&\n !settings.presence &&\n !settings.hissCut &&\n !settings.deEsser &&\n !settings.limiter &&\n gain === 1\n );\n}\n\n/** A chain that owns nothing, for an engine or a settings object with no work to do. */\nfunction passThrough(source: MediaStreamTrack, ownsSource: boolean): VoiceChain {\n return {\n track: source,\n release: () => {\n if (ownsSource) source.stop();\n },\n supported: false,\n };\n}\n\n/**\n * Build the processing a microphone is published through.\n *\n * Ordered the way a console is: cut what is not speech, gate what is left, level\n * it, shape it, set how loud it goes out, then hold a ceiling. **The order is not\n * cosmetic.** Gating before the high-pass lets a rumble hold the gate open;\n * compressing before the gate lifts the noise floor up to meet the threshold; and\n * a limiter placed before the output gain is a ceiling the gain then walks\n * straight through.\n *\n * This sits *after* the browser's own echo cancellation and noise suppression,\n * which stay on: the two solve different problems. The browser's is trained on\n * stationary noise inside the capture pipeline; this cuts what it leaves behind\n * and decides when the line should be silent at all.\n *\n * @param source - The captured microphone track.\n * @param settings - Which stages to build. Default {@link DEFAULT_VOICE_CHAIN}.\n * @param options - See {@link VoiceChainOptions}.\n * @returns The track to publish plus its teardown. On an engine with no Web Audio,\n * and when every stage is off, the source track is handed back untouched and\n * `supported` is `false` — a call without processing beats a call that throws.\n * The idle case is decided **before** a context is opened, because browsers cap\n * how many can be live and one built for a chain that does nothing still counts.\n *\n * @example\n * const floor = await measureNoiseFloor(stream);\n * const chain = createVoiceChain(micTrack, {\n * ...DEFAULT_VOICE_CHAIN,\n * gate: true,\n * gateThreshold: suggestGateThreshold(floor),\n * }, { gain: 1.4 });\n * await mesh.setLocalTrack(\"mic\", chain.track);\n */\nexport function createVoiceChain(\n source: MediaStreamTrack,\n settings: VoiceChainSettings = DEFAULT_VOICE_CHAIN,\n { gain = 1, context: injectedContext, ownsSource = true }: VoiceChainOptions = {},\n): VoiceChain {\n if (isVoiceChainIdle(settings, gain)) return passThrough(source, ownsSource);\n\n const Ctor = audioContextConstructor();\n const context = injectedContext ?? (Ctor ? new Ctor() : null);\n if (!context) return passThrough(source, ownsSource);\n\n const input = context.createMediaStreamSource(\n typeof MediaStream === \"undefined\"\n ? (source as unknown as MediaStream)\n : new MediaStream([source]),\n );\n const built: AudioNode[] = [input];\n const stops: (() => void)[] = [];\n let node: AudioNode = input;\n\n const chain = (next: AudioNode): void => {\n node.connect(next);\n node = next;\n built.push(next);\n };\n\n if (settings.highPass) chain(highPassStage(context));\n\n if (settings.gate) {\n const stage = gateStage(context, () => settings.gateThreshold);\n node.connect(stage.detector);\n built.push(stage.detector);\n stops.push(stage.stop);\n chain(stage.gain);\n }\n\n if (settings.compressor) chain(compressorStage(context));\n if (settings.presence) chain(presenceStage(context));\n if (settings.hissCut) chain(hissCutStage(context));\n\n if (settings.deEsser) {\n const stage = deEsserStage(context);\n node.connect(stage.band);\n built.push(stage.band, stage.detector);\n stops.push(stage.stop);\n chain(stage.shaper);\n }\n\n const output = context.createGain();\n output.gain.value = gain;\n chain(output);\n\n if (settings.limiter) chain(limiterStage(context));\n\n const destination = context.createMediaStreamDestination();\n node.connect(destination);\n built.push(destination);\n const track = destination.stream.getAudioTracks()[0];\n\n const teardown = (): void => {\n for (const stop of stops) stop();\n for (const built_ of built) built_.disconnect();\n };\n\n if (!track) {\n teardown();\n return passThrough(source, ownsSource);\n }\n\n return {\n track,\n release: (): void => {\n teardown();\n track.stop();\n if (ownsSource) source.stop();\n },\n supported: true,\n };\n}\n\n/** A running monitor. */\nexport interface VoiceMonitor {\n /** Stop listening and release the graph. Does **not** stop the source track. */\n stop: () => void;\n}\n\n/**\n * Play your own processed microphone back to you.\n *\n * The only way to hear what these filters do without a second person on the call.\n * Every number the chain is tuned by — how deep the de-esser cuts, where the gate\n * sits, how much presence is too much — is a judgement made by ear, and without\n * this the only available ear belongs to somebody else.\n *\n * **Feedback is the hazard, and the reason this is a held, explicit action rather\n * than a setting:** without headphones the speakers feed the microphone that feeds\n * the speakers. Say so in the UI that offers it.\n *\n * @param source - The raw captured track to listen to. It is never stopped here.\n * @param settings - The stages to hear it through. Default {@link DEFAULT_VOICE_CHAIN}.\n * @param options - See {@link VoiceChainOptions}; `ownsSource` is forced to `false`.\n * @returns A handle that stops the monitor.\n */\nexport function monitorVoiceChain(\n source: MediaStreamTrack,\n settings: VoiceChainSettings = DEFAULT_VOICE_CHAIN,\n options: Omit<VoiceChainOptions, \"ownsSource\"> = {},\n): VoiceMonitor {\n const Ctor = audioContextConstructor();\n const context = options.context ?? (Ctor ? new Ctor() : null);\n if (!context) return { stop: () => undefined };\n\n const chain = createVoiceChain(source, settings, { ...options, context, ownsSource: false });\n const playback = context.createMediaStreamSource(\n typeof MediaStream === \"undefined\"\n ? (chain.track as unknown as MediaStream)\n : new MediaStream([chain.track]),\n );\n playback.connect(context.destination);\n\n return {\n stop: (): void => {\n playback.disconnect();\n chain.release();\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/audio/wav.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wav.cjs","names":[],"sources":["../../src/audio/wav.ts"],"sourcesContent":["/** Raw PCM ready to be wrapped in a RIFF container. */\nexport interface PcmAudio {\n /** One `Float32Array` per channel, samples in −1…1. */\n channels: readonly Float32Array[];\n sampleRate: number;\n}\n\n/** Options for {@link blobToWav}. */\nexport interface WavOptions {\n /**\n * Mix down to one channel. Default `false`.\n *\n * Worth turning on for speech headed to a server: a microphone recorded in stereo\n * carries two nearly identical channels and doubles the upload for nothing.\n */\n mono?: boolean;\n /**\n * Resample to this rate. Default: keep the source rate.\n *\n * 16000 is the rate most speech-to-text APIs want, and dropping 48 kHz to 16 kHz\n * removes two thirds of the bytes with no audible loss on voice.\n */\n sampleRate?: number;\n}\n\n/** Bytes per sample in the output. 16-bit PCM is what every decoder accepts. */\nconst BYTES_PER_SAMPLE = 2;\n\n/**\n * Wrap PCM in a 16-bit RIFF/WAVE container.\n *\n * The header is the 44-byte canonical form: `RIFF` size, `WAVE`, a 16-byte `fmt `\n * chunk declaring format 1 (uncompressed PCM), then `data`. Samples are interleaved\n * and clamped before scaling, because a value even slightly past ±1 wraps around when\n * truncated to 16 bits and turns a loud passage into a burst of noise.\n *\n * Implemented here rather than pulled from a package: it is a fixed header and a\n * scaling loop, roughly forty lines, and a dependency for it would put its own\n * version bounds on every consumer of this SDK to save writing them.\n *\n * @param audio - Channels and sample rate.\n * @returns A `Blob` of type `audio/wav`.\n */\nexport function encodeWav({ channels, sampleRate }: PcmAudio): Blob {\n const channelCount = Math.max(1, channels.length);\n const frameCount = channels[0]?.length ?? 0;\n const dataBytes = frameCount * channelCount * BYTES_PER_SAMPLE;\n const buffer = new ArrayBuffer(44 + dataBytes);\n const view = new DataView(buffer);\n\n const ascii = (offset: number, text: string): void => {\n for (let index = 0; index < text.length; index += 1) {\n view.setUint8(offset + index, text.charCodeAt(index));\n }\n };\n\n const byteRate = sampleRate * channelCount * BYTES_PER_SAMPLE;\n ascii(0, \"RIFF\");\n view.setUint32(4, 36 + dataBytes, true);\n ascii(8, \"WAVE\");\n ascii(12, \"fmt \");\n view.setUint32(16, 16, true);\n view.setUint16(20, 1, true);\n view.setUint16(22, channelCount, true);\n view.setUint32(24, sampleRate, true);\n view.setUint32(28, byteRate, true);\n view.setUint16(32, channelCount * BYTES_PER_SAMPLE, true);\n view.setUint16(34, BYTES_PER_SAMPLE * 8, true);\n ascii(36, \"data\");\n view.setUint32(40, dataBytes, true);\n\n let offset = 44;\n for (let frame = 0; frame < frameCount; frame += 1) {\n for (let channel = 0; channel < channelCount; channel += 1) {\n const sample = channels[channel]?.[frame] ?? 0;\n const clamped = sample < -1 ? -1 : sample > 1 ? 1 : sample;\n // Asymmetric scaling: 16-bit PCM runs −32768…32767.\n view.setInt16(offset, clamped < 0 ? clamped * 0x8000 : clamped * 0x7fff, true);\n offset += BYTES_PER_SAMPLE;\n }\n }\n\n return new Blob([buffer], { type: \"audio/wav\" });\n}\n\n/** Average every channel of a decoded buffer into one. */\nfunction mixToMono(buffer: AudioBuffer): Float32Array {\n const frames = buffer.length;\n const out = new Float32Array(frames);\n for (let channel = 0; channel < buffer.numberOfChannels; channel += 1) {\n const data = buffer.getChannelData(channel);\n for (let frame = 0; frame < frames; frame += 1) out[frame] += data[frame];\n }\n if (buffer.numberOfChannels > 1) {\n for (let frame = 0; frame < frames; frame += 1) out[frame] /= buffer.numberOfChannels;\n }\n return out;\n}\n\n/**\n * Convert a recording to 16-bit WAV, with no dependency.\n *\n * `MediaRecorder` cannot produce WAV — it emits Opus on Chromium and Firefox and AAC\n * on Safari — so a backend that insists on WAV has to be served either by a\n * server-side transcode or by this. It decodes through `AudioContext.decodeAudioData`,\n * which is the browser's own decoder for whatever container the recorder chose, then\n * re-encodes the PCM.\n *\n * !!! The cost is real: WAV is uncompressed, so the same voice note that is 40 KB in\n * Opus is roughly 500 KB here at 48 kHz stereo. `{ mono: true, sampleRate: 16000 }`\n * takes that to about 80 KB and is what a speech-to-text endpoint wants anyway.\n *\n * Resampling uses `OfflineAudioContext`, i.e. the browser's own resampler, rather\n * than a hand-rolled one — this is exactly the \"we want the underlying call, not a\n * wrapper\" case.\n *\n * @param blob - A recording from {@link createAudioRecorder}, or any decodable audio.\n * @param options - See {@link WavOptions}.\n * @returns A `Blob` of type `audio/wav`.\n * @throws When the environment has no Web Audio, or the blob cannot be decoded.\n */\nexport async function blobToWav(blob: Blob, options: WavOptions = {}): Promise<Blob> {\n const { mono = false, sampleRate: target } = options;\n\n const Ctor: typeof AudioContext | undefined =\n typeof AudioContext !== \"undefined\"\n ? AudioContext\n : (globalThis as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (!Ctor) throw new Error(\"Web Audio is not available in this environment.\");\n\n const context = new Ctor();\n let decoded: AudioBuffer;\n try {\n decoded = await context.decodeAudioData(await blob.arrayBuffer());\n } finally {\n void context.close().catch(() => undefined);\n }\n\n const wantedChannels = mono ? 1 : decoded.numberOfChannels;\n const wantedRate = target ?? decoded.sampleRate;\n\n if (wantedRate === decoded.sampleRate) {\n const channels = mono\n ? [mixToMono(decoded)]\n : Array.from({ length: decoded.numberOfChannels }, (_, index) =>\n decoded.getChannelData(index),\n );\n return encodeWav({ channels, sampleRate: decoded.sampleRate });\n }\n\n const Offline: typeof OfflineAudioContext | undefined =\n typeof OfflineAudioContext !== \"undefined\" ? OfflineAudioContext : undefined;\n if (!Offline) throw new Error(\"Resampling requires OfflineAudioContext.\");\n\n const frames = Math.max(1, Math.round((decoded.duration * wantedRate) | 0) || 1);\n const offline = new Offline(wantedChannels, frames, wantedRate);\n const source = offline.createBufferSource();\n source.buffer = decoded;\n source.connect(offline.destination);\n source.start();\n const rendered = await offline.startRendering();\n\n return encodeWav({\n channels: Array.from({ length: rendered.numberOfChannels }, (_, index) =>\n rendered.getChannelData(index),\n ),\n sampleRate: rendered.sampleRate,\n });\n}\n"],"mappings":"AA2CA,
|
|
1
|
+
{"version":3,"file":"wav.cjs","names":["encodeWav","channelCount","channels","frameCount","dataBytes","buffer","view","ascii","index","text","offset","byteRate","sampleRate","frame","channel","sample","clamped","mixToMono","frames","out","data","blobToWav","target","options","Ctor","context","decoded","blob","wantedChannels","mono","wantedRate","Offline","offline","source","rendered"],"sources":["../../src/audio/wav.ts"],"sourcesContent":["/** Raw PCM ready to be wrapped in a RIFF container. */\nexport interface PcmAudio {\n /** One `Float32Array` per channel, samples in −1…1. */\n channels: readonly Float32Array[];\n sampleRate: number;\n}\n\n/** Options for {@link blobToWav}. */\nexport interface WavOptions {\n /**\n * Mix down to one channel. Default `false`.\n *\n * Worth turning on for speech headed to a server: a microphone recorded in stereo\n * carries two nearly identical channels and doubles the upload for nothing.\n */\n mono?: boolean;\n /**\n * Resample to this rate. Default: keep the source rate.\n *\n * 16000 is the rate most speech-to-text APIs want, and dropping 48 kHz to 16 kHz\n * removes two thirds of the bytes with no audible loss on voice.\n */\n sampleRate?: number;\n}\n\n/** Bytes per sample in the output. 16-bit PCM is what every decoder accepts. */\nconst BYTES_PER_SAMPLE = 2;\n\n/**\n * Wrap PCM in a 16-bit RIFF/WAVE container.\n *\n * The header is the 44-byte canonical form: `RIFF` size, `WAVE`, a 16-byte `fmt `\n * chunk declaring format 1 (uncompressed PCM), then `data`. Samples are interleaved\n * and clamped before scaling, because a value even slightly past ±1 wraps around when\n * truncated to 16 bits and turns a loud passage into a burst of noise.\n *\n * Implemented here rather than pulled from a package: it is a fixed header and a\n * scaling loop, roughly forty lines, and a dependency for it would put its own\n * version bounds on every consumer of this SDK to save writing them.\n *\n * @param audio - Channels and sample rate.\n * @returns A `Blob` of type `audio/wav`.\n */\nexport function encodeWav({ channels, sampleRate }: PcmAudio): Blob {\n const channelCount = Math.max(1, channels.length);\n const frameCount = channels[0]?.length ?? 0;\n const dataBytes = frameCount * channelCount * BYTES_PER_SAMPLE;\n const buffer = new ArrayBuffer(44 + dataBytes);\n const view = new DataView(buffer);\n\n const ascii = (offset: number, text: string): void => {\n for (let index = 0; index < text.length; index += 1) {\n view.setUint8(offset + index, text.charCodeAt(index));\n }\n };\n\n const byteRate = sampleRate * channelCount * BYTES_PER_SAMPLE;\n ascii(0, \"RIFF\");\n view.setUint32(4, 36 + dataBytes, true);\n ascii(8, \"WAVE\");\n ascii(12, \"fmt \");\n view.setUint32(16, 16, true);\n view.setUint16(20, 1, true);\n view.setUint16(22, channelCount, true);\n view.setUint32(24, sampleRate, true);\n view.setUint32(28, byteRate, true);\n view.setUint16(32, channelCount * BYTES_PER_SAMPLE, true);\n view.setUint16(34, BYTES_PER_SAMPLE * 8, true);\n ascii(36, \"data\");\n view.setUint32(40, dataBytes, true);\n\n let offset = 44;\n for (let frame = 0; frame < frameCount; frame += 1) {\n for (let channel = 0; channel < channelCount; channel += 1) {\n const sample = channels[channel]?.[frame] ?? 0;\n const clamped = sample < -1 ? -1 : sample > 1 ? 1 : sample;\n // Asymmetric scaling: 16-bit PCM runs −32768…32767.\n view.setInt16(offset, clamped < 0 ? clamped * 0x8000 : clamped * 0x7fff, true);\n offset += BYTES_PER_SAMPLE;\n }\n }\n\n return new Blob([buffer], { type: \"audio/wav\" });\n}\n\n/** Average every channel of a decoded buffer into one. */\nfunction mixToMono(buffer: AudioBuffer): Float32Array {\n const frames = buffer.length;\n const out = new Float32Array(frames);\n for (let channel = 0; channel < buffer.numberOfChannels; channel += 1) {\n const data = buffer.getChannelData(channel);\n for (let frame = 0; frame < frames; frame += 1) out[frame] += data[frame];\n }\n if (buffer.numberOfChannels > 1) {\n for (let frame = 0; frame < frames; frame += 1) out[frame] /= buffer.numberOfChannels;\n }\n return out;\n}\n\n/**\n * Convert a recording to 16-bit WAV, with no dependency.\n *\n * `MediaRecorder` cannot produce WAV — it emits Opus on Chromium and Firefox and AAC\n * on Safari — so a backend that insists on WAV has to be served either by a\n * server-side transcode or by this. It decodes through `AudioContext.decodeAudioData`,\n * which is the browser's own decoder for whatever container the recorder chose, then\n * re-encodes the PCM.\n *\n * !!! The cost is real: WAV is uncompressed, so the same voice note that is 40 KB in\n * Opus is roughly 500 KB here at 48 kHz stereo. `{ mono: true, sampleRate: 16000 }`\n * takes that to about 80 KB and is what a speech-to-text endpoint wants anyway.\n *\n * Resampling uses `OfflineAudioContext`, i.e. the browser's own resampler, rather\n * than a hand-rolled one — this is exactly the \"we want the underlying call, not a\n * wrapper\" case.\n *\n * @param blob - A recording from {@link createAudioRecorder}, or any decodable audio.\n * @param options - See {@link WavOptions}.\n * @returns A `Blob` of type `audio/wav`.\n * @throws When the environment has no Web Audio, or the blob cannot be decoded.\n */\nexport async function blobToWav(blob: Blob, options: WavOptions = {}): Promise<Blob> {\n const { mono = false, sampleRate: target } = options;\n\n const Ctor: typeof AudioContext | undefined =\n typeof AudioContext !== \"undefined\"\n ? AudioContext\n : (globalThis as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (!Ctor) throw new Error(\"Web Audio is not available in this environment.\");\n\n const context = new Ctor();\n let decoded: AudioBuffer;\n try {\n decoded = await context.decodeAudioData(await blob.arrayBuffer());\n } finally {\n void context.close().catch(() => undefined);\n }\n\n const wantedChannels = mono ? 1 : decoded.numberOfChannels;\n const wantedRate = target ?? decoded.sampleRate;\n\n if (wantedRate === decoded.sampleRate) {\n const channels = mono\n ? [mixToMono(decoded)]\n : Array.from({ length: decoded.numberOfChannels }, (_, index) =>\n decoded.getChannelData(index),\n );\n return encodeWav({ channels, sampleRate: decoded.sampleRate });\n }\n\n const Offline: typeof OfflineAudioContext | undefined =\n typeof OfflineAudioContext !== \"undefined\" ? OfflineAudioContext : undefined;\n if (!Offline) throw new Error(\"Resampling requires OfflineAudioContext.\");\n\n const frames = Math.max(1, Math.round((decoded.duration * wantedRate) | 0) || 1);\n const offline = new Offline(wantedChannels, frames, wantedRate);\n const source = offline.createBufferSource();\n source.buffer = decoded;\n source.connect(offline.destination);\n source.start();\n const rendered = await offline.startRendering();\n\n return encodeWav({\n channels: Array.from({ length: rendered.numberOfChannels }, (_, index) =>\n rendered.getChannelData(index),\n ),\n sampleRate: rendered.sampleRate,\n });\n}\n"],"mappings":"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"}
|
package/dist/audio/wav.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wav.js","names":[],"sources":["../../src/audio/wav.ts"],"sourcesContent":["/** Raw PCM ready to be wrapped in a RIFF container. */\nexport interface PcmAudio {\n /** One `Float32Array` per channel, samples in −1…1. */\n channels: readonly Float32Array[];\n sampleRate: number;\n}\n\n/** Options for {@link blobToWav}. */\nexport interface WavOptions {\n /**\n * Mix down to one channel. Default `false`.\n *\n * Worth turning on for speech headed to a server: a microphone recorded in stereo\n * carries two nearly identical channels and doubles the upload for nothing.\n */\n mono?: boolean;\n /**\n * Resample to this rate. Default: keep the source rate.\n *\n * 16000 is the rate most speech-to-text APIs want, and dropping 48 kHz to 16 kHz\n * removes two thirds of the bytes with no audible loss on voice.\n */\n sampleRate?: number;\n}\n\n/** Bytes per sample in the output. 16-bit PCM is what every decoder accepts. */\nconst BYTES_PER_SAMPLE = 2;\n\n/**\n * Wrap PCM in a 16-bit RIFF/WAVE container.\n *\n * The header is the 44-byte canonical form: `RIFF` size, `WAVE`, a 16-byte `fmt `\n * chunk declaring format 1 (uncompressed PCM), then `data`. Samples are interleaved\n * and clamped before scaling, because a value even slightly past ±1 wraps around when\n * truncated to 16 bits and turns a loud passage into a burst of noise.\n *\n * Implemented here rather than pulled from a package: it is a fixed header and a\n * scaling loop, roughly forty lines, and a dependency for it would put its own\n * version bounds on every consumer of this SDK to save writing them.\n *\n * @param audio - Channels and sample rate.\n * @returns A `Blob` of type `audio/wav`.\n */\nexport function encodeWav({ channels, sampleRate }: PcmAudio): Blob {\n const channelCount = Math.max(1, channels.length);\n const frameCount = channels[0]?.length ?? 0;\n const dataBytes = frameCount * channelCount * BYTES_PER_SAMPLE;\n const buffer = new ArrayBuffer(44 + dataBytes);\n const view = new DataView(buffer);\n\n const ascii = (offset: number, text: string): void => {\n for (let index = 0; index < text.length; index += 1) {\n view.setUint8(offset + index, text.charCodeAt(index));\n }\n };\n\n const byteRate = sampleRate * channelCount * BYTES_PER_SAMPLE;\n ascii(0, \"RIFF\");\n view.setUint32(4, 36 + dataBytes, true);\n ascii(8, \"WAVE\");\n ascii(12, \"fmt \");\n view.setUint32(16, 16, true);\n view.setUint16(20, 1, true);\n view.setUint16(22, channelCount, true);\n view.setUint32(24, sampleRate, true);\n view.setUint32(28, byteRate, true);\n view.setUint16(32, channelCount * BYTES_PER_SAMPLE, true);\n view.setUint16(34, BYTES_PER_SAMPLE * 8, true);\n ascii(36, \"data\");\n view.setUint32(40, dataBytes, true);\n\n let offset = 44;\n for (let frame = 0; frame < frameCount; frame += 1) {\n for (let channel = 0; channel < channelCount; channel += 1) {\n const sample = channels[channel]?.[frame] ?? 0;\n const clamped = sample < -1 ? -1 : sample > 1 ? 1 : sample;\n // Asymmetric scaling: 16-bit PCM runs −32768…32767.\n view.setInt16(offset, clamped < 0 ? clamped * 0x8000 : clamped * 0x7fff, true);\n offset += BYTES_PER_SAMPLE;\n }\n }\n\n return new Blob([buffer], { type: \"audio/wav\" });\n}\n\n/** Average every channel of a decoded buffer into one. */\nfunction mixToMono(buffer: AudioBuffer): Float32Array {\n const frames = buffer.length;\n const out = new Float32Array(frames);\n for (let channel = 0; channel < buffer.numberOfChannels; channel += 1) {\n const data = buffer.getChannelData(channel);\n for (let frame = 0; frame < frames; frame += 1) out[frame] += data[frame];\n }\n if (buffer.numberOfChannels > 1) {\n for (let frame = 0; frame < frames; frame += 1) out[frame] /= buffer.numberOfChannels;\n }\n return out;\n}\n\n/**\n * Convert a recording to 16-bit WAV, with no dependency.\n *\n * `MediaRecorder` cannot produce WAV — it emits Opus on Chromium and Firefox and AAC\n * on Safari — so a backend that insists on WAV has to be served either by a\n * server-side transcode or by this. It decodes through `AudioContext.decodeAudioData`,\n * which is the browser's own decoder for whatever container the recorder chose, then\n * re-encodes the PCM.\n *\n * !!! The cost is real: WAV is uncompressed, so the same voice note that is 40 KB in\n * Opus is roughly 500 KB here at 48 kHz stereo. `{ mono: true, sampleRate: 16000 }`\n * takes that to about 80 KB and is what a speech-to-text endpoint wants anyway.\n *\n * Resampling uses `OfflineAudioContext`, i.e. the browser's own resampler, rather\n * than a hand-rolled one — this is exactly the \"we want the underlying call, not a\n * wrapper\" case.\n *\n * @param blob - A recording from {@link createAudioRecorder}, or any decodable audio.\n * @param options - See {@link WavOptions}.\n * @returns A `Blob` of type `audio/wav`.\n * @throws When the environment has no Web Audio, or the blob cannot be decoded.\n */\nexport async function blobToWav(blob: Blob, options: WavOptions = {}): Promise<Blob> {\n const { mono = false, sampleRate: target } = options;\n\n const Ctor: typeof AudioContext | undefined =\n typeof AudioContext !== \"undefined\"\n ? AudioContext\n : (globalThis as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (!Ctor) throw new Error(\"Web Audio is not available in this environment.\");\n\n const context = new Ctor();\n let decoded: AudioBuffer;\n try {\n decoded = await context.decodeAudioData(await blob.arrayBuffer());\n } finally {\n void context.close().catch(() => undefined);\n }\n\n const wantedChannels = mono ? 1 : decoded.numberOfChannels;\n const wantedRate = target ?? decoded.sampleRate;\n\n if (wantedRate === decoded.sampleRate) {\n const channels = mono\n ? [mixToMono(decoded)]\n : Array.from({ length: decoded.numberOfChannels }, (_, index) =>\n decoded.getChannelData(index),\n );\n return encodeWav({ channels, sampleRate: decoded.sampleRate });\n }\n\n const Offline: typeof OfflineAudioContext | undefined =\n typeof OfflineAudioContext !== \"undefined\" ? OfflineAudioContext : undefined;\n if (!Offline) throw new Error(\"Resampling requires OfflineAudioContext.\");\n\n const frames = Math.max(1, Math.round((decoded.duration * wantedRate) | 0) || 1);\n const offline = new Offline(wantedChannels, frames, wantedRate);\n const source = offline.createBufferSource();\n source.buffer = decoded;\n source.connect(offline.destination);\n source.start();\n const rendered = await offline.startRendering();\n\n return encodeWav({\n channels: Array.from({ length: rendered.numberOfChannels }, (_, index) =>\n rendered.getChannelData(index),\n ),\n sampleRate: rendered.sampleRate,\n });\n}\n"],"mappings":"AA2CA,
|
|
1
|
+
{"version":3,"file":"wav.js","names":["encodeWav","channelCount","channels","frameCount","dataBytes","buffer","view","ascii","index","text","offset","byteRate","sampleRate","frame","channel","sample","clamped","mixToMono","frames","out","data","blobToWav","target","options","Ctor","context","decoded","blob","wantedChannels","mono","wantedRate","Offline","offline","source","rendered"],"sources":["../../src/audio/wav.ts"],"sourcesContent":["/** Raw PCM ready to be wrapped in a RIFF container. */\nexport interface PcmAudio {\n /** One `Float32Array` per channel, samples in −1…1. */\n channels: readonly Float32Array[];\n sampleRate: number;\n}\n\n/** Options for {@link blobToWav}. */\nexport interface WavOptions {\n /**\n * Mix down to one channel. Default `false`.\n *\n * Worth turning on for speech headed to a server: a microphone recorded in stereo\n * carries two nearly identical channels and doubles the upload for nothing.\n */\n mono?: boolean;\n /**\n * Resample to this rate. Default: keep the source rate.\n *\n * 16000 is the rate most speech-to-text APIs want, and dropping 48 kHz to 16 kHz\n * removes two thirds of the bytes with no audible loss on voice.\n */\n sampleRate?: number;\n}\n\n/** Bytes per sample in the output. 16-bit PCM is what every decoder accepts. */\nconst BYTES_PER_SAMPLE = 2;\n\n/**\n * Wrap PCM in a 16-bit RIFF/WAVE container.\n *\n * The header is the 44-byte canonical form: `RIFF` size, `WAVE`, a 16-byte `fmt `\n * chunk declaring format 1 (uncompressed PCM), then `data`. Samples are interleaved\n * and clamped before scaling, because a value even slightly past ±1 wraps around when\n * truncated to 16 bits and turns a loud passage into a burst of noise.\n *\n * Implemented here rather than pulled from a package: it is a fixed header and a\n * scaling loop, roughly forty lines, and a dependency for it would put its own\n * version bounds on every consumer of this SDK to save writing them.\n *\n * @param audio - Channels and sample rate.\n * @returns A `Blob` of type `audio/wav`.\n */\nexport function encodeWav({ channels, sampleRate }: PcmAudio): Blob {\n const channelCount = Math.max(1, channels.length);\n const frameCount = channels[0]?.length ?? 0;\n const dataBytes = frameCount * channelCount * BYTES_PER_SAMPLE;\n const buffer = new ArrayBuffer(44 + dataBytes);\n const view = new DataView(buffer);\n\n const ascii = (offset: number, text: string): void => {\n for (let index = 0; index < text.length; index += 1) {\n view.setUint8(offset + index, text.charCodeAt(index));\n }\n };\n\n const byteRate = sampleRate * channelCount * BYTES_PER_SAMPLE;\n ascii(0, \"RIFF\");\n view.setUint32(4, 36 + dataBytes, true);\n ascii(8, \"WAVE\");\n ascii(12, \"fmt \");\n view.setUint32(16, 16, true);\n view.setUint16(20, 1, true);\n view.setUint16(22, channelCount, true);\n view.setUint32(24, sampleRate, true);\n view.setUint32(28, byteRate, true);\n view.setUint16(32, channelCount * BYTES_PER_SAMPLE, true);\n view.setUint16(34, BYTES_PER_SAMPLE * 8, true);\n ascii(36, \"data\");\n view.setUint32(40, dataBytes, true);\n\n let offset = 44;\n for (let frame = 0; frame < frameCount; frame += 1) {\n for (let channel = 0; channel < channelCount; channel += 1) {\n const sample = channels[channel]?.[frame] ?? 0;\n const clamped = sample < -1 ? -1 : sample > 1 ? 1 : sample;\n // Asymmetric scaling: 16-bit PCM runs −32768…32767.\n view.setInt16(offset, clamped < 0 ? clamped * 0x8000 : clamped * 0x7fff, true);\n offset += BYTES_PER_SAMPLE;\n }\n }\n\n return new Blob([buffer], { type: \"audio/wav\" });\n}\n\n/** Average every channel of a decoded buffer into one. */\nfunction mixToMono(buffer: AudioBuffer): Float32Array {\n const frames = buffer.length;\n const out = new Float32Array(frames);\n for (let channel = 0; channel < buffer.numberOfChannels; channel += 1) {\n const data = buffer.getChannelData(channel);\n for (let frame = 0; frame < frames; frame += 1) out[frame] += data[frame];\n }\n if (buffer.numberOfChannels > 1) {\n for (let frame = 0; frame < frames; frame += 1) out[frame] /= buffer.numberOfChannels;\n }\n return out;\n}\n\n/**\n * Convert a recording to 16-bit WAV, with no dependency.\n *\n * `MediaRecorder` cannot produce WAV — it emits Opus on Chromium and Firefox and AAC\n * on Safari — so a backend that insists on WAV has to be served either by a\n * server-side transcode or by this. It decodes through `AudioContext.decodeAudioData`,\n * which is the browser's own decoder for whatever container the recorder chose, then\n * re-encodes the PCM.\n *\n * !!! The cost is real: WAV is uncompressed, so the same voice note that is 40 KB in\n * Opus is roughly 500 KB here at 48 kHz stereo. `{ mono: true, sampleRate: 16000 }`\n * takes that to about 80 KB and is what a speech-to-text endpoint wants anyway.\n *\n * Resampling uses `OfflineAudioContext`, i.e. the browser's own resampler, rather\n * than a hand-rolled one — this is exactly the \"we want the underlying call, not a\n * wrapper\" case.\n *\n * @param blob - A recording from {@link createAudioRecorder}, or any decodable audio.\n * @param options - See {@link WavOptions}.\n * @returns A `Blob` of type `audio/wav`.\n * @throws When the environment has no Web Audio, or the blob cannot be decoded.\n */\nexport async function blobToWav(blob: Blob, options: WavOptions = {}): Promise<Blob> {\n const { mono = false, sampleRate: target } = options;\n\n const Ctor: typeof AudioContext | undefined =\n typeof AudioContext !== \"undefined\"\n ? AudioContext\n : (globalThis as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (!Ctor) throw new Error(\"Web Audio is not available in this environment.\");\n\n const context = new Ctor();\n let decoded: AudioBuffer;\n try {\n decoded = await context.decodeAudioData(await blob.arrayBuffer());\n } finally {\n void context.close().catch(() => undefined);\n }\n\n const wantedChannels = mono ? 1 : decoded.numberOfChannels;\n const wantedRate = target ?? decoded.sampleRate;\n\n if (wantedRate === decoded.sampleRate) {\n const channels = mono\n ? [mixToMono(decoded)]\n : Array.from({ length: decoded.numberOfChannels }, (_, index) =>\n decoded.getChannelData(index),\n );\n return encodeWav({ channels, sampleRate: decoded.sampleRate });\n }\n\n const Offline: typeof OfflineAudioContext | undefined =\n typeof OfflineAudioContext !== \"undefined\" ? OfflineAudioContext : undefined;\n if (!Offline) throw new Error(\"Resampling requires OfflineAudioContext.\");\n\n const frames = Math.max(1, Math.round((decoded.duration * wantedRate) | 0) || 1);\n const offline = new Offline(wantedChannels, frames, wantedRate);\n const source = offline.createBufferSource();\n source.buffer = decoded;\n source.connect(offline.destination);\n source.start();\n const rendered = await offline.startRendering();\n\n return encodeWav({\n channels: Array.from({ length: rendered.numberOfChannels }, (_, index) =>\n rendered.getChannelData(index),\n ),\n sampleRate: rendered.sampleRate,\n });\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthGuard.cjs","names":[],"sources":["../../src/auth/AuthGuard.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\n\nexport interface AuthGuardProps {\n /** Whether the current user is authenticated. */\n isAuthenticated: boolean;\n /** Element to render when authenticated. */\n children: ReactNode;\n /** Element to render when not authenticated. Use this to redirect (e.g. `<Navigate to=\"/login\" />`). */\n fallback: ReactNode;\n}\n\n/**\n * Router-agnostic auth gate. The caller decides what to render in either\n * branch — typically `<Outlet />` for protected layouts and `<Navigate />` for\n * the redirect. Pair with {@link createAuthStore} or any custom auth source.\n *\n * @example\n * <AuthGuard\n * isAuthenticated={useAuthStore((s) => s.isAuthenticated)}\n * fallback={<Navigate to=\"/login\" replace />}\n * >\n * <Outlet />\n * </AuthGuard>\n */\nexport function AuthGuard({ isAuthenticated, children, fallback }: AuthGuardProps) {\n return <>{isAuthenticated ? children : fallback}</>;\n}\n"],"mappings":"mCAwBA,
|
|
1
|
+
{"version":3,"file":"AuthGuard.cjs","names":["_Fragment","react_jsx_runtime","AuthGuard","isAuthenticated","children","fallback"],"sources":["../../src/auth/AuthGuard.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\n\nexport interface AuthGuardProps {\n /** Whether the current user is authenticated. */\n isAuthenticated: boolean;\n /** Element to render when authenticated. */\n children: ReactNode;\n /** Element to render when not authenticated. Use this to redirect (e.g. `<Navigate to=\"/login\" />`). */\n fallback: ReactNode;\n}\n\n/**\n * Router-agnostic auth gate. The caller decides what to render in either\n * branch — typically `<Outlet />` for protected layouts and `<Navigate />` for\n * the redirect. Pair with {@link createAuthStore} or any custom auth source.\n *\n * @example\n * <AuthGuard\n * isAuthenticated={useAuthStore((s) => s.isAuthenticated)}\n * fallback={<Navigate to=\"/login\" replace />}\n * >\n * <Outlet />\n * </AuthGuard>\n */\nexport function AuthGuard({ isAuthenticated, children, fallback }: AuthGuardProps) {\n return <>{isAuthenticated ? children : fallback}</>;\n}\n"],"mappings":"A,mCAwBA,SAAgBE,EAAU,CAAE,kBAAiB,WAAU,YAA4B,CAC/E,OAAO,EAAAD,EAAA,IAAA,CAAAD,EAAAA,SAAA,CAAA,SAAGG,EAAkBC,EAAWC,CAAW,CAAA,CACtD,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthGuard.js","names":[],"sources":["../../src/auth/AuthGuard.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\n\nexport interface AuthGuardProps {\n /** Whether the current user is authenticated. */\n isAuthenticated: boolean;\n /** Element to render when authenticated. */\n children: ReactNode;\n /** Element to render when not authenticated. Use this to redirect (e.g. `<Navigate to=\"/login\" />`). */\n fallback: ReactNode;\n}\n\n/**\n * Router-agnostic auth gate. The caller decides what to render in either\n * branch — typically `<Outlet />` for protected layouts and `<Navigate />` for\n * the redirect. Pair with {@link createAuthStore} or any custom auth source.\n *\n * @example\n * <AuthGuard\n * isAuthenticated={useAuthStore((s) => s.isAuthenticated)}\n * fallback={<Navigate to=\"/login\" replace />}\n * >\n * <Outlet />\n * </AuthGuard>\n */\nexport function AuthGuard({ isAuthenticated, children, fallback }: AuthGuardProps) {\n return <>{isAuthenticated ? children : fallback}</>;\n}\n"],"mappings":";;AAwBA,
|
|
1
|
+
{"version":3,"file":"AuthGuard.js","names":["_Fragment","AuthGuard","Fragment","isAuthenticated","children","fallback"],"sources":["../../src/auth/AuthGuard.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\n\nexport interface AuthGuardProps {\n /** Whether the current user is authenticated. */\n isAuthenticated: boolean;\n /** Element to render when authenticated. */\n children: ReactNode;\n /** Element to render when not authenticated. Use this to redirect (e.g. `<Navigate to=\"/login\" />`). */\n fallback: ReactNode;\n}\n\n/**\n * Router-agnostic auth gate. The caller decides what to render in either\n * branch — typically `<Outlet />` for protected layouts and `<Navigate />` for\n * the redirect. Pair with {@link createAuthStore} or any custom auth source.\n *\n * @example\n * <AuthGuard\n * isAuthenticated={useAuthStore((s) => s.isAuthenticated)}\n * fallback={<Navigate to=\"/login\" replace />}\n * >\n * <Outlet />\n * </AuthGuard>\n */\nexport function AuthGuard({ isAuthenticated, children, fallback }: AuthGuardProps) {\n return <>{isAuthenticated ? children : fallback}</>;\n}\n"],"mappings":";;AAwBA,SAAgBC,EAAU,EAAE,oBAAiB,aAAU,eAA4B;CAC/E,OAAO,kBAAAD,GAAA,EAAA,UAAGG,IAAkBC,IAAWC,EAAW,CAAA;AACtD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-auth-store.cjs","names":[],"sources":["../../src/auth/create-auth-store.ts"],"sourcesContent":["import { create } from \"zustand\";\nimport { persist, createJSONStorage } from \"zustand/middleware\";\n\nexport interface AuthState<TUser> {\n user: TUser | null;\n token: string | null;\n isAuthenticated: boolean;\n setSession: (session: { user: TUser; token: string }) => void;\n setUser: (user: TUser | null) => void;\n setToken: (token: string | null) => void;\n logout: () => void;\n}\n\nexport interface CreateAuthStoreOptions<TUser> {\n /** Persist key used in storage (default: \"tempest-auth\"). */\n name?: string;\n /** Which storage to persist into (default: localStorage). */\n storage?: \"local\" | \"session\";\n /** Initial user (useful for SSR hydration). */\n initialUser?: TUser | null;\n /** Initial token. */\n initialToken?: string | null;\n}\n\n/**\n * Build a typed Zustand auth store with `persist` middleware. Each app passes\n * its own `TUser` shape so the SDK does not own the user model.\n *\n * @example\n * const useAuthStore = createAuthStore<UserResponse>();\n * const { user, token, logout } = useAuthStore();\n */\nexport function createAuthStore<TUser>(options: CreateAuthStoreOptions<TUser> = {}) {\n const name = options.name ?? \"tempest-auth\";\n const storageImpl = options.storage === \"session\" ? () => sessionStorage : () => localStorage;\n\n return create<AuthState<TUser>>()(\n persist(\n (set) => ({\n user: options.initialUser ?? null,\n token: options.initialToken ?? null,\n isAuthenticated: !!options.initialToken,\n setSession: ({ user, token }) => set({ user, token, isAuthenticated: true }),\n setUser: (user) => set({ user }),\n setToken: (token) => set({ token, isAuthenticated: !!token }),\n logout: () => set({ user: null, token: null, isAuthenticated: false }),\n }),\n {\n name,\n storage: createJSONStorage(storageImpl),\n partialize: (state) => ({ user: state.user, token: state.token }),\n onRehydrateStorage: () => (state) => {\n if (state) state.isAuthenticated = !!state.token;\n },\n },\n ),\n );\n}\n"],"mappings":"yDAgCA,
|
|
1
|
+
{"version":3,"file":"create-auth-store.cjs","names":["create","persist","createJSONStorage","zustand","zustand_middleware","createAuthStore","name","options","storageImpl","set","token","state"],"sources":["../../src/auth/create-auth-store.ts"],"sourcesContent":["import { create } from \"zustand\";\nimport { persist, createJSONStorage } from \"zustand/middleware\";\n\nexport interface AuthState<TUser> {\n user: TUser | null;\n token: string | null;\n isAuthenticated: boolean;\n setSession: (session: { user: TUser; token: string }) => void;\n setUser: (user: TUser | null) => void;\n setToken: (token: string | null) => void;\n logout: () => void;\n}\n\nexport interface CreateAuthStoreOptions<TUser> {\n /** Persist key used in storage (default: \"tempest-auth\"). */\n name?: string;\n /** Which storage to persist into (default: localStorage). */\n storage?: \"local\" | \"session\";\n /** Initial user (useful for SSR hydration). */\n initialUser?: TUser | null;\n /** Initial token. */\n initialToken?: string | null;\n}\n\n/**\n * Build a typed Zustand auth store with `persist` middleware. Each app passes\n * its own `TUser` shape so the SDK does not own the user model.\n *\n * @example\n * const useAuthStore = createAuthStore<UserResponse>();\n * const { user, token, logout } = useAuthStore();\n */\nexport function createAuthStore<TUser>(options: CreateAuthStoreOptions<TUser> = {}) {\n const name = options.name ?? \"tempest-auth\";\n const storageImpl = options.storage === \"session\" ? () => sessionStorage : () => localStorage;\n\n return create<AuthState<TUser>>()(\n persist(\n (set) => ({\n user: options.initialUser ?? null,\n token: options.initialToken ?? null,\n isAuthenticated: !!options.initialToken,\n setSession: ({ user, token }) => set({ user, token, isAuthenticated: true }),\n setUser: (user) => set({ user }),\n setToken: (token) => set({ token, isAuthenticated: !!token }),\n logout: () => set({ user: null, token: null, isAuthenticated: false }),\n }),\n {\n name,\n storage: createJSONStorage(storageImpl),\n partialize: (state) => ({ user: state.user, token: state.token }),\n onRehydrateStorage: () => (state) => {\n if (state) state.isAuthenticated = !!state.token;\n },\n },\n ),\n );\n}\n"],"mappings":"A,yDAgCA,SAAgBK,EAAuB,EAAyC,CAAC,EAAG,CAChF,IAAMC,EAAOC,EAAQ,MAAQ,eACvBC,EAAcD,EAAQ,UAAY,cAAkB,mBAAuB,aAEjF,OAAA,EAAOP,EAAAA,OAAAA,CAAyB,CAAC,EAAA,EAC7BC,EAAAA,QAAAA,CACK,IAAS,CACN,KAAMM,EAAQ,aAAe,KAC7B,MAAOA,EAAQ,cAAgB,KAC/B,gBAAiB,CAAC,CAACA,EAAQ,aAC3B,YAAa,CAAE,OAAM,WAAYE,EAAI,CAAE,OAAM,QAAO,gBAAiB,EAAK,CAAC,EAC3E,QAAU,GAASA,EAAI,CAAE,MAAK,CAAC,EAC/B,SAAW,GAAUA,EAAI,CAAE,QAAO,gBAAiB,CAAC,CAACC,CAAM,CAAC,EAC5D,WAAcD,EAAI,CAAE,KAAM,KAAM,MAAO,KAAM,gBAAiB,EAAM,CAAC,CACzE,GACA,CACI,OACA,SAAA,EAASP,EAAAA,kBAAAA,CAAkBM,CAAW,EACtC,WAAa,IAAW,CAAE,KAAMG,EAAM,KAAM,MAAOA,EAAM,KAAM,GAC/D,uBAA2B,GAAU,CAC7BA,IAAO,EAAM,gBAAkB,CAAC,CAACA,EAAM,MAC/C,CACJ,CACJ,CACJ,CACJ,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-auth-store.js","names":[],"sources":["../../src/auth/create-auth-store.ts"],"sourcesContent":["import { create } from \"zustand\";\nimport { persist, createJSONStorage } from \"zustand/middleware\";\n\nexport interface AuthState<TUser> {\n user: TUser | null;\n token: string | null;\n isAuthenticated: boolean;\n setSession: (session: { user: TUser; token: string }) => void;\n setUser: (user: TUser | null) => void;\n setToken: (token: string | null) => void;\n logout: () => void;\n}\n\nexport interface CreateAuthStoreOptions<TUser> {\n /** Persist key used in storage (default: \"tempest-auth\"). */\n name?: string;\n /** Which storage to persist into (default: localStorage). */\n storage?: \"local\" | \"session\";\n /** Initial user (useful for SSR hydration). */\n initialUser?: TUser | null;\n /** Initial token. */\n initialToken?: string | null;\n}\n\n/**\n * Build a typed Zustand auth store with `persist` middleware. Each app passes\n * its own `TUser` shape so the SDK does not own the user model.\n *\n * @example\n * const useAuthStore = createAuthStore<UserResponse>();\n * const { user, token, logout } = useAuthStore();\n */\nexport function createAuthStore<TUser>(options: CreateAuthStoreOptions<TUser> = {}) {\n const name = options.name ?? \"tempest-auth\";\n const storageImpl = options.storage === \"session\" ? () => sessionStorage : () => localStorage;\n\n return create<AuthState<TUser>>()(\n persist(\n (set) => ({\n user: options.initialUser ?? null,\n token: options.initialToken ?? null,\n isAuthenticated: !!options.initialToken,\n setSession: ({ user, token }) => set({ user, token, isAuthenticated: true }),\n setUser: (user) => set({ user }),\n setToken: (token) => set({ token, isAuthenticated: !!token }),\n logout: () => set({ user: null, token: null, isAuthenticated: false }),\n }),\n {\n name,\n storage: createJSONStorage(storageImpl),\n partialize: (state) => ({ user: state.user, token: state.token }),\n onRehydrateStorage: () => (state) => {\n if (state) state.isAuthenticated = !!state.token;\n },\n },\n ),\n );\n}\n"],"mappings":";;;AAgCA,
|
|
1
|
+
{"version":3,"file":"create-auth-store.js","names":["createAuthStore","name","options","storageImpl","create","persist","set","token","createJSONStorage","state"],"sources":["../../src/auth/create-auth-store.ts"],"sourcesContent":["import { create } from \"zustand\";\nimport { persist, createJSONStorage } from \"zustand/middleware\";\n\nexport interface AuthState<TUser> {\n user: TUser | null;\n token: string | null;\n isAuthenticated: boolean;\n setSession: (session: { user: TUser; token: string }) => void;\n setUser: (user: TUser | null) => void;\n setToken: (token: string | null) => void;\n logout: () => void;\n}\n\nexport interface CreateAuthStoreOptions<TUser> {\n /** Persist key used in storage (default: \"tempest-auth\"). */\n name?: string;\n /** Which storage to persist into (default: localStorage). */\n storage?: \"local\" | \"session\";\n /** Initial user (useful for SSR hydration). */\n initialUser?: TUser | null;\n /** Initial token. */\n initialToken?: string | null;\n}\n\n/**\n * Build a typed Zustand auth store with `persist` middleware. Each app passes\n * its own `TUser` shape so the SDK does not own the user model.\n *\n * @example\n * const useAuthStore = createAuthStore<UserResponse>();\n * const { user, token, logout } = useAuthStore();\n */\nexport function createAuthStore<TUser>(options: CreateAuthStoreOptions<TUser> = {}) {\n const name = options.name ?? \"tempest-auth\";\n const storageImpl = options.storage === \"session\" ? () => sessionStorage : () => localStorage;\n\n return create<AuthState<TUser>>()(\n persist(\n (set) => ({\n user: options.initialUser ?? null,\n token: options.initialToken ?? null,\n isAuthenticated: !!options.initialToken,\n setSession: ({ user, token }) => set({ user, token, isAuthenticated: true }),\n setUser: (user) => set({ user }),\n setToken: (token) => set({ token, isAuthenticated: !!token }),\n logout: () => set({ user: null, token: null, isAuthenticated: false }),\n }),\n {\n name,\n storage: createJSONStorage(storageImpl),\n partialize: (state) => ({ user: state.user, token: state.token }),\n onRehydrateStorage: () => (state) => {\n if (state) state.isAuthenticated = !!state.token;\n },\n },\n ),\n );\n}\n"],"mappings":";;;AAgCA,SAAgBA,EAAuB,IAAyC,CAAC,GAAG;CAChF,IAAMC,IAAOC,EAAQ,QAAQ,gBACvBC,IAAcD,EAAQ,YAAY,kBAAkB,uBAAuB;CAEjF,OAAOE,EAAyB,CAAC,CAC7BC,GACK,OAAS;EACN,MAAMH,EAAQ,eAAe;EAC7B,OAAOA,EAAQ,gBAAgB;EAC/B,iBAAiB,CAAC,CAACA,EAAQ;EAC3B,aAAa,EAAE,SAAM,eAAYI,EAAI;GAAE;GAAM;GAAO,iBAAiB;EAAK,CAAC;EAC3E,UAAU,MAASA,EAAI,EAAE,QAAK,CAAC;EAC/B,WAAW,MAAUA,EAAI;GAAE;GAAO,iBAAiB,CAAC,CAACC;EAAM,CAAC;EAC5D,cAAcD,EAAI;GAAE,MAAM;GAAM,OAAO;GAAM,iBAAiB;EAAM,CAAC;CACzE,IACA;EACI;EACA,SAASE,EAAkBL,CAAW;EACtC,aAAa,OAAW;GAAE,MAAMM,EAAM;GAAM,OAAOA,EAAM;EAAM;EAC/D,2BAA2B,MAAU;GACjC,AAAIA,MAAO,EAAM,kBAAkB,CAAC,CAACA,EAAM;EAC/C;CACJ,CACJ,CACJ;AACJ"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../utils/dev-mode.cjs"),t=require("../http/errors.cjs"),n=require("../http/api-client.cjs"),r=require("./create-auth-store.cjs"),i=require("./refresh-queue.cjs");var a=1e4;function o(e,t){return e.length===0?Promise.resolve():new Promise(n=>{let r=setTimeout(n,t);Promise.allSettled(e).then(()=>{clearTimeout(r),n()})})}function s(e){let t=e??{};return{token:t.access_token,refreshToken:t.refresh_token}}function c(c){let{baseURL:l,prefix:u,loginPath:d=`/api/auth/login`,refreshPath:ee=`/api/auth/refresh`,logoutPath:f,onLogoutError:te,mePath:p,storeName:m=`tempest-auth`,storage:h=`local`,withCredentials:g=!1,csrf:_,fetcher:v,parseTokens:y=s,parseUser:b,refreshBody:x=e=>e?{refresh_token:e}:void 0,retry:ne,redirectTo:S,onSessionEnd:C}=c,w=r.createAuthStore({name:m,storage:h}),T=`${m}-refresh`;function E(){return typeof window>`u`?null:h===`session`?window.sessionStorage:window.localStorage}function D(){return E()?.getItem(T)??null}function O(e){let t=E();t&&(e?t.setItem(T,e):t.removeItem(T))}let k=()=>w.getState(),A=()=>k().token;async function j(){if(!p)return k().user;let e=M,n;try{n=await $.get(p,{skipAuthRetry:!0})}catch(n){throw M===e?n:new t.SessionSupersededError}if(M!==e)throw new t.SessionSupersededError;return k().setUser(n),n}let M=0,N=Promise.resolve(),P=0,F=new Set,I=new Set,L=new Set,R=new Set;function z(e){let t=e.then(()=>void 0,()=>void 0);return L.add(t),t.then(()=>L.delete(t)),e}function B(t){e.isDevBuild()&&console.warn(`[tempest-react-sdk] createTempestAuth: logoutPath revocation failed`,t);try{te?.(t)}catch{return}}function V(e){let t=(async()=>{try{await e()}catch(e){B(e)}})();return I.add(t),t.then(()=>I.delete(t)),t}function H(e,t){f&&!g&&t&&V(()=>U(e).post(f,{body:x(t)}))}function U(e){return n.createApiClient({baseURL:l,prefix:u,withCredentials:g,csrf:_,fetcher:v,getToken:()=>e})}function W(){M+=1,K=i.createRefreshQueue(G)}async function G(){let e=M;R.add(e);try{let n;try{n=await z($.post(ee,{body:x(D()),skipAuth:!0}))}catch(n){throw M===e?n:new t.SessionSupersededError}let{token:r,refreshToken:i}=y(n);if(M!==e)throw H(r??null,i),new t.SessionSupersededError;k().setToken(r),i&&O(i)}finally{R.delete(e)}}let K=i.createRefreshQueue(G);function q(e){let t=A();return t===null?!1:e.token===null||e.token!==t}function J(){return A()===null&&D()===null}async function Y(){if(!(F.size>0&&P===0&&(await Promise.allSettled([...F]),A()!==null)))throw Error(`anonymous 401 with no session`)}async function X(e){if(e.epoch!==null&&e.epoch!==M)throw new t.SessionSupersededError;if(q(e)){if(e.token===null)throw Error(`anonymous 401 under a live session`)
|
|
1
|
+
const e=require("../utils/dev-mode.cjs"),t=require("../http/errors.cjs"),n=require("../http/api-client.cjs"),r=require("./create-auth-store.cjs"),i=require("./refresh-queue.cjs");var a=1e4;function o(e,t){return e.length===0?Promise.resolve():new Promise(n=>{let r=setTimeout(n,t);Promise.allSettled(e).then(()=>{clearTimeout(r),n()})})}function s(e){let t=e??{};return{token:t.access_token,refreshToken:t.refresh_token}}function c(c){let{baseURL:l,prefix:u,loginPath:d=`/api/auth/login`,refreshPath:ee=`/api/auth/refresh`,logoutPath:f,onLogoutError:te,mePath:p,storeName:m=`tempest-auth`,storage:h=`local`,withCredentials:g=!1,csrf:_,fetcher:v,parseTokens:y=s,parseUser:b,refreshBody:x=e=>e?{refresh_token:e}:void 0,retry:ne,redirectTo:S,onSessionEnd:C}=c,w=r.createAuthStore({name:m,storage:h}),T=`${m}-refresh`;function E(){return typeof window>`u`?null:h===`session`?window.sessionStorage:window.localStorage}function D(){return E()?.getItem(T)??null}function O(e){let t=E();t&&(e?t.setItem(T,e):t.removeItem(T))}let k=()=>w.getState(),A=()=>k().token;async function j(){if(!p)return k().user;let e=M,n;try{n=await $.get(p,{skipAuthRetry:!0})}catch(n){throw M===e?n:new t.SessionSupersededError}if(M!==e)throw new t.SessionSupersededError;return k().setUser(n),n}let M=0,N=Promise.resolve(),P=0,F=new Set,I=new Set,L=new Set,R=new Set;function z(e){let t=e.then(()=>void 0,()=>void 0);return L.add(t),t.then(()=>L.delete(t)),e}function B(t){e.isDevBuild()&&console.warn(`[tempest-react-sdk] createTempestAuth: logoutPath revocation failed`,t);try{te?.(t)}catch{return}}function V(e){let t=(async()=>{try{await e()}catch(e){B(e)}})();return I.add(t),t.then(()=>I.delete(t)),t}function H(e,t){f&&!g&&t&&V(()=>U(e).post(f,{body:x(t)}))}function U(e){return n.createApiClient({baseURL:l,prefix:u,withCredentials:g,csrf:_,fetcher:v,getToken:()=>e})}function W(){M+=1,K=i.createRefreshQueue(G)}async function G(){let e=M;R.add(e);try{let n;try{n=await z($.post(ee,{body:x(D()),skipAuth:!0}))}catch(n){throw M===e?n:new t.SessionSupersededError}let{token:r,refreshToken:i}=y(n);if(M!==e)throw H(r??null,i),new t.SessionSupersededError;k().setToken(r),i&&O(i)}finally{R.delete(e)}}let K=i.createRefreshQueue(G);function q(e){let t=A();return t===null?!1:e.token===null||e.token!==t}function J(){return A()===null&&D()===null}async function Y(){if(!(F.size>0&&P===0&&(await Promise.allSettled([...F]),A()!==null)))throw Error(`anonymous 401 with no session`)}async function X(e){if(e.epoch!==null&&e.epoch!==M)throw new t.SessionSupersededError;if(q(e)){if(e.token===null)throw Error(`anonymous 401 under a live session`)}else return e.token===null&&J()?R.has(M)?K():Y():K()}async function Z(e,n){if(n.epoch!==null&&n.epoch!==M)throw new t.SessionSupersededError;q(n)||n.token===null&&J()||await se()}async function re(e){I.size>0&&await o([...I],a);let t=ie(e);F.add(t);try{return await t}finally{F.delete(t)}}async function ie(e){let n=M,r=await z($.post(d,{body:e,skipAuth:!0})),{token:i,refreshToken:a}=y(r);if(M!==n)throw H(i??null,a),new t.SessionSupersededError;let{done:o}=Q(`switch`),s=M;if(await o.catch(()=>void 0),M!==s)throw new t.SessionSupersededError;k().setToken(i),O(a??null);let c=b?.(r);return c==null?j():(k().setUser(c),c)}function Q(e){let{user:t,token:n}=k(),r=n!==null||t!==null||D()!==null;if((r||e!==`expired`)&&W(),k().logout(),O(null),!r)return{live:r,done:e===`switch`||P===0?N:Promise.resolve()};if(!C)return{live:r,done:Promise.resolve()};let i=U(n);P+=1;let a=(async()=>{try{await C({reason:e,user:t,token:n,api:i})}finally{--P}})();return N=a.then(()=>void 0,()=>void 0),{live:r,done:a.then(()=>void 0)}}function ae(){if(!f)return null;let e=f,{token:t,user:n}=k(),r=D();if(!g&&t===null&&n===null&&r===null)return null;let i=g?[...L]:[];return V(async()=>(await o(i,a),U(t).post(e,{body:x(r)})))}function oe(){let e=ae(),{done:t}=Q(`logout`);return e?Promise.all([e,t]).then(()=>void 0):t}async function se(){let{live:e,done:t}=Q(`expired`);await t.catch(()=>void 0),e&&S&&typeof window<`u`&&window.location.assign(S)}let $=n.createApiClient({baseURL:l,prefix:u,withCredentials:g,csrf:_,fetcher:v,getToken:A,getSessionEpoch:()=>M,refresh:X,retry:ne,onUnauthorized:Z});return{useAuthStore:w,api:$,login:re,logout:oe,refresh:()=>K(),getToken:A}}exports.createTempestAuth=c;
|
|
2
2
|
//# sourceMappingURL=create-tempest-auth.cjs.map
|