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":"app-error-reporter.cjs","names":[],"sources":["../../src/telemetry/app-error-reporter.ts"],"sourcesContent":["import { ownerFingerprint } from \"@/utils/owner-fingerprint\";\nimport { createAppErrorQueue } from \"./app-error-queue\";\nimport type { AppErrorQueueEntry, AppErrorQueueStorage, AppErrorStamp } from \"./app-error-queue\";\nimport { fitAppErrorReport } from \"./app-error-schema\";\nimport type { AppErrorDeviceSchema } from \"./app-error-schema\";\nimport { readToken, sendOne } from \"./app-error-transport\";\nimport { describeAppError } from \"./describe-app-error\";\nimport { isDevBuild } from \"../utils/dev-mode\";\n\n/** Options for {@link createAppErrorReporter}. */\nexport interface CreateAppErrorReporterOptions {\n /** Full URL of the backend route, e.g. `${API_URL}/api/app-errors`. */\n endpoint: string;\n /**\n * Current access token, if any. Optional on purpose: the route is public,\n * and an error raised before login — or with a stale session — still has\n * to get through. A token that throws or resolves empty sends anonymously.\n */\n getToken?: () => string | null | undefined | Promise<string | null | undefined>;\n /**\n * Who is signed in right now — a stable, non-secret id such as the user id.\n * Read **when the error is reported**, and stored in the queue only as a\n * one-way fingerprint (`entry.owner`). A non-string (an `async` getter\n * from untyped JS, an object) or a getter that throws reads as nobody.\n *\n * It never grants the bearer. The bearer goes out only when the token at\n * send time is the very token that was in force at report time (its\n * fingerprint is `entry.session`): the principal and the token come from\n * two sources, and a principal store that lags behind a login would\n * otherwise send A's report with B's token. The principal only tells\n * {@link CreateAppErrorReporterOptions.foreignReports} `\"drop\"` whose\n * report is whose.\n */\n getPrincipal?: () => string | number | null | undefined;\n /**\n * What to do with a queued report that cannot go out with the current\n * bearer — raised under another token, or queued before 0.77.0. Default\n * `\"anonymous\"`.\n *\n * - `\"anonymous\"` — send it without `Authorization`. The route is public,\n * so the error still reaches the backend; it is only not attributed to\n * anybody. This includes the user's own reports raised before a token\n * refresh: attribution is lost, never misplaced.\n * - `\"drop\"` — discard every report not proven to be the current\n * principal's: another principal, nobody, or unknown (no principal at\n * report time, a legacy entry, or nobody signed in now). For apps where\n * a previous user's error text must not leave the device after they\n * signed out. **Needs `getPrincipal`**: without it the only identity is\n * the token fingerprint, and a refresh changes it, so a mismatch is no\n * proof the report is someone else's — the reporter then sends\n * anonymously instead of destroying the user's own reports.\n *\n * Never is a report sent with a bearer other than the one it was raised\n * under: that would credit the previous user's error to whoever signed in\n * next.\n */\n foreignReports?: \"anonymous\" | \"drop\";\n /**\n * Device facts, read **when the error is reported**, not when it is sent —\n * a report queued offline on `1.4.0` must not go out labelled `1.5.0`.\n */\n device?: () => AppErrorDeviceSchema;\n /** Where the queue persists. Defaults to `localStorage`; `null` keeps it in memory. */\n storage?: AppErrorQueueStorage | null;\n /** Storage key. Default `\"tempest:app-errors\"`. */\n storageKey?: string;\n /** Ceiling on distinct waiting reports; the oldest is evicted. Default `50`. */\n maxEntries?: number;\n /** `fetch` to send with. Defaults to the global one. */\n fetch?: typeof fetch;\n /** Send on every report and when the browser goes `online`. Default `true`. */\n autoFlush?: boolean;\n}\n\n/** What one {@link AppErrorReporter.flush} did. */\nexport interface AppErrorFlushResult {\n /** Reports the backend accepted. */\n sent: number;\n /** Reports the backend refused for good (a 4xx other than 408/429) and were dropped. */\n dropped: number;\n /** Reports still waiting. */\n pending: number;\n /** Milliseconds the backend asked to wait (429 `Retry-After`), or `null`. */\n retryAfterMs: number | null;\n}\n\n/** The reporter {@link createAppErrorReporter} returns. */\nexport interface AppErrorReporter {\n /** Queue an error with optional context, and try to send it. Never throws. */\n report: (error: unknown, context?: Record<string, unknown>) => void;\n /** Drain the queue now. Concurrent calls share one run. */\n flush: () => Promise<AppErrorFlushResult>;\n /**\n * The waiting entries, oldest first. With an async `getToken` and no\n * `getPrincipal`, a report joins them once its token resolves — `flush()`\n * waits for that, `pending()` does not.\n */\n pending: () => AppErrorQueueEntry[];\n /**\n * Drop every waiting report. Call it on logout when reports raised in that\n * session should not outlive it; even without it, a report never leaves\n * with the next user's bearer.\n *\n * It also stops a flush in flight before its next send (the one already on\n * the wire cannot be recalled), and discards reports still waiting for an\n * async `getToken` to stamp them — both would otherwise refill the queue or\n * keep sending what the logout meant to forget.\n */\n clear: () => void;\n /** Remove the `online` listener and the retry timer. */\n dispose: () => void;\n}\n\n/** Set once the warning has printed, so every reporter built after it stays quiet. */\nlet warnedDropWithoutPrincipal = false;\n\n/**\n * Reset the warn-once latch. Test-only: the latch is module state, so a suite\n * asserting the warning more than once would otherwise see it only the first time.\n */\nexport function resetDropWithoutPrincipalWarning(): void {\n warnedDropWithoutPrincipal = false;\n}\n\n/**\n * Warn once, in development, that `foreignReports: \"drop\"` was asked for\n * without the `getPrincipal` it needs.\n *\n * Without a principal the only identity is the token fingerprint, which a\n * refresh changes, so the reporter cannot tell a foreign report from the\n * user's own and sends them anonymously instead of dropping them. The option\n * type-checks either way, so nothing else would tell the app its privacy\n * choice is not in force.\n *\n * @param options - The reporter's options.\n */\nfunction warnOnDropWithoutPrincipal(options: CreateAppErrorReporterOptions): void {\n if (warnedDropWithoutPrincipal || options.foreignReports !== \"drop\") return;\n if (options.getPrincipal !== undefined || !isDevBuild()) return;\n warnedDropWithoutPrincipal = true;\n console.warn(\n '[tempest-react-sdk] createAppErrorReporter({ foreignReports: \"drop\" }) needs ' +\n \"`getPrincipal`: without it the reporter cannot prove a queued report belongs \" +\n \"to someone else, so it drops nothing and those reports go out anonymously. \" +\n 'Pass `getPrincipal` to make \"drop\" take effect.',\n );\n}\n\n/**\n * Pick the default store, guarding hosts where touching `localStorage` throws.\n *\n * @returns `localStorage`, or `null` when there is none.\n */\nfunction defaultStorage(): AppErrorQueueStorage | null {\n try {\n return typeof localStorage === \"undefined\" ? null : localStorage;\n } catch {\n return null;\n }\n}\n\n/**\n * Read the device facts, reporting without them when the getter throws.\n *\n * @param device - The caller's getter.\n * @returns The facts, or an empty object.\n */\nfunction readDevice(device: CreateAppErrorReporterOptions[\"device\"]): AppErrorDeviceSchema {\n try {\n return device?.() ?? {};\n } catch {\n return {};\n }\n}\n\n/**\n * Fingerprint whoever `getPrincipal` says is signed in.\n *\n * @param getPrincipal - The app's principal getter.\n * @returns The owner, or `null` when nobody is signed in or the getter throws.\n */\nfunction principalOwner(getPrincipal: () => unknown): string | null {\n try {\n return ownerFingerprint(\"p\", getPrincipal());\n } catch {\n return null;\n }\n}\n\n/**\n * Stamp a report being raised now with its session and, when given, principal.\n *\n * @param getPrincipal - The app's principal getter, read synchronously.\n * @param token - The token read now, or a promise of it.\n * @returns The stamp, or a promise of it when the token is still arriving.\n */\nfunction stampNow(\n getPrincipal: CreateAppErrorReporterOptions[\"getPrincipal\"],\n token: string | null | Promise<string | null>,\n): AppErrorStamp | Promise<AppErrorStamp> {\n const owner = getPrincipal ? { owner: principalOwner(getPrincipal) } : {};\n if (typeof token === \"string\" || token === null) {\n return { session: ownerFingerprint(\"t\", token), ...owner };\n }\n return token.then((value) => ({ session: ownerFingerprint(\"t\", value), ...owner }));\n}\n\n/**\n * Report client errors to a Tempest backend's `POST /api/app-errors`, surviving\n * the offline stretches where field errors actually happen.\n *\n * The client half of `tempest-fastapi-sdk`'s `app_errors` module. An error is\n * described ({@link describeAppError}), stamped with the device facts of that\n * moment, fitted to the backend's column limits and queued in `localStorage`\n * before anything goes over the network — so a report raised with no signal is\n * sent when the browser comes back `online`, not lost.\n *\n * What each answer does to the queue:\n *\n * - **2xx** — removed.\n * - **429** — kept; sending pauses for `Retry-After`, then resumes on its own.\n * - **5xx, 408, network failure** — kept; the next report, `online` event or\n * `flush()` retries.\n * - **any other 4xx** — dropped: the backend will refuse that body forever, and\n * keeping it would block every report queued behind it.\n *\n * Each report is stamped with a one-way fingerprint of the token in force when\n * it was raised, and goes out with a bearer only when the token at send time is\n * that same one — never with the token of whoever signed in next. The queue\n * never stores a token. `clear()` also stops a flush in flight and discards\n * reports still waiting for an async token.\n *\n * @example\n * import { createAppErrorReporter } from \"tempest-react-sdk\";\n *\n * const reporter = createAppErrorReporter({\n * endpoint: `${import.meta.env.VITE_API_URL}/api/app-errors`,\n * getToken: () => sessionStorage.getItem(\"access_token\"),\n * device: () => ({ platform: \"web\", app_version: \"1.4.0\" }),\n * });\n *\n * reporter.report(new Error(\"crop failed\"), { step: \"crop\", size: 0 });\n *\n * @param options - Endpoint, token and device getters, storage and limits.\n * @returns The reporter.\n */\nexport function createAppErrorReporter(options: CreateAppErrorReporterOptions): AppErrorReporter {\n const { endpoint, getToken, getPrincipal, device, autoFlush = true } = options;\n warnOnDropWithoutPrincipal(options);\n const strict = getPrincipal !== undefined && options.foreignReports === \"drop\";\n const queue = createAppErrorQueue(\n options.storage === undefined ? defaultStorage() : options.storage,\n options.storageKey ?? \"tempest:app-errors\",\n options.maxEntries ?? 50,\n );\n let running: Promise<AppErrorFlushResult> | null = null;\n let pausedUntil = 0;\n let timer: ReturnType<typeof setTimeout> | null = null;\n const stamping = new Set<Promise<void>>();\n let generation = 0;\n\n const drain = async (): Promise<AppErrorFlushResult> => {\n const send = options.fetch ?? globalThis.fetch.bind(globalThis);\n await Promise.all(stamping);\n const token = await readToken(getToken);\n const session = ownerFingerprint(\"t\", token);\n const current = getPrincipal ? principalOwner(getPrincipal) : null;\n const started = generation;\n const result: AppErrorFlushResult = { sent: 0, dropped: 0, pending: 0, retryAfterMs: null };\n for (const entry of queue.entries()) {\n if (!queue.has(entry)) continue;\n if (strict && (entry.owner == null || entry.owner !== current)) {\n queue.remove(entry);\n result.dropped += 1;\n continue;\n }\n const bearer = entry.session != null && entry.session === session ? token : null;\n const outcome = await sendOne(send, endpoint, bearer, entry);\n if (generation !== started) break;\n if (outcome.kind === \"stop\") break;\n if (outcome.kind === \"wait\") {\n result.retryAfterMs = outcome.ms;\n pausedUntil = Date.now() + outcome.ms;\n timer ??= setTimeout(() => {\n timer = null;\n void flush();\n }, outcome.ms);\n break;\n }\n queue.remove(entry);\n result[outcome.kind === \"sent\" ? \"sent\" : \"dropped\"] += 1;\n }\n result.pending = queue.entries().length;\n return result;\n };\n\n const flush = (): Promise<AppErrorFlushResult> => {\n running ??= drain().finally(() => {\n running = null;\n });\n return running;\n };\n\n const shouldSend = (): boolean =>\n autoFlush &&\n Date.now() >= pausedUntil &&\n (typeof navigator === \"undefined\" || navigator.onLine !== false);\n\n const onOnline = (): void => {\n if (shouldSend()) void flush();\n };\n if (autoFlush && typeof window !== \"undefined\") window.addEventListener(\"online\", onOnline);\n\n return {\n report(error, context) {\n const description = describeAppError(error, context);\n const report = fitAppErrorReport({ ...readDevice(device), ...description });\n const stamp = stampNow(getPrincipal, readToken(getToken));\n if (!(stamp instanceof Promise)) {\n queue.push(report, stamp);\n if (shouldSend()) void flush();\n return;\n }\n const raisedIn = generation;\n const stamped = stamp.then((value) => {\n stamping.delete(stamped);\n if (generation !== raisedIn) return;\n queue.push(report, value);\n if (shouldSend()) void flush();\n });\n stamping.add(stamped);\n },\n flush,\n pending: () => queue.entries(),\n clear() {\n generation += 1;\n queue.clear();\n },\n dispose() {\n if (typeof window !== \"undefined\") window.removeEventListener(\"online\", onOnline);\n if (timer) clearTimeout(timer);\n timer = null;\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app-error-reporter.cjs","names":["isDevBuild","ownerFingerprint","createAppErrorQueue","readToken","sendOne","describeAppError","fitAppErrorReport","require_dev_mode","require_owner_fingerprint","require_app_error_queue","require_app_error_schema","require_app_error_transport","require_describe_app_error","warnedDropWithoutPrincipal","warnOnDropWithoutPrincipal","options","defaultStorage","readDevice","device","principalOwner","getPrincipal","stampNow","owner","token","value","createAppErrorReporter","strict","queue","running","pausedUntil","timer","stamping","generation","drain","send","getToken","session","current","started","result","entry","bearer","outcome","endpoint","flush","shouldSend","autoFlush","onOnline","description","error","context","report","stamp","raisedIn","stamped"],"sources":["../../src/telemetry/app-error-reporter.ts"],"sourcesContent":["import { ownerFingerprint } from \"@/utils/owner-fingerprint\";\nimport { createAppErrorQueue } from \"./app-error-queue\";\nimport type { AppErrorQueueEntry, AppErrorQueueStorage, AppErrorStamp } from \"./app-error-queue\";\nimport { fitAppErrorReport } from \"./app-error-schema\";\nimport type { AppErrorDeviceSchema } from \"./app-error-schema\";\nimport { readToken, sendOne } from \"./app-error-transport\";\nimport { describeAppError } from \"./describe-app-error\";\nimport { isDevBuild } from \"../utils/dev-mode\";\n\n/** Options for {@link createAppErrorReporter}. */\nexport interface CreateAppErrorReporterOptions {\n /** Full URL of the backend route, e.g. `${API_URL}/api/app-errors`. */\n endpoint: string;\n /**\n * Current access token, if any. Optional on purpose: the route is public,\n * and an error raised before login — or with a stale session — still has\n * to get through. A token that throws or resolves empty sends anonymously.\n */\n getToken?: () => string | null | undefined | Promise<string | null | undefined>;\n /**\n * Who is signed in right now — a stable, non-secret id such as the user id.\n * Read **when the error is reported**, and stored in the queue only as a\n * one-way fingerprint (`entry.owner`). A non-string (an `async` getter\n * from untyped JS, an object) or a getter that throws reads as nobody.\n *\n * It never grants the bearer. The bearer goes out only when the token at\n * send time is the very token that was in force at report time (its\n * fingerprint is `entry.session`): the principal and the token come from\n * two sources, and a principal store that lags behind a login would\n * otherwise send A's report with B's token. The principal only tells\n * {@link CreateAppErrorReporterOptions.foreignReports} `\"drop\"` whose\n * report is whose.\n */\n getPrincipal?: () => string | number | null | undefined;\n /**\n * What to do with a queued report that cannot go out with the current\n * bearer — raised under another token, or queued before 0.77.0. Default\n * `\"anonymous\"`.\n *\n * - `\"anonymous\"` — send it without `Authorization`. The route is public,\n * so the error still reaches the backend; it is only not attributed to\n * anybody. This includes the user's own reports raised before a token\n * refresh: attribution is lost, never misplaced.\n * - `\"drop\"` — discard every report not proven to be the current\n * principal's: another principal, nobody, or unknown (no principal at\n * report time, a legacy entry, or nobody signed in now). For apps where\n * a previous user's error text must not leave the device after they\n * signed out. **Needs `getPrincipal`**: without it the only identity is\n * the token fingerprint, and a refresh changes it, so a mismatch is no\n * proof the report is someone else's — the reporter then sends\n * anonymously instead of destroying the user's own reports.\n *\n * Never is a report sent with a bearer other than the one it was raised\n * under: that would credit the previous user's error to whoever signed in\n * next.\n */\n foreignReports?: \"anonymous\" | \"drop\";\n /**\n * Device facts, read **when the error is reported**, not when it is sent —\n * a report queued offline on `1.4.0` must not go out labelled `1.5.0`.\n */\n device?: () => AppErrorDeviceSchema;\n /** Where the queue persists. Defaults to `localStorage`; `null` keeps it in memory. */\n storage?: AppErrorQueueStorage | null;\n /** Storage key. Default `\"tempest:app-errors\"`. */\n storageKey?: string;\n /** Ceiling on distinct waiting reports; the oldest is evicted. Default `50`. */\n maxEntries?: number;\n /** `fetch` to send with. Defaults to the global one. */\n fetch?: typeof fetch;\n /** Send on every report and when the browser goes `online`. Default `true`. */\n autoFlush?: boolean;\n}\n\n/** What one {@link AppErrorReporter.flush} did. */\nexport interface AppErrorFlushResult {\n /** Reports the backend accepted. */\n sent: number;\n /** Reports the backend refused for good (a 4xx other than 408/429) and were dropped. */\n dropped: number;\n /** Reports still waiting. */\n pending: number;\n /** Milliseconds the backend asked to wait (429 `Retry-After`), or `null`. */\n retryAfterMs: number | null;\n}\n\n/** The reporter {@link createAppErrorReporter} returns. */\nexport interface AppErrorReporter {\n /** Queue an error with optional context, and try to send it. Never throws. */\n report: (error: unknown, context?: Record<string, unknown>) => void;\n /** Drain the queue now. Concurrent calls share one run. */\n flush: () => Promise<AppErrorFlushResult>;\n /**\n * The waiting entries, oldest first. With an async `getToken` and no\n * `getPrincipal`, a report joins them once its token resolves — `flush()`\n * waits for that, `pending()` does not.\n */\n pending: () => AppErrorQueueEntry[];\n /**\n * Drop every waiting report. Call it on logout when reports raised in that\n * session should not outlive it; even without it, a report never leaves\n * with the next user's bearer.\n *\n * It also stops a flush in flight before its next send (the one already on\n * the wire cannot be recalled), and discards reports still waiting for an\n * async `getToken` to stamp them — both would otherwise refill the queue or\n * keep sending what the logout meant to forget.\n */\n clear: () => void;\n /** Remove the `online` listener and the retry timer. */\n dispose: () => void;\n}\n\n/** Set once the warning has printed, so every reporter built after it stays quiet. */\nlet warnedDropWithoutPrincipal = false;\n\n/**\n * Reset the warn-once latch. Test-only: the latch is module state, so a suite\n * asserting the warning more than once would otherwise see it only the first time.\n */\nexport function resetDropWithoutPrincipalWarning(): void {\n warnedDropWithoutPrincipal = false;\n}\n\n/**\n * Warn once, in development, that `foreignReports: \"drop\"` was asked for\n * without the `getPrincipal` it needs.\n *\n * Without a principal the only identity is the token fingerprint, which a\n * refresh changes, so the reporter cannot tell a foreign report from the\n * user's own and sends them anonymously instead of dropping them. The option\n * type-checks either way, so nothing else would tell the app its privacy\n * choice is not in force.\n *\n * @param options - The reporter's options.\n */\nfunction warnOnDropWithoutPrincipal(options: CreateAppErrorReporterOptions): void {\n if (warnedDropWithoutPrincipal || options.foreignReports !== \"drop\") return;\n if (options.getPrincipal !== undefined || !isDevBuild()) return;\n warnedDropWithoutPrincipal = true;\n console.warn(\n '[tempest-react-sdk] createAppErrorReporter({ foreignReports: \"drop\" }) needs ' +\n \"`getPrincipal`: without it the reporter cannot prove a queued report belongs \" +\n \"to someone else, so it drops nothing and those reports go out anonymously. \" +\n 'Pass `getPrincipal` to make \"drop\" take effect.',\n );\n}\n\n/**\n * Pick the default store, guarding hosts where touching `localStorage` throws.\n *\n * @returns `localStorage`, or `null` when there is none.\n */\nfunction defaultStorage(): AppErrorQueueStorage | null {\n try {\n return typeof localStorage === \"undefined\" ? null : localStorage;\n } catch {\n return null;\n }\n}\n\n/**\n * Read the device facts, reporting without them when the getter throws.\n *\n * @param device - The caller's getter.\n * @returns The facts, or an empty object.\n */\nfunction readDevice(device: CreateAppErrorReporterOptions[\"device\"]): AppErrorDeviceSchema {\n try {\n return device?.() ?? {};\n } catch {\n return {};\n }\n}\n\n/**\n * Fingerprint whoever `getPrincipal` says is signed in.\n *\n * @param getPrincipal - The app's principal getter.\n * @returns The owner, or `null` when nobody is signed in or the getter throws.\n */\nfunction principalOwner(getPrincipal: () => unknown): string | null {\n try {\n return ownerFingerprint(\"p\", getPrincipal());\n } catch {\n return null;\n }\n}\n\n/**\n * Stamp a report being raised now with its session and, when given, principal.\n *\n * @param getPrincipal - The app's principal getter, read synchronously.\n * @param token - The token read now, or a promise of it.\n * @returns The stamp, or a promise of it when the token is still arriving.\n */\nfunction stampNow(\n getPrincipal: CreateAppErrorReporterOptions[\"getPrincipal\"],\n token: string | null | Promise<string | null>,\n): AppErrorStamp | Promise<AppErrorStamp> {\n const owner = getPrincipal ? { owner: principalOwner(getPrincipal) } : {};\n if (typeof token === \"string\" || token === null) {\n return { session: ownerFingerprint(\"t\", token), ...owner };\n }\n return token.then((value) => ({ session: ownerFingerprint(\"t\", value), ...owner }));\n}\n\n/**\n * Report client errors to a Tempest backend's `POST /api/app-errors`, surviving\n * the offline stretches where field errors actually happen.\n *\n * The client half of `tempest-fastapi-sdk`'s `app_errors` module. An error is\n * described ({@link describeAppError}), stamped with the device facts of that\n * moment, fitted to the backend's column limits and queued in `localStorage`\n * before anything goes over the network — so a report raised with no signal is\n * sent when the browser comes back `online`, not lost.\n *\n * What each answer does to the queue:\n *\n * - **2xx** — removed.\n * - **429** — kept; sending pauses for `Retry-After`, then resumes on its own.\n * - **5xx, 408, network failure** — kept; the next report, `online` event or\n * `flush()` retries.\n * - **any other 4xx** — dropped: the backend will refuse that body forever, and\n * keeping it would block every report queued behind it.\n *\n * Each report is stamped with a one-way fingerprint of the token in force when\n * it was raised, and goes out with a bearer only when the token at send time is\n * that same one — never with the token of whoever signed in next. The queue\n * never stores a token. `clear()` also stops a flush in flight and discards\n * reports still waiting for an async token.\n *\n * @example\n * import { createAppErrorReporter } from \"tempest-react-sdk\";\n *\n * const reporter = createAppErrorReporter({\n * endpoint: `${import.meta.env.VITE_API_URL}/api/app-errors`,\n * getToken: () => sessionStorage.getItem(\"access_token\"),\n * device: () => ({ platform: \"web\", app_version: \"1.4.0\" }),\n * });\n *\n * reporter.report(new Error(\"crop failed\"), { step: \"crop\", size: 0 });\n *\n * @param options - Endpoint, token and device getters, storage and limits.\n * @returns The reporter.\n */\nexport function createAppErrorReporter(options: CreateAppErrorReporterOptions): AppErrorReporter {\n const { endpoint, getToken, getPrincipal, device, autoFlush = true } = options;\n warnOnDropWithoutPrincipal(options);\n const strict = getPrincipal !== undefined && options.foreignReports === \"drop\";\n const queue = createAppErrorQueue(\n options.storage === undefined ? defaultStorage() : options.storage,\n options.storageKey ?? \"tempest:app-errors\",\n options.maxEntries ?? 50,\n );\n let running: Promise<AppErrorFlushResult> | null = null;\n let pausedUntil = 0;\n let timer: ReturnType<typeof setTimeout> | null = null;\n const stamping = new Set<Promise<void>>();\n let generation = 0;\n\n const drain = async (): Promise<AppErrorFlushResult> => {\n const send = options.fetch ?? globalThis.fetch.bind(globalThis);\n await Promise.all(stamping);\n const token = await readToken(getToken);\n const session = ownerFingerprint(\"t\", token);\n const current = getPrincipal ? principalOwner(getPrincipal) : null;\n const started = generation;\n const result: AppErrorFlushResult = { sent: 0, dropped: 0, pending: 0, retryAfterMs: null };\n for (const entry of queue.entries()) {\n if (!queue.has(entry)) continue;\n if (strict && (entry.owner == null || entry.owner !== current)) {\n queue.remove(entry);\n result.dropped += 1;\n continue;\n }\n const bearer = entry.session != null && entry.session === session ? token : null;\n const outcome = await sendOne(send, endpoint, bearer, entry);\n if (generation !== started) break;\n if (outcome.kind === \"stop\") break;\n if (outcome.kind === \"wait\") {\n result.retryAfterMs = outcome.ms;\n pausedUntil = Date.now() + outcome.ms;\n timer ??= setTimeout(() => {\n timer = null;\n void flush();\n }, outcome.ms);\n break;\n }\n queue.remove(entry);\n result[outcome.kind === \"sent\" ? \"sent\" : \"dropped\"] += 1;\n }\n result.pending = queue.entries().length;\n return result;\n };\n\n const flush = (): Promise<AppErrorFlushResult> => {\n running ??= drain().finally(() => {\n running = null;\n });\n return running;\n };\n\n const shouldSend = (): boolean =>\n autoFlush &&\n Date.now() >= pausedUntil &&\n (typeof navigator === \"undefined\" || navigator.onLine !== false);\n\n const onOnline = (): void => {\n if (shouldSend()) void flush();\n };\n if (autoFlush && typeof window !== \"undefined\") window.addEventListener(\"online\", onOnline);\n\n return {\n report(error, context) {\n const description = describeAppError(error, context);\n const report = fitAppErrorReport({ ...readDevice(device), ...description });\n const stamp = stampNow(getPrincipal, readToken(getToken));\n if (!(stamp instanceof Promise)) {\n queue.push(report, stamp);\n if (shouldSend()) void flush();\n return;\n }\n const raisedIn = generation;\n const stamped = stamp.then((value) => {\n stamping.delete(stamped);\n if (generation !== raisedIn) return;\n queue.push(report, value);\n if (shouldSend()) void flush();\n });\n stamping.add(stamped);\n },\n flush,\n pending: () => queue.entries(),\n clear() {\n generation += 1;\n queue.clear();\n },\n dispose() {\n if (typeof window !== \"undefined\") window.removeEventListener(\"online\", onOnline);\n if (timer) clearTimeout(timer);\n timer = null;\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-error-reporter.js","names":[],"sources":["../../src/telemetry/app-error-reporter.ts"],"sourcesContent":["import { ownerFingerprint } from \"@/utils/owner-fingerprint\";\nimport { createAppErrorQueue } from \"./app-error-queue\";\nimport type { AppErrorQueueEntry, AppErrorQueueStorage, AppErrorStamp } from \"./app-error-queue\";\nimport { fitAppErrorReport } from \"./app-error-schema\";\nimport type { AppErrorDeviceSchema } from \"./app-error-schema\";\nimport { readToken, sendOne } from \"./app-error-transport\";\nimport { describeAppError } from \"./describe-app-error\";\nimport { isDevBuild } from \"../utils/dev-mode\";\n\n/** Options for {@link createAppErrorReporter}. */\nexport interface CreateAppErrorReporterOptions {\n /** Full URL of the backend route, e.g. `${API_URL}/api/app-errors`. */\n endpoint: string;\n /**\n * Current access token, if any. Optional on purpose: the route is public,\n * and an error raised before login — or with a stale session — still has\n * to get through. A token that throws or resolves empty sends anonymously.\n */\n getToken?: () => string | null | undefined | Promise<string | null | undefined>;\n /**\n * Who is signed in right now — a stable, non-secret id such as the user id.\n * Read **when the error is reported**, and stored in the queue only as a\n * one-way fingerprint (`entry.owner`). A non-string (an `async` getter\n * from untyped JS, an object) or a getter that throws reads as nobody.\n *\n * It never grants the bearer. The bearer goes out only when the token at\n * send time is the very token that was in force at report time (its\n * fingerprint is `entry.session`): the principal and the token come from\n * two sources, and a principal store that lags behind a login would\n * otherwise send A's report with B's token. The principal only tells\n * {@link CreateAppErrorReporterOptions.foreignReports} `\"drop\"` whose\n * report is whose.\n */\n getPrincipal?: () => string | number | null | undefined;\n /**\n * What to do with a queued report that cannot go out with the current\n * bearer — raised under another token, or queued before 0.77.0. Default\n * `\"anonymous\"`.\n *\n * - `\"anonymous\"` — send it without `Authorization`. The route is public,\n * so the error still reaches the backend; it is only not attributed to\n * anybody. This includes the user's own reports raised before a token\n * refresh: attribution is lost, never misplaced.\n * - `\"drop\"` — discard every report not proven to be the current\n * principal's: another principal, nobody, or unknown (no principal at\n * report time, a legacy entry, or nobody signed in now). For apps where\n * a previous user's error text must not leave the device after they\n * signed out. **Needs `getPrincipal`**: without it the only identity is\n * the token fingerprint, and a refresh changes it, so a mismatch is no\n * proof the report is someone else's — the reporter then sends\n * anonymously instead of destroying the user's own reports.\n *\n * Never is a report sent with a bearer other than the one it was raised\n * under: that would credit the previous user's error to whoever signed in\n * next.\n */\n foreignReports?: \"anonymous\" | \"drop\";\n /**\n * Device facts, read **when the error is reported**, not when it is sent —\n * a report queued offline on `1.4.0` must not go out labelled `1.5.0`.\n */\n device?: () => AppErrorDeviceSchema;\n /** Where the queue persists. Defaults to `localStorage`; `null` keeps it in memory. */\n storage?: AppErrorQueueStorage | null;\n /** Storage key. Default `\"tempest:app-errors\"`. */\n storageKey?: string;\n /** Ceiling on distinct waiting reports; the oldest is evicted. Default `50`. */\n maxEntries?: number;\n /** `fetch` to send with. Defaults to the global one. */\n fetch?: typeof fetch;\n /** Send on every report and when the browser goes `online`. Default `true`. */\n autoFlush?: boolean;\n}\n\n/** What one {@link AppErrorReporter.flush} did. */\nexport interface AppErrorFlushResult {\n /** Reports the backend accepted. */\n sent: number;\n /** Reports the backend refused for good (a 4xx other than 408/429) and were dropped. */\n dropped: number;\n /** Reports still waiting. */\n pending: number;\n /** Milliseconds the backend asked to wait (429 `Retry-After`), or `null`. */\n retryAfterMs: number | null;\n}\n\n/** The reporter {@link createAppErrorReporter} returns. */\nexport interface AppErrorReporter {\n /** Queue an error with optional context, and try to send it. Never throws. */\n report: (error: unknown, context?: Record<string, unknown>) => void;\n /** Drain the queue now. Concurrent calls share one run. */\n flush: () => Promise<AppErrorFlushResult>;\n /**\n * The waiting entries, oldest first. With an async `getToken` and no\n * `getPrincipal`, a report joins them once its token resolves — `flush()`\n * waits for that, `pending()` does not.\n */\n pending: () => AppErrorQueueEntry[];\n /**\n * Drop every waiting report. Call it on logout when reports raised in that\n * session should not outlive it; even without it, a report never leaves\n * with the next user's bearer.\n *\n * It also stops a flush in flight before its next send (the one already on\n * the wire cannot be recalled), and discards reports still waiting for an\n * async `getToken` to stamp them — both would otherwise refill the queue or\n * keep sending what the logout meant to forget.\n */\n clear: () => void;\n /** Remove the `online` listener and the retry timer. */\n dispose: () => void;\n}\n\n/** Set once the warning has printed, so every reporter built after it stays quiet. */\nlet warnedDropWithoutPrincipal = false;\n\n/**\n * Reset the warn-once latch. Test-only: the latch is module state, so a suite\n * asserting the warning more than once would otherwise see it only the first time.\n */\nexport function resetDropWithoutPrincipalWarning(): void {\n warnedDropWithoutPrincipal = false;\n}\n\n/**\n * Warn once, in development, that `foreignReports: \"drop\"` was asked for\n * without the `getPrincipal` it needs.\n *\n * Without a principal the only identity is the token fingerprint, which a\n * refresh changes, so the reporter cannot tell a foreign report from the\n * user's own and sends them anonymously instead of dropping them. The option\n * type-checks either way, so nothing else would tell the app its privacy\n * choice is not in force.\n *\n * @param options - The reporter's options.\n */\nfunction warnOnDropWithoutPrincipal(options: CreateAppErrorReporterOptions): void {\n if (warnedDropWithoutPrincipal || options.foreignReports !== \"drop\") return;\n if (options.getPrincipal !== undefined || !isDevBuild()) return;\n warnedDropWithoutPrincipal = true;\n console.warn(\n '[tempest-react-sdk] createAppErrorReporter({ foreignReports: \"drop\" }) needs ' +\n \"`getPrincipal`: without it the reporter cannot prove a queued report belongs \" +\n \"to someone else, so it drops nothing and those reports go out anonymously. \" +\n 'Pass `getPrincipal` to make \"drop\" take effect.',\n );\n}\n\n/**\n * Pick the default store, guarding hosts where touching `localStorage` throws.\n *\n * @returns `localStorage`, or `null` when there is none.\n */\nfunction defaultStorage(): AppErrorQueueStorage | null {\n try {\n return typeof localStorage === \"undefined\" ? null : localStorage;\n } catch {\n return null;\n }\n}\n\n/**\n * Read the device facts, reporting without them when the getter throws.\n *\n * @param device - The caller's getter.\n * @returns The facts, or an empty object.\n */\nfunction readDevice(device: CreateAppErrorReporterOptions[\"device\"]): AppErrorDeviceSchema {\n try {\n return device?.() ?? {};\n } catch {\n return {};\n }\n}\n\n/**\n * Fingerprint whoever `getPrincipal` says is signed in.\n *\n * @param getPrincipal - The app's principal getter.\n * @returns The owner, or `null` when nobody is signed in or the getter throws.\n */\nfunction principalOwner(getPrincipal: () => unknown): string | null {\n try {\n return ownerFingerprint(\"p\", getPrincipal());\n } catch {\n return null;\n }\n}\n\n/**\n * Stamp a report being raised now with its session and, when given, principal.\n *\n * @param getPrincipal - The app's principal getter, read synchronously.\n * @param token - The token read now, or a promise of it.\n * @returns The stamp, or a promise of it when the token is still arriving.\n */\nfunction stampNow(\n getPrincipal: CreateAppErrorReporterOptions[\"getPrincipal\"],\n token: string | null | Promise<string | null>,\n): AppErrorStamp | Promise<AppErrorStamp> {\n const owner = getPrincipal ? { owner: principalOwner(getPrincipal) } : {};\n if (typeof token === \"string\" || token === null) {\n return { session: ownerFingerprint(\"t\", token), ...owner };\n }\n return token.then((value) => ({ session: ownerFingerprint(\"t\", value), ...owner }));\n}\n\n/**\n * Report client errors to a Tempest backend's `POST /api/app-errors`, surviving\n * the offline stretches where field errors actually happen.\n *\n * The client half of `tempest-fastapi-sdk`'s `app_errors` module. An error is\n * described ({@link describeAppError}), stamped with the device facts of that\n * moment, fitted to the backend's column limits and queued in `localStorage`\n * before anything goes over the network — so a report raised with no signal is\n * sent when the browser comes back `online`, not lost.\n *\n * What each answer does to the queue:\n *\n * - **2xx** — removed.\n * - **429** — kept; sending pauses for `Retry-After`, then resumes on its own.\n * - **5xx, 408, network failure** — kept; the next report, `online` event or\n * `flush()` retries.\n * - **any other 4xx** — dropped: the backend will refuse that body forever, and\n * keeping it would block every report queued behind it.\n *\n * Each report is stamped with a one-way fingerprint of the token in force when\n * it was raised, and goes out with a bearer only when the token at send time is\n * that same one — never with the token of whoever signed in next. The queue\n * never stores a token. `clear()` also stops a flush in flight and discards\n * reports still waiting for an async token.\n *\n * @example\n * import { createAppErrorReporter } from \"tempest-react-sdk\";\n *\n * const reporter = createAppErrorReporter({\n * endpoint: `${import.meta.env.VITE_API_URL}/api/app-errors`,\n * getToken: () => sessionStorage.getItem(\"access_token\"),\n * device: () => ({ platform: \"web\", app_version: \"1.4.0\" }),\n * });\n *\n * reporter.report(new Error(\"crop failed\"), { step: \"crop\", size: 0 });\n *\n * @param options - Endpoint, token and device getters, storage and limits.\n * @returns The reporter.\n */\nexport function createAppErrorReporter(options: CreateAppErrorReporterOptions): AppErrorReporter {\n const { endpoint, getToken, getPrincipal, device, autoFlush = true } = options;\n warnOnDropWithoutPrincipal(options);\n const strict = getPrincipal !== undefined && options.foreignReports === \"drop\";\n const queue = createAppErrorQueue(\n options.storage === undefined ? defaultStorage() : options.storage,\n options.storageKey ?? \"tempest:app-errors\",\n options.maxEntries ?? 50,\n );\n let running: Promise<AppErrorFlushResult> | null = null;\n let pausedUntil = 0;\n let timer: ReturnType<typeof setTimeout> | null = null;\n const stamping = new Set<Promise<void>>();\n let generation = 0;\n\n const drain = async (): Promise<AppErrorFlushResult> => {\n const send = options.fetch ?? globalThis.fetch.bind(globalThis);\n await Promise.all(stamping);\n const token = await readToken(getToken);\n const session = ownerFingerprint(\"t\", token);\n const current = getPrincipal ? principalOwner(getPrincipal) : null;\n const started = generation;\n const result: AppErrorFlushResult = { sent: 0, dropped: 0, pending: 0, retryAfterMs: null };\n for (const entry of queue.entries()) {\n if (!queue.has(entry)) continue;\n if (strict && (entry.owner == null || entry.owner !== current)) {\n queue.remove(entry);\n result.dropped += 1;\n continue;\n }\n const bearer = entry.session != null && entry.session === session ? token : null;\n const outcome = await sendOne(send, endpoint, bearer, entry);\n if (generation !== started) break;\n if (outcome.kind === \"stop\") break;\n if (outcome.kind === \"wait\") {\n result.retryAfterMs = outcome.ms;\n pausedUntil = Date.now() + outcome.ms;\n timer ??= setTimeout(() => {\n timer = null;\n void flush();\n }, outcome.ms);\n break;\n }\n queue.remove(entry);\n result[outcome.kind === \"sent\" ? \"sent\" : \"dropped\"] += 1;\n }\n result.pending = queue.entries().length;\n return result;\n };\n\n const flush = (): Promise<AppErrorFlushResult> => {\n running ??= drain().finally(() => {\n running = null;\n });\n return running;\n };\n\n const shouldSend = (): boolean =>\n autoFlush &&\n Date.now() >= pausedUntil &&\n (typeof navigator === \"undefined\" || navigator.onLine !== false);\n\n const onOnline = (): void => {\n if (shouldSend()) void flush();\n };\n if (autoFlush && typeof window !== \"undefined\") window.addEventListener(\"online\", onOnline);\n\n return {\n report(error, context) {\n const description = describeAppError(error, context);\n const report = fitAppErrorReport({ ...readDevice(device), ...description });\n const stamp = stampNow(getPrincipal, readToken(getToken));\n if (!(stamp instanceof Promise)) {\n queue.push(report, stamp);\n if (shouldSend()) void flush();\n return;\n }\n const raisedIn = generation;\n const stamped = stamp.then((value) => {\n stamping.delete(stamped);\n if (generation !== raisedIn) return;\n queue.push(report, value);\n if (shouldSend()) void flush();\n });\n stamping.add(stamped);\n },\n flush,\n pending: () => queue.entries(),\n clear() {\n generation += 1;\n queue.clear();\n },\n dispose() {\n if (typeof window !== \"undefined\") window.removeEventListener(\"online\", onOnline);\n if (timer) clearTimeout(timer);\n timer = null;\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app-error-reporter.js","names":["warnedDropWithoutPrincipal","warnOnDropWithoutPrincipal","options","isDevBuild","defaultStorage","readDevice","device","principalOwner","ownerFingerprint","getPrincipal","stampNow","owner","token","value","createAppErrorReporter","strict","queue","createAppErrorQueue","running","pausedUntil","timer","stamping","generation","drain","send","readToken","getToken","session","current","started","result","entry","bearer","outcome","sendOne","endpoint","flush","shouldSend","autoFlush","onOnline","description","describeAppError","error","context","report","fitAppErrorReport","stamp","raisedIn","stamped"],"sources":["../../src/telemetry/app-error-reporter.ts"],"sourcesContent":["import { ownerFingerprint } from \"@/utils/owner-fingerprint\";\nimport { createAppErrorQueue } from \"./app-error-queue\";\nimport type { AppErrorQueueEntry, AppErrorQueueStorage, AppErrorStamp } from \"./app-error-queue\";\nimport { fitAppErrorReport } from \"./app-error-schema\";\nimport type { AppErrorDeviceSchema } from \"./app-error-schema\";\nimport { readToken, sendOne } from \"./app-error-transport\";\nimport { describeAppError } from \"./describe-app-error\";\nimport { isDevBuild } from \"../utils/dev-mode\";\n\n/** Options for {@link createAppErrorReporter}. */\nexport interface CreateAppErrorReporterOptions {\n /** Full URL of the backend route, e.g. `${API_URL}/api/app-errors`. */\n endpoint: string;\n /**\n * Current access token, if any. Optional on purpose: the route is public,\n * and an error raised before login — or with a stale session — still has\n * to get through. A token that throws or resolves empty sends anonymously.\n */\n getToken?: () => string | null | undefined | Promise<string | null | undefined>;\n /**\n * Who is signed in right now — a stable, non-secret id such as the user id.\n * Read **when the error is reported**, and stored in the queue only as a\n * one-way fingerprint (`entry.owner`). A non-string (an `async` getter\n * from untyped JS, an object) or a getter that throws reads as nobody.\n *\n * It never grants the bearer. The bearer goes out only when the token at\n * send time is the very token that was in force at report time (its\n * fingerprint is `entry.session`): the principal and the token come from\n * two sources, and a principal store that lags behind a login would\n * otherwise send A's report with B's token. The principal only tells\n * {@link CreateAppErrorReporterOptions.foreignReports} `\"drop\"` whose\n * report is whose.\n */\n getPrincipal?: () => string | number | null | undefined;\n /**\n * What to do with a queued report that cannot go out with the current\n * bearer — raised under another token, or queued before 0.77.0. Default\n * `\"anonymous\"`.\n *\n * - `\"anonymous\"` — send it without `Authorization`. The route is public,\n * so the error still reaches the backend; it is only not attributed to\n * anybody. This includes the user's own reports raised before a token\n * refresh: attribution is lost, never misplaced.\n * - `\"drop\"` — discard every report not proven to be the current\n * principal's: another principal, nobody, or unknown (no principal at\n * report time, a legacy entry, or nobody signed in now). For apps where\n * a previous user's error text must not leave the device after they\n * signed out. **Needs `getPrincipal`**: without it the only identity is\n * the token fingerprint, and a refresh changes it, so a mismatch is no\n * proof the report is someone else's — the reporter then sends\n * anonymously instead of destroying the user's own reports.\n *\n * Never is a report sent with a bearer other than the one it was raised\n * under: that would credit the previous user's error to whoever signed in\n * next.\n */\n foreignReports?: \"anonymous\" | \"drop\";\n /**\n * Device facts, read **when the error is reported**, not when it is sent —\n * a report queued offline on `1.4.0` must not go out labelled `1.5.0`.\n */\n device?: () => AppErrorDeviceSchema;\n /** Where the queue persists. Defaults to `localStorage`; `null` keeps it in memory. */\n storage?: AppErrorQueueStorage | null;\n /** Storage key. Default `\"tempest:app-errors\"`. */\n storageKey?: string;\n /** Ceiling on distinct waiting reports; the oldest is evicted. Default `50`. */\n maxEntries?: number;\n /** `fetch` to send with. Defaults to the global one. */\n fetch?: typeof fetch;\n /** Send on every report and when the browser goes `online`. Default `true`. */\n autoFlush?: boolean;\n}\n\n/** What one {@link AppErrorReporter.flush} did. */\nexport interface AppErrorFlushResult {\n /** Reports the backend accepted. */\n sent: number;\n /** Reports the backend refused for good (a 4xx other than 408/429) and were dropped. */\n dropped: number;\n /** Reports still waiting. */\n pending: number;\n /** Milliseconds the backend asked to wait (429 `Retry-After`), or `null`. */\n retryAfterMs: number | null;\n}\n\n/** The reporter {@link createAppErrorReporter} returns. */\nexport interface AppErrorReporter {\n /** Queue an error with optional context, and try to send it. Never throws. */\n report: (error: unknown, context?: Record<string, unknown>) => void;\n /** Drain the queue now. Concurrent calls share one run. */\n flush: () => Promise<AppErrorFlushResult>;\n /**\n * The waiting entries, oldest first. With an async `getToken` and no\n * `getPrincipal`, a report joins them once its token resolves — `flush()`\n * waits for that, `pending()` does not.\n */\n pending: () => AppErrorQueueEntry[];\n /**\n * Drop every waiting report. Call it on logout when reports raised in that\n * session should not outlive it; even without it, a report never leaves\n * with the next user's bearer.\n *\n * It also stops a flush in flight before its next send (the one already on\n * the wire cannot be recalled), and discards reports still waiting for an\n * async `getToken` to stamp them — both would otherwise refill the queue or\n * keep sending what the logout meant to forget.\n */\n clear: () => void;\n /** Remove the `online` listener and the retry timer. */\n dispose: () => void;\n}\n\n/** Set once the warning has printed, so every reporter built after it stays quiet. */\nlet warnedDropWithoutPrincipal = false;\n\n/**\n * Reset the warn-once latch. Test-only: the latch is module state, so a suite\n * asserting the warning more than once would otherwise see it only the first time.\n */\nexport function resetDropWithoutPrincipalWarning(): void {\n warnedDropWithoutPrincipal = false;\n}\n\n/**\n * Warn once, in development, that `foreignReports: \"drop\"` was asked for\n * without the `getPrincipal` it needs.\n *\n * Without a principal the only identity is the token fingerprint, which a\n * refresh changes, so the reporter cannot tell a foreign report from the\n * user's own and sends them anonymously instead of dropping them. The option\n * type-checks either way, so nothing else would tell the app its privacy\n * choice is not in force.\n *\n * @param options - The reporter's options.\n */\nfunction warnOnDropWithoutPrincipal(options: CreateAppErrorReporterOptions): void {\n if (warnedDropWithoutPrincipal || options.foreignReports !== \"drop\") return;\n if (options.getPrincipal !== undefined || !isDevBuild()) return;\n warnedDropWithoutPrincipal = true;\n console.warn(\n '[tempest-react-sdk] createAppErrorReporter({ foreignReports: \"drop\" }) needs ' +\n \"`getPrincipal`: without it the reporter cannot prove a queued report belongs \" +\n \"to someone else, so it drops nothing and those reports go out anonymously. \" +\n 'Pass `getPrincipal` to make \"drop\" take effect.',\n );\n}\n\n/**\n * Pick the default store, guarding hosts where touching `localStorage` throws.\n *\n * @returns `localStorage`, or `null` when there is none.\n */\nfunction defaultStorage(): AppErrorQueueStorage | null {\n try {\n return typeof localStorage === \"undefined\" ? null : localStorage;\n } catch {\n return null;\n }\n}\n\n/**\n * Read the device facts, reporting without them when the getter throws.\n *\n * @param device - The caller's getter.\n * @returns The facts, or an empty object.\n */\nfunction readDevice(device: CreateAppErrorReporterOptions[\"device\"]): AppErrorDeviceSchema {\n try {\n return device?.() ?? {};\n } catch {\n return {};\n }\n}\n\n/**\n * Fingerprint whoever `getPrincipal` says is signed in.\n *\n * @param getPrincipal - The app's principal getter.\n * @returns The owner, or `null` when nobody is signed in or the getter throws.\n */\nfunction principalOwner(getPrincipal: () => unknown): string | null {\n try {\n return ownerFingerprint(\"p\", getPrincipal());\n } catch {\n return null;\n }\n}\n\n/**\n * Stamp a report being raised now with its session and, when given, principal.\n *\n * @param getPrincipal - The app's principal getter, read synchronously.\n * @param token - The token read now, or a promise of it.\n * @returns The stamp, or a promise of it when the token is still arriving.\n */\nfunction stampNow(\n getPrincipal: CreateAppErrorReporterOptions[\"getPrincipal\"],\n token: string | null | Promise<string | null>,\n): AppErrorStamp | Promise<AppErrorStamp> {\n const owner = getPrincipal ? { owner: principalOwner(getPrincipal) } : {};\n if (typeof token === \"string\" || token === null) {\n return { session: ownerFingerprint(\"t\", token), ...owner };\n }\n return token.then((value) => ({ session: ownerFingerprint(\"t\", value), ...owner }));\n}\n\n/**\n * Report client errors to a Tempest backend's `POST /api/app-errors`, surviving\n * the offline stretches where field errors actually happen.\n *\n * The client half of `tempest-fastapi-sdk`'s `app_errors` module. An error is\n * described ({@link describeAppError}), stamped with the device facts of that\n * moment, fitted to the backend's column limits and queued in `localStorage`\n * before anything goes over the network — so a report raised with no signal is\n * sent when the browser comes back `online`, not lost.\n *\n * What each answer does to the queue:\n *\n * - **2xx** — removed.\n * - **429** — kept; sending pauses for `Retry-After`, then resumes on its own.\n * - **5xx, 408, network failure** — kept; the next report, `online` event or\n * `flush()` retries.\n * - **any other 4xx** — dropped: the backend will refuse that body forever, and\n * keeping it would block every report queued behind it.\n *\n * Each report is stamped with a one-way fingerprint of the token in force when\n * it was raised, and goes out with a bearer only when the token at send time is\n * that same one — never with the token of whoever signed in next. The queue\n * never stores a token. `clear()` also stops a flush in flight and discards\n * reports still waiting for an async token.\n *\n * @example\n * import { createAppErrorReporter } from \"tempest-react-sdk\";\n *\n * const reporter = createAppErrorReporter({\n * endpoint: `${import.meta.env.VITE_API_URL}/api/app-errors`,\n * getToken: () => sessionStorage.getItem(\"access_token\"),\n * device: () => ({ platform: \"web\", app_version: \"1.4.0\" }),\n * });\n *\n * reporter.report(new Error(\"crop failed\"), { step: \"crop\", size: 0 });\n *\n * @param options - Endpoint, token and device getters, storage and limits.\n * @returns The reporter.\n */\nexport function createAppErrorReporter(options: CreateAppErrorReporterOptions): AppErrorReporter {\n const { endpoint, getToken, getPrincipal, device, autoFlush = true } = options;\n warnOnDropWithoutPrincipal(options);\n const strict = getPrincipal !== undefined && options.foreignReports === \"drop\";\n const queue = createAppErrorQueue(\n options.storage === undefined ? defaultStorage() : options.storage,\n options.storageKey ?? \"tempest:app-errors\",\n options.maxEntries ?? 50,\n );\n let running: Promise<AppErrorFlushResult> | null = null;\n let pausedUntil = 0;\n let timer: ReturnType<typeof setTimeout> | null = null;\n const stamping = new Set<Promise<void>>();\n let generation = 0;\n\n const drain = async (): Promise<AppErrorFlushResult> => {\n const send = options.fetch ?? globalThis.fetch.bind(globalThis);\n await Promise.all(stamping);\n const token = await readToken(getToken);\n const session = ownerFingerprint(\"t\", token);\n const current = getPrincipal ? principalOwner(getPrincipal) : null;\n const started = generation;\n const result: AppErrorFlushResult = { sent: 0, dropped: 0, pending: 0, retryAfterMs: null };\n for (const entry of queue.entries()) {\n if (!queue.has(entry)) continue;\n if (strict && (entry.owner == null || entry.owner !== current)) {\n queue.remove(entry);\n result.dropped += 1;\n continue;\n }\n const bearer = entry.session != null && entry.session === session ? token : null;\n const outcome = await sendOne(send, endpoint, bearer, entry);\n if (generation !== started) break;\n if (outcome.kind === \"stop\") break;\n if (outcome.kind === \"wait\") {\n result.retryAfterMs = outcome.ms;\n pausedUntil = Date.now() + outcome.ms;\n timer ??= setTimeout(() => {\n timer = null;\n void flush();\n }, outcome.ms);\n break;\n }\n queue.remove(entry);\n result[outcome.kind === \"sent\" ? \"sent\" : \"dropped\"] += 1;\n }\n result.pending = queue.entries().length;\n return result;\n };\n\n const flush = (): Promise<AppErrorFlushResult> => {\n running ??= drain().finally(() => {\n running = null;\n });\n return running;\n };\n\n const shouldSend = (): boolean =>\n autoFlush &&\n Date.now() >= pausedUntil &&\n (typeof navigator === \"undefined\" || navigator.onLine !== false);\n\n const onOnline = (): void => {\n if (shouldSend()) void flush();\n };\n if (autoFlush && typeof window !== \"undefined\") window.addEventListener(\"online\", onOnline);\n\n return {\n report(error, context) {\n const description = describeAppError(error, context);\n const report = fitAppErrorReport({ ...readDevice(device), ...description });\n const stamp = stampNow(getPrincipal, readToken(getToken));\n if (!(stamp instanceof Promise)) {\n queue.push(report, stamp);\n if (shouldSend()) void flush();\n return;\n }\n const raisedIn = generation;\n const stamped = stamp.then((value) => {\n stamping.delete(stamped);\n if (generation !== raisedIn) return;\n queue.push(report, value);\n if (shouldSend()) void flush();\n });\n stamping.add(stamped);\n },\n flush,\n pending: () => queue.entries(),\n clear() {\n generation += 1;\n queue.clear();\n },\n dispose() {\n if (typeof window !== \"undefined\") window.removeEventListener(\"online\", onOnline);\n if (timer) clearTimeout(timer);\n timer = null;\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-error-schema.cjs","names":[],"sources":["../../src/telemetry/app-error-schema.ts"],"sourcesContent":["/**\n * The client platform an error was reported from.\n *\n * The closed set the backend filters on, mirrored from `tempest-fastapi-sdk`'s\n * `AppPlatform`: an error that only shows up on iOS is not the same bug as one\n * that only shows up on Android, and a PWA reports `\"web\"`.\n */\nexport type AppErrorPlatform = \"ios\" | \"android\" | \"web\" | \"unknown\";\n\n/**\n * Device data travelling with a report — the wire shape of\n * `tempest-fastapi-sdk`'s `AppErrorDeviceSchema`, snake_case included.\n *\n * Every field is optional on purpose: the app sends whatever it managed to\n * collect at the moment of the failure, and requiring any of them would turn an\n * incomplete collection into a lost report.\n */\nexport interface AppErrorDeviceSchema {\n /** Reporting client's platform. The backend stores `\"unknown\"` when absent. */\n platform?: AppErrorPlatform;\n /** Operating system version, e.g. `\"Android 14\"`. */\n os_version?: string;\n /** Application version or build — with `code`, the cut that isolates one defect. */\n app_version?: string;\n /** Device model, e.g. `\"SM-A105M\"`. */\n device_model?: string;\n /** Anonymous device identifier, used to group reports from one device. */\n device_id?: string;\n}\n\n/**\n * The body of `POST /api/app-errors` — `tempest-fastapi-sdk`'s\n * `AppErrorReportSchema`. There is deliberately no `user_id`: the backend takes\n * it from the bearer token, never from the body, so a client cannot attribute a\n * report to somebody else.\n */\nexport interface AppErrorReportSchema extends AppErrorDeviceSchema {\n /** Stable error identifier — the first thing anyone groups by. */\n code: string;\n /** Message, cause chain, context and stack, as one text. */\n message: string;\n}\n\n/**\n * Longest `code` the backend column holds.\n *\n * Ported from tempest-fastapi-sdk's `APP_ERROR_CODE_MAX_LENGTH`.\n */\nexport const APP_ERROR_CODE_MAX_LENGTH = 120;\n\n/**\n * Longest `message` the backend keeps.\n *\n * Ported from tempest-fastapi-sdk's `APP_ERROR_MESSAGE_MAX_LENGTH`. The server\n * truncates on its own; cutting here too is what keeps a queue of fifty stack\n * traces from filling `localStorage` while the device is offline.\n */\nexport const APP_ERROR_MESSAGE_MAX_LENGTH = 4000;\n\n/**\n * Longest device text field (`os_version`, `app_version`, …) the backend holds.\n *\n * Ported from tempest-fastapi-sdk's `APP_ERROR_TEXT_FIELD_MAX_LENGTH`.\n */\nexport const APP_ERROR_TEXT_FIELD_MAX_LENGTH = 200;\n\n/**\n * Marker appended where a value was cut.\n *\n * Ported from tempest-fastapi-sdk's `APP_ERROR_TRUNCATION_SUFFIX`, so a report\n * cut on the device reads exactly like one cut by the server.\n */\nexport const APP_ERROR_TRUNCATION_SUFFIX = \"…[truncado]\";\n\n/**\n * Shorten `value` to `limit` characters, marking the cut.\n *\n * Same rule as the backend's `AppErrorService.truncate`: shortened, never\n * refused, because the sender has just failed and has no way to handle a\n * rejection.\n *\n * @param value - The text to fit.\n * @param limit - Maximum length, suffix included.\n * @returns `value` unchanged when it fits, the cut version with the suffix otherwise.\n */\nexport function truncateAppErrorText(value: string, limit: number): string {\n if (value.length <= limit) return value;\n const keep = Math.max(limit - APP_ERROR_TRUNCATION_SUFFIX.length, 0);\n return `${value.slice(0, keep)}${APP_ERROR_TRUNCATION_SUFFIX}`.slice(0, limit);\n}\n\nconst DEVICE_TEXT_FIELDS = [\"os_version\", \"app_version\", \"device_model\", \"device_id\"] as const;\n\n/**\n * Fit every field of a report to the backend's column limits.\n *\n * @param report - The report as built.\n * @returns A copy with `code`, `message` and the device text fields truncated.\n */\nexport function fitAppErrorReport(report: AppErrorReportSchema): AppErrorReportSchema {\n const fitted: AppErrorReportSchema = {\n ...report,\n code: truncateAppErrorText(report.code, APP_ERROR_CODE_MAX_LENGTH),\n message: truncateAppErrorText(report.message, APP_ERROR_MESSAGE_MAX_LENGTH),\n };\n for (const field of DEVICE_TEXT_FIELDS) {\n const value = fitted[field];\n if (value !== undefined) {\n fitted[field] = truncateAppErrorText(value, APP_ERROR_TEXT_FIELD_MAX_LENGTH);\n }\n }\n return fitted;\n}\n"],"mappings":"AAyDA,
|
|
1
|
+
{"version":3,"file":"app-error-schema.cjs","names":["APP_ERROR_MESSAGE_MAX_LENGTH","APP_ERROR_TRUNCATION_SUFFIX","truncateAppErrorText","value","limit","keep","DEVICE_TEXT_FIELDS","fitAppErrorReport","fitted","report","field"],"sources":["../../src/telemetry/app-error-schema.ts"],"sourcesContent":["/**\n * The client platform an error was reported from.\n *\n * The closed set the backend filters on, mirrored from `tempest-fastapi-sdk`'s\n * `AppPlatform`: an error that only shows up on iOS is not the same bug as one\n * that only shows up on Android, and a PWA reports `\"web\"`.\n */\nexport type AppErrorPlatform = \"ios\" | \"android\" | \"web\" | \"unknown\";\n\n/**\n * Device data travelling with a report — the wire shape of\n * `tempest-fastapi-sdk`'s `AppErrorDeviceSchema`, snake_case included.\n *\n * Every field is optional on purpose: the app sends whatever it managed to\n * collect at the moment of the failure, and requiring any of them would turn an\n * incomplete collection into a lost report.\n */\nexport interface AppErrorDeviceSchema {\n /** Reporting client's platform. The backend stores `\"unknown\"` when absent. */\n platform?: AppErrorPlatform;\n /** Operating system version, e.g. `\"Android 14\"`. */\n os_version?: string;\n /** Application version or build — with `code`, the cut that isolates one defect. */\n app_version?: string;\n /** Device model, e.g. `\"SM-A105M\"`. */\n device_model?: string;\n /** Anonymous device identifier, used to group reports from one device. */\n device_id?: string;\n}\n\n/**\n * The body of `POST /api/app-errors` — `tempest-fastapi-sdk`'s\n * `AppErrorReportSchema`. There is deliberately no `user_id`: the backend takes\n * it from the bearer token, never from the body, so a client cannot attribute a\n * report to somebody else.\n */\nexport interface AppErrorReportSchema extends AppErrorDeviceSchema {\n /** Stable error identifier — the first thing anyone groups by. */\n code: string;\n /** Message, cause chain, context and stack, as one text. */\n message: string;\n}\n\n/**\n * Longest `code` the backend column holds.\n *\n * Ported from tempest-fastapi-sdk's `APP_ERROR_CODE_MAX_LENGTH`.\n */\nexport const APP_ERROR_CODE_MAX_LENGTH = 120;\n\n/**\n * Longest `message` the backend keeps.\n *\n * Ported from tempest-fastapi-sdk's `APP_ERROR_MESSAGE_MAX_LENGTH`. The server\n * truncates on its own; cutting here too is what keeps a queue of fifty stack\n * traces from filling `localStorage` while the device is offline.\n */\nexport const APP_ERROR_MESSAGE_MAX_LENGTH = 4000;\n\n/**\n * Longest device text field (`os_version`, `app_version`, …) the backend holds.\n *\n * Ported from tempest-fastapi-sdk's `APP_ERROR_TEXT_FIELD_MAX_LENGTH`.\n */\nexport const APP_ERROR_TEXT_FIELD_MAX_LENGTH = 200;\n\n/**\n * Marker appended where a value was cut.\n *\n * Ported from tempest-fastapi-sdk's `APP_ERROR_TRUNCATION_SUFFIX`, so a report\n * cut on the device reads exactly like one cut by the server.\n */\nexport const APP_ERROR_TRUNCATION_SUFFIX = \"…[truncado]\";\n\n/**\n * Shorten `value` to `limit` characters, marking the cut.\n *\n * Same rule as the backend's `AppErrorService.truncate`: shortened, never\n * refused, because the sender has just failed and has no way to handle a\n * rejection.\n *\n * @param value - The text to fit.\n * @param limit - Maximum length, suffix included.\n * @returns `value` unchanged when it fits, the cut version with the suffix otherwise.\n */\nexport function truncateAppErrorText(value: string, limit: number): string {\n if (value.length <= limit) return value;\n const keep = Math.max(limit - APP_ERROR_TRUNCATION_SUFFIX.length, 0);\n return `${value.slice(0, keep)}${APP_ERROR_TRUNCATION_SUFFIX}`.slice(0, limit);\n}\n\nconst DEVICE_TEXT_FIELDS = [\"os_version\", \"app_version\", \"device_model\", \"device_id\"] as const;\n\n/**\n * Fit every field of a report to the backend's column limits.\n *\n * @param report - The report as built.\n * @returns A copy with `code`, `message` and the device text fields truncated.\n */\nexport function fitAppErrorReport(report: AppErrorReportSchema): AppErrorReportSchema {\n const fitted: AppErrorReportSchema = {\n ...report,\n code: truncateAppErrorText(report.code, APP_ERROR_CODE_MAX_LENGTH),\n message: truncateAppErrorText(report.message, APP_ERROR_MESSAGE_MAX_LENGTH),\n };\n for (const field of DEVICE_TEXT_FIELDS) {\n const value = fitted[field];\n if (value !== undefined) {\n fitted[field] = truncateAppErrorText(value, APP_ERROR_TEXT_FIELD_MAX_LENGTH);\n }\n }\n return fitted;\n}\n"],"mappings":"AAyDA,IAAaA,EAA+B,IAe/BC,EAA8B,cAa3C,SAAgBC,EAAqB,EAAe,EAAuB,CACvE,GAAIC,EAAM,QAAUC,EAAO,OAAOD,EAClC,IAAME,EAAO,KAAK,IAAID,EAAQ,GAAoC,CAAC,EACnE,MAAO,GAAGD,EAAM,MAAM,EAAGE,CAAI,IAAIJ,IAA8B,MAAM,EAAGG,CAAK,CACjF,CAEA,IAAME,EAAqB,CAAC,aAAc,cAAe,eAAgB,WAAW,EAQpF,SAAgBC,EAAkB,EAAoD,CAClF,IAAMC,EAA+B,CACjC,GAAGC,EACH,KAAMP,EAAqBO,EAAO,KAAA,GAA+B,EACjE,QAASP,EAAqBO,EAAO,QAAST,CAA4B,CAC9E,EACA,IAAK,IAAMU,KAASJ,EAAoB,CACpC,IAAMH,EAAQK,EAAOE,GACjBP,IAAU,IAAA,KACV,EAAOO,GAASR,EAAqBC,EAAA,GAAsC,EAEnF,CACA,OAAOK,CACX,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-error-schema.js","names":[],"sources":["../../src/telemetry/app-error-schema.ts"],"sourcesContent":["/**\n * The client platform an error was reported from.\n *\n * The closed set the backend filters on, mirrored from `tempest-fastapi-sdk`'s\n * `AppPlatform`: an error that only shows up on iOS is not the same bug as one\n * that only shows up on Android, and a PWA reports `\"web\"`.\n */\nexport type AppErrorPlatform = \"ios\" | \"android\" | \"web\" | \"unknown\";\n\n/**\n * Device data travelling with a report — the wire shape of\n * `tempest-fastapi-sdk`'s `AppErrorDeviceSchema`, snake_case included.\n *\n * Every field is optional on purpose: the app sends whatever it managed to\n * collect at the moment of the failure, and requiring any of them would turn an\n * incomplete collection into a lost report.\n */\nexport interface AppErrorDeviceSchema {\n /** Reporting client's platform. The backend stores `\"unknown\"` when absent. */\n platform?: AppErrorPlatform;\n /** Operating system version, e.g. `\"Android 14\"`. */\n os_version?: string;\n /** Application version or build — with `code`, the cut that isolates one defect. */\n app_version?: string;\n /** Device model, e.g. `\"SM-A105M\"`. */\n device_model?: string;\n /** Anonymous device identifier, used to group reports from one device. */\n device_id?: string;\n}\n\n/**\n * The body of `POST /api/app-errors` — `tempest-fastapi-sdk`'s\n * `AppErrorReportSchema`. There is deliberately no `user_id`: the backend takes\n * it from the bearer token, never from the body, so a client cannot attribute a\n * report to somebody else.\n */\nexport interface AppErrorReportSchema extends AppErrorDeviceSchema {\n /** Stable error identifier — the first thing anyone groups by. */\n code: string;\n /** Message, cause chain, context and stack, as one text. */\n message: string;\n}\n\n/**\n * Longest `code` the backend column holds.\n *\n * Ported from tempest-fastapi-sdk's `APP_ERROR_CODE_MAX_LENGTH`.\n */\nexport const APP_ERROR_CODE_MAX_LENGTH = 120;\n\n/**\n * Longest `message` the backend keeps.\n *\n * Ported from tempest-fastapi-sdk's `APP_ERROR_MESSAGE_MAX_LENGTH`. The server\n * truncates on its own; cutting here too is what keeps a queue of fifty stack\n * traces from filling `localStorage` while the device is offline.\n */\nexport const APP_ERROR_MESSAGE_MAX_LENGTH = 4000;\n\n/**\n * Longest device text field (`os_version`, `app_version`, …) the backend holds.\n *\n * Ported from tempest-fastapi-sdk's `APP_ERROR_TEXT_FIELD_MAX_LENGTH`.\n */\nexport const APP_ERROR_TEXT_FIELD_MAX_LENGTH = 200;\n\n/**\n * Marker appended where a value was cut.\n *\n * Ported from tempest-fastapi-sdk's `APP_ERROR_TRUNCATION_SUFFIX`, so a report\n * cut on the device reads exactly like one cut by the server.\n */\nexport const APP_ERROR_TRUNCATION_SUFFIX = \"…[truncado]\";\n\n/**\n * Shorten `value` to `limit` characters, marking the cut.\n *\n * Same rule as the backend's `AppErrorService.truncate`: shortened, never\n * refused, because the sender has just failed and has no way to handle a\n * rejection.\n *\n * @param value - The text to fit.\n * @param limit - Maximum length, suffix included.\n * @returns `value` unchanged when it fits, the cut version with the suffix otherwise.\n */\nexport function truncateAppErrorText(value: string, limit: number): string {\n if (value.length <= limit) return value;\n const keep = Math.max(limit - APP_ERROR_TRUNCATION_SUFFIX.length, 0);\n return `${value.slice(0, keep)}${APP_ERROR_TRUNCATION_SUFFIX}`.slice(0, limit);\n}\n\nconst DEVICE_TEXT_FIELDS = [\"os_version\", \"app_version\", \"device_model\", \"device_id\"] as const;\n\n/**\n * Fit every field of a report to the backend's column limits.\n *\n * @param report - The report as built.\n * @returns A copy with `code`, `message` and the device text fields truncated.\n */\nexport function fitAppErrorReport(report: AppErrorReportSchema): AppErrorReportSchema {\n const fitted: AppErrorReportSchema = {\n ...report,\n code: truncateAppErrorText(report.code, APP_ERROR_CODE_MAX_LENGTH),\n message: truncateAppErrorText(report.message, APP_ERROR_MESSAGE_MAX_LENGTH),\n };\n for (const field of DEVICE_TEXT_FIELDS) {\n const value = fitted[field];\n if (value !== undefined) {\n fitted[field] = truncateAppErrorText(value, APP_ERROR_TEXT_FIELD_MAX_LENGTH);\n }\n }\n return fitted;\n}\n"],"mappings":"AAyDA,
|
|
1
|
+
{"version":3,"file":"app-error-schema.js","names":["APP_ERROR_MESSAGE_MAX_LENGTH","APP_ERROR_TRUNCATION_SUFFIX","truncateAppErrorText","value","limit","keep","DEVICE_TEXT_FIELDS","fitAppErrorReport","fitted","report","field"],"sources":["../../src/telemetry/app-error-schema.ts"],"sourcesContent":["/**\n * The client platform an error was reported from.\n *\n * The closed set the backend filters on, mirrored from `tempest-fastapi-sdk`'s\n * `AppPlatform`: an error that only shows up on iOS is not the same bug as one\n * that only shows up on Android, and a PWA reports `\"web\"`.\n */\nexport type AppErrorPlatform = \"ios\" | \"android\" | \"web\" | \"unknown\";\n\n/**\n * Device data travelling with a report — the wire shape of\n * `tempest-fastapi-sdk`'s `AppErrorDeviceSchema`, snake_case included.\n *\n * Every field is optional on purpose: the app sends whatever it managed to\n * collect at the moment of the failure, and requiring any of them would turn an\n * incomplete collection into a lost report.\n */\nexport interface AppErrorDeviceSchema {\n /** Reporting client's platform. The backend stores `\"unknown\"` when absent. */\n platform?: AppErrorPlatform;\n /** Operating system version, e.g. `\"Android 14\"`. */\n os_version?: string;\n /** Application version or build — with `code`, the cut that isolates one defect. */\n app_version?: string;\n /** Device model, e.g. `\"SM-A105M\"`. */\n device_model?: string;\n /** Anonymous device identifier, used to group reports from one device. */\n device_id?: string;\n}\n\n/**\n * The body of `POST /api/app-errors` — `tempest-fastapi-sdk`'s\n * `AppErrorReportSchema`. There is deliberately no `user_id`: the backend takes\n * it from the bearer token, never from the body, so a client cannot attribute a\n * report to somebody else.\n */\nexport interface AppErrorReportSchema extends AppErrorDeviceSchema {\n /** Stable error identifier — the first thing anyone groups by. */\n code: string;\n /** Message, cause chain, context and stack, as one text. */\n message: string;\n}\n\n/**\n * Longest `code` the backend column holds.\n *\n * Ported from tempest-fastapi-sdk's `APP_ERROR_CODE_MAX_LENGTH`.\n */\nexport const APP_ERROR_CODE_MAX_LENGTH = 120;\n\n/**\n * Longest `message` the backend keeps.\n *\n * Ported from tempest-fastapi-sdk's `APP_ERROR_MESSAGE_MAX_LENGTH`. The server\n * truncates on its own; cutting here too is what keeps a queue of fifty stack\n * traces from filling `localStorage` while the device is offline.\n */\nexport const APP_ERROR_MESSAGE_MAX_LENGTH = 4000;\n\n/**\n * Longest device text field (`os_version`, `app_version`, …) the backend holds.\n *\n * Ported from tempest-fastapi-sdk's `APP_ERROR_TEXT_FIELD_MAX_LENGTH`.\n */\nexport const APP_ERROR_TEXT_FIELD_MAX_LENGTH = 200;\n\n/**\n * Marker appended where a value was cut.\n *\n * Ported from tempest-fastapi-sdk's `APP_ERROR_TRUNCATION_SUFFIX`, so a report\n * cut on the device reads exactly like one cut by the server.\n */\nexport const APP_ERROR_TRUNCATION_SUFFIX = \"…[truncado]\";\n\n/**\n * Shorten `value` to `limit` characters, marking the cut.\n *\n * Same rule as the backend's `AppErrorService.truncate`: shortened, never\n * refused, because the sender has just failed and has no way to handle a\n * rejection.\n *\n * @param value - The text to fit.\n * @param limit - Maximum length, suffix included.\n * @returns `value` unchanged when it fits, the cut version with the suffix otherwise.\n */\nexport function truncateAppErrorText(value: string, limit: number): string {\n if (value.length <= limit) return value;\n const keep = Math.max(limit - APP_ERROR_TRUNCATION_SUFFIX.length, 0);\n return `${value.slice(0, keep)}${APP_ERROR_TRUNCATION_SUFFIX}`.slice(0, limit);\n}\n\nconst DEVICE_TEXT_FIELDS = [\"os_version\", \"app_version\", \"device_model\", \"device_id\"] as const;\n\n/**\n * Fit every field of a report to the backend's column limits.\n *\n * @param report - The report as built.\n * @returns A copy with `code`, `message` and the device text fields truncated.\n */\nexport function fitAppErrorReport(report: AppErrorReportSchema): AppErrorReportSchema {\n const fitted: AppErrorReportSchema = {\n ...report,\n code: truncateAppErrorText(report.code, APP_ERROR_CODE_MAX_LENGTH),\n message: truncateAppErrorText(report.message, APP_ERROR_MESSAGE_MAX_LENGTH),\n };\n for (const field of DEVICE_TEXT_FIELDS) {\n const value = fitted[field];\n if (value !== undefined) {\n fitted[field] = truncateAppErrorText(value, APP_ERROR_TEXT_FIELD_MAX_LENGTH);\n }\n }\n return fitted;\n}\n"],"mappings":"AAyDA,IAAaA,IAA+B,KAe/BC,IAA8B;AAa3C,SAAgBC,EAAqB,GAAe,GAAuB;CACvE,IAAIC,EAAM,UAAUC,GAAO,OAAOD;CAClC,IAAME,IAAO,KAAK,IAAID,IAAQ,IAAoC,CAAC;CACnE,OAAO,GAAGD,EAAM,MAAM,GAAGE,CAAI,IAAIJ,IAA8B,MAAM,GAAGG,CAAK;AACjF;AAEA,IAAME,IAAqB;CAAC;CAAc;CAAe;CAAgB;AAAW;AAQpF,SAAgBC,EAAkB,GAAoD;CAClF,IAAMC,IAA+B;EACjC,GAAGC;EACH,MAAMP,EAAqBO,EAAO,MAAA,GAA+B;EACjE,SAASP,EAAqBO,EAAO,SAAST,CAA4B;CAC9E;CACA,KAAK,IAAMU,KAASJ,GAAoB;EACpC,IAAMH,IAAQK,EAAOE;EACrB,AAAIP,MAAU,KAAA,MACV,EAAOO,KAASR,EAAqBC,GAAA,GAAsC;CAEnF;CACA,OAAOK;AACX"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-error-transport.cjs","names":[],"sources":["../../src/telemetry/app-error-transport.ts"],"sourcesContent":["import type { AppErrorQueueEntry } from \"./app-error-queue\";\nimport { fitAppErrorReport } from \"./app-error-schema\";\nimport type { AppErrorReportSchema } from \"./app-error-schema\";\n\n/** What the backend's answer to one send means for the queue. */\nexport type SendOutcome = { kind: \"sent\" | \"drop\" | \"stop\" } | { kind: \"wait\"; ms: number };\n\n/**\n * Read a `Retry-After` header as milliseconds.\n *\n * @param header - The header value: delay-seconds or an HTTP date.\n * @returns The delay, at least one second.\n */\nexport function retryAfterMs(header: string | null): number {\n const seconds = Number(header);\n if (header !== null && Number.isFinite(seconds)) return Math.max(seconds, 1) * 1000;\n const date = header ? Date.parse(header) : Number.NaN;\n return Number.isNaN(date) ? 60_000 : Math.max(date - Date.now(), 1000);\n}\n\n/**\n * Build the body for one queued entry, marking how often it repeated.\n *\n * @param entry - The queued entry.\n * @returns The report to send.\n */\nexport function bodyFor(entry: AppErrorQueueEntry): AppErrorReportSchema {\n if (entry.count <= 1) return entry.report;\n const message = `[repeated ${entry.count}×]\\n${entry.report.message}`;\n return fitAppErrorReport({ ...entry.report, message });\n}\n\n/**\n * Send one entry and classify what the backend answered.\n *\n * @param send - The `fetch` to use.\n * @param endpoint - Route URL.\n * @param token - Bearer token, or `null`.\n * @param entry - What to send.\n * @returns `sent` (2xx), `wait` (429), `drop` (other 4xx) or `stop` (5xx, 408, network).\n * Anything unexpected — a rejected `fetch`, a wrapper that resolves without a\n * `Response` — is `stop`: the report stays queued, and the flush that\n * `report()` fires in the background never becomes an unhandled rejection.\n */\nexport async function sendOne(\n send: typeof fetch,\n endpoint: string,\n token: string | null,\n entry: AppErrorQueueEntry,\n): Promise<SendOutcome> {\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (token) headers.Authorization = `Bearer ${token}`;\n try {\n const response = await send(endpoint, {\n method: \"POST\",\n headers,\n body: JSON.stringify(bodyFor(entry)),\n });\n if (response.ok) return { kind: \"sent\" };\n if (response.status === 429) {\n return { kind: \"wait\", ms: retryAfterMs(response.headers.get(\"Retry-After\")) };\n }\n if (response.status === 408 || response.status >= 500) return { kind: \"stop\" };\n return { kind: \"drop\" };\n } catch {\n return { kind: \"stop\" };\n }\n}\n\n/**\n * How long a report or a flush waits for an async `getToken` before giving up\n * and going without a token.\n *\n * A getter that never settles — a refresh stuck on a dead network, a promise\n * nobody resolves — must not hold the report out of the queue, nor the flush\n * (and every later one, which shares its run) forever. Five seconds covers a\n * slow refresh round trip on a weak connection; past it the report is stamped\n * with no session and leaves anonymously, which never misattributes.\n */\nexport const APP_ERROR_TOKEN_TIMEOUT_MS = 5_000;\n\n/** The token getter's shape, as {@link readToken} accepts it. */\nexport type AppErrorTokenGetter = () =>\n string | null | undefined | Promise<string | null | undefined>;\n\n/**\n * Keep only a usable token: a non-empty string.\n *\n * @param value - Whatever the getter produced, possibly from untyped JS.\n * @returns The token, or `null`.\n */\nfunction asToken(value: unknown): string | null {\n return typeof value === \"string\" && value !== \"\" ? value : null;\n}\n\n/**\n * Read the token, synchronously when the getter is synchronous.\n *\n * Staying synchronous for a synchronous getter is what lets `report()` queue\n * the report before it returns; an async getter is bounded by\n * {@link APP_ERROR_TOKEN_TIMEOUT_MS}. A getter that throws, rejects, times out\n * or produces anything but a non-empty string reads as no token.\n *\n * @param getToken - The caller's token getter.\n * @returns The token or `null`, directly or as a promise that always settles.\n */\nexport function readToken(\n getToken: AppErrorTokenGetter | undefined,\n): string | null | Promise<string | null> {\n let value: unknown;\n try {\n value = getToken?.();\n } catch {\n return null;\n }\n if (typeof value !== \"object\" || value === null) return asToken(value);\n return new Promise<string | null>((resolve) => {\n const timer = setTimeout(() => resolve(null), APP_ERROR_TOKEN_TIMEOUT_MS);\n Promise.resolve(value).then(\n (token) => {\n clearTimeout(timer);\n resolve(asToken(token));\n },\n () => {\n clearTimeout(timer);\n resolve(null);\n },\n );\n });\n}\n"],"mappings":"0CAaA,
|
|
1
|
+
{"version":3,"file":"app-error-transport.cjs","names":["fitAppErrorReport","require_app_error_schema","retryAfterMs","seconds","header","date","bodyFor","entry","message","sendOne","headers","token","response","send","endpoint","APP_ERROR_TOKEN_TIMEOUT_MS","asToken","value","readToken","getToken","timer","resolve"],"sources":["../../src/telemetry/app-error-transport.ts"],"sourcesContent":["import type { AppErrorQueueEntry } from \"./app-error-queue\";\nimport { fitAppErrorReport } from \"./app-error-schema\";\nimport type { AppErrorReportSchema } from \"./app-error-schema\";\n\n/** What the backend's answer to one send means for the queue. */\nexport type SendOutcome = { kind: \"sent\" | \"drop\" | \"stop\" } | { kind: \"wait\"; ms: number };\n\n/**\n * Read a `Retry-After` header as milliseconds.\n *\n * @param header - The header value: delay-seconds or an HTTP date.\n * @returns The delay, at least one second.\n */\nexport function retryAfterMs(header: string | null): number {\n const seconds = Number(header);\n if (header !== null && Number.isFinite(seconds)) return Math.max(seconds, 1) * 1000;\n const date = header ? Date.parse(header) : Number.NaN;\n return Number.isNaN(date) ? 60_000 : Math.max(date - Date.now(), 1000);\n}\n\n/**\n * Build the body for one queued entry, marking how often it repeated.\n *\n * @param entry - The queued entry.\n * @returns The report to send.\n */\nexport function bodyFor(entry: AppErrorQueueEntry): AppErrorReportSchema {\n if (entry.count <= 1) return entry.report;\n const message = `[repeated ${entry.count}×]\\n${entry.report.message}`;\n return fitAppErrorReport({ ...entry.report, message });\n}\n\n/**\n * Send one entry and classify what the backend answered.\n *\n * @param send - The `fetch` to use.\n * @param endpoint - Route URL.\n * @param token - Bearer token, or `null`.\n * @param entry - What to send.\n * @returns `sent` (2xx), `wait` (429), `drop` (other 4xx) or `stop` (5xx, 408, network).\n * Anything unexpected — a rejected `fetch`, a wrapper that resolves without a\n * `Response` — is `stop`: the report stays queued, and the flush that\n * `report()` fires in the background never becomes an unhandled rejection.\n */\nexport async function sendOne(\n send: typeof fetch,\n endpoint: string,\n token: string | null,\n entry: AppErrorQueueEntry,\n): Promise<SendOutcome> {\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (token) headers.Authorization = `Bearer ${token}`;\n try {\n const response = await send(endpoint, {\n method: \"POST\",\n headers,\n body: JSON.stringify(bodyFor(entry)),\n });\n if (response.ok) return { kind: \"sent\" };\n if (response.status === 429) {\n return { kind: \"wait\", ms: retryAfterMs(response.headers.get(\"Retry-After\")) };\n }\n if (response.status === 408 || response.status >= 500) return { kind: \"stop\" };\n return { kind: \"drop\" };\n } catch {\n return { kind: \"stop\" };\n }\n}\n\n/**\n * How long a report or a flush waits for an async `getToken` before giving up\n * and going without a token.\n *\n * A getter that never settles — a refresh stuck on a dead network, a promise\n * nobody resolves — must not hold the report out of the queue, nor the flush\n * (and every later one, which shares its run) forever. Five seconds covers a\n * slow refresh round trip on a weak connection; past it the report is stamped\n * with no session and leaves anonymously, which never misattributes.\n */\nexport const APP_ERROR_TOKEN_TIMEOUT_MS = 5_000;\n\n/** The token getter's shape, as {@link readToken} accepts it. */\nexport type AppErrorTokenGetter = () =>\n string | null | undefined | Promise<string | null | undefined>;\n\n/**\n * Keep only a usable token: a non-empty string.\n *\n * @param value - Whatever the getter produced, possibly from untyped JS.\n * @returns The token, or `null`.\n */\nfunction asToken(value: unknown): string | null {\n return typeof value === \"string\" && value !== \"\" ? value : null;\n}\n\n/**\n * Read the token, synchronously when the getter is synchronous.\n *\n * Staying synchronous for a synchronous getter is what lets `report()` queue\n * the report before it returns; an async getter is bounded by\n * {@link APP_ERROR_TOKEN_TIMEOUT_MS}. A getter that throws, rejects, times out\n * or produces anything but a non-empty string reads as no token.\n *\n * @param getToken - The caller's token getter.\n * @returns The token or `null`, directly or as a promise that always settles.\n */\nexport function readToken(\n getToken: AppErrorTokenGetter | undefined,\n): string | null | Promise<string | null> {\n let value: unknown;\n try {\n value = getToken?.();\n } catch {\n return null;\n }\n if (typeof value !== \"object\" || value === null) return asToken(value);\n return new Promise<string | null>((resolve) => {\n const timer = setTimeout(() => resolve(null), APP_ERROR_TOKEN_TIMEOUT_MS);\n Promise.resolve(value).then(\n (token) => {\n clearTimeout(timer);\n resolve(asToken(token));\n },\n () => {\n clearTimeout(timer);\n resolve(null);\n },\n );\n });\n}\n"],"mappings":"A,0CAaA,SAAgBE,EAAa,EAA+B,CACxD,IAAMC,EAAU,OAAOC,CAAM,EAC7B,GAAIA,IAAW,MAAQ,OAAO,SAASD,CAAO,EAAG,OAAO,KAAK,IAAIA,EAAS,CAAC,EAAI,IAC/E,IAAME,EAAOD,EAAS,KAAK,MAAMA,CAAM,EAAI,IAC3C,OAAO,OAAO,MAAMC,CAAI,EAAI,IAAS,KAAK,IAAIA,EAAO,KAAK,IAAI,EAAG,GAAI,CACzE,CAQA,SAAgBC,EAAQ,EAAiD,CACrE,GAAIC,EAAM,OAAS,EAAG,OAAOA,EAAM,OACnC,IAAMC,EAAU,aAAaD,EAAM,MAAM,MAAMA,EAAM,OAAO,UAC5D,OAAOP,EAAAA,kBAAkB,CAAE,GAAGO,EAAM,OAAQ,SAAQ,CAAC,CACzD,CAcA,eAAsBE,EAClB,EACA,EACA,EACA,EACoB,CACpB,IAAMC,EAAkC,CAAE,eAAgB,kBAAmB,EACzEC,IAAO,EAAQ,cAAgB,UAAUA,KAC7C,GAAI,CACA,IAAMC,EAAW,MAAMC,EAAKC,EAAU,CAClC,OAAQ,OACR,UACA,KAAM,KAAK,UAAUR,EAAQC,CAAK,CAAC,CACvC,CAAC,EAMD,OALIK,EAAS,GAAW,CAAE,KAAM,MAAO,EACnCA,EAAS,SAAW,IACb,CAAE,KAAM,OAAQ,GAAIV,EAAaU,EAAS,QAAQ,IAAI,aAAa,CAAC,CAAE,EAE7EA,EAAS,SAAW,KAAOA,EAAS,QAAU,IAAY,CAAE,KAAM,MAAO,EACtE,CAAE,KAAM,MAAO,CAC1B,MAAQ,CACJ,MAAO,CAAE,KAAM,MAAO,CAC1B,CACJ,CAYA,IAAaG,EAA6B,IAY1C,SAASC,EAAQ,EAA+B,CAC5C,OAAO,OAAOC,GAAU,UAAYA,IAAU,GAAKA,EAAQ,IAC/D,CAaA,SAAgBC,EACZ,EACsC,CACtC,IAAID,EACJ,GAAI,CACA,EAAQE,IAAW,CACvB,MAAQ,CACJ,OAAO,IACX,CAEA,OADI,OAAOF,GAAU,WAAYA,EAAuBD,EAAQC,CAAK,EAC9D,IAAI,QAAwB,GAAY,CAC3C,IAAMG,EAAQ,eAAiBC,EAAQ,IAAI,EAAGN,CAA0B,EACxE,QAAQ,QAAQE,CAAK,CAAC,CAAC,KAClB,GAAU,CACP,aAAaG,CAAK,EAClBC,EAAQL,EAAQL,CAAK,CAAC,CAC1B,MACM,CACF,aAAaS,CAAK,EAClBC,EAAQ,IAAI,CAChB,CACJ,CACJ,CAAC,CACL,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-error-transport.js","names":[],"sources":["../../src/telemetry/app-error-transport.ts"],"sourcesContent":["import type { AppErrorQueueEntry } from \"./app-error-queue\";\nimport { fitAppErrorReport } from \"./app-error-schema\";\nimport type { AppErrorReportSchema } from \"./app-error-schema\";\n\n/** What the backend's answer to one send means for the queue. */\nexport type SendOutcome = { kind: \"sent\" | \"drop\" | \"stop\" } | { kind: \"wait\"; ms: number };\n\n/**\n * Read a `Retry-After` header as milliseconds.\n *\n * @param header - The header value: delay-seconds or an HTTP date.\n * @returns The delay, at least one second.\n */\nexport function retryAfterMs(header: string | null): number {\n const seconds = Number(header);\n if (header !== null && Number.isFinite(seconds)) return Math.max(seconds, 1) * 1000;\n const date = header ? Date.parse(header) : Number.NaN;\n return Number.isNaN(date) ? 60_000 : Math.max(date - Date.now(), 1000);\n}\n\n/**\n * Build the body for one queued entry, marking how often it repeated.\n *\n * @param entry - The queued entry.\n * @returns The report to send.\n */\nexport function bodyFor(entry: AppErrorQueueEntry): AppErrorReportSchema {\n if (entry.count <= 1) return entry.report;\n const message = `[repeated ${entry.count}×]\\n${entry.report.message}`;\n return fitAppErrorReport({ ...entry.report, message });\n}\n\n/**\n * Send one entry and classify what the backend answered.\n *\n * @param send - The `fetch` to use.\n * @param endpoint - Route URL.\n * @param token - Bearer token, or `null`.\n * @param entry - What to send.\n * @returns `sent` (2xx), `wait` (429), `drop` (other 4xx) or `stop` (5xx, 408, network).\n * Anything unexpected — a rejected `fetch`, a wrapper that resolves without a\n * `Response` — is `stop`: the report stays queued, and the flush that\n * `report()` fires in the background never becomes an unhandled rejection.\n */\nexport async function sendOne(\n send: typeof fetch,\n endpoint: string,\n token: string | null,\n entry: AppErrorQueueEntry,\n): Promise<SendOutcome> {\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (token) headers.Authorization = `Bearer ${token}`;\n try {\n const response = await send(endpoint, {\n method: \"POST\",\n headers,\n body: JSON.stringify(bodyFor(entry)),\n });\n if (response.ok) return { kind: \"sent\" };\n if (response.status === 429) {\n return { kind: \"wait\", ms: retryAfterMs(response.headers.get(\"Retry-After\")) };\n }\n if (response.status === 408 || response.status >= 500) return { kind: \"stop\" };\n return { kind: \"drop\" };\n } catch {\n return { kind: \"stop\" };\n }\n}\n\n/**\n * How long a report or a flush waits for an async `getToken` before giving up\n * and going without a token.\n *\n * A getter that never settles — a refresh stuck on a dead network, a promise\n * nobody resolves — must not hold the report out of the queue, nor the flush\n * (and every later one, which shares its run) forever. Five seconds covers a\n * slow refresh round trip on a weak connection; past it the report is stamped\n * with no session and leaves anonymously, which never misattributes.\n */\nexport const APP_ERROR_TOKEN_TIMEOUT_MS = 5_000;\n\n/** The token getter's shape, as {@link readToken} accepts it. */\nexport type AppErrorTokenGetter = () =>\n string | null | undefined | Promise<string | null | undefined>;\n\n/**\n * Keep only a usable token: a non-empty string.\n *\n * @param value - Whatever the getter produced, possibly from untyped JS.\n * @returns The token, or `null`.\n */\nfunction asToken(value: unknown): string | null {\n return typeof value === \"string\" && value !== \"\" ? value : null;\n}\n\n/**\n * Read the token, synchronously when the getter is synchronous.\n *\n * Staying synchronous for a synchronous getter is what lets `report()` queue\n * the report before it returns; an async getter is bounded by\n * {@link APP_ERROR_TOKEN_TIMEOUT_MS}. A getter that throws, rejects, times out\n * or produces anything but a non-empty string reads as no token.\n *\n * @param getToken - The caller's token getter.\n * @returns The token or `null`, directly or as a promise that always settles.\n */\nexport function readToken(\n getToken: AppErrorTokenGetter | undefined,\n): string | null | Promise<string | null> {\n let value: unknown;\n try {\n value = getToken?.();\n } catch {\n return null;\n }\n if (typeof value !== \"object\" || value === null) return asToken(value);\n return new Promise<string | null>((resolve) => {\n const timer = setTimeout(() => resolve(null), APP_ERROR_TOKEN_TIMEOUT_MS);\n Promise.resolve(value).then(\n (token) => {\n clearTimeout(timer);\n resolve(asToken(token));\n },\n () => {\n clearTimeout(timer);\n resolve(null);\n },\n );\n });\n}\n"],"mappings":";;AAaA,
|
|
1
|
+
{"version":3,"file":"app-error-transport.js","names":["retryAfterMs","seconds","header","date","bodyFor","entry","message","fitAppErrorReport","sendOne","headers","token","response","send","endpoint","APP_ERROR_TOKEN_TIMEOUT_MS","asToken","value","readToken","getToken","timer","resolve"],"sources":["../../src/telemetry/app-error-transport.ts"],"sourcesContent":["import type { AppErrorQueueEntry } from \"./app-error-queue\";\nimport { fitAppErrorReport } from \"./app-error-schema\";\nimport type { AppErrorReportSchema } from \"./app-error-schema\";\n\n/** What the backend's answer to one send means for the queue. */\nexport type SendOutcome = { kind: \"sent\" | \"drop\" | \"stop\" } | { kind: \"wait\"; ms: number };\n\n/**\n * Read a `Retry-After` header as milliseconds.\n *\n * @param header - The header value: delay-seconds or an HTTP date.\n * @returns The delay, at least one second.\n */\nexport function retryAfterMs(header: string | null): number {\n const seconds = Number(header);\n if (header !== null && Number.isFinite(seconds)) return Math.max(seconds, 1) * 1000;\n const date = header ? Date.parse(header) : Number.NaN;\n return Number.isNaN(date) ? 60_000 : Math.max(date - Date.now(), 1000);\n}\n\n/**\n * Build the body for one queued entry, marking how often it repeated.\n *\n * @param entry - The queued entry.\n * @returns The report to send.\n */\nexport function bodyFor(entry: AppErrorQueueEntry): AppErrorReportSchema {\n if (entry.count <= 1) return entry.report;\n const message = `[repeated ${entry.count}×]\\n${entry.report.message}`;\n return fitAppErrorReport({ ...entry.report, message });\n}\n\n/**\n * Send one entry and classify what the backend answered.\n *\n * @param send - The `fetch` to use.\n * @param endpoint - Route URL.\n * @param token - Bearer token, or `null`.\n * @param entry - What to send.\n * @returns `sent` (2xx), `wait` (429), `drop` (other 4xx) or `stop` (5xx, 408, network).\n * Anything unexpected — a rejected `fetch`, a wrapper that resolves without a\n * `Response` — is `stop`: the report stays queued, and the flush that\n * `report()` fires in the background never becomes an unhandled rejection.\n */\nexport async function sendOne(\n send: typeof fetch,\n endpoint: string,\n token: string | null,\n entry: AppErrorQueueEntry,\n): Promise<SendOutcome> {\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (token) headers.Authorization = `Bearer ${token}`;\n try {\n const response = await send(endpoint, {\n method: \"POST\",\n headers,\n body: JSON.stringify(bodyFor(entry)),\n });\n if (response.ok) return { kind: \"sent\" };\n if (response.status === 429) {\n return { kind: \"wait\", ms: retryAfterMs(response.headers.get(\"Retry-After\")) };\n }\n if (response.status === 408 || response.status >= 500) return { kind: \"stop\" };\n return { kind: \"drop\" };\n } catch {\n return { kind: \"stop\" };\n }\n}\n\n/**\n * How long a report or a flush waits for an async `getToken` before giving up\n * and going without a token.\n *\n * A getter that never settles — a refresh stuck on a dead network, a promise\n * nobody resolves — must not hold the report out of the queue, nor the flush\n * (and every later one, which shares its run) forever. Five seconds covers a\n * slow refresh round trip on a weak connection; past it the report is stamped\n * with no session and leaves anonymously, which never misattributes.\n */\nexport const APP_ERROR_TOKEN_TIMEOUT_MS = 5_000;\n\n/** The token getter's shape, as {@link readToken} accepts it. */\nexport type AppErrorTokenGetter = () =>\n string | null | undefined | Promise<string | null | undefined>;\n\n/**\n * Keep only a usable token: a non-empty string.\n *\n * @param value - Whatever the getter produced, possibly from untyped JS.\n * @returns The token, or `null`.\n */\nfunction asToken(value: unknown): string | null {\n return typeof value === \"string\" && value !== \"\" ? value : null;\n}\n\n/**\n * Read the token, synchronously when the getter is synchronous.\n *\n * Staying synchronous for a synchronous getter is what lets `report()` queue\n * the report before it returns; an async getter is bounded by\n * {@link APP_ERROR_TOKEN_TIMEOUT_MS}. A getter that throws, rejects, times out\n * or produces anything but a non-empty string reads as no token.\n *\n * @param getToken - The caller's token getter.\n * @returns The token or `null`, directly or as a promise that always settles.\n */\nexport function readToken(\n getToken: AppErrorTokenGetter | undefined,\n): string | null | Promise<string | null> {\n let value: unknown;\n try {\n value = getToken?.();\n } catch {\n return null;\n }\n if (typeof value !== \"object\" || value === null) return asToken(value);\n return new Promise<string | null>((resolve) => {\n const timer = setTimeout(() => resolve(null), APP_ERROR_TOKEN_TIMEOUT_MS);\n Promise.resolve(value).then(\n (token) => {\n clearTimeout(timer);\n resolve(asToken(token));\n },\n () => {\n clearTimeout(timer);\n resolve(null);\n },\n );\n });\n}\n"],"mappings":";;AAaA,SAAgBA,EAAa,GAA+B;CACxD,IAAMC,IAAU,OAAOC,CAAM;CAC7B,IAAIA,MAAW,QAAQ,OAAO,SAASD,CAAO,GAAG,OAAO,KAAK,IAAIA,GAAS,CAAC,IAAI;CAC/E,IAAME,IAAOD,IAAS,KAAK,MAAMA,CAAM,IAAI;CAC3C,OAAO,OAAO,MAAMC,CAAI,IAAI,MAAS,KAAK,IAAIA,IAAO,KAAK,IAAI,GAAG,GAAI;AACzE;AAQA,SAAgBC,EAAQ,GAAiD;CACrE,IAAIC,EAAM,SAAS,GAAG,OAAOA,EAAM;CACnC,IAAMC,IAAU,aAAaD,EAAM,MAAM,MAAMA,EAAM,OAAO;CAC5D,OAAOE,EAAkB;EAAE,GAAGF,EAAM;EAAQ;CAAQ,CAAC;AACzD;AAcA,eAAsBG,EAClB,GACA,GACA,GACA,GACoB;CACpB,IAAMC,IAAkC,EAAE,gBAAgB,mBAAmB;CAC7E,AAAIC,MAAO,EAAQ,gBAAgB,UAAUA;CAC7C,IAAI;EACA,IAAMC,IAAW,MAAMC,EAAKC,GAAU;GAClC,QAAQ;GACR;GACA,MAAM,KAAK,UAAUT,EAAQC,CAAK,CAAC;EACvC,CAAC;EAMD,OALIM,EAAS,KAAW,EAAE,MAAM,OAAO,IACnCA,EAAS,WAAW,MACb;GAAE,MAAM;GAAQ,IAAIX,EAAaW,EAAS,QAAQ,IAAI,aAAa,CAAC;EAAE,IAE7EA,EAAS,WAAW,OAAOA,EAAS,UAAU,MAAY,EAAE,MAAM,OAAO,IACtE,EAAE,MAAM,OAAO;CAC1B,QAAQ;EACJ,OAAO,EAAE,MAAM,OAAO;CAC1B;AACJ;AAYA,IAAaG,IAA6B;AAY1C,SAASC,EAAQ,GAA+B;CAC5C,OAAO,OAAOC,KAAU,YAAYA,MAAU,KAAKA,IAAQ;AAC/D;AAaA,SAAgBC,EACZ,GACsC;CACtC,IAAID;CACJ,IAAI;EACA,IAAQE,IAAW;CACvB,QAAQ;EACJ,OAAO;CACX;CAEA,OADI,OAAOF,KAAU,aAAYA,IAAuBD,EAAQC,CAAK,IAC9D,IAAI,SAAwB,MAAY;EAC3C,IAAMG,IAAQ,iBAAiBC,EAAQ,IAAI,GAAGN,CAA0B;EACxE,QAAQ,QAAQE,CAAK,CAAC,CAAC,MAClB,MAAU;GAEP,AADA,aAAaG,CAAK,GAClBC,EAAQL,EAAQL,CAAK,CAAC;EAC1B,SACM;GAEF,AADA,aAAaS,CAAK,GAClBC,EAAQ,IAAI;EAChB,CACJ;CACJ,CAAC;AACL"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"console-adapter.cjs","names":[],"sources":["../../src/telemetry/console-adapter.ts"],"sourcesContent":["import type { TelemetryAdapter } from \"./types\";\n\n/**\n * Dev-friendly adapter that logs every call to `console`. Use as a default\n * before plugging the real provider (Sentry / Datadog / PostHog).\n */\nexport const consoleTelemetryAdapter: TelemetryAdapter = {\n identify(user) {\n console.info(\"[telemetry] identify\", user);\n },\n track(event) {\n console.info(\"[telemetry] track\", event.name, event.properties);\n },\n captureException(error, context) {\n console.error(\"[telemetry] exception\", error, context);\n },\n};\n"],"mappings":"AAMA,
|
|
1
|
+
{"version":3,"file":"console-adapter.cjs","names":["consoleTelemetryAdapter","user","event","error","context"],"sources":["../../src/telemetry/console-adapter.ts"],"sourcesContent":["import type { TelemetryAdapter } from \"./types\";\n\n/**\n * Dev-friendly adapter that logs every call to `console`. Use as a default\n * before plugging the real provider (Sentry / Datadog / PostHog).\n */\nexport const consoleTelemetryAdapter: TelemetryAdapter = {\n identify(user) {\n console.info(\"[telemetry] identify\", user);\n },\n track(event) {\n console.info(\"[telemetry] track\", event.name, event.properties);\n },\n captureException(error, context) {\n console.error(\"[telemetry] exception\", error, context);\n },\n};\n"],"mappings":"AAMA,IAAaA,EAA4C,CACrD,SAAS,EAAM,CACX,QAAQ,KAAK,uBAAwBC,CAAI,CAC7C,EACA,MAAM,EAAO,CACT,QAAQ,KAAK,oBAAqBC,EAAM,KAAMA,EAAM,UAAU,CAClE,EACA,iBAAiB,EAAO,EAAS,CAC7B,QAAQ,MAAM,wBAAyBC,EAAOC,CAAO,CACzD,CACJ,E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"console-adapter.js","names":[],"sources":["../../src/telemetry/console-adapter.ts"],"sourcesContent":["import type { TelemetryAdapter } from \"./types\";\n\n/**\n * Dev-friendly adapter that logs every call to `console`. Use as a default\n * before plugging the real provider (Sentry / Datadog / PostHog).\n */\nexport const consoleTelemetryAdapter: TelemetryAdapter = {\n identify(user) {\n console.info(\"[telemetry] identify\", user);\n },\n track(event) {\n console.info(\"[telemetry] track\", event.name, event.properties);\n },\n captureException(error, context) {\n console.error(\"[telemetry] exception\", error, context);\n },\n};\n"],"mappings":";AAMA,
|
|
1
|
+
{"version":3,"file":"console-adapter.js","names":["consoleTelemetryAdapter","user","event","error","context"],"sources":["../../src/telemetry/console-adapter.ts"],"sourcesContent":["import type { TelemetryAdapter } from \"./types\";\n\n/**\n * Dev-friendly adapter that logs every call to `console`. Use as a default\n * before plugging the real provider (Sentry / Datadog / PostHog).\n */\nexport const consoleTelemetryAdapter: TelemetryAdapter = {\n identify(user) {\n console.info(\"[telemetry] identify\", user);\n },\n track(event) {\n console.info(\"[telemetry] track\", event.name, event.properties);\n },\n captureException(error, context) {\n console.error(\"[telemetry] exception\", error, context);\n },\n};\n"],"mappings":";AAMA,IAAaA,IAA4C;CACrD,SAAS,GAAM;EACX,QAAQ,KAAK,wBAAwBC,CAAI;CAC7C;CACA,MAAM,GAAO;EACT,QAAQ,KAAK,qBAAqBC,EAAM,MAAMA,EAAM,UAAU;CAClE;CACA,iBAAiB,GAAO,GAAS;EAC7B,QAAQ,MAAM,yBAAyBC,GAAOC,CAAO;CACzD;AACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"describe-app-error.cjs","names":[],"sources":["../../src/telemetry/describe-app-error.ts"],"sourcesContent":["/** How deep the `cause` chain is followed before the rest is elided. */\nconst MAX_CAUSE_DEPTH = 5;\n\n/**\n * The `code` and `message` a thrown value becomes on the wire.\n */\nexport interface AppErrorDescription {\n /** The error's `name` — `\"UnreadableFileError\"`, `\"TypeError\"` — or `\"Error\"`. */\n code: string;\n /** Header, cause chain, context and stack, in that order. */\n message: string;\n}\n\n/** The shape every thrown error shares, whichever realm built it. */\ninterface ErrorLike {\n name?: unknown;\n message: string;\n stack?: unknown;\n cause?: unknown;\n}\n\n/**\n * Whether a value carries an error's `message`, `instanceof` or not.\n *\n * `instanceof Error` is not enough: a `DOMException` — the `NotReadableError`\n * a picker raises for a file that only lives in the cloud — fails it in jsdom\n * and across realms, and was being rendered as `{}`, losing exactly the cause\n * a field report exists to carry.\n *\n * @param value - The thrown value.\n * @returns `true` for anything with a string `message`.\n */\nfunction isErrorLike(value: unknown): value is ErrorLike {\n return (\n value instanceof Error ||\n (typeof value === \"object\" &&\n value !== null &&\n typeof (value as { message?: unknown }).message === \"string\")\n );\n}\n\n/**\n * The identifier a thrown value reports as, including a `DOMException`, which\n * is not always an `Error` instance across realms.\n *\n * @param value - The thrown value.\n * @returns Its `name`, or `\"Error\"`.\n */\nfunction nameOf(value: unknown): string {\n if (value instanceof Error && value.name) return value.name;\n if (typeof value === \"object\" && value !== null && \"name\" in value) {\n const name = (value as { name: unknown }).name;\n if (typeof name === \"string\" && name) return name;\n }\n return \"Error\";\n}\n\n/**\n * One line naming the value: `Name: message` for an error.\n *\n * @param value - The thrown value or a cause.\n * @returns The line.\n */\nfunction headline(value: unknown): string {\n if (isErrorLike(value)) return `${nameOf(value)}: ${value.message}`;\n if (typeof value === \"string\") return value;\n try {\n return JSON.stringify(value) ?? String(value);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Follow `error.cause` into one line per link, bounded and cycle-safe.\n *\n * @param error - The top-level error.\n * @returns `caused by: …` lines, outermost first.\n */\nfunction causeLines(error: unknown): string[] {\n const lines: string[] = [];\n const seen = new Set<unknown>([error]);\n let current: unknown = isErrorLike(error) ? error.cause : undefined;\n while (current !== undefined && current !== null) {\n if (seen.has(current)) {\n lines.push(\"caused by: [circular]\");\n break;\n }\n if (lines.length === MAX_CAUSE_DEPTH) {\n lines.push(\"caused by: […]\");\n break;\n }\n seen.add(current);\n lines.push(`caused by: ${headline(current)}`);\n current = isErrorLike(current) ? current.cause : undefined;\n }\n return lines;\n}\n\n/**\n * Render the caller's context as one JSON line.\n *\n * @param context - Extra facts, or nothing.\n * @returns The line, or `null` when there is no context.\n */\nfunction contextLine(context: Record<string, unknown> | undefined): string | null {\n if (!context || Object.keys(context).length === 0) return null;\n try {\n return `context: ${JSON.stringify(context)}`;\n } catch {\n return \"context: [unserializable]\";\n }\n}\n\n/**\n * Turn any thrown value into the `code` + `message` pair the backend stores.\n *\n * The message is ordered by how much each part is worth when the backend cuts\n * it at 4000 characters: the headline, then the **`cause` chain** — where the\n * real failure usually is (`UnreadableFileError` caused by `NotReadableError`)\n * — then the caller's context, and the stack last, since it is the longest and\n * the first thing worth losing.\n *\n * @example\n * describeAppError(new Error(\"boom\", { cause: new TypeError(\"x\") }), { step: \"crop\" });\n * // { code: \"Error\", message: \"Error: boom\\ncaused by: TypeError: x\\ncontext: {\\\"step\\\":\\\"crop\\\"}\\n…\" }\n *\n * @param error - Whatever was thrown — an `Error`, a `DOMException`, a string.\n * @param context - Extra facts to keep with it (file size, MIME, step).\n * @returns The wire `code` and `message`.\n */\nexport function describeAppError(\n error: unknown,\n context?: Record<string, unknown>,\n): AppErrorDescription {\n const parts: string[] = [headline(error), ...causeLines(error)];\n const ctx = contextLine(context);\n if (ctx) parts.push(ctx);\n if (isErrorLike(error) && typeof error.stack === \"string\") parts.push(error.stack);\n return { code: nameOf(error), message: parts.join(\"\\n\") };\n}\n"],"mappings":"AAgCA,
|
|
1
|
+
{"version":3,"file":"describe-app-error.cjs","names":["isErrorLike","value","nameOf","name","headline","causeLines","lines","seen","error","current","contextLine","context","describeAppError","parts","ctx"],"sources":["../../src/telemetry/describe-app-error.ts"],"sourcesContent":["/** How deep the `cause` chain is followed before the rest is elided. */\nconst MAX_CAUSE_DEPTH = 5;\n\n/**\n * The `code` and `message` a thrown value becomes on the wire.\n */\nexport interface AppErrorDescription {\n /** The error's `name` — `\"UnreadableFileError\"`, `\"TypeError\"` — or `\"Error\"`. */\n code: string;\n /** Header, cause chain, context and stack, in that order. */\n message: string;\n}\n\n/** The shape every thrown error shares, whichever realm built it. */\ninterface ErrorLike {\n name?: unknown;\n message: string;\n stack?: unknown;\n cause?: unknown;\n}\n\n/**\n * Whether a value carries an error's `message`, `instanceof` or not.\n *\n * `instanceof Error` is not enough: a `DOMException` — the `NotReadableError`\n * a picker raises for a file that only lives in the cloud — fails it in jsdom\n * and across realms, and was being rendered as `{}`, losing exactly the cause\n * a field report exists to carry.\n *\n * @param value - The thrown value.\n * @returns `true` for anything with a string `message`.\n */\nfunction isErrorLike(value: unknown): value is ErrorLike {\n return (\n value instanceof Error ||\n (typeof value === \"object\" &&\n value !== null &&\n typeof (value as { message?: unknown }).message === \"string\")\n );\n}\n\n/**\n * The identifier a thrown value reports as, including a `DOMException`, which\n * is not always an `Error` instance across realms.\n *\n * @param value - The thrown value.\n * @returns Its `name`, or `\"Error\"`.\n */\nfunction nameOf(value: unknown): string {\n if (value instanceof Error && value.name) return value.name;\n if (typeof value === \"object\" && value !== null && \"name\" in value) {\n const name = (value as { name: unknown }).name;\n if (typeof name === \"string\" && name) return name;\n }\n return \"Error\";\n}\n\n/**\n * One line naming the value: `Name: message` for an error.\n *\n * @param value - The thrown value or a cause.\n * @returns The line.\n */\nfunction headline(value: unknown): string {\n if (isErrorLike(value)) return `${nameOf(value)}: ${value.message}`;\n if (typeof value === \"string\") return value;\n try {\n return JSON.stringify(value) ?? String(value);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Follow `error.cause` into one line per link, bounded and cycle-safe.\n *\n * @param error - The top-level error.\n * @returns `caused by: …` lines, outermost first.\n */\nfunction causeLines(error: unknown): string[] {\n const lines: string[] = [];\n const seen = new Set<unknown>([error]);\n let current: unknown = isErrorLike(error) ? error.cause : undefined;\n while (current !== undefined && current !== null) {\n if (seen.has(current)) {\n lines.push(\"caused by: [circular]\");\n break;\n }\n if (lines.length === MAX_CAUSE_DEPTH) {\n lines.push(\"caused by: […]\");\n break;\n }\n seen.add(current);\n lines.push(`caused by: ${headline(current)}`);\n current = isErrorLike(current) ? current.cause : undefined;\n }\n return lines;\n}\n\n/**\n * Render the caller's context as one JSON line.\n *\n * @param context - Extra facts, or nothing.\n * @returns The line, or `null` when there is no context.\n */\nfunction contextLine(context: Record<string, unknown> | undefined): string | null {\n if (!context || Object.keys(context).length === 0) return null;\n try {\n return `context: ${JSON.stringify(context)}`;\n } catch {\n return \"context: [unserializable]\";\n }\n}\n\n/**\n * Turn any thrown value into the `code` + `message` pair the backend stores.\n *\n * The message is ordered by how much each part is worth when the backend cuts\n * it at 4000 characters: the headline, then the **`cause` chain** — where the\n * real failure usually is (`UnreadableFileError` caused by `NotReadableError`)\n * — then the caller's context, and the stack last, since it is the longest and\n * the first thing worth losing.\n *\n * @example\n * describeAppError(new Error(\"boom\", { cause: new TypeError(\"x\") }), { step: \"crop\" });\n * // { code: \"Error\", message: \"Error: boom\\ncaused by: TypeError: x\\ncontext: {\\\"step\\\":\\\"crop\\\"}\\n…\" }\n *\n * @param error - Whatever was thrown — an `Error`, a `DOMException`, a string.\n * @param context - Extra facts to keep with it (file size, MIME, step).\n * @returns The wire `code` and `message`.\n */\nexport function describeAppError(\n error: unknown,\n context?: Record<string, unknown>,\n): AppErrorDescription {\n const parts: string[] = [headline(error), ...causeLines(error)];\n const ctx = contextLine(context);\n if (ctx) parts.push(ctx);\n if (isErrorLike(error) && typeof error.stack === \"string\") parts.push(error.stack);\n return { code: nameOf(error), message: parts.join(\"\\n\") };\n}\n"],"mappings":"AAgCA,SAASA,EAAY,EAAoC,CACrD,OACIC,aAAiB,OAChB,OAAOA,GAAU,YACdA,GACA,OAAQA,EAAgC,SAAY,QAEhE,CASA,SAASC,EAAO,EAAwB,CACpC,GAAID,aAAiB,OAASA,EAAM,KAAM,OAAOA,EAAM,KACvD,GAAI,OAAOA,GAAU,UAAYA,GAAkB,SAAUA,EAAO,CAChE,IAAME,EAAQF,EAA4B,KAC1C,GAAI,OAAOE,GAAS,UAAYA,EAAM,OAAOA,CACjD,CACA,MAAO,OACX,CAQA,SAASC,EAAS,EAAwB,CACtC,GAAIJ,EAAYC,CAAK,EAAG,MAAO,GAAGC,EAAOD,CAAK,EAAE,IAAIA,EAAM,UAC1D,GAAI,OAAOA,GAAU,SAAU,OAAOA,EACtC,GAAI,CACA,OAAO,KAAK,UAAUA,CAAK,GAAK,OAAOA,CAAK,CAChD,MAAQ,CACJ,OAAO,OAAOA,CAAK,CACvB,CACJ,CAQA,SAASI,EAAW,EAA0B,CAC1C,IAAMC,EAAkB,CAAC,EACnBC,EAAO,IAAI,IAAa,CAACC,CAAK,CAAC,EACjCC,EAAmBT,EAAYQ,CAAK,EAAIA,EAAM,MAAQ,IAAA,GAC1D,KAAOC,GAAqC,MAAM,CAC9C,GAAIF,EAAK,IAAIE,CAAO,EAAG,CACnBH,EAAM,KAAK,uBAAuB,EAClC,KACJ,CACA,GAAIA,EAAM,SAAW,EAAiB,CAClCA,EAAM,KAAK,gBAAgB,EAC3B,KACJ,CACAC,EAAK,IAAIE,CAAO,EAChBH,EAAM,KAAK,cAAcF,EAASK,CAAO,GAAG,EAC5C,EAAUT,EAAYS,CAAO,EAAIA,EAAQ,MAAQ,IAAA,EACrD,CACA,OAAOH,CACX,CAQA,SAASI,EAAY,EAA6D,CAC9E,GAAI,CAACC,GAAW,OAAO,KAAKA,CAAO,CAAC,CAAC,SAAW,EAAG,OAAO,KAC1D,GAAI,CACA,MAAO,YAAY,KAAK,UAAUA,CAAO,GAC7C,MAAQ,CACJ,MAAO,2BACX,CACJ,CAmBA,SAAgBC,EACZ,EACA,EACmB,CACnB,IAAMC,EAAkB,CAACT,EAASI,CAAK,EAAG,GAAGH,EAAWG,CAAK,CAAC,EACxDM,EAAMJ,EAAYC,CAAO,EAG/B,OAFIG,GAAKD,EAAM,KAAKC,CAAG,EACnBd,EAAYQ,CAAK,GAAK,OAAOA,EAAM,OAAU,UAAUK,EAAM,KAAKL,EAAM,KAAK,EAC1E,CAAE,KAAMN,EAAOM,CAAK,EAAG,QAASK,EAAM,KAAK;CAAI,CAAE,CAC5D,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"describe-app-error.js","names":[],"sources":["../../src/telemetry/describe-app-error.ts"],"sourcesContent":["/** How deep the `cause` chain is followed before the rest is elided. */\nconst MAX_CAUSE_DEPTH = 5;\n\n/**\n * The `code` and `message` a thrown value becomes on the wire.\n */\nexport interface AppErrorDescription {\n /** The error's `name` — `\"UnreadableFileError\"`, `\"TypeError\"` — or `\"Error\"`. */\n code: string;\n /** Header, cause chain, context and stack, in that order. */\n message: string;\n}\n\n/** The shape every thrown error shares, whichever realm built it. */\ninterface ErrorLike {\n name?: unknown;\n message: string;\n stack?: unknown;\n cause?: unknown;\n}\n\n/**\n * Whether a value carries an error's `message`, `instanceof` or not.\n *\n * `instanceof Error` is not enough: a `DOMException` — the `NotReadableError`\n * a picker raises for a file that only lives in the cloud — fails it in jsdom\n * and across realms, and was being rendered as `{}`, losing exactly the cause\n * a field report exists to carry.\n *\n * @param value - The thrown value.\n * @returns `true` for anything with a string `message`.\n */\nfunction isErrorLike(value: unknown): value is ErrorLike {\n return (\n value instanceof Error ||\n (typeof value === \"object\" &&\n value !== null &&\n typeof (value as { message?: unknown }).message === \"string\")\n );\n}\n\n/**\n * The identifier a thrown value reports as, including a `DOMException`, which\n * is not always an `Error` instance across realms.\n *\n * @param value - The thrown value.\n * @returns Its `name`, or `\"Error\"`.\n */\nfunction nameOf(value: unknown): string {\n if (value instanceof Error && value.name) return value.name;\n if (typeof value === \"object\" && value !== null && \"name\" in value) {\n const name = (value as { name: unknown }).name;\n if (typeof name === \"string\" && name) return name;\n }\n return \"Error\";\n}\n\n/**\n * One line naming the value: `Name: message` for an error.\n *\n * @param value - The thrown value or a cause.\n * @returns The line.\n */\nfunction headline(value: unknown): string {\n if (isErrorLike(value)) return `${nameOf(value)}: ${value.message}`;\n if (typeof value === \"string\") return value;\n try {\n return JSON.stringify(value) ?? String(value);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Follow `error.cause` into one line per link, bounded and cycle-safe.\n *\n * @param error - The top-level error.\n * @returns `caused by: …` lines, outermost first.\n */\nfunction causeLines(error: unknown): string[] {\n const lines: string[] = [];\n const seen = new Set<unknown>([error]);\n let current: unknown = isErrorLike(error) ? error.cause : undefined;\n while (current !== undefined && current !== null) {\n if (seen.has(current)) {\n lines.push(\"caused by: [circular]\");\n break;\n }\n if (lines.length === MAX_CAUSE_DEPTH) {\n lines.push(\"caused by: […]\");\n break;\n }\n seen.add(current);\n lines.push(`caused by: ${headline(current)}`);\n current = isErrorLike(current) ? current.cause : undefined;\n }\n return lines;\n}\n\n/**\n * Render the caller's context as one JSON line.\n *\n * @param context - Extra facts, or nothing.\n * @returns The line, or `null` when there is no context.\n */\nfunction contextLine(context: Record<string, unknown> | undefined): string | null {\n if (!context || Object.keys(context).length === 0) return null;\n try {\n return `context: ${JSON.stringify(context)}`;\n } catch {\n return \"context: [unserializable]\";\n }\n}\n\n/**\n * Turn any thrown value into the `code` + `message` pair the backend stores.\n *\n * The message is ordered by how much each part is worth when the backend cuts\n * it at 4000 characters: the headline, then the **`cause` chain** — where the\n * real failure usually is (`UnreadableFileError` caused by `NotReadableError`)\n * — then the caller's context, and the stack last, since it is the longest and\n * the first thing worth losing.\n *\n * @example\n * describeAppError(new Error(\"boom\", { cause: new TypeError(\"x\") }), { step: \"crop\" });\n * // { code: \"Error\", message: \"Error: boom\\ncaused by: TypeError: x\\ncontext: {\\\"step\\\":\\\"crop\\\"}\\n…\" }\n *\n * @param error - Whatever was thrown — an `Error`, a `DOMException`, a string.\n * @param context - Extra facts to keep with it (file size, MIME, step).\n * @returns The wire `code` and `message`.\n */\nexport function describeAppError(\n error: unknown,\n context?: Record<string, unknown>,\n): AppErrorDescription {\n const parts: string[] = [headline(error), ...causeLines(error)];\n const ctx = contextLine(context);\n if (ctx) parts.push(ctx);\n if (isErrorLike(error) && typeof error.stack === \"string\") parts.push(error.stack);\n return { code: nameOf(error), message: parts.join(\"\\n\") };\n}\n"],"mappings":"AAgCA,
|
|
1
|
+
{"version":3,"file":"describe-app-error.js","names":["isErrorLike","value","nameOf","name","headline","causeLines","lines","seen","error","current","contextLine","context","describeAppError","parts","ctx"],"sources":["../../src/telemetry/describe-app-error.ts"],"sourcesContent":["/** How deep the `cause` chain is followed before the rest is elided. */\nconst MAX_CAUSE_DEPTH = 5;\n\n/**\n * The `code` and `message` a thrown value becomes on the wire.\n */\nexport interface AppErrorDescription {\n /** The error's `name` — `\"UnreadableFileError\"`, `\"TypeError\"` — or `\"Error\"`. */\n code: string;\n /** Header, cause chain, context and stack, in that order. */\n message: string;\n}\n\n/** The shape every thrown error shares, whichever realm built it. */\ninterface ErrorLike {\n name?: unknown;\n message: string;\n stack?: unknown;\n cause?: unknown;\n}\n\n/**\n * Whether a value carries an error's `message`, `instanceof` or not.\n *\n * `instanceof Error` is not enough: a `DOMException` — the `NotReadableError`\n * a picker raises for a file that only lives in the cloud — fails it in jsdom\n * and across realms, and was being rendered as `{}`, losing exactly the cause\n * a field report exists to carry.\n *\n * @param value - The thrown value.\n * @returns `true` for anything with a string `message`.\n */\nfunction isErrorLike(value: unknown): value is ErrorLike {\n return (\n value instanceof Error ||\n (typeof value === \"object\" &&\n value !== null &&\n typeof (value as { message?: unknown }).message === \"string\")\n );\n}\n\n/**\n * The identifier a thrown value reports as, including a `DOMException`, which\n * is not always an `Error` instance across realms.\n *\n * @param value - The thrown value.\n * @returns Its `name`, or `\"Error\"`.\n */\nfunction nameOf(value: unknown): string {\n if (value instanceof Error && value.name) return value.name;\n if (typeof value === \"object\" && value !== null && \"name\" in value) {\n const name = (value as { name: unknown }).name;\n if (typeof name === \"string\" && name) return name;\n }\n return \"Error\";\n}\n\n/**\n * One line naming the value: `Name: message` for an error.\n *\n * @param value - The thrown value or a cause.\n * @returns The line.\n */\nfunction headline(value: unknown): string {\n if (isErrorLike(value)) return `${nameOf(value)}: ${value.message}`;\n if (typeof value === \"string\") return value;\n try {\n return JSON.stringify(value) ?? String(value);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Follow `error.cause` into one line per link, bounded and cycle-safe.\n *\n * @param error - The top-level error.\n * @returns `caused by: …` lines, outermost first.\n */\nfunction causeLines(error: unknown): string[] {\n const lines: string[] = [];\n const seen = new Set<unknown>([error]);\n let current: unknown = isErrorLike(error) ? error.cause : undefined;\n while (current !== undefined && current !== null) {\n if (seen.has(current)) {\n lines.push(\"caused by: [circular]\");\n break;\n }\n if (lines.length === MAX_CAUSE_DEPTH) {\n lines.push(\"caused by: […]\");\n break;\n }\n seen.add(current);\n lines.push(`caused by: ${headline(current)}`);\n current = isErrorLike(current) ? current.cause : undefined;\n }\n return lines;\n}\n\n/**\n * Render the caller's context as one JSON line.\n *\n * @param context - Extra facts, or nothing.\n * @returns The line, or `null` when there is no context.\n */\nfunction contextLine(context: Record<string, unknown> | undefined): string | null {\n if (!context || Object.keys(context).length === 0) return null;\n try {\n return `context: ${JSON.stringify(context)}`;\n } catch {\n return \"context: [unserializable]\";\n }\n}\n\n/**\n * Turn any thrown value into the `code` + `message` pair the backend stores.\n *\n * The message is ordered by how much each part is worth when the backend cuts\n * it at 4000 characters: the headline, then the **`cause` chain** — where the\n * real failure usually is (`UnreadableFileError` caused by `NotReadableError`)\n * — then the caller's context, and the stack last, since it is the longest and\n * the first thing worth losing.\n *\n * @example\n * describeAppError(new Error(\"boom\", { cause: new TypeError(\"x\") }), { step: \"crop\" });\n * // { code: \"Error\", message: \"Error: boom\\ncaused by: TypeError: x\\ncontext: {\\\"step\\\":\\\"crop\\\"}\\n…\" }\n *\n * @param error - Whatever was thrown — an `Error`, a `DOMException`, a string.\n * @param context - Extra facts to keep with it (file size, MIME, step).\n * @returns The wire `code` and `message`.\n */\nexport function describeAppError(\n error: unknown,\n context?: Record<string, unknown>,\n): AppErrorDescription {\n const parts: string[] = [headline(error), ...causeLines(error)];\n const ctx = contextLine(context);\n if (ctx) parts.push(ctx);\n if (isErrorLike(error) && typeof error.stack === \"string\") parts.push(error.stack);\n return { code: nameOf(error), message: parts.join(\"\\n\") };\n}\n"],"mappings":"AAgCA,SAASA,EAAY,GAAoC;CACrD,OACIC,aAAiB,SAChB,OAAOA,KAAU,cACdA,KACA,OAAQA,EAAgC,WAAY;AAEhE;AASA,SAASC,EAAO,GAAwB;CACpC,IAAID,aAAiB,SAASA,EAAM,MAAM,OAAOA,EAAM;CACvD,IAAI,OAAOA,KAAU,YAAYA,KAAkB,UAAUA,GAAO;EAChE,IAAME,IAAQF,EAA4B;EAC1C,IAAI,OAAOE,KAAS,YAAYA,GAAM,OAAOA;CACjD;CACA,OAAO;AACX;AAQA,SAASC,EAAS,GAAwB;CACtC,IAAIJ,EAAYC,CAAK,GAAG,OAAO,GAAGC,EAAOD,CAAK,EAAE,IAAIA,EAAM;CAC1D,IAAI,OAAOA,KAAU,UAAU,OAAOA;CACtC,IAAI;EACA,OAAO,KAAK,UAAUA,CAAK,KAAK,OAAOA,CAAK;CAChD,QAAQ;EACJ,OAAO,OAAOA,CAAK;CACvB;AACJ;AAQA,SAASI,EAAW,GAA0B;CAC1C,IAAMC,IAAkB,CAAC,GACnBC,oBAAO,IAAI,IAAa,CAACC,CAAK,CAAC,GACjCC,IAAmBT,EAAYQ,CAAK,IAAIA,EAAM,QAAQ,KAAA;CAC1D,OAAOC,KAAqC,OAAM;EAC9C,IAAIF,EAAK,IAAIE,CAAO,GAAG;GACnB,EAAM,KAAK,uBAAuB;GAClC;EACJ;EACA,IAAIH,EAAM,WAAW,GAAiB;GAClC,EAAM,KAAK,gBAAgB;GAC3B;EACJ;EAGA,AAFAC,EAAK,IAAIE,CAAO,GAChBH,EAAM,KAAK,cAAcF,EAASK,CAAO,GAAG,GAC5C,IAAUT,EAAYS,CAAO,IAAIA,EAAQ,QAAQ,KAAA;CACrD;CACA,OAAOH;AACX;AAQA,SAASI,EAAY,GAA6D;CAC9E,IAAI,CAACC,KAAW,OAAO,KAAKA,CAAO,CAAC,CAAC,WAAW,GAAG,OAAO;CAC1D,IAAI;EACA,OAAO,YAAY,KAAK,UAAUA,CAAO;CAC7C,QAAQ;EACJ,OAAO;CACX;AACJ;AAmBA,SAAgBC,EACZ,GACA,GACmB;CACnB,IAAMC,IAAkB,CAACT,EAASI,CAAK,GAAG,GAAGH,EAAWG,CAAK,CAAC,GACxDM,IAAMJ,EAAYC,CAAO;CAG/B,OAFIG,KAAKD,EAAM,KAAKC,CAAG,GACnBd,EAAYQ,CAAK,KAAK,OAAOA,EAAM,SAAU,YAAUK,EAAM,KAAKL,EAAM,KAAK,GAC1E;EAAE,MAAMN,EAAOM,CAAK;EAAG,SAASK,EAAM,KAAK,IAAI;CAAE;AAC5D"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function e(e){let{email:t,name:n,traits:r}=e;return{...t===void 0?null:{email:t},...n===void 0?null:{name:n},...r??null}}function t(t){let{posthog:n,init:r}=t;return{init(){r&&n.init&&n.init(r.apiKey,r.options)},identify(t){
|
|
1
|
+
function e(e){let{email:t,name:n,traits:r}=e;return{...t===void 0?null:{email:t},...n===void 0?null:{name:n},...r??null}}function t(t){let{posthog:n,init:r}=t;return{init(){r&&n.init&&n.init(r.apiKey,r.options)},identify(t){t===null?n.reset?.():t.id!==void 0&&n.identify(t.id,e(t))},track(e){n.capture(e.name,e.properties)},captureException(e,t){if(n.captureException){n.captureException(e,t);return}let r=e instanceof Error?e:Error(String(e));n.capture(`$exception`,{$exception_message:r.message,$exception_type:r.name,$exception_stack_trace_raw:r.stack,...t})}}}exports.createPostHogTelemetryAdapter=t;
|
|
2
2
|
//# sourceMappingURL=posthog-adapter.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"posthog-adapter.cjs","names":[],"sources":["../../src/telemetry/posthog-adapter.ts"],"sourcesContent":["import type { TelemetryAdapter, TelemetryEvent, TelemetryUser } from \"./types\";\n\n/**\n * Minimal subset of `posthog-js` used by the adapter. Pass either the real\n * default export (`import posthog from \"posthog-js\"`) or a stubbed object\n * in tests.\n */\nexport interface PostHogLike {\n init?: (apiKey: string, options?: Record<string, unknown>) => void;\n identify: (distinctId: string, properties?: Record<string, unknown>) => void;\n capture: (eventName: string, properties?: Record<string, unknown>) => void;\n captureException?: (error: unknown, properties?: Record<string, unknown>) => void;\n reset?: () => void;\n}\n\nexport interface CreatePostHogTelemetryAdapterOptions {\n /** The PostHog JS client (the default export of `posthog-js`). Required. */\n posthog: PostHogLike;\n /** Project API key + options. When provided, `Provider.init` calls `posthog.init(apiKey, options)`. */\n init?: { apiKey: string; options?: Record<string, unknown> };\n}\n\nfunction userToProperties(user: TelemetryUser): Record<string, unknown> {\n const { email, name, traits } = user;\n return {\n ...(email !== undefined ? { email } : null),\n ...(name !== undefined ? { name } : null),\n ...(traits ?? null),\n };\n}\n\n/**\n * Build a [[TelemetryAdapter]] backed by [`posthog-js`](https://posthog.com/docs/libraries/js).\n * The PostHog client is supplied by the caller (not bundled).\n *\n * Mapping:\n * - `identify(user)` → `posthog.identify(user.id, { email, name, ...traits })` (or `posthog.reset()` when `null`)\n * - `track({ name, properties })` → `posthog.capture(name, properties)`\n * - `captureException(err, ctx)` → `posthog.captureException(err, ctx)` when available, otherwise `posthog.capture(\"$exception\", { …err, …ctx })`\n * - `flush()` → no-op (PostHog batches automatically)\n *\n * @example\n * import posthog from \"posthog-js\";\n * import { createPostHogTelemetryAdapter, TelemetryProvider } from \"tempest-react-sdk\";\n *\n * const adapter = createPostHogTelemetryAdapter({\n * posthog,\n * init: { apiKey: import.meta.env.VITE_POSTHOG_KEY, options: { api_host: \"https://us.i.posthog.com\" } },\n * });\n *\n * <TelemetryProvider adapter={adapter}><App /></TelemetryProvider>;\n */\nexport function createPostHogTelemetryAdapter(\n options: CreatePostHogTelemetryAdapterOptions,\n): TelemetryAdapter {\n const { posthog, init } = options;\n\n return {\n init() {\n if (init && posthog.init) {\n posthog.init(init.apiKey, init.options);\n }\n },\n identify(user: TelemetryUser | null) {\n if (user === null) {\n posthog.reset?.();\n return;\n }\n if (user.id === undefined) return;\n posthog.identify(user.id, userToProperties(user));\n },\n track(event: TelemetryEvent) {\n posthog.capture(event.name, event.properties);\n },\n captureException(error: unknown, context?: Record<string, unknown>) {\n if (posthog.captureException) {\n posthog.captureException(error, context);\n return;\n }\n const err = error instanceof Error ? error : new Error(String(error));\n posthog.capture(\"$exception\", {\n $exception_message: err.message,\n $exception_type: err.name,\n $exception_stack_trace_raw: err.stack,\n ...context,\n });\n },\n };\n}\n"],"mappings":"AAsBA,
|
|
1
|
+
{"version":3,"file":"posthog-adapter.cjs","names":["userToProperties","user","email","name","traits","createPostHogTelemetryAdapter","options","init","posthog","event","error","context","err"],"sources":["../../src/telemetry/posthog-adapter.ts"],"sourcesContent":["import type { TelemetryAdapter, TelemetryEvent, TelemetryUser } from \"./types\";\n\n/**\n * Minimal subset of `posthog-js` used by the adapter. Pass either the real\n * default export (`import posthog from \"posthog-js\"`) or a stubbed object\n * in tests.\n */\nexport interface PostHogLike {\n init?: (apiKey: string, options?: Record<string, unknown>) => void;\n identify: (distinctId: string, properties?: Record<string, unknown>) => void;\n capture: (eventName: string, properties?: Record<string, unknown>) => void;\n captureException?: (error: unknown, properties?: Record<string, unknown>) => void;\n reset?: () => void;\n}\n\nexport interface CreatePostHogTelemetryAdapterOptions {\n /** The PostHog JS client (the default export of `posthog-js`). Required. */\n posthog: PostHogLike;\n /** Project API key + options. When provided, `Provider.init` calls `posthog.init(apiKey, options)`. */\n init?: { apiKey: string; options?: Record<string, unknown> };\n}\n\nfunction userToProperties(user: TelemetryUser): Record<string, unknown> {\n const { email, name, traits } = user;\n return {\n ...(email !== undefined ? { email } : null),\n ...(name !== undefined ? { name } : null),\n ...(traits ?? null),\n };\n}\n\n/**\n * Build a [[TelemetryAdapter]] backed by [`posthog-js`](https://posthog.com/docs/libraries/js).\n * The PostHog client is supplied by the caller (not bundled).\n *\n * Mapping:\n * - `identify(user)` → `posthog.identify(user.id, { email, name, ...traits })` (or `posthog.reset()` when `null`)\n * - `track({ name, properties })` → `posthog.capture(name, properties)`\n * - `captureException(err, ctx)` → `posthog.captureException(err, ctx)` when available, otherwise `posthog.capture(\"$exception\", { …err, …ctx })`\n * - `flush()` → no-op (PostHog batches automatically)\n *\n * @example\n * import posthog from \"posthog-js\";\n * import { createPostHogTelemetryAdapter, TelemetryProvider } from \"tempest-react-sdk\";\n *\n * const adapter = createPostHogTelemetryAdapter({\n * posthog,\n * init: { apiKey: import.meta.env.VITE_POSTHOG_KEY, options: { api_host: \"https://us.i.posthog.com\" } },\n * });\n *\n * <TelemetryProvider adapter={adapter}><App /></TelemetryProvider>;\n */\nexport function createPostHogTelemetryAdapter(\n options: CreatePostHogTelemetryAdapterOptions,\n): TelemetryAdapter {\n const { posthog, init } = options;\n\n return {\n init() {\n if (init && posthog.init) {\n posthog.init(init.apiKey, init.options);\n }\n },\n identify(user: TelemetryUser | null) {\n if (user === null) {\n posthog.reset?.();\n return;\n }\n if (user.id === undefined) return;\n posthog.identify(user.id, userToProperties(user));\n },\n track(event: TelemetryEvent) {\n posthog.capture(event.name, event.properties);\n },\n captureException(error: unknown, context?: Record<string, unknown>) {\n if (posthog.captureException) {\n posthog.captureException(error, context);\n return;\n }\n const err = error instanceof Error ? error : new Error(String(error));\n posthog.capture(\"$exception\", {\n $exception_message: err.message,\n $exception_type: err.name,\n $exception_stack_trace_raw: err.stack,\n ...context,\n });\n },\n };\n}\n"],"mappings":"AAsBA,SAASA,EAAiB,EAA8C,CACpE,GAAM,CAAE,QAAO,OAAM,UAAWC,EAChC,MAAO,CACH,GAAIC,IAAU,IAAA,GAAwB,KAAZ,CAAE,OAAM,EAClC,GAAIC,IAAS,IAAA,GAAuB,KAAX,CAAE,MAAK,EAChC,GAAIC,GAAU,IAClB,CACJ,CAuBA,SAAgBC,EACZ,EACgB,CAChB,GAAM,CAAE,UAAS,QAASC,EAE1B,MAAO,CACH,MAAO,CACCC,GAAQC,EAAQ,MAChBA,EAAQ,KAAKD,EAAK,OAAQA,EAAK,OAAO,CAE9C,EACA,SAAS,EAA4B,CAC7BN,IAAS,KACTO,EAAQ,QAAQ,EAGhBP,EAAK,KAAO,IAAA,IAChBO,EAAQ,SAASP,EAAK,GAAID,EAAiBC,CAAI,CAAC,CACpD,EACA,MAAM,EAAuB,CACzBO,EAAQ,QAAQC,EAAM,KAAMA,EAAM,UAAU,CAChD,EACA,iBAAiB,EAAgB,EAAmC,CAChE,GAAID,EAAQ,iBAAkB,CAC1BA,EAAQ,iBAAiBE,EAAOC,CAAO,EACvC,MACJ,CACA,IAAMC,EAAMF,aAAiB,MAAQA,EAAY,MAAM,OAAOA,CAAK,CAAC,EACpEF,EAAQ,QAAQ,aAAc,CAC1B,mBAAoBI,EAAI,QACxB,gBAAiBA,EAAI,KACrB,2BAA4BA,EAAI,MAChC,GAAGD,CACP,CAAC,CACL,CACJ,CACJ,C"}
|
|
@@ -14,11 +14,7 @@ function t(t) {
|
|
|
14
14
|
r && n.init && n.init(r.apiKey, r.options);
|
|
15
15
|
},
|
|
16
16
|
identify(t) {
|
|
17
|
-
|
|
18
|
-
n.reset?.();
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
t.id !== void 0 && n.identify(t.id, e(t));
|
|
17
|
+
t === null ? n.reset?.() : t.id !== void 0 && n.identify(t.id, e(t));
|
|
22
18
|
},
|
|
23
19
|
track(e) {
|
|
24
20
|
n.capture(e.name, e.properties);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"posthog-adapter.js","names":[],"sources":["../../src/telemetry/posthog-adapter.ts"],"sourcesContent":["import type { TelemetryAdapter, TelemetryEvent, TelemetryUser } from \"./types\";\n\n/**\n * Minimal subset of `posthog-js` used by the adapter. Pass either the real\n * default export (`import posthog from \"posthog-js\"`) or a stubbed object\n * in tests.\n */\nexport interface PostHogLike {\n init?: (apiKey: string, options?: Record<string, unknown>) => void;\n identify: (distinctId: string, properties?: Record<string, unknown>) => void;\n capture: (eventName: string, properties?: Record<string, unknown>) => void;\n captureException?: (error: unknown, properties?: Record<string, unknown>) => void;\n reset?: () => void;\n}\n\nexport interface CreatePostHogTelemetryAdapterOptions {\n /** The PostHog JS client (the default export of `posthog-js`). Required. */\n posthog: PostHogLike;\n /** Project API key + options. When provided, `Provider.init` calls `posthog.init(apiKey, options)`. */\n init?: { apiKey: string; options?: Record<string, unknown> };\n}\n\nfunction userToProperties(user: TelemetryUser): Record<string, unknown> {\n const { email, name, traits } = user;\n return {\n ...(email !== undefined ? { email } : null),\n ...(name !== undefined ? { name } : null),\n ...(traits ?? null),\n };\n}\n\n/**\n * Build a [[TelemetryAdapter]] backed by [`posthog-js`](https://posthog.com/docs/libraries/js).\n * The PostHog client is supplied by the caller (not bundled).\n *\n * Mapping:\n * - `identify(user)` → `posthog.identify(user.id, { email, name, ...traits })` (or `posthog.reset()` when `null`)\n * - `track({ name, properties })` → `posthog.capture(name, properties)`\n * - `captureException(err, ctx)` → `posthog.captureException(err, ctx)` when available, otherwise `posthog.capture(\"$exception\", { …err, …ctx })`\n * - `flush()` → no-op (PostHog batches automatically)\n *\n * @example\n * import posthog from \"posthog-js\";\n * import { createPostHogTelemetryAdapter, TelemetryProvider } from \"tempest-react-sdk\";\n *\n * const adapter = createPostHogTelemetryAdapter({\n * posthog,\n * init: { apiKey: import.meta.env.VITE_POSTHOG_KEY, options: { api_host: \"https://us.i.posthog.com\" } },\n * });\n *\n * <TelemetryProvider adapter={adapter}><App /></TelemetryProvider>;\n */\nexport function createPostHogTelemetryAdapter(\n options: CreatePostHogTelemetryAdapterOptions,\n): TelemetryAdapter {\n const { posthog, init } = options;\n\n return {\n init() {\n if (init && posthog.init) {\n posthog.init(init.apiKey, init.options);\n }\n },\n identify(user: TelemetryUser | null) {\n if (user === null) {\n posthog.reset?.();\n return;\n }\n if (user.id === undefined) return;\n posthog.identify(user.id, userToProperties(user));\n },\n track(event: TelemetryEvent) {\n posthog.capture(event.name, event.properties);\n },\n captureException(error: unknown, context?: Record<string, unknown>) {\n if (posthog.captureException) {\n posthog.captureException(error, context);\n return;\n }\n const err = error instanceof Error ? error : new Error(String(error));\n posthog.capture(\"$exception\", {\n $exception_message: err.message,\n $exception_type: err.name,\n $exception_stack_trace_raw: err.stack,\n ...context,\n });\n },\n };\n}\n"],"mappings":";AAsBA,
|
|
1
|
+
{"version":3,"file":"posthog-adapter.js","names":["userToProperties","user","email","name","traits","createPostHogTelemetryAdapter","options","init","posthog","event","error","context","err"],"sources":["../../src/telemetry/posthog-adapter.ts"],"sourcesContent":["import type { TelemetryAdapter, TelemetryEvent, TelemetryUser } from \"./types\";\n\n/**\n * Minimal subset of `posthog-js` used by the adapter. Pass either the real\n * default export (`import posthog from \"posthog-js\"`) or a stubbed object\n * in tests.\n */\nexport interface PostHogLike {\n init?: (apiKey: string, options?: Record<string, unknown>) => void;\n identify: (distinctId: string, properties?: Record<string, unknown>) => void;\n capture: (eventName: string, properties?: Record<string, unknown>) => void;\n captureException?: (error: unknown, properties?: Record<string, unknown>) => void;\n reset?: () => void;\n}\n\nexport interface CreatePostHogTelemetryAdapterOptions {\n /** The PostHog JS client (the default export of `posthog-js`). Required. */\n posthog: PostHogLike;\n /** Project API key + options. When provided, `Provider.init` calls `posthog.init(apiKey, options)`. */\n init?: { apiKey: string; options?: Record<string, unknown> };\n}\n\nfunction userToProperties(user: TelemetryUser): Record<string, unknown> {\n const { email, name, traits } = user;\n return {\n ...(email !== undefined ? { email } : null),\n ...(name !== undefined ? { name } : null),\n ...(traits ?? null),\n };\n}\n\n/**\n * Build a [[TelemetryAdapter]] backed by [`posthog-js`](https://posthog.com/docs/libraries/js).\n * The PostHog client is supplied by the caller (not bundled).\n *\n * Mapping:\n * - `identify(user)` → `posthog.identify(user.id, { email, name, ...traits })` (or `posthog.reset()` when `null`)\n * - `track({ name, properties })` → `posthog.capture(name, properties)`\n * - `captureException(err, ctx)` → `posthog.captureException(err, ctx)` when available, otherwise `posthog.capture(\"$exception\", { …err, …ctx })`\n * - `flush()` → no-op (PostHog batches automatically)\n *\n * @example\n * import posthog from \"posthog-js\";\n * import { createPostHogTelemetryAdapter, TelemetryProvider } from \"tempest-react-sdk\";\n *\n * const adapter = createPostHogTelemetryAdapter({\n * posthog,\n * init: { apiKey: import.meta.env.VITE_POSTHOG_KEY, options: { api_host: \"https://us.i.posthog.com\" } },\n * });\n *\n * <TelemetryProvider adapter={adapter}><App /></TelemetryProvider>;\n */\nexport function createPostHogTelemetryAdapter(\n options: CreatePostHogTelemetryAdapterOptions,\n): TelemetryAdapter {\n const { posthog, init } = options;\n\n return {\n init() {\n if (init && posthog.init) {\n posthog.init(init.apiKey, init.options);\n }\n },\n identify(user: TelemetryUser | null) {\n if (user === null) {\n posthog.reset?.();\n return;\n }\n if (user.id === undefined) return;\n posthog.identify(user.id, userToProperties(user));\n },\n track(event: TelemetryEvent) {\n posthog.capture(event.name, event.properties);\n },\n captureException(error: unknown, context?: Record<string, unknown>) {\n if (posthog.captureException) {\n posthog.captureException(error, context);\n return;\n }\n const err = error instanceof Error ? error : new Error(String(error));\n posthog.capture(\"$exception\", {\n $exception_message: err.message,\n $exception_type: err.name,\n $exception_stack_trace_raw: err.stack,\n ...context,\n });\n },\n };\n}\n"],"mappings":";AAsBA,SAASA,EAAiB,GAA8C;CACpE,IAAM,EAAE,UAAO,SAAM,cAAWC;CAChC,OAAO;EACH,GAAIC,MAAU,KAAA,IAAwB,OAAZ,EAAE,SAAM;EAClC,GAAIC,MAAS,KAAA,IAAuB,OAAX,EAAE,QAAK;EAChC,GAAIC,KAAU;CAClB;AACJ;AAuBA,SAAgBC,EACZ,GACgB;CAChB,IAAM,EAAE,YAAS,YAASC;CAE1B,OAAO;EACH,OAAO;GACH,AAAIC,KAAQC,EAAQ,QAChBA,EAAQ,KAAKD,EAAK,QAAQA,EAAK,OAAO;EAE9C;EACA,SAAS,GAA4B;GACjC,AAAIN,MAAS,OACTO,EAAQ,QAAQ,IAGhBP,EAAK,OAAO,KAAA,KAChBO,EAAQ,SAASP,EAAK,IAAID,EAAiBC,CAAI,CAAC;EACpD;EACA,MAAM,GAAuB;GACzB,EAAQ,QAAQQ,EAAM,MAAMA,EAAM,UAAU;EAChD;EACA,iBAAiB,GAAgB,GAAmC;GAChE,IAAID,EAAQ,kBAAkB;IAC1B,EAAQ,iBAAiBE,GAAOC,CAAO;IACvC;GACJ;GACA,IAAMC,IAAMF,aAAiB,QAAQA,IAAY,MAAM,OAAOA,CAAK,CAAC;GACpE,EAAQ,QAAQ,cAAc;IAC1B,oBAAoBE,EAAI;IACxB,iBAAiBA,EAAI;IACrB,4BAA4BA,EAAI;IAChC,GAAGD;GACP,CAAC;EACL;CACJ;AACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sentry-adapter.cjs","names":[],"sources":["../../src/telemetry/sentry-adapter.ts"],"sourcesContent":["import type { TelemetryAdapter, TelemetryEvent, TelemetryUser } from \"./types\";\n\n/**\n * Minimal subset of `@sentry/browser` used by the adapter. Lets you pass\n * either the real SDK module (`import * as Sentry from \"@sentry/browser\"`)\n * or a stubbed object in tests.\n */\nexport interface SentryLike {\n init?: (options: Record<string, unknown>) => void;\n setUser: (user: Record<string, unknown> | null) => void;\n addBreadcrumb: (breadcrumb: {\n category?: string;\n message?: string;\n level?: string;\n data?: Record<string, unknown>;\n }) => void;\n captureException: (\n error: unknown,\n hint?: { extra?: Record<string, unknown>; contexts?: Record<string, unknown> },\n ) => void;\n flush?: (timeout?: number) => Promise<boolean>;\n}\n\nexport interface CreateSentryTelemetryAdapterOptions {\n /** The Sentry browser SDK namespace. Required. */\n sentry: SentryLike;\n /** Optional init payload — passed verbatim to `Sentry.init` when the provider mounts. */\n initOptions?: Record<string, unknown>;\n /** Flush timeout in ms (default `2000`). */\n flushTimeout?: number;\n /** Breadcrumb category for `track` events (default `\"app\"`). */\n breadcrumbCategory?: string;\n}\n\nfunction userToSentry(user: TelemetryUser | null): Record<string, unknown> | null {\n if (user === null) return null;\n const { id, email, name, traits } = user;\n return {\n ...(id !== undefined ? { id } : null),\n ...(email !== undefined ? { email } : null),\n ...(name !== undefined ? { username: name } : null),\n ...(traits ?? null),\n };\n}\n\n/**\n * Build a [[TelemetryAdapter]] backed by `@sentry/browser`. The Sentry SDK\n * is supplied by the caller (not bundled) so apps that already initialise\n * Sentry at startup can share that instance — and apps that don't use\n * Sentry never pay for it.\n *\n * Mapping:\n * - `identify(user)` → `Sentry.setUser`\n * - `track(event)` → `Sentry.addBreadcrumb({ category, message: event.name, data })`\n * - `captureException(err, ctx)` → `Sentry.captureException(err, { extra: ctx })`\n * - `flush()` → `Sentry.flush(flushTimeout)`\n *\n * @example\n * import * as Sentry from \"@sentry/browser\";\n * import { createSentryTelemetryAdapter, TelemetryProvider } from \"tempest-react-sdk\";\n *\n * const adapter = createSentryTelemetryAdapter({\n * sentry: Sentry,\n * initOptions: { dsn: import.meta.env.VITE_SENTRY_DSN, tracesSampleRate: 0.1 },\n * });\n *\n * <TelemetryProvider adapter={adapter}><App /></TelemetryProvider>;\n */\nexport function createSentryTelemetryAdapter(\n options: CreateSentryTelemetryAdapterOptions,\n): TelemetryAdapter {\n const { sentry, initOptions, flushTimeout = 2000, breadcrumbCategory = \"app\" } = options;\n\n return {\n init() {\n if (initOptions && sentry.init) {\n sentry.init(initOptions);\n }\n },\n identify(user: TelemetryUser | null) {\n sentry.setUser(userToSentry(user));\n },\n track(event: TelemetryEvent) {\n sentry.addBreadcrumb({\n category: breadcrumbCategory,\n message: event.name,\n level: \"info\",\n ...(event.properties ? { data: event.properties } : null),\n });\n },\n captureException(error: unknown, context?: Record<string, unknown>) {\n sentry.captureException(error, context ? { extra: context } : undefined);\n },\n async flush() {\n if (sentry.flush) {\n await sentry.flush(flushTimeout);\n }\n },\n };\n}\n"],"mappings":"AAkCA,
|
|
1
|
+
{"version":3,"file":"sentry-adapter.cjs","names":["userToSentry","user","id","email","name","traits","createSentryTelemetryAdapter","options","initOptions","sentry","breadcrumbCategory","event","error","context","flushTimeout"],"sources":["../../src/telemetry/sentry-adapter.ts"],"sourcesContent":["import type { TelemetryAdapter, TelemetryEvent, TelemetryUser } from \"./types\";\n\n/**\n * Minimal subset of `@sentry/browser` used by the adapter. Lets you pass\n * either the real SDK module (`import * as Sentry from \"@sentry/browser\"`)\n * or a stubbed object in tests.\n */\nexport interface SentryLike {\n init?: (options: Record<string, unknown>) => void;\n setUser: (user: Record<string, unknown> | null) => void;\n addBreadcrumb: (breadcrumb: {\n category?: string;\n message?: string;\n level?: string;\n data?: Record<string, unknown>;\n }) => void;\n captureException: (\n error: unknown,\n hint?: { extra?: Record<string, unknown>; contexts?: Record<string, unknown> },\n ) => void;\n flush?: (timeout?: number) => Promise<boolean>;\n}\n\nexport interface CreateSentryTelemetryAdapterOptions {\n /** The Sentry browser SDK namespace. Required. */\n sentry: SentryLike;\n /** Optional init payload — passed verbatim to `Sentry.init` when the provider mounts. */\n initOptions?: Record<string, unknown>;\n /** Flush timeout in ms (default `2000`). */\n flushTimeout?: number;\n /** Breadcrumb category for `track` events (default `\"app\"`). */\n breadcrumbCategory?: string;\n}\n\nfunction userToSentry(user: TelemetryUser | null): Record<string, unknown> | null {\n if (user === null) return null;\n const { id, email, name, traits } = user;\n return {\n ...(id !== undefined ? { id } : null),\n ...(email !== undefined ? { email } : null),\n ...(name !== undefined ? { username: name } : null),\n ...(traits ?? null),\n };\n}\n\n/**\n * Build a [[TelemetryAdapter]] backed by `@sentry/browser`. The Sentry SDK\n * is supplied by the caller (not bundled) so apps that already initialise\n * Sentry at startup can share that instance — and apps that don't use\n * Sentry never pay for it.\n *\n * Mapping:\n * - `identify(user)` → `Sentry.setUser`\n * - `track(event)` → `Sentry.addBreadcrumb({ category, message: event.name, data })`\n * - `captureException(err, ctx)` → `Sentry.captureException(err, { extra: ctx })`\n * - `flush()` → `Sentry.flush(flushTimeout)`\n *\n * @example\n * import * as Sentry from \"@sentry/browser\";\n * import { createSentryTelemetryAdapter, TelemetryProvider } from \"tempest-react-sdk\";\n *\n * const adapter = createSentryTelemetryAdapter({\n * sentry: Sentry,\n * initOptions: { dsn: import.meta.env.VITE_SENTRY_DSN, tracesSampleRate: 0.1 },\n * });\n *\n * <TelemetryProvider adapter={adapter}><App /></TelemetryProvider>;\n */\nexport function createSentryTelemetryAdapter(\n options: CreateSentryTelemetryAdapterOptions,\n): TelemetryAdapter {\n const { sentry, initOptions, flushTimeout = 2000, breadcrumbCategory = \"app\" } = options;\n\n return {\n init() {\n if (initOptions && sentry.init) {\n sentry.init(initOptions);\n }\n },\n identify(user: TelemetryUser | null) {\n sentry.setUser(userToSentry(user));\n },\n track(event: TelemetryEvent) {\n sentry.addBreadcrumb({\n category: breadcrumbCategory,\n message: event.name,\n level: \"info\",\n ...(event.properties ? { data: event.properties } : null),\n });\n },\n captureException(error: unknown, context?: Record<string, unknown>) {\n sentry.captureException(error, context ? { extra: context } : undefined);\n },\n async flush() {\n if (sentry.flush) {\n await sentry.flush(flushTimeout);\n }\n },\n };\n}\n"],"mappings":"AAkCA,SAASA,EAAa,EAA4D,CAC9E,GAAIC,IAAS,KAAM,OAAO,KAC1B,GAAM,CAAE,KAAI,QAAO,OAAM,UAAWA,EACpC,MAAO,CACH,GAAIC,IAAO,IAAA,GAAqB,KAAT,CAAE,IAAG,EAC5B,GAAIC,IAAU,IAAA,GAAwB,KAAZ,CAAE,OAAM,EAClC,GAAIC,IAAS,IAAA,GAAiC,KAArB,CAAE,SAAUA,CAAK,EAC1C,GAAIC,GAAU,IAClB,CACJ,CAyBA,SAAgBC,EACZ,EACgB,CAChB,GAAM,CAAE,SAAQ,cAAa,eAAe,IAAM,qBAAqB,OAAUC,EAEjF,MAAO,CACH,MAAO,CACCC,GAAeC,EAAO,MACtBA,EAAO,KAAKD,CAAW,CAE/B,EACA,SAAS,EAA4B,CACjCC,EAAO,QAAQT,EAAaC,CAAI,CAAC,CACrC,EACA,MAAM,EAAuB,CACzBQ,EAAO,cAAc,CACjB,SAAUC,EACV,QAASC,EAAM,KACf,MAAO,OACP,GAAIA,EAAM,WAAa,CAAE,KAAMA,EAAM,UAAW,EAAI,IACxD,CAAC,CACL,EACA,iBAAiB,EAAgB,EAAmC,CAChEF,EAAO,iBAAiBG,EAAOC,EAAU,CAAE,MAAOA,CAAQ,EAAI,IAAA,EAAS,CAC3E,EACA,MAAM,OAAQ,CACNJ,EAAO,OACP,MAAMA,EAAO,MAAMK,CAAY,CAEvC,CACJ,CACJ,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sentry-adapter.js","names":[],"sources":["../../src/telemetry/sentry-adapter.ts"],"sourcesContent":["import type { TelemetryAdapter, TelemetryEvent, TelemetryUser } from \"./types\";\n\n/**\n * Minimal subset of `@sentry/browser` used by the adapter. Lets you pass\n * either the real SDK module (`import * as Sentry from \"@sentry/browser\"`)\n * or a stubbed object in tests.\n */\nexport interface SentryLike {\n init?: (options: Record<string, unknown>) => void;\n setUser: (user: Record<string, unknown> | null) => void;\n addBreadcrumb: (breadcrumb: {\n category?: string;\n message?: string;\n level?: string;\n data?: Record<string, unknown>;\n }) => void;\n captureException: (\n error: unknown,\n hint?: { extra?: Record<string, unknown>; contexts?: Record<string, unknown> },\n ) => void;\n flush?: (timeout?: number) => Promise<boolean>;\n}\n\nexport interface CreateSentryTelemetryAdapterOptions {\n /** The Sentry browser SDK namespace. Required. */\n sentry: SentryLike;\n /** Optional init payload — passed verbatim to `Sentry.init` when the provider mounts. */\n initOptions?: Record<string, unknown>;\n /** Flush timeout in ms (default `2000`). */\n flushTimeout?: number;\n /** Breadcrumb category for `track` events (default `\"app\"`). */\n breadcrumbCategory?: string;\n}\n\nfunction userToSentry(user: TelemetryUser | null): Record<string, unknown> | null {\n if (user === null) return null;\n const { id, email, name, traits } = user;\n return {\n ...(id !== undefined ? { id } : null),\n ...(email !== undefined ? { email } : null),\n ...(name !== undefined ? { username: name } : null),\n ...(traits ?? null),\n };\n}\n\n/**\n * Build a [[TelemetryAdapter]] backed by `@sentry/browser`. The Sentry SDK\n * is supplied by the caller (not bundled) so apps that already initialise\n * Sentry at startup can share that instance — and apps that don't use\n * Sentry never pay for it.\n *\n * Mapping:\n * - `identify(user)` → `Sentry.setUser`\n * - `track(event)` → `Sentry.addBreadcrumb({ category, message: event.name, data })`\n * - `captureException(err, ctx)` → `Sentry.captureException(err, { extra: ctx })`\n * - `flush()` → `Sentry.flush(flushTimeout)`\n *\n * @example\n * import * as Sentry from \"@sentry/browser\";\n * import { createSentryTelemetryAdapter, TelemetryProvider } from \"tempest-react-sdk\";\n *\n * const adapter = createSentryTelemetryAdapter({\n * sentry: Sentry,\n * initOptions: { dsn: import.meta.env.VITE_SENTRY_DSN, tracesSampleRate: 0.1 },\n * });\n *\n * <TelemetryProvider adapter={adapter}><App /></TelemetryProvider>;\n */\nexport function createSentryTelemetryAdapter(\n options: CreateSentryTelemetryAdapterOptions,\n): TelemetryAdapter {\n const { sentry, initOptions, flushTimeout = 2000, breadcrumbCategory = \"app\" } = options;\n\n return {\n init() {\n if (initOptions && sentry.init) {\n sentry.init(initOptions);\n }\n },\n identify(user: TelemetryUser | null) {\n sentry.setUser(userToSentry(user));\n },\n track(event: TelemetryEvent) {\n sentry.addBreadcrumb({\n category: breadcrumbCategory,\n message: event.name,\n level: \"info\",\n ...(event.properties ? { data: event.properties } : null),\n });\n },\n captureException(error: unknown, context?: Record<string, unknown>) {\n sentry.captureException(error, context ? { extra: context } : undefined);\n },\n async flush() {\n if (sentry.flush) {\n await sentry.flush(flushTimeout);\n }\n },\n };\n}\n"],"mappings":";AAkCA,
|
|
1
|
+
{"version":3,"file":"sentry-adapter.js","names":["userToSentry","user","id","email","name","traits","createSentryTelemetryAdapter","options","initOptions","sentry","breadcrumbCategory","event","error","context","flushTimeout"],"sources":["../../src/telemetry/sentry-adapter.ts"],"sourcesContent":["import type { TelemetryAdapter, TelemetryEvent, TelemetryUser } from \"./types\";\n\n/**\n * Minimal subset of `@sentry/browser` used by the adapter. Lets you pass\n * either the real SDK module (`import * as Sentry from \"@sentry/browser\"`)\n * or a stubbed object in tests.\n */\nexport interface SentryLike {\n init?: (options: Record<string, unknown>) => void;\n setUser: (user: Record<string, unknown> | null) => void;\n addBreadcrumb: (breadcrumb: {\n category?: string;\n message?: string;\n level?: string;\n data?: Record<string, unknown>;\n }) => void;\n captureException: (\n error: unknown,\n hint?: { extra?: Record<string, unknown>; contexts?: Record<string, unknown> },\n ) => void;\n flush?: (timeout?: number) => Promise<boolean>;\n}\n\nexport interface CreateSentryTelemetryAdapterOptions {\n /** The Sentry browser SDK namespace. Required. */\n sentry: SentryLike;\n /** Optional init payload — passed verbatim to `Sentry.init` when the provider mounts. */\n initOptions?: Record<string, unknown>;\n /** Flush timeout in ms (default `2000`). */\n flushTimeout?: number;\n /** Breadcrumb category for `track` events (default `\"app\"`). */\n breadcrumbCategory?: string;\n}\n\nfunction userToSentry(user: TelemetryUser | null): Record<string, unknown> | null {\n if (user === null) return null;\n const { id, email, name, traits } = user;\n return {\n ...(id !== undefined ? { id } : null),\n ...(email !== undefined ? { email } : null),\n ...(name !== undefined ? { username: name } : null),\n ...(traits ?? null),\n };\n}\n\n/**\n * Build a [[TelemetryAdapter]] backed by `@sentry/browser`. The Sentry SDK\n * is supplied by the caller (not bundled) so apps that already initialise\n * Sentry at startup can share that instance — and apps that don't use\n * Sentry never pay for it.\n *\n * Mapping:\n * - `identify(user)` → `Sentry.setUser`\n * - `track(event)` → `Sentry.addBreadcrumb({ category, message: event.name, data })`\n * - `captureException(err, ctx)` → `Sentry.captureException(err, { extra: ctx })`\n * - `flush()` → `Sentry.flush(flushTimeout)`\n *\n * @example\n * import * as Sentry from \"@sentry/browser\";\n * import { createSentryTelemetryAdapter, TelemetryProvider } from \"tempest-react-sdk\";\n *\n * const adapter = createSentryTelemetryAdapter({\n * sentry: Sentry,\n * initOptions: { dsn: import.meta.env.VITE_SENTRY_DSN, tracesSampleRate: 0.1 },\n * });\n *\n * <TelemetryProvider adapter={adapter}><App /></TelemetryProvider>;\n */\nexport function createSentryTelemetryAdapter(\n options: CreateSentryTelemetryAdapterOptions,\n): TelemetryAdapter {\n const { sentry, initOptions, flushTimeout = 2000, breadcrumbCategory = \"app\" } = options;\n\n return {\n init() {\n if (initOptions && sentry.init) {\n sentry.init(initOptions);\n }\n },\n identify(user: TelemetryUser | null) {\n sentry.setUser(userToSentry(user));\n },\n track(event: TelemetryEvent) {\n sentry.addBreadcrumb({\n category: breadcrumbCategory,\n message: event.name,\n level: \"info\",\n ...(event.properties ? { data: event.properties } : null),\n });\n },\n captureException(error: unknown, context?: Record<string, unknown>) {\n sentry.captureException(error, context ? { extra: context } : undefined);\n },\n async flush() {\n if (sentry.flush) {\n await sentry.flush(flushTimeout);\n }\n },\n };\n}\n"],"mappings":";AAkCA,SAASA,EAAa,GAA4D;CAC9E,IAAIC,MAAS,MAAM,OAAO;CAC1B,IAAM,EAAE,OAAI,UAAO,SAAM,cAAWA;CACpC,OAAO;EACH,GAAIC,MAAO,KAAA,IAAqB,OAAT,EAAE,MAAG;EAC5B,GAAIC,MAAU,KAAA,IAAwB,OAAZ,EAAE,SAAM;EAClC,GAAIC,MAAS,KAAA,IAAiC,OAArB,EAAE,UAAUA,EAAK;EAC1C,GAAIC,KAAU;CAClB;AACJ;AAyBA,SAAgBC,EACZ,GACgB;CAChB,IAAM,EAAE,WAAQ,gBAAa,kBAAe,KAAM,wBAAqB,UAAUC;CAEjF,OAAO;EACH,OAAO;GACH,AAAIC,KAAeC,EAAO,QACtBA,EAAO,KAAKD,CAAW;EAE/B;EACA,SAAS,GAA4B;GACjC,EAAO,QAAQR,EAAaC,CAAI,CAAC;EACrC;EACA,MAAM,GAAuB;GACzB,EAAO,cAAc;IACjB,UAAUS;IACV,SAASC,EAAM;IACf,OAAO;IACP,GAAIA,EAAM,aAAa,EAAE,MAAMA,EAAM,WAAW,IAAI;GACxD,CAAC;EACL;EACA,iBAAiB,GAAgB,GAAmC;GAChE,EAAO,iBAAiBC,GAAOC,IAAU,EAAE,OAAOA,EAAQ,IAAI,KAAA,CAAS;EAC3E;EACA,MAAM,QAAQ;GACV,AAAIJ,EAAO,SACP,MAAMA,EAAO,MAAMK,CAAY;EAEvC;CACJ;AACJ"}
|