@mentra/engine 0.1.0-dev.0 → 0.1.0-dev.1
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 +42 -1
- package/build/engine.d.ts +11 -3
- package/build/engine.d.ts.map +1 -1
- package/build/engine.js +7 -2
- package/build/engine.js.map +1 -1
- package/build/facades/dev.d.ts +3 -2
- package/build/facades/dev.d.ts.map +1 -1
- package/build/facades/dev.js +18 -12
- package/build/facades/dev.js.map +1 -1
- package/build/facades/gallery.js +1 -1
- package/build/facades/gallery.js.map +1 -1
- package/build/facades/glasses.d.ts +1 -0
- package/build/facades/glasses.d.ts.map +1 -1
- package/build/facades/glasses.js +19 -4
- package/build/facades/glasses.js.map +1 -1
- package/build/facades/glassesSettings.d.ts.map +1 -1
- package/build/facades/glassesSettings.js +1 -0
- package/build/facades/glassesSettings.js.map +1 -1
- package/build/facades/miniapps.d.ts +4 -0
- package/build/facades/miniapps.d.ts.map +1 -1
- package/build/facades/miniapps.js +5 -0
- package/build/facades/miniapps.js.map +1 -1
- package/build/facades/ota.d.ts +11 -2
- package/build/facades/ota.d.ts.map +1 -1
- package/build/facades/ota.js +19 -4
- package/build/facades/ota.js.map +1 -1
- package/build/facades/pairing.d.ts +4 -0
- package/build/facades/pairing.d.ts.map +1 -1
- package/build/facades/pairing.js +10 -8
- package/build/facades/pairing.js.map +1 -1
- package/build/facades/permissions.d.ts +10 -0
- package/build/facades/permissions.d.ts.map +1 -1
- package/build/facades/permissions.js +10 -0
- package/build/facades/permissions.js.map +1 -1
- package/build/facades/phoneNotifications.d.ts +0 -4
- package/build/facades/phoneNotifications.d.ts.map +1 -1
- package/build/facades/phoneNotifications.js +4 -14
- package/build/facades/phoneNotifications.js.map +1 -1
- package/build/index.d.ts +6 -3
- package/build/index.d.ts.map +1 -1
- package/build/index.js +4 -2
- package/build/index.js.map +1 -1
- package/build/internal.d.ts +3 -2
- package/build/internal.d.ts.map +1 -1
- package/build/internal.js +2 -1
- package/build/internal.js.map +1 -1
- package/build/react/MentraLiveOtaFlow.d.ts +38 -0
- package/build/react/MentraLiveOtaFlow.d.ts.map +1 -0
- package/build/react/MentraLiveOtaFlow.js +528 -0
- package/build/react/MentraLiveOtaFlow.js.map +1 -0
- package/build/react/index.d.ts +2 -0
- package/build/react/index.d.ts.map +1 -0
- package/build/react/index.js +2 -0
- package/build/react/index.js.map +1 -0
- package/build/react/useEngineSnapshot.d.ts +2 -0
- package/build/react/useEngineSnapshot.d.ts.map +1 -0
- package/build/react/useEngineSnapshot.js +14 -0
- package/build/react/useEngineSnapshot.js.map +1 -0
- package/build/runtime/bootstrap.d.ts +24 -1
- package/build/runtime/bootstrap.d.ts.map +1 -1
- package/build/runtime/bootstrap.js +17 -0
- package/build/runtime/bootstrap.js.map +1 -1
- package/build/runtime/scanQrSeam.d.ts +7 -0
- package/build/runtime/scanQrSeam.d.ts.map +1 -0
- package/build/runtime/scanQrSeam.js +16 -0
- package/build/runtime/scanQrSeam.js.map +1 -0
- package/build/services/AppRegistry.d.ts +33 -57
- package/build/services/AppRegistry.d.ts.map +1 -1
- package/build/services/AppRegistry.js +193 -144
- package/build/services/AppRegistry.js.map +1 -1
- package/build/services/AudioCloudUplink.d.ts +12 -0
- package/build/services/AudioCloudUplink.d.ts.map +1 -1
- package/build/services/AudioCloudUplink.js +22 -1
- package/build/services/AudioCloudUplink.js.map +1 -1
- package/build/services/AudioPlaybackService.d.ts +41 -2
- package/build/services/AudioPlaybackService.d.ts.map +1 -1
- package/build/services/AudioPlaybackService.js +250 -33
- package/build/services/AudioPlaybackService.js.map +1 -1
- package/build/services/BlobStore.d.ts +2 -1
- package/build/services/BlobStore.d.ts.map +1 -1
- package/build/services/BlobStore.js +17 -9
- package/build/services/BlobStore.js.map +1 -1
- package/build/services/CloudAudioSubscriptionSync.d.ts.map +1 -1
- package/build/services/CloudAudioSubscriptionSync.js +13 -1
- package/build/services/CloudAudioSubscriptionSync.js.map +1 -1
- package/build/services/CloudClientService.d.ts +15 -0
- package/build/services/CloudClientService.d.ts.map +1 -1
- package/build/services/CloudClientService.js +93 -1
- package/build/services/CloudClientService.js.map +1 -1
- package/build/services/DeviceEventRouter.js +5 -5
- package/build/services/DeviceEventRouter.js.map +1 -1
- package/build/services/ForegroundLocationPermission.d.ts +13 -0
- package/build/services/ForegroundLocationPermission.d.ts.map +1 -0
- package/build/services/ForegroundLocationPermission.js +12 -0
- package/build/services/ForegroundLocationPermission.js.map +1 -0
- package/build/services/GlassesSettingsSync.d.ts.map +1 -1
- package/build/services/GlassesSettingsSync.js +9 -3
- package/build/services/GlassesSettingsSync.js.map +1 -1
- package/build/services/GlassesStatusProjection.d.ts +2 -1
- package/build/services/GlassesStatusProjection.d.ts.map +1 -1
- package/build/services/GlassesStatusProjection.js +15 -8
- package/build/services/GlassesStatusProjection.js.map +1 -1
- package/build/services/HotspotOtaTransport.d.ts +29 -0
- package/build/services/HotspotOtaTransport.d.ts.map +1 -0
- package/build/services/HotspotOtaTransport.js +146 -0
- package/build/services/HotspotOtaTransport.js.map +1 -0
- package/build/services/HotspotShutdown.d.ts +17 -0
- package/build/services/HotspotShutdown.d.ts.map +1 -0
- package/build/services/HotspotShutdown.js +29 -0
- package/build/services/HotspotShutdown.js.map +1 -0
- package/build/services/LocalDisplayManager.d.ts +15 -0
- package/build/services/LocalDisplayManager.d.ts.map +1 -1
- package/build/services/LocalDisplayManager.js +106 -20
- package/build/services/LocalDisplayManager.js.map +1 -1
- package/build/services/LocalMiniappRuntime.d.ts +74 -2
- package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
- package/build/services/LocalMiniappRuntime.js +785 -291
- package/build/services/LocalMiniappRuntime.js.map +1 -1
- package/build/services/LocalMiniappStorage.d.ts +32 -0
- package/build/services/LocalMiniappStorage.d.ts.map +1 -0
- package/build/services/LocalMiniappStorage.js +66 -0
- package/build/services/LocalMiniappStorage.js.map +1 -0
- package/build/services/LocalMiniappUserIdentity.d.ts +20 -0
- package/build/services/LocalMiniappUserIdentity.d.ts.map +1 -0
- package/build/services/LocalMiniappUserIdentity.js +43 -0
- package/build/services/LocalMiniappUserIdentity.js.map +1 -0
- package/build/services/LocalSttFallbackCoordinator.d.ts +9 -6
- package/build/services/LocalSttFallbackCoordinator.d.ts.map +1 -1
- package/build/services/LocalSttFallbackCoordinator.js +18 -12
- package/build/services/LocalSttFallbackCoordinator.js.map +1 -1
- package/build/services/MicStateCoordinator.d.ts +42 -1
- package/build/services/MicStateCoordinator.d.ts.map +1 -1
- package/build/services/MicStateCoordinator.js +141 -3
- package/build/services/MicStateCoordinator.js.map +1 -1
- package/build/services/MiniappLauncher.d.ts.map +1 -1
- package/build/services/MiniappLauncher.js +23 -3
- package/build/services/MiniappLauncher.js.map +1 -1
- package/build/services/MiniappLiveness.d.ts +12 -0
- package/build/services/MiniappLiveness.d.ts.map +1 -0
- package/build/services/MiniappLiveness.js +16 -0
- package/build/services/MiniappLiveness.js.map +1 -0
- package/build/services/NativeHttpResponse.d.ts +3 -0
- package/build/services/NativeHttpResponse.d.ts.map +1 -0
- package/build/services/NativeHttpResponse.js +6 -0
- package/build/services/NativeHttpResponse.js.map +1 -0
- package/build/services/OtaArtifactDownloader.d.ts +65 -0
- package/build/services/OtaArtifactDownloader.d.ts.map +1 -0
- package/build/services/OtaArtifactDownloader.js +226 -0
- package/build/services/OtaArtifactDownloader.js.map +1 -0
- package/build/services/OtaAutoChain.d.ts +34 -0
- package/build/services/OtaAutoChain.d.ts.map +1 -0
- package/build/services/OtaAutoChain.js +83 -0
- package/build/services/OtaAutoChain.js.map +1 -0
- package/build/services/OtaErrorMapping.d.ts +18 -0
- package/build/services/OtaErrorMapping.d.ts.map +1 -0
- package/build/services/OtaErrorMapping.js +63 -0
- package/build/services/OtaErrorMapping.js.map +1 -0
- package/build/services/OtaInstallCoordinator.d.ts +94 -14
- package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
- package/build/services/OtaInstallCoordinator.js +574 -130
- package/build/services/OtaInstallCoordinator.js.map +1 -1
- package/build/services/OtaService.d.ts.map +1 -1
- package/build/services/OtaService.js +8 -1
- package/build/services/OtaService.js.map +1 -1
- package/build/services/OtaUpdateCheckService.d.ts +38 -3
- package/build/services/OtaUpdateCheckService.d.ts.map +1 -1
- package/build/services/OtaUpdateCheckService.js +142 -22
- package/build/services/OtaUpdateCheckService.js.map +1 -1
- package/build/services/PhoneCalendarHelpers.d.ts +32 -0
- package/build/services/PhoneCalendarHelpers.d.ts.map +1 -0
- package/build/services/PhoneCalendarHelpers.js +157 -0
- package/build/services/PhoneCalendarHelpers.js.map +1 -0
- package/build/services/PhoneCalendarService.d.ts +5 -0
- package/build/services/PhoneCalendarService.d.ts.map +1 -0
- package/build/services/PhoneCalendarService.js +45 -0
- package/build/services/PhoneCalendarService.js.map +1 -0
- package/build/services/PhoneCameraFovCoordinator.d.ts +30 -0
- package/build/services/PhoneCameraFovCoordinator.d.ts.map +1 -0
- package/build/services/PhoneCameraFovCoordinator.js +194 -0
- package/build/services/PhoneCameraFovCoordinator.js.map +1 -0
- package/build/services/PhoneNotificationsSync.d.ts.map +1 -1
- package/build/services/PhoneNotificationsSync.js +12 -10
- package/build/services/PhoneNotificationsSync.js.map +1 -1
- package/build/services/PhonePhotoCoordinator.d.ts +26 -2
- package/build/services/PhonePhotoCoordinator.d.ts.map +1 -1
- package/build/services/PhonePhotoCoordinator.js +79 -9
- package/build/services/PhonePhotoCoordinator.js.map +1 -1
- package/build/services/PhoneStreamCoordinator.d.ts +8 -1
- package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
- package/build/services/PhoneStreamCoordinator.js +125 -13
- package/build/services/PhoneStreamCoordinator.js.map +1 -1
- package/build/services/PhoneVideoCoordinator.d.ts +2 -0
- package/build/services/PhoneVideoCoordinator.d.ts.map +1 -1
- package/build/services/PhoneVideoCoordinator.js +10 -0
- package/build/services/PhoneVideoCoordinator.js.map +1 -1
- package/build/services/SceneRenderer.d.ts.map +1 -1
- package/build/services/SceneRenderer.js +15 -0
- package/build/services/SceneRenderer.js.map +1 -1
- package/build/services/SentenceTtsPipeline.d.ts +31 -0
- package/build/services/SentenceTtsPipeline.d.ts.map +1 -0
- package/build/services/SentenceTtsPipeline.js +67 -0
- package/build/services/SentenceTtsPipeline.js.map +1 -0
- package/build/services/SupportProfileSync.d.ts +22 -0
- package/build/services/SupportProfileSync.d.ts.map +1 -0
- package/build/services/SupportProfileSync.js +213 -0
- package/build/services/SupportProfileSync.js.map +1 -0
- package/build/services/TranscriptionRouting.d.ts +12 -0
- package/build/services/TranscriptionRouting.d.ts.map +1 -0
- package/build/services/TranscriptionRouting.js +24 -0
- package/build/services/TranscriptionRouting.js.map +1 -0
- package/build/services/TtsTextSanitizer.d.ts +5 -0
- package/build/services/TtsTextSanitizer.d.ts.map +1 -0
- package/build/services/TtsTextSanitizer.js +61 -0
- package/build/services/TtsTextSanitizer.js.map +1 -0
- package/build/services/WifiAdbRequest.d.ts +17 -0
- package/build/services/WifiAdbRequest.d.ts.map +1 -0
- package/build/services/WifiAdbRequest.js +35 -0
- package/build/services/WifiAdbRequest.js.map +1 -0
- package/build/services/asg/asgCameraApi.d.ts +43 -0
- package/build/services/asg/asgCameraApi.d.ts.map +1 -1
- package/build/services/asg/asgCameraApi.js +509 -26
- package/build/services/asg/asgCameraApi.js.map +1 -1
- package/build/services/asg/cameraRollExportCoordinator.d.ts +60 -0
- package/build/services/asg/cameraRollExportCoordinator.d.ts.map +1 -0
- package/build/services/asg/cameraRollExportCoordinator.js +618 -0
- package/build/services/asg/cameraRollExportCoordinator.js.map +1 -0
- package/build/services/asg/cameraRollExportLedger.d.ts +44 -0
- package/build/services/asg/cameraRollExportLedger.d.ts.map +1 -0
- package/build/services/asg/cameraRollExportLedger.js +78 -0
- package/build/services/asg/cameraRollExportLedger.js.map +1 -0
- package/build/services/asg/galleryNotices.d.ts +1 -1
- package/build/services/asg/galleryNotices.d.ts.map +1 -1
- package/build/services/asg/galleryNotices.js.map +1 -1
- package/build/services/asg/galleryPathMigration.d.ts +3 -0
- package/build/services/asg/galleryPathMigration.d.ts.map +1 -0
- package/build/services/asg/galleryPathMigration.js +26 -0
- package/build/services/asg/galleryPathMigration.js.map +1 -0
- package/build/services/asg/gallerySettingsService.d.ts +1 -0
- package/build/services/asg/gallerySettingsService.d.ts.map +1 -1
- package/build/services/asg/gallerySettingsService.js +2 -0
- package/build/services/asg/gallerySettingsService.js.map +1 -1
- package/build/services/asg/gallerySyncService.d.ts.map +1 -1
- package/build/services/asg/gallerySyncService.js +162 -56
- package/build/services/asg/gallerySyncService.js.map +1 -1
- package/build/services/asg/galleryTransferLedger.d.ts +58 -0
- package/build/services/asg/galleryTransferLedger.d.ts.map +1 -0
- package/build/services/asg/galleryTransferLedger.js +225 -0
- package/build/services/asg/galleryTransferLedger.js.map +1 -0
- package/build/services/asg/localNetworkTransport.d.ts +15 -0
- package/build/services/asg/localNetworkTransport.d.ts.map +1 -0
- package/build/services/asg/localNetworkTransport.js +144 -0
- package/build/services/asg/localNetworkTransport.js.map +1 -0
- package/build/services/asg/localStorageService.d.ts +18 -0
- package/build/services/asg/localStorageService.d.ts.map +1 -1
- package/build/services/asg/localStorageService.js +168 -19
- package/build/services/asg/localStorageService.js.map +1 -1
- package/build/services/asg/mediaProcessingQueue.d.ts +10 -0
- package/build/services/asg/mediaProcessingQueue.d.ts.map +1 -1
- package/build/services/asg/mediaProcessingQueue.js +193 -62
- package/build/services/asg/mediaProcessingQueue.js.map +1 -1
- package/build/services/audioPlaybackAssets.d.ts +8 -0
- package/build/services/audioPlaybackAssets.d.ts.map +1 -0
- package/build/services/audioPlaybackAssets.js +7 -0
- package/build/services/audioPlaybackAssets.js.map +1 -0
- package/build/services/gallerySyncClock.js +1 -1
- package/build/services/gallerySyncClock.js.map +1 -1
- package/build/services/glassesClockSync.js +2 -2
- package/build/services/glassesClockSync.js.map +1 -1
- package/build/services/manifestActions.d.ts +7 -0
- package/build/services/manifestActions.d.ts.map +1 -0
- package/build/services/manifestActions.js +25 -0
- package/build/services/manifestActions.js.map +1 -0
- package/build/services/otaDisplayState.d.ts +22 -11
- package/build/services/otaDisplayState.d.ts.map +1 -1
- package/build/services/otaDisplayState.js +36 -14
- package/build/services/otaDisplayState.js.map +1 -1
- package/build/services/otaInstallPolicy.d.ts +15 -3
- package/build/services/otaInstallPolicy.d.ts.map +1 -1
- package/build/services/otaInstallPolicy.js +24 -3
- package/build/services/otaInstallPolicy.js.map +1 -1
- package/build/services/otaManifestUrl.d.ts +2 -0
- package/build/services/otaManifestUrl.d.ts.map +1 -0
- package/build/services/{asgOtaVersionUrl.js → otaManifestUrl.js} +15 -5
- package/build/services/otaManifestUrl.js.map +1 -0
- package/build/services/slimStreamStatus.d.ts +11 -0
- package/build/services/slimStreamStatus.d.ts.map +1 -1
- package/build/services/slimStreamStatus.js +14 -4
- package/build/services/slimStreamStatus.js.map +1 -1
- package/build/stores/apps.d.ts.map +1 -1
- package/build/stores/apps.js +11 -0
- package/build/stores/apps.js.map +1 -1
- package/build/stores/bluetoothSettingKeys.d.ts.map +1 -1
- package/build/stores/bluetoothSettingKeys.js +2 -0
- package/build/stores/bluetoothSettingKeys.js.map +1 -1
- package/build/stores/gallerySync.d.ts +2 -0
- package/build/stores/gallerySync.d.ts.map +1 -1
- package/build/stores/gallerySync.js +2 -0
- package/build/stores/gallerySync.js.map +1 -1
- package/build/stores/glasses.d.ts.map +1 -1
- package/build/stores/glasses.js +3 -0
- package/build/stores/glasses.js.map +1 -1
- package/build/stores/settings.d.ts +17 -0
- package/build/stores/settings.d.ts.map +1 -1
- package/build/stores/settings.js +157 -17
- package/build/stores/settings.js.map +1 -1
- package/build/types/applet.d.ts +2 -0
- package/build/types/applet.d.ts.map +1 -1
- package/build/types/applet.js.map +1 -1
- package/build/types/asg.d.ts +7 -0
- package/build/types/asg.d.ts.map +1 -1
- package/build/types/asg.js.map +1 -1
- package/build/types/enums.d.ts +1 -0
- package/build/types/enums.d.ts.map +1 -1
- package/build/types/enums.js +1 -0
- package/build/types/enums.js.map +1 -1
- package/build/types/hardware.d.ts +1 -0
- package/build/types/hardware.d.ts.map +1 -1
- package/build/types/hardware.js +14 -0
- package/build/types/hardware.js.map +1 -1
- package/build/utils/configuredDevHost.d.ts +6 -0
- package/build/utils/configuredDevHost.d.ts.map +1 -0
- package/build/utils/configuredDevHost.js +19 -0
- package/build/utils/configuredDevHost.js.map +1 -0
- package/build/utils/devMiniappLaunch.d.ts +19 -8
- package/build/utils/devMiniappLaunch.d.ts.map +1 -1
- package/build/utils/devMiniappLaunch.js +144 -21
- package/build/utils/devMiniappLaunch.js.map +1 -1
- package/build/utils/diagnosticContext.d.ts.map +1 -1
- package/build/utils/diagnosticContext.js +15 -17
- package/build/utils/diagnosticContext.js.map +1 -1
- package/build/utils/hardware/hardware.d.ts.map +1 -1
- package/build/utils/hardware/hardware.js +7 -3
- package/build/utils/hardware/hardware.js.map +1 -1
- package/build/utils/miniappDiagnostics.d.ts +64 -0
- package/build/utils/miniappDiagnostics.d.ts.map +1 -0
- package/build/utils/miniappDiagnostics.js +173 -0
- package/build/utils/miniappDiagnostics.js.map +1 -0
- package/build/utils/permissions/MediaLibraryPermissions.d.ts +11 -0
- package/build/utils/permissions/MediaLibraryPermissions.d.ts.map +1 -1
- package/build/utils/permissions/MediaLibraryPermissions.js +27 -4
- package/build/utils/permissions/MediaLibraryPermissions.js.map +1 -1
- package/build/utils/timers/timers.d.ts.map +1 -1
- package/build/utils/timers/timers.js +55 -18
- package/build/utils/timers/timers.js.map +1 -1
- package/package.json +25 -15
- package/src/assets/silence.wav +0 -0
- package/src/engine.ts +7 -2
- package/src/facades/dev.ts +17 -12
- package/src/facades/gallery.ts +1 -1
- package/src/facades/glasses.ts +17 -4
- package/src/facades/glassesSettings.ts +5 -0
- package/src/facades/miniapps.ts +7 -0
- package/src/facades/ota.ts +19 -4
- package/src/facades/pairing.ts +11 -7
- package/src/facades/permissions.ts +14 -0
- package/src/facades/phoneNotifications.ts +4 -13
- package/src/index.ts +26 -2
- package/src/internal.ts +3 -1
- package/src/react/MentraLiveOtaFlow.tsx +856 -0
- package/src/react/index.ts +7 -0
- package/src/react/useEngineSnapshot.ts +16 -0
- package/src/runtime/bootstrap.ts +33 -1
- package/src/runtime/scanQrSeam.ts +20 -0
- package/src/services/AppRegistry.ts +224 -149
- package/src/services/AudioCloudUplink.ts +23 -1
- package/src/services/AudioPlaybackService.ts +287 -38
- package/src/services/BlobStore.ts +22 -9
- package/src/services/CloudAudioSubscriptionSync.ts +13 -1
- package/src/services/CloudClientService.ts +96 -1
- package/src/services/DeviceEventRouter.ts +5 -5
- package/src/services/ForegroundLocationPermission.ts +24 -0
- package/src/services/GlassesSettingsSync.ts +9 -3
- package/src/services/GlassesStatusProjection.ts +16 -8
- package/src/services/HotspotOtaTransport.ts +184 -0
- package/src/services/HotspotShutdown.ts +41 -0
- package/src/services/LocalDisplayManager.ts +112 -21
- package/src/services/LocalMiniappRuntime.ts +967 -346
- package/src/services/LocalMiniappStorage.ts +82 -0
- package/src/services/LocalMiniappUserIdentity.ts +46 -0
- package/src/services/LocalSttFallbackCoordinator.ts +19 -12
- package/src/services/MicStateCoordinator.ts +169 -4
- package/src/services/MiniappLauncher.ts +30 -3
- package/src/services/MiniappLiveness.ts +24 -0
- package/src/services/NativeHttpResponse.ts +6 -0
- package/src/services/OtaArtifactDownloader.ts +312 -0
- package/src/services/OtaAutoChain.ts +106 -0
- package/src/services/OtaErrorMapping.ts +80 -0
- package/src/services/OtaInstallCoordinator.ts +645 -143
- package/src/services/OtaService.ts +11 -5
- package/src/services/OtaUpdateCheckService.ts +180 -20
- package/src/services/PhoneCalendarHelpers.ts +212 -0
- package/src/services/PhoneCalendarService.ts +65 -0
- package/src/services/PhoneCameraFovCoordinator.ts +210 -0
- package/src/services/PhoneNotificationsSync.ts +12 -10
- package/src/services/PhonePhotoCoordinator.ts +116 -18
- package/src/services/PhoneStreamCoordinator.ts +139 -25
- package/src/services/PhoneVideoCoordinator.ts +11 -0
- package/src/services/SceneRenderer.ts +16 -0
- package/src/services/SentenceTtsPipeline.ts +106 -0
- package/src/services/SupportProfileSync.ts +218 -0
- package/src/services/TranscriptionRouting.ts +37 -0
- package/src/services/TtsTextSanitizer.ts +66 -0
- package/src/services/WifiAdbRequest.ts +53 -0
- package/src/services/asg/asgCameraApi.ts +615 -33
- package/src/services/asg/cameraRollExportCoordinator.ts +627 -0
- package/src/services/asg/cameraRollExportLedger.ts +122 -0
- package/src/services/asg/galleryNotices.ts +1 -0
- package/src/services/asg/galleryPathMigration.ts +22 -0
- package/src/services/asg/gallerySettingsService.ts +3 -0
- package/src/services/asg/gallerySyncService.ts +184 -73
- package/src/services/asg/galleryTransferLedger.ts +312 -0
- package/src/services/asg/localNetworkTransport.ts +169 -0
- package/src/services/asg/localStorageService.ts +179 -24
- package/src/services/asg/mediaProcessingQueue.ts +209 -62
- package/src/services/audioPlaybackAssets.ts +8 -0
- package/src/services/gallerySyncClock.ts +1 -1
- package/src/services/glassesClockSync.ts +2 -2
- package/src/services/manifestActions.ts +30 -0
- package/src/services/otaDisplayState.ts +57 -16
- package/src/services/otaInstallPolicy.ts +29 -3
- package/src/services/{asgOtaVersionUrl.ts → otaManifestUrl.ts} +16 -4
- package/src/services/slimStreamStatus.ts +16 -5
- package/src/stores/apps.ts +12 -0
- package/src/stores/bluetoothSettingKeys.ts +2 -0
- package/src/stores/gallerySync.ts +4 -0
- package/src/stores/glasses.ts +3 -0
- package/src/stores/settings.ts +179 -18
- package/src/types/applet.ts +2 -0
- package/src/types/asg.ts +7 -0
- package/src/types/enums.ts +2 -1
- package/src/types/hardware.ts +17 -0
- package/src/utils/configuredDevHost.ts +17 -0
- package/src/utils/devMiniappLaunch.ts +151 -23
- package/src/utils/diagnosticContext.ts +17 -17
- package/src/utils/hardware/hardware.ts +7 -9
- package/src/utils/miniappDiagnostics.ts +226 -0
- package/src/utils/permissions/MediaLibraryPermissions.ts +35 -4
- package/src/utils/timers/timers.ts +57 -21
- package/build/services/asgOtaVersionUrl.d.ts +0 -2
- package/build/services/asgOtaVersionUrl.d.ts.map +0 -1
- package/build/services/asgOtaVersionUrl.js.map +0 -1
|
@@ -12,7 +12,8 @@ import { INVALID_DOWNLOADED_MEDIA, validateDownloadedMediaFile } from "./gallery
|
|
|
12
12
|
import { reportInvalidGalleryMedia } from "./GalleryMediaIntegrityReportService";
|
|
13
13
|
import { useGallerySyncStore } from "../../stores/gallerySync";
|
|
14
14
|
import { BgTimer } from "../../utils/timers";
|
|
15
|
-
import {
|
|
15
|
+
import { galleryTransferLedger } from "./galleryTransferLedger";
|
|
16
|
+
import { cameraRollExportCoordinator } from "./cameraRollExportCoordinator";
|
|
16
17
|
const TAG = "[MediaProcessingQueue]";
|
|
17
18
|
class MediaProcessingQueue {
|
|
18
19
|
queue = [];
|
|
@@ -50,7 +51,7 @@ class MediaProcessingQueue {
|
|
|
50
51
|
return this.queue.length > 0 || this.isRunning;
|
|
51
52
|
}
|
|
52
53
|
/** Returns a promise that resolves when the queue is fully drained, or rejects on timeout. */
|
|
53
|
-
waitUntilDrained(timeoutMs =
|
|
54
|
+
waitUntilDrained(timeoutMs = 4 * 60 * 60 * 1000) {
|
|
54
55
|
if (!this.hasPending)
|
|
55
56
|
return Promise.resolve();
|
|
56
57
|
return new Promise((resolve, reject) => {
|
|
@@ -71,6 +72,69 @@ class MediaProcessingQueue {
|
|
|
71
72
|
check();
|
|
72
73
|
});
|
|
73
74
|
}
|
|
75
|
+
/** Retry durable export/ack work after an app restart without downloading media again. */
|
|
76
|
+
async retryPending() {
|
|
77
|
+
let retried = 0;
|
|
78
|
+
let failed = 0;
|
|
79
|
+
for (let entry of galleryTransferLedger.pendingRecovery()) {
|
|
80
|
+
try {
|
|
81
|
+
if (entry.state === "RESTORE_PENDING") {
|
|
82
|
+
await asgCameraApi.restoreCapture(entry.captureId);
|
|
83
|
+
galleryTransferLedger.transition(entry.captureId, "DISCOVERED", { lastError: undefined });
|
|
84
|
+
retried++;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (!entry.finalPath || !(await RNFS.exists(entry.finalPath))) {
|
|
88
|
+
throw new Error(`Recovery file is missing for ${entry.captureId}`);
|
|
89
|
+
}
|
|
90
|
+
// Rebuild a missing app index before any source acknowledgement, even when camera-roll
|
|
91
|
+
// saving is disabled or an export receipt was already committed before restart.
|
|
92
|
+
const downloadedFile = await this.recoverDownloadedFile(entry);
|
|
93
|
+
if (entry.state === "EXPORT_PENDING" || entry.state === "INDEXED") {
|
|
94
|
+
const shouldAutoSave = await cameraRollExportCoordinator.isAutoSaveEnabled();
|
|
95
|
+
entry = galleryTransferLedger.update(entry.captureId, { shouldAutoSave, lastError: undefined });
|
|
96
|
+
if (shouldAutoSave) {
|
|
97
|
+
if (entry.state !== "EXPORT_PENDING") {
|
|
98
|
+
entry = galleryTransferLedger.transition(entry.captureId, "EXPORT_PENDING");
|
|
99
|
+
}
|
|
100
|
+
const receipt = await cameraRollExportCoordinator.exportForSource(downloadedFile, entry.captureId);
|
|
101
|
+
entry = receipt
|
|
102
|
+
? galleryTransferLedger.transition(entry.captureId, "EXPORTED", { assetReceipt: receipt })
|
|
103
|
+
: galleryTransferLedger.transition(entry.captureId, "INDEXED", {
|
|
104
|
+
shouldAutoSave: false,
|
|
105
|
+
lastError: undefined,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
else if (entry.state === "EXPORT_PENDING") {
|
|
109
|
+
entry = galleryTransferLedger.transition(entry.captureId, "INDEXED", {
|
|
110
|
+
shouldAutoSave: false,
|
|
111
|
+
lastError: undefined,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
entry = galleryTransferLedger.transition(entry.captureId, "ACK_PENDING");
|
|
116
|
+
await this.acknowledgeEntry(entry);
|
|
117
|
+
galleryTransferLedger.transition(entry.captureId, "TRASHED", { lastError: undefined });
|
|
118
|
+
retried++;
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
galleryTransferLedger.recordFailure(entry.captureId, error);
|
|
122
|
+
failed++;
|
|
123
|
+
console.warn(`${TAG} Recovery remains pending for ${entry.captureId}:`, error);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return { retried, failed };
|
|
127
|
+
}
|
|
128
|
+
async acknowledgeEntry(entry) {
|
|
129
|
+
if (entry.protocolVersion >= 3) {
|
|
130
|
+
await asgCameraApi.acknowledgeCapture(entry.captureId, entry.ackId);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const result = await asgCameraApi.deleteFilesFromServer(entry.deleteFromGlasses.length > 0 ? entry.deleteFromGlasses : [entry.captureId]);
|
|
134
|
+
if (result.failed.length > 0 || result.deleted.length === 0) {
|
|
135
|
+
throw new Error(`Glasses did not acknowledge ${entry.captureId}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
74
138
|
/** Process items one at a time. */
|
|
75
139
|
async processLoop() {
|
|
76
140
|
if (this.isRunning)
|
|
@@ -86,6 +150,10 @@ class MediaProcessingQueue {
|
|
|
86
150
|
catch (error) {
|
|
87
151
|
console.error(`${TAG} Error processing ${item.id}:`, error);
|
|
88
152
|
processFailed = true;
|
|
153
|
+
const store = useGallerySyncStore.getState();
|
|
154
|
+
if (!store.failedFiles.includes(item.id)) {
|
|
155
|
+
store.onFileFailed(item.id, error instanceof Error ? error.message : String(error));
|
|
156
|
+
}
|
|
89
157
|
}
|
|
90
158
|
// Exit if generation changed (reset was called during processing)
|
|
91
159
|
if (this.generation !== myGeneration)
|
|
@@ -96,9 +164,8 @@ class MediaProcessingQueue {
|
|
|
96
164
|
store.onFileProcessed(item.id);
|
|
97
165
|
}
|
|
98
166
|
else {
|
|
99
|
-
// Failure
|
|
100
|
-
//
|
|
101
|
-
// Still clear the processingFiles entry so the UI doesn't show it as in-progress.
|
|
167
|
+
// Failure is counted exactly once above. Still clear the processingFiles entry so the UI
|
|
168
|
+
// does not show it as in-progress.
|
|
102
169
|
const current = store.processingFiles;
|
|
103
170
|
if (current.has(item.id)) {
|
|
104
171
|
const newSet = new Set(current);
|
|
@@ -116,6 +183,20 @@ class MediaProcessingQueue {
|
|
|
116
183
|
async processItem(item) {
|
|
117
184
|
const startTime = Date.now();
|
|
118
185
|
let filePathToSave = item.primaryPath;
|
|
186
|
+
let ledgerEntry = galleryTransferLedger.get(item.id);
|
|
187
|
+
if (!ledgerEntry) {
|
|
188
|
+
ledgerEntry = galleryTransferLedger.ensureCapture({
|
|
189
|
+
capture_id: item.id,
|
|
190
|
+
type: item.type,
|
|
191
|
+
timestamp: item.timestamp || Date.now(),
|
|
192
|
+
total_size: item.totalSize,
|
|
193
|
+
files: (item.deleteFromGlasses?.length ? item.deleteFromGlasses : [item.id]).map((name, index) => ({
|
|
194
|
+
name,
|
|
195
|
+
size: index === 0 ? item.totalSize : 0,
|
|
196
|
+
role: index === 0 ? "primary" : "sidecar",
|
|
197
|
+
})),
|
|
198
|
+
}, item.protocolVersion || 2);
|
|
199
|
+
}
|
|
119
200
|
// 1. HDR merge (photos with brackets only)
|
|
120
201
|
if (item.shouldProcess && item.type === "photo" && item.bracketPaths && item.bracketPaths.length >= 3) {
|
|
121
202
|
try {
|
|
@@ -188,8 +269,8 @@ class MediaProcessingQueue {
|
|
|
188
269
|
});
|
|
189
270
|
}
|
|
190
271
|
catch (validationError) {
|
|
191
|
-
const reason = validationError?.message?.includes(INVALID_DOWNLOADED_MEDIA)
|
|
192
|
-
validationError.message
|
|
272
|
+
const reason = validationError?.message?.includes(INVALID_DOWNLOADED_MEDIA)
|
|
273
|
+
? validationError.message
|
|
193
274
|
: `${INVALID_DOWNLOADED_MEDIA}: ${item.id}`;
|
|
194
275
|
console.error(`${TAG} Validation failed for ${item.id}: ${reason}`);
|
|
195
276
|
reportInvalidGalleryMedia({
|
|
@@ -204,54 +285,69 @@ class MediaProcessingQueue {
|
|
|
204
285
|
});
|
|
205
286
|
const store = useGallerySyncStore.getState();
|
|
206
287
|
store.onFileFailed(item.id, reason);
|
|
207
|
-
|
|
208
|
-
for (const intermediate of [
|
|
209
|
-
item.primaryPath + ".hdr.jpg",
|
|
210
|
-
item.primaryPath + ".processed.jpg",
|
|
211
|
-
item.primaryPath + ".stabilized.mp4",
|
|
212
|
-
]) {
|
|
213
|
-
if (intermediate !== filePathToSave) {
|
|
214
|
-
await RNFS.unlink(intermediate).catch(() => { });
|
|
215
|
-
}
|
|
216
|
-
}
|
|
288
|
+
galleryTransferLedger.recordFailure(item.id, validationError);
|
|
217
289
|
throw new Error(reason);
|
|
218
290
|
}
|
|
219
|
-
// 6.
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
if (success) {
|
|
223
|
-
console.log(`${TAG} ✅ Saved to camera roll: ${item.id}`);
|
|
224
|
-
}
|
|
225
|
-
else {
|
|
226
|
-
console.warn(`${TAG} ❌ Failed to save to camera roll: ${item.id}`);
|
|
227
|
-
// D1: Surface camera roll save failures to the UI
|
|
228
|
-
const store = useGallerySyncStore.getState();
|
|
229
|
-
store.onFileFailed(item.id, "camera roll save failed");
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
// 7. Save metadata
|
|
291
|
+
// 6. Commit the app-local index before any export or source acknowledgement. Use the final
|
|
292
|
+
// on-disk output metadata for camera-roll identity: processing can change byte size, while
|
|
293
|
+
// recovery reconstructs this row from the same file and the transfer ledger timestamp.
|
|
233
294
|
const isVideo = item.type === "video";
|
|
295
|
+
const finalFileStat = await RNFS.stat(filePathToSave);
|
|
296
|
+
const finalFileSize = Number(finalFileStat.size);
|
|
234
297
|
const downloadedFile = localStorageService.convertToDownloadedFile({
|
|
235
298
|
name: item.id,
|
|
236
299
|
url: "",
|
|
237
300
|
download: "",
|
|
238
|
-
size:
|
|
239
|
-
modified:
|
|
301
|
+
size: finalFileSize,
|
|
302
|
+
modified: ledgerEntry.timestamp,
|
|
240
303
|
is_video: isVideo,
|
|
241
304
|
thumbnail_data: item.thumbnailData,
|
|
242
305
|
duration: item.duration,
|
|
243
306
|
filePath: filePathToSave,
|
|
244
307
|
glassesModel: item.glassesModel,
|
|
245
308
|
}, filePathToSave, localThumbnailPath, item.glassesModel);
|
|
309
|
+
downloadedFile.capture_id = item.id;
|
|
310
|
+
const shouldAutoSave = await cameraRollExportCoordinator.isAutoSaveEnabled();
|
|
246
311
|
try {
|
|
247
312
|
await localStorageService.saveDownloadedFile(downloadedFile);
|
|
313
|
+
ledgerEntry = galleryTransferLedger.transition(item.id, "INDEXED", {
|
|
314
|
+
finalPath: filePathToSave,
|
|
315
|
+
thumbnailPath: localThumbnailPath,
|
|
316
|
+
shouldAutoSave,
|
|
317
|
+
});
|
|
318
|
+
await cameraRollExportCoordinator.recordIndexed(downloadedFile, shouldAutoSave, shouldAutoSave ? "SOURCE_BARRIER" : "HISTORICAL_BACKFILL", item.id);
|
|
248
319
|
}
|
|
249
320
|
catch (metadataError) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
await RNFS.unlink(filePathToSave).catch(() => { });
|
|
321
|
+
console.error(`${TAG} Metadata save failed for ${item.id}; retaining local and glasses copies:`, metadataError);
|
|
322
|
+
galleryTransferLedger.recordFailure(item.id, metadataError);
|
|
253
323
|
throw metadataError;
|
|
254
324
|
}
|
|
325
|
+
// 7. While enabled, export is a durable, receipted step whose failures block ack. Turning
|
|
326
|
+
// auto-save off safely falls back to the already-verified app-local copy and later backfill.
|
|
327
|
+
if (shouldAutoSave) {
|
|
328
|
+
galleryTransferLedger.transition(item.id, "EXPORT_PENDING");
|
|
329
|
+
let receipt;
|
|
330
|
+
try {
|
|
331
|
+
receipt = await cameraRollExportCoordinator.exportForSource(downloadedFile, item.id);
|
|
332
|
+
}
|
|
333
|
+
catch (error) {
|
|
334
|
+
galleryTransferLedger.recordFailure(item.id, error);
|
|
335
|
+
throw error;
|
|
336
|
+
}
|
|
337
|
+
if (receipt) {
|
|
338
|
+
ledgerEntry = galleryTransferLedger.transition(item.id, "EXPORTED", {
|
|
339
|
+
assetReceipt: receipt,
|
|
340
|
+
});
|
|
341
|
+
console.log(`${TAG} ✅ Saved to camera roll with receipt: ${item.id}`);
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
ledgerEntry = galleryTransferLedger.transition(item.id, "INDEXED", {
|
|
345
|
+
shouldAutoSave: false,
|
|
346
|
+
lastError: undefined,
|
|
347
|
+
});
|
|
348
|
+
console.log(`${TAG} Automatic camera-roll saving was disabled; keeping app-local copy: ${item.id}`);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
255
351
|
// S4: Clean up intermediate processing files
|
|
256
352
|
const intermediates = [
|
|
257
353
|
item.primaryPath + ".hdr.jpg",
|
|
@@ -275,8 +371,8 @@ class MediaProcessingQueue {
|
|
|
275
371
|
name: item.id,
|
|
276
372
|
url: localFileUrl,
|
|
277
373
|
download: localFileUrl,
|
|
278
|
-
size:
|
|
279
|
-
modified:
|
|
374
|
+
size: finalFileSize,
|
|
375
|
+
modified: ledgerEntry.timestamp,
|
|
280
376
|
is_video: isVideo,
|
|
281
377
|
filePath: filePathToSave,
|
|
282
378
|
mime_type: isVideo ? "video/mp4" : "image/jpeg",
|
|
@@ -284,36 +380,71 @@ class MediaProcessingQueue {
|
|
|
284
380
|
thumbnailPath: localThumbUrl,
|
|
285
381
|
duration: item.duration,
|
|
286
382
|
});
|
|
287
|
-
// 9.
|
|
288
|
-
//
|
|
289
|
-
|
|
290
|
-
|
|
383
|
+
// 9. Acknowledge only after VERIFIED -> INDEXED -> (EXPORTED). The server turns this into
|
|
384
|
+
// recoverable trash; failures remain ACK_PENDING and are retried without re-downloading.
|
|
385
|
+
const localFileExists = await RNFS.exists(filePathToSave);
|
|
386
|
+
const localStat = localFileExists ? await RNFS.stat(filePathToSave) : null;
|
|
387
|
+
if (!localStat || localStat.size <= 0) {
|
|
388
|
+
const error = new Error(`Cannot acknowledge ${item.id}: committed local file is missing or empty`);
|
|
389
|
+
galleryTransferLedger.recordFailure(item.id, error);
|
|
390
|
+
throw error;
|
|
391
|
+
}
|
|
392
|
+
ledgerEntry = galleryTransferLedger.transition(item.id, "ACK_PENDING");
|
|
393
|
+
try {
|
|
394
|
+
await this.acknowledgeEntry(ledgerEntry);
|
|
395
|
+
galleryTransferLedger.transition(item.id, "TRASHED", { lastError: undefined });
|
|
396
|
+
}
|
|
397
|
+
catch (ackError) {
|
|
398
|
+
galleryTransferLedger.recordFailure(item.id, ackError);
|
|
399
|
+
throw ackError;
|
|
400
|
+
}
|
|
401
|
+
const elapsed = Date.now() - startTime;
|
|
402
|
+
console.log(`${TAG} ✅ Finished ${item.id} in ${elapsed}ms`);
|
|
403
|
+
}
|
|
404
|
+
/** Rebuild a missing app-local index row from the durable transfer ledger. */
|
|
405
|
+
async recoverDownloadedFile(entry) {
|
|
406
|
+
if (!entry.finalPath)
|
|
407
|
+
throw new Error(`Recovery file is missing for ${entry.captureId}`);
|
|
408
|
+
// The transfer ledger is the durable source of truth for a committed generation. A local
|
|
409
|
+
// index row can survive an interrupted replacement and still point at an older/missing path,
|
|
410
|
+
// or contain the pre-processing size. Only reuse it when its path and identity still match the
|
|
411
|
+
// ledger's committed file; otherwise rebuild the row before export or source acknowledgement.
|
|
412
|
+
const finalPath = entry.finalPath.replace(/^file:\/\//, "");
|
|
413
|
+
const indexed = await localStorageService.getDownloadedFile(entry.captureId);
|
|
414
|
+
if (indexed) {
|
|
291
415
|
try {
|
|
292
|
-
const
|
|
293
|
-
if (
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
if (localStat.size === 0) {
|
|
299
|
-
console.error(`${TAG} Skipping glasses deletion for ${item.id}: local file is 0 bytes`);
|
|
300
|
-
}
|
|
301
|
-
else if (item.totalSize > 0 && localStat.size < item.totalSize * 0.5) {
|
|
302
|
-
// If local file is less than 50% of expected size, something went wrong
|
|
303
|
-
console.error(`${TAG} Skipping glasses deletion for ${item.id}: local file ${localStat.size} bytes is much smaller than expected ${item.totalSize} bytes`);
|
|
304
|
-
}
|
|
305
|
-
else {
|
|
306
|
-
await asgCameraApi.deleteFilesFromServer(item.deleteFromGlasses);
|
|
307
|
-
console.log(`${TAG} 🗑️ Deleted ${item.deleteFromGlasses.join(", ")} from glasses`);
|
|
416
|
+
const indexedPath = indexed.filePath?.replace(/^file:\/\//, "");
|
|
417
|
+
if (indexedPath === finalPath && (await RNFS.exists(indexedPath))) {
|
|
418
|
+
const indexedStat = await RNFS.stat(indexedPath);
|
|
419
|
+
const indexedSize = Number(indexedStat.size);
|
|
420
|
+
if (indexedSize > 0 && indexed.size === indexedSize && indexed.modified === entry.timestamp) {
|
|
421
|
+
return indexed;
|
|
308
422
|
}
|
|
309
423
|
}
|
|
310
424
|
}
|
|
311
|
-
catch (
|
|
312
|
-
console.warn(`${TAG}
|
|
425
|
+
catch (error) {
|
|
426
|
+
console.warn(`${TAG} Ignoring stale local index for ${entry.captureId}:`, error);
|
|
313
427
|
}
|
|
314
428
|
}
|
|
315
|
-
const
|
|
316
|
-
|
|
429
|
+
const stat = await RNFS.stat(finalPath);
|
|
430
|
+
const finalSize = Number(stat.size);
|
|
431
|
+
if (!Number.isFinite(finalSize) || finalSize <= 0) {
|
|
432
|
+
throw new Error(`Recovery file is missing or empty for ${entry.captureId}`);
|
|
433
|
+
}
|
|
434
|
+
const recovered = localStorageService.convertToDownloadedFile({
|
|
435
|
+
name: entry.captureId,
|
|
436
|
+
url: "",
|
|
437
|
+
download: "",
|
|
438
|
+
size: finalSize,
|
|
439
|
+
modified: entry.timestamp,
|
|
440
|
+
mime_type: entry.captureType === "video" ? "video/mp4" : "image/jpeg",
|
|
441
|
+
is_video: entry.captureType === "video",
|
|
442
|
+
filePath: finalPath,
|
|
443
|
+
}, finalPath, entry.thumbnailPath);
|
|
444
|
+
recovered.capture_id = entry.captureId;
|
|
445
|
+
recovered.assetReceipt = entry.assetReceipt;
|
|
446
|
+
await localStorageService.saveDownloadedFile(recovered);
|
|
447
|
+
return recovered;
|
|
317
448
|
}
|
|
318
449
|
}
|
|
319
450
|
export const mediaProcessingQueue = new MediaProcessingQueue();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mediaProcessingQueue.js","sourceRoot":"","sources":["../../../src/services/asg/mediaProcessingQueue.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Media Processing Queue\n *\n * Decouples media processing (HDR merge, color correction, stabilization, camera roll save)\n * from the download pipeline. Downloads push items here; processing runs independently.\n */\n\nimport * as RNFS from \"@dr.pogodin/react-native-fs\"\nimport CrustModule from \"@mentra/crust\"\n\nimport {asgCameraApi} from \"./asgCameraApi\"\nimport {localStorageService} from \"./localStorageService\"\nimport {INVALID_DOWNLOADED_MEDIA, validateDownloadedMediaFile} from \"./galleryMediaValidation\"\nimport {reportInvalidGalleryMedia} from \"./GalleryMediaIntegrityReportService\"\nimport {useGallerySyncStore} from \"../../stores/gallerySync\"\nimport {BgTimer} from \"../../utils/timers\"\nimport {MediaLibraryPermissions} from \"../../utils/permissions/MediaLibraryPermissions\"\n\nconst TAG = \"[MediaProcessingQueue]\"\n\nexport interface ProcessingItem {\n /** Unique ID — capture_id (v2) or file name (v1) */\n id: string\n type: \"photo\" | \"video\"\n /** Path to the primary downloaded file */\n primaryPath: string\n /** HDR bracket paths (v2 only) */\n bracketPaths?: string[]\n /** IMU sidecar path for video stabilization */\n sidecarPath?: string\n /** Thumbnail base64 data */\n thumbnailData?: string\n /** Capture directory for saving thumbnail */\n captureDir?: string\n /** Original capture timestamp */\n timestamp?: number\n /** Total file size */\n totalSize: number\n /** Video duration in ms */\n duration?: number\n /** Glasses model */\n glassesModel?: string\n /** Whether to process (lens/color/stabilization) */\n shouldProcess: boolean\n /** Whether to auto-save to camera roll */\n shouldAutoSave: boolean\n /** Pre-downloaded thumbnail path (v1 legacy sync) */\n thumbnailPath?: string\n /** File names to delete from glasses after processing completes */\n deleteFromGlasses?: string[]\n}\n\nclass MediaProcessingQueue {\n private queue: ProcessingItem[] = []\n private isRunning = false\n private aborted = false\n private generation = 0 // C2: incremented on reset() to invalidate stale processLoop()\n\n /** Add an item to the processing queue. Starts processing if not already running. */\n enqueue(item: ProcessingItem): void {\n this.queue.push(item)\n console.log(`${TAG} Enqueued ${item.id} (${item.type}), queue size: ${this.queue.length}`)\n\n // Only mark as processing if we'll actually process this item\n if (item.shouldProcess) {\n const store = useGallerySyncStore.getState()\n store.onFileProcessing(item.id)\n }\n\n if (!this.isRunning) {\n this.processLoop()\n }\n }\n\n /** Cancel all pending processing. */\n abort(): void {\n this.aborted = true\n this.queue = []\n console.log(`${TAG} Aborted`)\n }\n\n /** Reset state for a new sync session. */\n reset(): void {\n this.queue = []\n this.isRunning = false\n this.aborted = false\n this.generation++ // C2: invalidate any running processLoop\n }\n\n /** Returns true if there are items queued or currently processing. */\n get hasPending(): boolean {\n return this.queue.length > 0 || this.isRunning\n }\n\n /** Returns a promise that resolves when the queue is fully drained, or rejects on timeout. */\n waitUntilDrained(timeoutMs: number = 600000): Promise<void> {\n if (!this.hasPending) return Promise.resolve()\n return new Promise((resolve, reject) => {\n const deadline = Date.now() + timeoutMs\n const check = () => {\n if (!this.hasPending || this.aborted) {\n resolve()\n } else if (Date.now() >= deadline) {\n console.error(`${TAG} waitUntilDrained timed out after ${timeoutMs}ms, aborting queue`)\n this.abort()\n reject(new Error(`Processing queue timed out after ${timeoutMs / 1000}s`))\n } else {\n BgTimer.setTimeout(check, 200)\n }\n }\n check()\n })\n }\n\n /** Process items one at a time. */\n private async processLoop(): Promise<void> {\n if (this.isRunning) return\n this.isRunning = true\n const myGeneration = this.generation // C2: capture generation to detect reset()\n\n while (this.queue.length > 0 && !this.aborted && this.generation === myGeneration) {\n const item = this.queue.shift()!\n let processFailed = false\n try {\n await this.processItem(item)\n } catch (error) {\n console.error(`${TAG} Error processing ${item.id}:`, error)\n processFailed = true\n }\n\n // Exit if generation changed (reset was called during processing)\n if (this.generation !== myGeneration) break\n\n const store = useGallerySyncStore.getState()\n if (!processFailed) {\n // Success: increment processedFiles and remove from processingFiles set.\n store.onFileProcessed(item.id)\n } else {\n // Failure: processItem already called onFileFailed. Calling onFileProcessed\n // here would double-count the item (counted as both failed AND processed).\n // Still clear the processingFiles entry so the UI doesn't show it as in-progress.\n const current = store.processingFiles\n if (current.has(item.id)) {\n const newSet = new Set(current)\n newSet.delete(item.id)\n useGallerySyncStore.setState({processingFiles: newSet})\n }\n }\n }\n\n // Only clear isRunning if this loop owns the current generation\n if (this.generation === myGeneration) {\n this.isRunning = false\n }\n }\n\n /** Process a single item through the full pipeline. */\n private async processItem(item: ProcessingItem): Promise<void> {\n const startTime = Date.now()\n let filePathToSave = item.primaryPath\n\n // 1. HDR merge (photos with brackets only)\n if (item.shouldProcess && item.type === \"photo\" && item.bracketPaths && item.bracketPaths.length >= 3) {\n try {\n const underPath = item.bracketPaths.find((p) => p.includes(\"ev-2\")) || item.bracketPaths[0]\n const normalPath = item.bracketPaths.find((p) => p.includes(\"ev0\")) || item.bracketPaths[1]\n const overPath = item.bracketPaths.find((p) => p.includes(\"ev2\") && !p.includes(\"ev-2\")) || item.bracketPaths[2]\n\n const hdrPath = item.primaryPath + \".hdr.jpg\"\n const hdrResult = await CrustModule.mergeHdrBrackets(underPath, normalPath, overPath, hdrPath)\n if (hdrResult.success && hdrResult.outputPath) {\n filePathToSave = hdrResult.outputPath\n console.log(`${TAG} HDR merged ${item.id} in ${hdrResult.processingTimeMs}ms`)\n }\n } catch (hdrError) {\n console.warn(`${TAG} HDR merge error for ${item.id}, continuing:`, hdrError)\n }\n }\n\n // 2. Image processing (lens + color correction)\n if (item.shouldProcess && item.type === \"photo\") {\n try {\n const processedPath = filePathToSave + \".processed.jpg\"\n const result = await CrustModule.processGalleryImage(filePathToSave, processedPath, {\n lensCorrection: true,\n colorCorrection: true,\n })\n if (result.success && result.outputPath) {\n filePathToSave = result.outputPath\n console.log(`${TAG} 🎨 Processed ${item.id} in ${result.processingTimeMs}ms`)\n }\n } catch (procError) {\n console.warn(`${TAG} Processing error for ${item.id}, using original:`, procError)\n }\n }\n\n // 3. Video stabilization + color correction\n if (item.shouldProcess && item.type === \"video\" && item.sidecarPath) {\n try {\n const stabilizedPath = item.primaryPath + \".stabilized.mp4\"\n const result = await CrustModule.stabilizeVideo(item.primaryPath, item.sidecarPath, stabilizedPath)\n if (result.success && result.outputPath) {\n filePathToSave = result.outputPath\n console.log(`${TAG} 📹 Stabilized ${item.id} in ${result.processingTimeMs}ms`)\n }\n } catch (stabError) {\n console.warn(`${TAG} Stabilization error for ${item.id}, using original:`, stabError)\n }\n }\n\n // 4. Save thumbnail to disk (or use pre-downloaded thumbnail from v1 sync)\n let localThumbnailPath: string | undefined = item.thumbnailPath\n if (item.thumbnailData && item.captureDir) {\n try {\n const thumbPath = `${item.captureDir}/.thumb.jpg`\n const base64Data = item.thumbnailData.startsWith(\"data:\")\n ? item.thumbnailData.split(\",\")[1]\n : item.thumbnailData\n await RNFS.writeFile(thumbPath, base64Data, \"base64\")\n localThumbnailPath = thumbPath\n } catch (thumbError) {\n console.warn(`${TAG} Failed to save thumbnail for ${item.id}:`, thumbError)\n }\n }\n\n // 5. Validate local file before persisting metadata or deleting from glasses\n try {\n await validateDownloadedMediaFile({\n path: filePathToSave,\n name: item.id,\n mediaKind: item.type,\n })\n } catch (validationError: any) {\n const reason =\n validationError?.message?.includes(INVALID_DOWNLOADED_MEDIA) ?\n validationError.message\n : `${INVALID_DOWNLOADED_MEDIA}: ${item.id}`\n console.error(`${TAG} Validation failed for ${item.id}: ${reason}`)\n reportInvalidGalleryMedia({\n name: item.id,\n path: filePathToSave,\n mediaKind: item.type,\n stage: \"processing_validation\",\n reason,\n expectedSize: item.totalSize,\n duration: item.duration,\n glassesModel: item.glassesModel,\n })\n const store = useGallerySyncStore.getState()\n store.onFileFailed(item.id, reason)\n await RNFS.unlink(filePathToSave).catch(() => {})\n for (const intermediate of [\n item.primaryPath + \".hdr.jpg\",\n item.primaryPath + \".processed.jpg\",\n item.primaryPath + \".stabilized.mp4\",\n ]) {\n if (intermediate !== filePathToSave) {\n await RNFS.unlink(intermediate).catch(() => {})\n }\n }\n throw new Error(reason)\n }\n\n // 6. Save to camera roll\n if (item.shouldAutoSave) {\n const success = await MediaLibraryPermissions.saveToLibrary(filePathToSave, item.timestamp)\n if (success) {\n console.log(`${TAG} ✅ Saved to camera roll: ${item.id}`)\n } else {\n console.warn(`${TAG} ❌ Failed to save to camera roll: ${item.id}`)\n // D1: Surface camera roll save failures to the UI\n const store = useGallerySyncStore.getState()\n store.onFileFailed(item.id, \"camera roll save failed\")\n }\n }\n\n // 7. Save metadata\n const isVideo = item.type === \"video\"\n const downloadedFile = localStorageService.convertToDownloadedFile(\n {\n name: item.id,\n url: \"\",\n download: \"\",\n size: item.totalSize,\n modified: item.timestamp || Date.now(),\n is_video: isVideo,\n thumbnail_data: item.thumbnailData,\n duration: item.duration,\n filePath: filePathToSave,\n glassesModel: item.glassesModel,\n },\n filePathToSave,\n localThumbnailPath,\n item.glassesModel,\n )\n try {\n await localStorageService.saveDownloadedFile(downloadedFile)\n } catch (metadataError) {\n // D2: Clean up orphaned file if metadata save fails, then re-throw\n console.error(`${TAG} Metadata save failed for ${item.id}, cleaning up file:`, metadataError)\n await RNFS.unlink(filePathToSave).catch(() => {})\n throw metadataError\n }\n\n // S4: Clean up intermediate processing files\n const intermediates = [\n item.primaryPath + \".hdr.jpg\",\n item.primaryPath + \".processed.jpg\",\n item.primaryPath + \".stabilized.mp4\",\n ]\n for (const intermediate of intermediates) {\n if (intermediate !== filePathToSave) {\n RNFS.unlink(intermediate).catch(() => {}) // fire-and-forget\n }\n }\n\n // 8. Update file in sync queue with local paths for gallery display\n const store = useGallerySyncStore.getState()\n const localFileUrl = filePathToSave.startsWith(\"file://\") ? filePathToSave : `file://${filePathToSave}`\n const localThumbUrl = localThumbnailPath\n ? localThumbnailPath.startsWith(\"file://\")\n ? localThumbnailPath\n : `file://${localThumbnailPath}`\n : undefined\n store.updateFileInQueue(item.id, {\n name: item.id,\n url: localFileUrl,\n download: localFileUrl,\n size: item.totalSize,\n modified: item.timestamp || Date.now(),\n is_video: isVideo,\n filePath: filePathToSave,\n mime_type: isVideo ? \"video/mp4\" : \"image/jpeg\",\n thumbnail_data: item.thumbnailData,\n thumbnailPath: localThumbUrl,\n duration: item.duration,\n })\n\n // 9. Delete from glasses now that processing is complete — but only if the\n // local file actually exists and has data. If the download was truncated or\n // processing failed silently, we must not destroy the only good copy.\n if (item.deleteFromGlasses && item.deleteFromGlasses.length > 0) {\n try {\n const localFileExists = await RNFS.exists(filePathToSave)\n if (!localFileExists) {\n console.error(`${TAG} Skipping glasses deletion for ${item.id}: local file missing at ${filePathToSave}`)\n } else {\n const localStat = await RNFS.stat(filePathToSave)\n if (localStat.size === 0) {\n console.error(`${TAG} Skipping glasses deletion for ${item.id}: local file is 0 bytes`)\n } else if (item.totalSize > 0 && localStat.size < item.totalSize * 0.5) {\n // If local file is less than 50% of expected size, something went wrong\n console.error(\n `${TAG} Skipping glasses deletion for ${item.id}: local file ${localStat.size} bytes is much smaller than expected ${item.totalSize} bytes`,\n )\n } else {\n await asgCameraApi.deleteFilesFromServer(item.deleteFromGlasses)\n console.log(`${TAG} 🗑️ Deleted ${item.deleteFromGlasses.join(\", \")} from glasses`)\n }\n }\n } catch (deleteError) {\n console.warn(`${TAG} Delete from glasses failed for ${item.id} (non-fatal):`, deleteError)\n }\n }\n\n const elapsed = Date.now() - startTime\n console.log(`${TAG} ✅ Finished ${item.id} in ${elapsed}ms`)\n }\n}\n\nexport const mediaProcessingQueue = new MediaProcessingQueue()\n"]}
|
|
1
|
+
{"version":3,"file":"mediaProcessingQueue.js","sourceRoot":"","sources":["../../../src/services/asg/mediaProcessingQueue.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Media Processing Queue\n *\n * Decouples media processing (HDR merge, color correction, stabilization, camera roll save)\n * from the download pipeline. Downloads push items here; processing runs independently.\n */\n\nimport * as RNFS from \"@dr.pogodin/react-native-fs\"\nimport CrustModule from \"@mentra/crust\"\n\nimport {asgCameraApi} from \"./asgCameraApi\"\nimport {localStorageService} from \"./localStorageService\"\nimport {INVALID_DOWNLOADED_MEDIA, validateDownloadedMediaFile} from \"./galleryMediaValidation\"\nimport {reportInvalidGalleryMedia} from \"./GalleryMediaIntegrityReportService\"\nimport {useGallerySyncStore} from \"../../stores/gallerySync\"\nimport {BgTimer} from \"../../utils/timers\"\nimport {galleryTransferLedger, GalleryTransferEntry} from \"./galleryTransferLedger\"\nimport {cameraRollExportCoordinator} from \"./cameraRollExportCoordinator\"\n\nconst TAG = \"[MediaProcessingQueue]\"\n\nexport interface ProcessingItem {\n /** Unique ID — capture_id (v2) or file name (v1) */\n id: string\n type: \"photo\" | \"video\"\n /** Path to the primary downloaded file */\n primaryPath: string\n /** HDR bracket paths (v2 only) */\n bracketPaths?: string[]\n /** IMU sidecar path for video stabilization */\n sidecarPath?: string\n /** Thumbnail base64 data */\n thumbnailData?: string\n /** Capture directory for saving thumbnail */\n captureDir?: string\n /** Original capture timestamp */\n timestamp?: number\n /** Total file size */\n totalSize: number\n /** Video duration in ms */\n duration?: number\n /** Glasses model */\n glassesModel?: string\n /** Whether to process (lens/color/stabilization) */\n shouldProcess: boolean\n /** Whether to auto-save to camera roll */\n shouldAutoSave: boolean\n /** Pre-downloaded thumbnail path (v1 legacy sync) */\n thumbnailPath?: string\n /** File names to delete from glasses after processing completes */\n deleteFromGlasses?: string[]\n /** Negotiated gallery protocol; absent entries are inferred from the transfer ledger. */\n protocolVersion?: number\n}\n\nclass MediaProcessingQueue {\n private queue: ProcessingItem[] = []\n private isRunning = false\n private aborted = false\n private generation = 0 // C2: incremented on reset() to invalidate stale processLoop()\n\n /** Add an item to the processing queue. Starts processing if not already running. */\n enqueue(item: ProcessingItem): void {\n this.queue.push(item)\n console.log(`${TAG} Enqueued ${item.id} (${item.type}), queue size: ${this.queue.length}`)\n\n // Only mark as processing if we'll actually process this item\n if (item.shouldProcess) {\n const store = useGallerySyncStore.getState()\n store.onFileProcessing(item.id)\n }\n\n if (!this.isRunning) {\n this.processLoop()\n }\n }\n\n /** Cancel all pending processing. */\n abort(): void {\n this.aborted = true\n this.queue = []\n console.log(`${TAG} Aborted`)\n }\n\n /** Reset state for a new sync session. */\n reset(): void {\n this.queue = []\n this.isRunning = false\n this.aborted = false\n this.generation++ // C2: invalidate any running processLoop\n }\n\n /** Returns true if there are items queued or currently processing. */\n get hasPending(): boolean {\n return this.queue.length > 0 || this.isRunning\n }\n\n /** Returns a promise that resolves when the queue is fully drained, or rejects on timeout. */\n waitUntilDrained(timeoutMs: number = 4 * 60 * 60 * 1000): Promise<void> {\n if (!this.hasPending) return Promise.resolve()\n return new Promise((resolve, reject) => {\n const deadline = Date.now() + timeoutMs\n const check = () => {\n if (!this.hasPending || this.aborted) {\n resolve()\n } else if (Date.now() >= deadline) {\n console.error(`${TAG} waitUntilDrained timed out after ${timeoutMs}ms, aborting queue`)\n this.abort()\n reject(new Error(`Processing queue timed out after ${timeoutMs / 1000}s`))\n } else {\n BgTimer.setTimeout(check, 200)\n }\n }\n check()\n })\n }\n\n /** Retry durable export/ack work after an app restart without downloading media again. */\n async retryPending(): Promise<{retried: number; failed: number}> {\n let retried = 0\n let failed = 0\n for (let entry of galleryTransferLedger.pendingRecovery()) {\n try {\n if (entry.state === \"RESTORE_PENDING\") {\n await asgCameraApi.restoreCapture(entry.captureId)\n galleryTransferLedger.transition(entry.captureId, \"DISCOVERED\", {lastError: undefined})\n retried++\n continue\n }\n if (!entry.finalPath || !(await RNFS.exists(entry.finalPath))) {\n throw new Error(`Recovery file is missing for ${entry.captureId}`)\n }\n // Rebuild a missing app index before any source acknowledgement, even when camera-roll\n // saving is disabled or an export receipt was already committed before restart.\n const downloadedFile = await this.recoverDownloadedFile(entry)\n if (entry.state === \"EXPORT_PENDING\" || entry.state === \"INDEXED\") {\n const shouldAutoSave = await cameraRollExportCoordinator.isAutoSaveEnabled()\n entry = galleryTransferLedger.update(entry.captureId, {shouldAutoSave, lastError: undefined})\n if (shouldAutoSave) {\n if (entry.state !== \"EXPORT_PENDING\") {\n entry = galleryTransferLedger.transition(entry.captureId, \"EXPORT_PENDING\")\n }\n const receipt = await cameraRollExportCoordinator.exportForSource(downloadedFile, entry.captureId)\n entry = receipt\n ? galleryTransferLedger.transition(entry.captureId, \"EXPORTED\", {assetReceipt: receipt})\n : galleryTransferLedger.transition(entry.captureId, \"INDEXED\", {\n shouldAutoSave: false,\n lastError: undefined,\n })\n } else if (entry.state === \"EXPORT_PENDING\") {\n entry = galleryTransferLedger.transition(entry.captureId, \"INDEXED\", {\n shouldAutoSave: false,\n lastError: undefined,\n })\n }\n }\n entry = galleryTransferLedger.transition(entry.captureId, \"ACK_PENDING\")\n await this.acknowledgeEntry(entry)\n galleryTransferLedger.transition(entry.captureId, \"TRASHED\", {lastError: undefined})\n retried++\n } catch (error) {\n galleryTransferLedger.recordFailure(entry.captureId, error)\n failed++\n console.warn(`${TAG} Recovery remains pending for ${entry.captureId}:`, error)\n }\n }\n return {retried, failed}\n }\n\n private async acknowledgeEntry(entry: GalleryTransferEntry): Promise<void> {\n if (entry.protocolVersion >= 3) {\n await asgCameraApi.acknowledgeCapture(entry.captureId, entry.ackId)\n return\n }\n const result = await asgCameraApi.deleteFilesFromServer(\n entry.deleteFromGlasses.length > 0 ? entry.deleteFromGlasses : [entry.captureId],\n )\n if (result.failed.length > 0 || result.deleted.length === 0) {\n throw new Error(`Glasses did not acknowledge ${entry.captureId}`)\n }\n }\n\n /** Process items one at a time. */\n private async processLoop(): Promise<void> {\n if (this.isRunning) return\n this.isRunning = true\n const myGeneration = this.generation // C2: capture generation to detect reset()\n\n while (this.queue.length > 0 && !this.aborted && this.generation === myGeneration) {\n const item = this.queue.shift()!\n let processFailed = false\n try {\n await this.processItem(item)\n } catch (error) {\n console.error(`${TAG} Error processing ${item.id}:`, error)\n processFailed = true\n const store = useGallerySyncStore.getState()\n if (!store.failedFiles.includes(item.id)) {\n store.onFileFailed(item.id, error instanceof Error ? error.message : String(error))\n }\n }\n\n // Exit if generation changed (reset was called during processing)\n if (this.generation !== myGeneration) break\n\n const store = useGallerySyncStore.getState()\n if (!processFailed) {\n // Success: increment processedFiles and remove from processingFiles set.\n store.onFileProcessed(item.id)\n } else {\n // Failure is counted exactly once above. Still clear the processingFiles entry so the UI\n // does not show it as in-progress.\n const current = store.processingFiles\n if (current.has(item.id)) {\n const newSet = new Set(current)\n newSet.delete(item.id)\n useGallerySyncStore.setState({processingFiles: newSet})\n }\n }\n }\n\n // Only clear isRunning if this loop owns the current generation\n if (this.generation === myGeneration) {\n this.isRunning = false\n }\n }\n\n /** Process a single item through the full pipeline. */\n private async processItem(item: ProcessingItem): Promise<void> {\n const startTime = Date.now()\n let filePathToSave = item.primaryPath\n let ledgerEntry = galleryTransferLedger.get(item.id)\n if (!ledgerEntry) {\n ledgerEntry = galleryTransferLedger.ensureCapture(\n {\n capture_id: item.id,\n type: item.type,\n timestamp: item.timestamp || Date.now(),\n total_size: item.totalSize,\n files: (item.deleteFromGlasses?.length ? item.deleteFromGlasses : [item.id]).map((name, index) => ({\n name,\n size: index === 0 ? item.totalSize : 0,\n role: index === 0 ? \"primary\" : \"sidecar\",\n })),\n },\n item.protocolVersion || 2,\n )\n }\n\n // 1. HDR merge (photos with brackets only)\n if (item.shouldProcess && item.type === \"photo\" && item.bracketPaths && item.bracketPaths.length >= 3) {\n try {\n const underPath = item.bracketPaths.find((p) => p.includes(\"ev-2\")) || item.bracketPaths[0]\n const normalPath = item.bracketPaths.find((p) => p.includes(\"ev0\")) || item.bracketPaths[1]\n const overPath = item.bracketPaths.find((p) => p.includes(\"ev2\") && !p.includes(\"ev-2\")) || item.bracketPaths[2]\n\n const hdrPath = item.primaryPath + \".hdr.jpg\"\n const hdrResult = await CrustModule.mergeHdrBrackets(underPath, normalPath, overPath, hdrPath)\n if (hdrResult.success && hdrResult.outputPath) {\n filePathToSave = hdrResult.outputPath\n console.log(`${TAG} HDR merged ${item.id} in ${hdrResult.processingTimeMs}ms`)\n }\n } catch (hdrError) {\n console.warn(`${TAG} HDR merge error for ${item.id}, continuing:`, hdrError)\n }\n }\n\n // 2. Image processing (lens + color correction)\n if (item.shouldProcess && item.type === \"photo\") {\n try {\n const processedPath = filePathToSave + \".processed.jpg\"\n const result = await CrustModule.processGalleryImage(filePathToSave, processedPath, {\n lensCorrection: true,\n colorCorrection: true,\n })\n if (result.success && result.outputPath) {\n filePathToSave = result.outputPath\n console.log(`${TAG} 🎨 Processed ${item.id} in ${result.processingTimeMs}ms`)\n }\n } catch (procError) {\n console.warn(`${TAG} Processing error for ${item.id}, using original:`, procError)\n }\n }\n\n // 3. Video stabilization + color correction\n if (item.shouldProcess && item.type === \"video\" && item.sidecarPath) {\n try {\n const stabilizedPath = item.primaryPath + \".stabilized.mp4\"\n const result = await CrustModule.stabilizeVideo(item.primaryPath, item.sidecarPath, stabilizedPath)\n if (result.success && result.outputPath) {\n filePathToSave = result.outputPath\n console.log(`${TAG} 📹 Stabilized ${item.id} in ${result.processingTimeMs}ms`)\n }\n } catch (stabError) {\n console.warn(`${TAG} Stabilization error for ${item.id}, using original:`, stabError)\n }\n }\n\n // 4. Save thumbnail to disk (or use pre-downloaded thumbnail from v1 sync)\n let localThumbnailPath: string | undefined = item.thumbnailPath\n if (item.thumbnailData && item.captureDir) {\n try {\n const thumbPath = `${item.captureDir}/.thumb.jpg`\n const base64Data = item.thumbnailData.startsWith(\"data:\")\n ? item.thumbnailData.split(\",\")[1]\n : item.thumbnailData\n await RNFS.writeFile(thumbPath, base64Data, \"base64\")\n localThumbnailPath = thumbPath\n } catch (thumbError) {\n console.warn(`${TAG} Failed to save thumbnail for ${item.id}:`, thumbError)\n }\n }\n\n // 5. Validate local file before persisting metadata or deleting from glasses\n try {\n await validateDownloadedMediaFile({\n path: filePathToSave,\n name: item.id,\n mediaKind: item.type,\n })\n } catch (validationError: any) {\n const reason = validationError?.message?.includes(INVALID_DOWNLOADED_MEDIA)\n ? validationError.message\n : `${INVALID_DOWNLOADED_MEDIA}: ${item.id}`\n console.error(`${TAG} Validation failed for ${item.id}: ${reason}`)\n reportInvalidGalleryMedia({\n name: item.id,\n path: filePathToSave,\n mediaKind: item.type,\n stage: \"processing_validation\",\n reason,\n expectedSize: item.totalSize,\n duration: item.duration,\n glassesModel: item.glassesModel,\n })\n const store = useGallerySyncStore.getState()\n store.onFileFailed(item.id, reason)\n galleryTransferLedger.recordFailure(item.id, validationError)\n throw new Error(reason)\n }\n\n // 6. Commit the app-local index before any export or source acknowledgement. Use the final\n // on-disk output metadata for camera-roll identity: processing can change byte size, while\n // recovery reconstructs this row from the same file and the transfer ledger timestamp.\n const isVideo = item.type === \"video\"\n const finalFileStat = await RNFS.stat(filePathToSave)\n const finalFileSize = Number(finalFileStat.size)\n const downloadedFile = localStorageService.convertToDownloadedFile(\n {\n name: item.id,\n url: \"\",\n download: \"\",\n size: finalFileSize,\n modified: ledgerEntry.timestamp,\n is_video: isVideo,\n thumbnail_data: item.thumbnailData,\n duration: item.duration,\n filePath: filePathToSave,\n glassesModel: item.glassesModel,\n },\n filePathToSave,\n localThumbnailPath,\n item.glassesModel,\n )\n downloadedFile.capture_id = item.id\n const shouldAutoSave = await cameraRollExportCoordinator.isAutoSaveEnabled()\n try {\n await localStorageService.saveDownloadedFile(downloadedFile)\n ledgerEntry = galleryTransferLedger.transition(item.id, \"INDEXED\", {\n finalPath: filePathToSave,\n thumbnailPath: localThumbnailPath,\n shouldAutoSave,\n })\n await cameraRollExportCoordinator.recordIndexed(\n downloadedFile,\n shouldAutoSave,\n shouldAutoSave ? \"SOURCE_BARRIER\" : \"HISTORICAL_BACKFILL\",\n item.id,\n )\n } catch (metadataError) {\n console.error(`${TAG} Metadata save failed for ${item.id}; retaining local and glasses copies:`, metadataError)\n galleryTransferLedger.recordFailure(item.id, metadataError)\n throw metadataError\n }\n\n // 7. While enabled, export is a durable, receipted step whose failures block ack. Turning\n // auto-save off safely falls back to the already-verified app-local copy and later backfill.\n if (shouldAutoSave) {\n galleryTransferLedger.transition(item.id, \"EXPORT_PENDING\")\n let receipt\n try {\n receipt = await cameraRollExportCoordinator.exportForSource(downloadedFile, item.id)\n } catch (error) {\n galleryTransferLedger.recordFailure(item.id, error)\n throw error\n }\n if (receipt) {\n ledgerEntry = galleryTransferLedger.transition(item.id, \"EXPORTED\", {\n assetReceipt: receipt,\n })\n console.log(`${TAG} ✅ Saved to camera roll with receipt: ${item.id}`)\n } else {\n ledgerEntry = galleryTransferLedger.transition(item.id, \"INDEXED\", {\n shouldAutoSave: false,\n lastError: undefined,\n })\n console.log(`${TAG} Automatic camera-roll saving was disabled; keeping app-local copy: ${item.id}`)\n }\n }\n\n // S4: Clean up intermediate processing files\n const intermediates = [\n item.primaryPath + \".hdr.jpg\",\n item.primaryPath + \".processed.jpg\",\n item.primaryPath + \".stabilized.mp4\",\n ]\n for (const intermediate of intermediates) {\n if (intermediate !== filePathToSave) {\n RNFS.unlink(intermediate).catch(() => {}) // fire-and-forget\n }\n }\n\n // 8. Update file in sync queue with local paths for gallery display\n const store = useGallerySyncStore.getState()\n const localFileUrl = filePathToSave.startsWith(\"file://\") ? filePathToSave : `file://${filePathToSave}`\n const localThumbUrl = localThumbnailPath\n ? localThumbnailPath.startsWith(\"file://\")\n ? localThumbnailPath\n : `file://${localThumbnailPath}`\n : undefined\n store.updateFileInQueue(item.id, {\n name: item.id,\n url: localFileUrl,\n download: localFileUrl,\n size: finalFileSize,\n modified: ledgerEntry.timestamp,\n is_video: isVideo,\n filePath: filePathToSave,\n mime_type: isVideo ? \"video/mp4\" : \"image/jpeg\",\n thumbnail_data: item.thumbnailData,\n thumbnailPath: localThumbUrl,\n duration: item.duration,\n })\n\n // 9. Acknowledge only after VERIFIED -> INDEXED -> (EXPORTED). The server turns this into\n // recoverable trash; failures remain ACK_PENDING and are retried without re-downloading.\n const localFileExists = await RNFS.exists(filePathToSave)\n const localStat = localFileExists ? await RNFS.stat(filePathToSave) : null\n if (!localStat || localStat.size <= 0) {\n const error = new Error(`Cannot acknowledge ${item.id}: committed local file is missing or empty`)\n galleryTransferLedger.recordFailure(item.id, error)\n throw error\n }\n ledgerEntry = galleryTransferLedger.transition(item.id, \"ACK_PENDING\")\n try {\n await this.acknowledgeEntry(ledgerEntry)\n galleryTransferLedger.transition(item.id, \"TRASHED\", {lastError: undefined})\n } catch (ackError) {\n galleryTransferLedger.recordFailure(item.id, ackError)\n throw ackError\n }\n\n const elapsed = Date.now() - startTime\n console.log(`${TAG} ✅ Finished ${item.id} in ${elapsed}ms`)\n }\n\n /** Rebuild a missing app-local index row from the durable transfer ledger. */\n private async recoverDownloadedFile(entry: GalleryTransferEntry) {\n if (!entry.finalPath) throw new Error(`Recovery file is missing for ${entry.captureId}`)\n\n // The transfer ledger is the durable source of truth for a committed generation. A local\n // index row can survive an interrupted replacement and still point at an older/missing path,\n // or contain the pre-processing size. Only reuse it when its path and identity still match the\n // ledger's committed file; otherwise rebuild the row before export or source acknowledgement.\n const finalPath = entry.finalPath.replace(/^file:\\/\\//, \"\")\n const indexed = await localStorageService.getDownloadedFile(entry.captureId)\n if (indexed) {\n try {\n const indexedPath = indexed.filePath?.replace(/^file:\\/\\//, \"\")\n if (indexedPath === finalPath && (await RNFS.exists(indexedPath))) {\n const indexedStat = await RNFS.stat(indexedPath)\n const indexedSize = Number(indexedStat.size)\n if (indexedSize > 0 && indexed.size === indexedSize && indexed.modified === entry.timestamp) {\n return indexed\n }\n }\n } catch (error) {\n console.warn(`${TAG} Ignoring stale local index for ${entry.captureId}:`, error)\n }\n }\n\n const stat = await RNFS.stat(finalPath)\n const finalSize = Number(stat.size)\n if (!Number.isFinite(finalSize) || finalSize <= 0) {\n throw new Error(`Recovery file is missing or empty for ${entry.captureId}`)\n }\n const recovered = localStorageService.convertToDownloadedFile(\n {\n name: entry.captureId,\n url: \"\",\n download: \"\",\n size: finalSize,\n modified: entry.timestamp,\n mime_type: entry.captureType === \"video\" ? \"video/mp4\" : \"image/jpeg\",\n is_video: entry.captureType === \"video\",\n filePath: finalPath,\n },\n finalPath,\n entry.thumbnailPath,\n )\n recovered.capture_id = entry.captureId\n recovered.assetReceipt = entry.assetReceipt\n await localStorageService.saveDownloadedFile(recovered)\n return recovered\n }\n}\n\nexport const mediaProcessingQueue = new MediaProcessingQueue()\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AudioSource } from "expo-audio";
|
|
2
|
+
/**
|
|
3
|
+
* A tiny bundled source used to detach completed or interrupted audio without
|
|
4
|
+
* destroying the reusable native player. If a media control later sends Play,
|
|
5
|
+
* only this silence can be resumed instead of the previous miniapp audio.
|
|
6
|
+
*/
|
|
7
|
+
export declare const SILENT_AUDIO_SOURCE: AudioSource;
|
|
8
|
+
//# sourceMappingURL=audioPlaybackAssets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audioPlaybackAssets.d.ts","sourceRoot":"","sources":["../../src/services/audioPlaybackAssets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,YAAY,CAAA;AAE3C;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,WAA8C,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A tiny bundled source used to detach completed or interrupted audio without
|
|
3
|
+
* destroying the reusable native player. If a media control later sends Play,
|
|
4
|
+
* only this silence can be resumed instead of the previous miniapp audio.
|
|
5
|
+
*/
|
|
6
|
+
export const SILENT_AUDIO_SOURCE = require("../assets/silence.wav");
|
|
7
|
+
//# sourceMappingURL=audioPlaybackAssets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audioPlaybackAssets.js","sourceRoot":"","sources":["../../src/services/audioPlaybackAssets.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAgB,OAAO,CAAC,uBAAuB,CAAC,CAAA","sourcesContent":["import type {AudioSource} from \"expo-audio\"\n\n/**\n * A tiny bundled source used to detach completed or interrupted audio without\n * destroying the reusable native player. If a media control later sends Play,\n * only this silence can be resumed instead of the previous miniapp audio.\n */\nexport const SILENT_AUDIO_SOURCE: AudioSource = require(\"../assets/silence.wav\")\n"]}
|
|
@@ -13,7 +13,7 @@ export function detectClockSkew(phoneNow, glassesServerTime, lastSyncTime, toler
|
|
|
13
13
|
return { skewed: false, reason: "" };
|
|
14
14
|
}
|
|
15
15
|
export function isSyncManifestEmpty(syncData) {
|
|
16
|
-
if (syncData.api_version
|
|
16
|
+
if ((syncData.api_version || 0) >= 2 && syncData.captures && syncData.captures.length > 0) {
|
|
17
17
|
return false;
|
|
18
18
|
}
|
|
19
19
|
return !syncData.changed_files || syncData.changed_files.length === 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gallerySyncClock.js","sourceRoot":"","sources":["../../src/services/gallerySyncClock.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAA;AAS7C,MAAM,UAAU,eAAe,CAC7B,QAAgB,EAChB,iBAAyB,EACzB,YAAoB,EACpB,cAAsB,uBAAuB;IAE7C,IAAI,YAAY,GAAG,iBAAiB,GAAG,WAAW,EAAE,CAAC;QACnD,OAAO,EAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,4BAA4B,EAAC,CAAA;IAC7D,CAAC;IACD,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,iBAAiB,CAAC,GAAG,WAAW,EAAE,CAAC;QACzD,OAAO,EAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,kBAAkB,EAAC,CAAA;IACnD,CAAC;IACD,OAAO,EAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAC,CAAA;AACpC,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,QAInC;IACC,IAAI,QAAQ,CAAC,WAAW,
|
|
1
|
+
{"version":3,"file":"gallerySyncClock.js","sourceRoot":"","sources":["../../src/services/gallerySyncClock.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAA;AAS7C,MAAM,UAAU,eAAe,CAC7B,QAAgB,EAChB,iBAAyB,EACzB,YAAoB,EACpB,cAAsB,uBAAuB;IAE7C,IAAI,YAAY,GAAG,iBAAiB,GAAG,WAAW,EAAE,CAAC;QACnD,OAAO,EAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,4BAA4B,EAAC,CAAA;IAC7D,CAAC;IACD,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,iBAAiB,CAAC,GAAG,WAAW,EAAE,CAAC;QACzD,OAAO,EAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,kBAAkB,EAAC,CAAA;IACnD,CAAC;IACD,OAAO,EAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAC,CAAA;AACpC,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,QAInC;IACC,IAAI,CAAC,QAAQ,CAAC,WAAW,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1F,OAAO,KAAK,CAAA;IACd,CAAC;IACD,OAAO,CAAC,QAAQ,CAAC,aAAa,IAAI,QAAQ,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,CAAA;AACvE,CAAC","sourcesContent":["/**\n * Clock skew detection for gallery sync (phone vs glasses).\n * Phone pushes time to glasses only when skew is detected during sync.\n */\n\nexport const CLOCK_SKEW_TOLERANCE_MS = 60_000\n\nexport type ClockSkewReason = \"watermark_ahead_of_glasses\" | \"wall_clock_drift\" | \"\"\n\nexport interface ClockSkewResult {\n skewed: boolean\n reason: ClockSkewReason\n}\n\nexport function detectClockSkew(\n phoneNow: number,\n glassesServerTime: number,\n lastSyncTime: number,\n toleranceMs: number = CLOCK_SKEW_TOLERANCE_MS,\n): ClockSkewResult {\n if (lastSyncTime > glassesServerTime + toleranceMs) {\n return {skewed: true, reason: \"watermark_ahead_of_glasses\"}\n }\n if (Math.abs(phoneNow - glassesServerTime) > toleranceMs) {\n return {skewed: true, reason: \"wall_clock_drift\"}\n }\n return {skewed: false, reason: \"\"}\n}\n\nexport function isSyncManifestEmpty(syncData: {\n api_version?: number\n captures?: unknown[]\n changed_files?: unknown[]\n}): boolean {\n if ((syncData.api_version || 0) >= 2 && syncData.captures && syncData.captures.length > 0) {\n return false\n }\n return !syncData.changed_files || syncData.changed_files.length === 0\n}\n"]}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import BluetoothSdk from "@mentra/bluetooth-sdk/internal";
|
|
5
5
|
import { BgTimer } from "../utils/timers";
|
|
6
6
|
import { useGlassesStore } from "../stores/glasses";
|
|
7
|
-
import {
|
|
7
|
+
import { resolveOtaManifestUrl } from "./otaManifestUrl";
|
|
8
8
|
import { detectClockSkew } from "./gallerySyncClock";
|
|
9
9
|
export const CLOCK_SETTLE_MS = 500;
|
|
10
10
|
const OTA_CLOCK_FIX_COOLDOWN_MS = 30_000;
|
|
@@ -70,7 +70,7 @@ export async function handleOtaClockSkewFromGlasses(errorCode, glassesTimeMs) {
|
|
|
70
70
|
}
|
|
71
71
|
lastOtaClockFixAt = Date.now();
|
|
72
72
|
const { buildNumber, otaVersionUrl } = useGlassesStore.getState();
|
|
73
|
-
const manifestUrl =
|
|
73
|
+
const manifestUrl = resolveOtaManifestUrl(otaVersionUrl, buildNumber);
|
|
74
74
|
console.log("[GlassesClockSync] ⏰ Restarting OTA with ota_start after clock fix");
|
|
75
75
|
await BluetoothSdk.startOtaUpdate(manifestUrl);
|
|
76
76
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glassesClockSync.js","sourceRoot":"","sources":["../../src/services/glassesClockSync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,YAAY,MAAM,gCAAgC,CAAA;AACzD,OAAO,EAAC,OAAO,EAAC,MAAM,iBAAiB,CAAA;AACvC,OAAO,EAAC,eAAe,EAAC,MAAM,mBAAmB,CAAA;AAEjD,OAAO,EAAC,
|
|
1
|
+
{"version":3,"file":"glassesClockSync.js","sourceRoot":"","sources":["../../src/services/glassesClockSync.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Push phone time to glasses only when clock skew is detected (gallery sync, OTA, etc.).\n */\n\nimport BluetoothSdk from \"@mentra/bluetooth-sdk/internal\"\nimport {BgTimer} from \"../utils/timers\"\nimport {useGlassesStore} from \"../stores/glasses\"\n\nimport {resolveOtaManifestUrl} from \"./otaManifestUrl\"\nimport {detectClockSkew} from \"./gallerySyncClock\"\n\nexport const CLOCK_SETTLE_MS = 500\n\nconst OTA_CLOCK_FIX_COOLDOWN_MS = 30_000\nlet lastOtaClockFixAt = 0\n// Coalesce concurrent OTA clock-fix attempts. Glasses can emit two clock_skew events\n// back-to-back during BLE handshake; without this guard both would await the BLE fix\n// + retry pair before either updated `lastOtaClockFixAt`.\nlet inflightOtaClockFix: Promise<boolean> | null = null\n\n/** @internal test-only */\nexport function resetOtaClockFixCooldownForTests(): void {\n lastOtaClockFixAt = 0\n inflightOtaClockFix = null\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => BgTimer.setTimeout(resolve, ms))\n}\n\n/**\n * Set glasses system clock from phone when skew is detected.\n */\nexport async function fixGlassesClockIfSkewed(glassesServerTime: number, lastSyncTime = 0): Promise<boolean> {\n const {skewed, reason} = detectClockSkew(Date.now(), glassesServerTime, lastSyncTime)\n if (!skewed) {\n return false\n }\n console.log(`[GlassesClockSync] ⏰ Clock skew detected (${reason}) — setting glasses time from phone`)\n await BluetoothSdk.setSystemTime(Date.now())\n await delay(CLOCK_SETTLE_MS)\n return true\n}\n\n/**\n * After glasses report OTA failure due to clock skew, fix time and restart\n * through the normal phone-driven ota_start path.\n */\nexport async function handleOtaClockSkewFromGlasses(\n errorCode: string | undefined,\n glassesTimeMs?: number,\n): Promise<boolean> {\n if (Date.now() - lastOtaClockFixAt < OTA_CLOCK_FIX_COOLDOWN_MS) {\n return false\n }\n\n const hasGlassesTime = typeof glassesTimeMs === \"number\" && Number.isFinite(glassesTimeMs) && glassesTimeMs > 0\n\n if (errorCode === \"ssl_error\") {\n if (!hasGlassesTime) {\n return false\n }\n const {skewed} = detectClockSkew(Date.now(), glassesTimeMs, 0)\n if (!skewed) {\n return false\n }\n console.log(\"[GlassesClockSync] ⏰ OTA ssl_error with wall-clock drift — treating as clock skew\")\n } else if (errorCode !== \"clock_skew\") {\n return false\n }\n\n // Coalesce concurrent attempts: if a fix is already in flight, await its result instead\n // of racing it through the cooldown guard.\n if (inflightOtaClockFix) {\n return inflightOtaClockFix\n }\n\n const glassesTime = hasGlassesTime ? glassesTimeMs : Date.now() - 86_400_000\n\n inflightOtaClockFix = (async () => {\n try {\n const fixed = await fixGlassesClockIfSkewed(glassesTime, 0)\n if (!fixed) {\n return false\n }\n\n lastOtaClockFixAt = Date.now()\n const {buildNumber, otaVersionUrl} = useGlassesStore.getState()\n const manifestUrl = resolveOtaManifestUrl(otaVersionUrl, buildNumber)\n console.log(\"[GlassesClockSync] ⏰ Restarting OTA with ota_start after clock fix\")\n await BluetoothSdk.startOtaUpdate(manifestUrl)\n return true\n } finally {\n inflightOtaClockFix = null\n }\n })()\n\n return inflightOtaClockFix\n}\n\n/**\n * Proactive fix when version_info includes glasses system_time_ms before OTA manifest checks.\n */\nexport async function maybeFixGlassesClockFromVersionInfo(systemTimeMs: number | undefined): Promise<boolean> {\n if (typeof systemTimeMs !== \"number\" || systemTimeMs <= 0) {\n return false\n }\n\n const fixed = await fixGlassesClockIfSkewed(systemTimeMs, 0)\n if (!fixed) {\n return false\n }\n\n return true\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DeclaredAction } from "../types/applet";
|
|
2
|
+
/**
|
|
3
|
+
* Normalize manifest actions defensively for installed and dev-sideloaded
|
|
4
|
+
* bundles. Input and output schemas are passed through as opaque JSON Schema.
|
|
5
|
+
*/
|
|
6
|
+
export declare function normalizeManifestActions(raw: unknown): DeclaredAction[];
|
|
7
|
+
//# sourceMappingURL=manifestActions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifestActions.d.ts","sourceRoot":"","sources":["../../src/services/manifestActions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,iBAAiB,CAAA;AAEnD;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,EAAE,CAuBvE"}
|