@mentra/engine 0.1.0-dev.0 → 3.1.0-dev.4
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 +55 -18
- package/build/bluetooth-sdk/debug.d.ts +2 -0
- package/build/bluetooth-sdk/debug.d.ts.map +1 -0
- package/build/bluetooth-sdk/debug.js +2 -0
- package/build/bluetooth-sdk/debug.js.map +1 -0
- package/build/bluetooth-sdk/index.d.ts +3 -0
- package/build/bluetooth-sdk/index.d.ts.map +1 -0
- package/build/bluetooth-sdk/index.js +3 -0
- package/build/bluetooth-sdk/index.js.map +1 -0
- package/build/bluetooth-sdk/photo-receiver.d.ts +3 -0
- package/build/bluetooth-sdk/photo-receiver.d.ts.map +1 -0
- package/build/bluetooth-sdk/photo-receiver.js +3 -0
- package/build/bluetooth-sdk/photo-receiver.js.map +1 -0
- package/build/bluetooth-sdk/react.d.ts +2 -0
- package/build/bluetooth-sdk/react.d.ts.map +1 -0
- package/build/bluetooth-sdk/react.js +2 -0
- package/build/bluetooth-sdk/react.js.map +1 -0
- package/build/bluetooth-sdk/types.d.ts +2 -0
- package/build/bluetooth-sdk/types.d.ts.map +1 -0
- package/build/bluetooth-sdk/types.js +2 -0
- package/build/bluetooth-sdk/types.js.map +1 -0
- package/build/engine.d.ts +24 -16
- package/build/engine.d.ts.map +1 -1
- package/build/engine.js +9 -4
- 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/display.d.ts +1 -1
- package/build/facades/display.d.ts.map +1 -1
- package/build/facades/display.js +1 -1
- package/build/facades/display.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 +4 -13
- package/build/facades/glasses.d.ts.map +1 -1
- package/build/facades/glasses.js +21 -6
- 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 +14 -16
- package/build/facades/ota.d.ts.map +1 -1
- package/build/facades/ota.js +22 -7
- package/build/facades/ota.js.map +1 -1
- package/build/facades/pairing.d.ts +8 -5
- package/build/facades/pairing.d.ts.map +1 -1
- package/build/facades/pairing.js +12 -10
- 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/facades/speech.d.ts +7 -6
- package/build/facades/speech.d.ts.map +1 -1
- package/build/facades/speech.js +1 -1
- package/build/facades/speech.js.map +1 -1
- package/build/generated/releaseMetadata.d.ts +12 -0
- package/build/generated/releaseMetadata.d.ts.map +1 -0
- package/build/generated/releaseMetadata.js +10 -0
- package/build/generated/releaseMetadata.js.map +1 -0
- package/build/index.d.ts +10 -8
- package/build/index.d.ts.map +1 -1
- package/build/index.js +6 -5
- package/build/index.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 +41 -57
- package/build/services/AppRegistry.d.ts.map +1 -1
- package/build/services/AppRegistry.js +208 -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 +95 -15
- package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
- package/build/services/OtaInstallCoordinator.js +577 -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 +39 -4
- package/build/services/OtaUpdateCheckService.d.ts.map +1 -1
- package/build/services/OtaUpdateCheckService.js +138 -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.d.ts.map +1 -1
- package/build/services/glassesClockSync.js +6 -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 +23 -12
- 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 +16 -4
- 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/otaLegacyMapping.d.ts +1 -1
- package/build/services/otaLegacyMapping.d.ts.map +1 -1
- package/build/services/otaLegacyMapping.js.map +1 -1
- package/build/services/otaManifestPolicy.d.ts +14 -0
- package/build/services/otaManifestPolicy.d.ts.map +1 -0
- package/build/services/otaManifestPolicy.js +19 -0
- package/build/services/otaManifestPolicy.js.map +1 -0
- package/build/services/otaManifestUrl.d.ts +3 -0
- package/build/services/otaManifestUrl.d.ts.map +1 -0
- package/build/services/otaManifestUrl.js +38 -0
- 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 +2 -25
- package/build/types/enums.d.ts.map +1 -1
- package/build/types/enums.js +2 -27
- package/build/types/enums.js.map +1 -1
- package/build/types/hardware.d.ts +4 -13
- package/build/types/hardware.d.ts.map +1 -1
- package/build/types/hardware.js +15 -3
- package/build/types/hardware.js.map +1 -1
- package/build/types/index.d.ts +2 -6
- package/build/types/index.d.ts.map +1 -1
- package/build/types/index.js +2 -6
- package/build/types/index.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 +59 -31
- package/src/assets/silence.wav +0 -0
- package/src/bluetooth-sdk/debug.ts +1 -0
- package/src/bluetooth-sdk/index.ts +2 -0
- package/src/bluetooth-sdk/photo-receiver.ts +2 -0
- package/src/bluetooth-sdk/react.ts +1 -0
- package/src/bluetooth-sdk/types.ts +1 -0
- package/src/engine.ts +9 -4
- package/src/facades/dev.ts +17 -12
- package/src/facades/display.ts +1 -1
- package/src/facades/gallery.ts +1 -1
- package/src/facades/glasses.ts +20 -7
- package/src/facades/glassesSettings.ts +5 -0
- package/src/facades/miniapps.ts +7 -0
- package/src/facades/ota.ts +23 -8
- package/src/facades/pairing.ts +15 -11
- package/src/facades/permissions.ts +14 -0
- package/src/facades/phoneNotifications.ts +4 -13
- package/src/facades/speech.ts +21 -7
- package/src/generated/releaseMetadata.ts +20 -0
- package/src/index.ts +39 -13
- 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 +240 -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 +649 -144
- package/src/services/OtaService.ts +11 -5
- package/src/services/OtaUpdateCheckService.ts +181 -21
- 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 +6 -2
- package/src/services/manifestActions.ts +30 -0
- package/src/services/otaDisplayState.ts +58 -17
- package/src/services/otaInstallPolicy.ts +30 -4
- package/src/services/otaLegacyMapping.ts +1 -1
- package/src/services/otaManifestPolicy.ts +42 -0
- package/src/services/otaManifestUrl.ts +44 -0
- 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 +3 -28
- package/src/types/hardware.ts +20 -13
- package/src/types/index.ts +2 -6
- 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/devtools.d.ts +0 -11
- package/build/devtools.d.ts.map +0 -1
- package/build/devtools.js +0 -13
- package/build/devtools.js.map +0 -1
- package/build/internal.d.ts +0 -66
- package/build/internal.d.ts.map +0 -1
- package/build/internal.js +0 -89
- package/build/internal.js.map +0 -1
- package/build/services/asgOtaVersionUrl.d.ts +0 -2
- package/build/services/asgOtaVersionUrl.d.ts.map +0 -1
- package/build/services/asgOtaVersionUrl.js +0 -36
- package/build/services/asgOtaVersionUrl.js.map +0 -1
- package/src/devtools.ts +0 -13
- package/src/internal.ts +0 -158
- package/src/services/asgOtaVersionUrl.ts +0 -41
|
@@ -5,12 +5,15 @@
|
|
|
5
5
|
import * as RNFS from "@dr.pogodin/react-native-fs";
|
|
6
6
|
import { BgTimer } from "../../utils/timers";
|
|
7
7
|
import { storage, StorageValueNotFoundError } from "../../utils/storage";
|
|
8
|
+
import { galleryTransferLedger } from "./galleryTransferLedger";
|
|
9
|
+
import { toPortableGalleryPath } from "./galleryPathMigration";
|
|
8
10
|
export class LocalStorageService {
|
|
9
11
|
static instance;
|
|
10
12
|
DOWNLOADED_FILES_KEY = "asg_downloaded_files";
|
|
11
13
|
SYNC_STATE_KEY = "asg_sync_state";
|
|
12
14
|
CLIENT_ID_KEY = "asg_client_id";
|
|
13
15
|
SYNC_QUEUE_KEY = "asg_sync_queue";
|
|
16
|
+
QUARANTINED_FILES_KEY = "asg_quarantined_downloaded_files_v1";
|
|
14
17
|
ASG_PHOTOS_DIR = `${RNFS.DocumentDirectoryPath}/MentraPhotos`;
|
|
15
18
|
ASG_THUMBNAILS_DIR = `${RNFS.DocumentDirectoryPath}/MentraPhotos/thumbnails`;
|
|
16
19
|
constructor() {
|
|
@@ -112,7 +115,22 @@ export class LocalStorageService {
|
|
|
112
115
|
*/
|
|
113
116
|
async saveDownloadedFile(file) {
|
|
114
117
|
try {
|
|
115
|
-
const
|
|
118
|
+
const rawFiles = this.loadRawDownloadedFiles();
|
|
119
|
+
const files = {};
|
|
120
|
+
const quarantined = this.loadQuarantinedFiles();
|
|
121
|
+
const missingCaptureIds = [];
|
|
122
|
+
for (const [name, existing] of Object.entries(rawFiles)) {
|
|
123
|
+
const existingPath = this.toPortableRelativePath(existing.filePath);
|
|
124
|
+
const existingThumbnail = existing.thumbnailPath
|
|
125
|
+
? this.toPortableRelativePath(existing.thumbnailPath) || undefined
|
|
126
|
+
: undefined;
|
|
127
|
+
if (!existingPath) {
|
|
128
|
+
quarantined[name] = existing;
|
|
129
|
+
missingCaptureIds.push(name);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
files[name] = { ...existing, filePath: existingPath, thumbnailPath: existingThumbnail };
|
|
133
|
+
}
|
|
116
134
|
// 🔍 DIAGNOSTIC: Check if file already exists
|
|
117
135
|
// const existingFile = files[file.name]
|
|
118
136
|
// if (existingFile) {
|
|
@@ -133,22 +151,28 @@ export class LocalStorageService {
|
|
|
133
151
|
// }
|
|
134
152
|
// Store relative paths to handle iOS app container changes between launches
|
|
135
153
|
// Convert absolute paths to relative (remove DocumentDirectoryPath prefix)
|
|
136
|
-
const
|
|
137
|
-
const relativePath = file.filePath.startsWith(docPath)
|
|
138
|
-
? file.filePath.substring(docPath.length + 1) // +1 for the slash
|
|
139
|
-
: file.filePath;
|
|
154
|
+
const relativePath = this.toPortableRelativePath(file.filePath);
|
|
140
155
|
const relativeThumbnailPath = file.thumbnailPath
|
|
141
|
-
? file.thumbnailPath
|
|
142
|
-
? file.thumbnailPath.substring(docPath.length + 1)
|
|
143
|
-
: file.thumbnailPath
|
|
156
|
+
? this.toPortableRelativePath(file.thumbnailPath) || undefined
|
|
144
157
|
: undefined;
|
|
158
|
+
if (!relativePath) {
|
|
159
|
+
throw new Error(`Cannot persist non-portable gallery path: ${file.filePath}`);
|
|
160
|
+
}
|
|
145
161
|
files[file.name] = {
|
|
146
162
|
...file,
|
|
147
163
|
// Store relative paths instead of absolute
|
|
148
164
|
filePath: relativePath,
|
|
149
165
|
thumbnailPath: relativeThumbnailPath,
|
|
150
166
|
};
|
|
151
|
-
|
|
167
|
+
const saveResult = storage.save(this.DOWNLOADED_FILES_KEY, files);
|
|
168
|
+
if (saveResult.is_error())
|
|
169
|
+
throw saveResult.error;
|
|
170
|
+
const quarantineResult = storage.save(this.QUARANTINED_FILES_KEY, quarantined);
|
|
171
|
+
if (quarantineResult.is_error())
|
|
172
|
+
throw quarantineResult.error;
|
|
173
|
+
for (const captureId of missingCaptureIds) {
|
|
174
|
+
galleryTransferLedger.releaseMissingLocalCommit(captureId, true);
|
|
175
|
+
}
|
|
152
176
|
// console.log(`[LocalStorage] 💾 Saved metadata for ${file.name} with relative path: ${relativePath}`)
|
|
153
177
|
}
|
|
154
178
|
catch (error) {
|
|
@@ -169,26 +193,109 @@ export class LocalStorageService {
|
|
|
169
193
|
}
|
|
170
194
|
const files = res.value;
|
|
171
195
|
const reconstructedFiles = {};
|
|
172
|
-
const
|
|
173
|
-
|
|
196
|
+
const normalizedFiles = {};
|
|
197
|
+
const quarantined = this.loadQuarantinedFiles();
|
|
198
|
+
const missingCaptureIds = [];
|
|
199
|
+
let didMigrate = false;
|
|
200
|
+
// Normalize every record before saving. This fixes the old read-absolute/write-one-relative
|
|
201
|
+
// bug and migrates stale iOS container UUID paths via their Documents/MentraPhotos suffix.
|
|
174
202
|
for (const [name, file] of Object.entries(files)) {
|
|
175
|
-
|
|
176
|
-
const
|
|
177
|
-
? file.
|
|
178
|
-
:
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
203
|
+
const relativePath = this.toPortableRelativePath(file.filePath);
|
|
204
|
+
const relativeThumbnailPath = file.thumbnailPath
|
|
205
|
+
? this.toPortableRelativePath(file.thumbnailPath) || undefined
|
|
206
|
+
: undefined;
|
|
207
|
+
if (!relativePath) {
|
|
208
|
+
quarantined[name] = { ...file, downloaded_at: file.downloaded_at || Date.now() };
|
|
209
|
+
missingCaptureIds.push(name);
|
|
210
|
+
didMigrate = true;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
const absolutePath = `${RNFS.DocumentDirectoryPath}/${relativePath}`;
|
|
214
|
+
const absoluteThumbnailPath = relativeThumbnailPath
|
|
215
|
+
? `${RNFS.DocumentDirectoryPath}/${relativeThumbnailPath}`
|
|
183
216
|
: undefined;
|
|
217
|
+
normalizedFiles[name] = {
|
|
218
|
+
...file,
|
|
219
|
+
filePath: relativePath,
|
|
220
|
+
thumbnailPath: relativeThumbnailPath,
|
|
221
|
+
};
|
|
184
222
|
reconstructedFiles[name] = {
|
|
185
223
|
...file,
|
|
186
224
|
filePath: absolutePath,
|
|
187
225
|
thumbnailPath: absoluteThumbnailPath,
|
|
188
226
|
};
|
|
227
|
+
if (file.filePath !== relativePath || file.thumbnailPath !== relativeThumbnailPath)
|
|
228
|
+
didMigrate = true;
|
|
229
|
+
}
|
|
230
|
+
if (didMigrate) {
|
|
231
|
+
const saveResult = storage.save(this.DOWNLOADED_FILES_KEY, normalizedFiles);
|
|
232
|
+
if (saveResult.is_error())
|
|
233
|
+
throw saveResult.error;
|
|
234
|
+
const quarantineResult = storage.save(this.QUARANTINED_FILES_KEY, quarantined);
|
|
235
|
+
if (quarantineResult.is_error())
|
|
236
|
+
throw quarantineResult.error;
|
|
237
|
+
for (const captureId of missingCaptureIds) {
|
|
238
|
+
galleryTransferLedger.releaseMissingLocalCommit(captureId, true);
|
|
239
|
+
}
|
|
189
240
|
}
|
|
190
241
|
return reconstructedFiles;
|
|
191
242
|
}
|
|
243
|
+
/**
|
|
244
|
+
* Reconcile the remote manifest against the app-local gallery index before ledger filtering.
|
|
245
|
+
* Android backup/restore and data-preserving reinstalls can restore MMKV ledger rows without
|
|
246
|
+
* restoring app-private media. Only captures currently advertised by the glasses are released,
|
|
247
|
+
* so acknowledged captures that remain in glasses trash are not resurrected unnecessarily.
|
|
248
|
+
*/
|
|
249
|
+
async reconcileRemoteCaptures(captureIds, downloadedFiles) {
|
|
250
|
+
const localFiles = downloadedFiles || (await this.getDownloadedFiles());
|
|
251
|
+
let released = 0;
|
|
252
|
+
for (const captureId of captureIds) {
|
|
253
|
+
const entry = galleryTransferLedger.get(captureId);
|
|
254
|
+
if (!entry || !galleryTransferLedger.isLocallyCommitted(captureId))
|
|
255
|
+
continue;
|
|
256
|
+
const localFile = localFiles[captureId];
|
|
257
|
+
const localFileExists = localFile?.filePath ? await RNFS.exists(localFile.filePath).catch(() => false) : false;
|
|
258
|
+
if (localFileExists)
|
|
259
|
+
continue;
|
|
260
|
+
// The transfer ledger and gallery index are persisted independently. A crash can leave the
|
|
261
|
+
// committed media in place after its index write was lost, so repair the index from the
|
|
262
|
+
// ledger before deciding that the capture needs to be restored from the glasses.
|
|
263
|
+
const committedPath = entry.finalPath?.replace(/^file:\/\//, "");
|
|
264
|
+
const committedFileExists = committedPath ? await RNFS.exists(committedPath).catch(() => false) : false;
|
|
265
|
+
if (committedPath && committedFileExists) {
|
|
266
|
+
try {
|
|
267
|
+
const stat = await RNFS.stat(committedPath);
|
|
268
|
+
const size = Number(stat.size);
|
|
269
|
+
if (Number.isFinite(size) && size > 0) {
|
|
270
|
+
const recovered = this.convertToDownloadedFile({
|
|
271
|
+
name: captureId,
|
|
272
|
+
url: "",
|
|
273
|
+
download: "",
|
|
274
|
+
size,
|
|
275
|
+
modified: entry.timestamp,
|
|
276
|
+
mime_type: entry.captureType === "video" ? "video/mp4" : "image/jpeg",
|
|
277
|
+
is_video: entry.captureType === "video",
|
|
278
|
+
filePath: committedPath,
|
|
279
|
+
}, committedPath, entry.thumbnailPath);
|
|
280
|
+
recovered.capture_id = captureId;
|
|
281
|
+
recovered.assetReceipt = entry.assetReceipt;
|
|
282
|
+
await this.saveDownloadedFile(recovered);
|
|
283
|
+
localFiles[captureId] = recovered;
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
catch (error) {
|
|
288
|
+
console.warn(`[LocalStorage] Could not recover gallery index for ${captureId}:`, error);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
galleryTransferLedger.releaseMissingLocalCommit(captureId, true);
|
|
292
|
+
released++;
|
|
293
|
+
}
|
|
294
|
+
if (released > 0) {
|
|
295
|
+
console.warn(`[LocalStorage] Released ${released} stale gallery ledger commit(s) missing local media`);
|
|
296
|
+
}
|
|
297
|
+
return released;
|
|
298
|
+
}
|
|
192
299
|
/**
|
|
193
300
|
* Get downloaded file by name
|
|
194
301
|
*/
|
|
@@ -202,6 +309,14 @@ export class LocalStorageService {
|
|
|
202
309
|
return null;
|
|
203
310
|
}
|
|
204
311
|
}
|
|
312
|
+
/** Persist a durable camera-roll receipt without replacing the local-file generation. */
|
|
313
|
+
async updateDownloadedFileAssetReceipt(fileName, assetReceipt) {
|
|
314
|
+
const files = await this.getDownloadedFiles();
|
|
315
|
+
const file = files[fileName];
|
|
316
|
+
if (!file)
|
|
317
|
+
throw new Error(`Downloaded file is missing: ${fileName}`);
|
|
318
|
+
await this.saveDownloadedFile({ ...file, assetReceipt });
|
|
319
|
+
}
|
|
205
320
|
/**
|
|
206
321
|
* Delete downloaded file (both metadata and actual files)
|
|
207
322
|
*/
|
|
@@ -229,6 +344,7 @@ export class LocalStorageService {
|
|
|
229
344
|
const rawFiles = res.value;
|
|
230
345
|
delete rawFiles[fileName];
|
|
231
346
|
await storage.save(this.DOWNLOADED_FILES_KEY, rawFiles);
|
|
347
|
+
galleryTransferLedger.releaseMissingLocalCommit(fileName);
|
|
232
348
|
return true;
|
|
233
349
|
}
|
|
234
350
|
return false;
|
|
@@ -238,6 +354,26 @@ export class LocalStorageService {
|
|
|
238
354
|
return false;
|
|
239
355
|
}
|
|
240
356
|
}
|
|
357
|
+
/** Preserve unresolved metadata for repair instead of silently deleting it from the gallery. */
|
|
358
|
+
async quarantineDownloadedFile(fileName, reason) {
|
|
359
|
+
const rawFiles = this.loadRawDownloadedFiles();
|
|
360
|
+
const file = rawFiles[fileName];
|
|
361
|
+
if (!file)
|
|
362
|
+
return;
|
|
363
|
+
const quarantined = this.loadQuarantinedFiles();
|
|
364
|
+
quarantined[fileName] = { ...file, quarantineReason: reason };
|
|
365
|
+
delete rawFiles[fileName];
|
|
366
|
+
const quarantineResult = storage.save(this.QUARANTINED_FILES_KEY, quarantined);
|
|
367
|
+
if (quarantineResult.is_error())
|
|
368
|
+
throw quarantineResult.error;
|
|
369
|
+
const filesResult = storage.save(this.DOWNLOADED_FILES_KEY, rawFiles);
|
|
370
|
+
if (filesResult.is_error())
|
|
371
|
+
throw filesResult.error;
|
|
372
|
+
galleryTransferLedger.releaseMissingLocalCommit(fileName, true);
|
|
373
|
+
}
|
|
374
|
+
async getQuarantinedDownloadedFiles() {
|
|
375
|
+
return this.loadQuarantinedFiles();
|
|
376
|
+
}
|
|
241
377
|
/**
|
|
242
378
|
* Convert PhotoInfo to DownloadedFile (assumes files are already saved to filesystem)
|
|
243
379
|
*/
|
|
@@ -335,6 +471,8 @@ export class LocalStorageService {
|
|
|
335
471
|
console.error("[LocalStorage] Error clearing downloaded files:", res.error);
|
|
336
472
|
throw res.error;
|
|
337
473
|
}
|
|
474
|
+
storage.remove(this.QUARANTINED_FILES_KEY);
|
|
475
|
+
galleryTransferLedger.releaseAllMissingLocalCommits();
|
|
338
476
|
console.log("[LocalStorage] Cleared all downloaded files and thumbnails");
|
|
339
477
|
}
|
|
340
478
|
// ============================================
|
|
@@ -418,6 +556,17 @@ export class LocalStorageService {
|
|
|
418
556
|
// Has resumable queue if there are still files to process
|
|
419
557
|
return queue.currentIndex < queue.files.length;
|
|
420
558
|
}
|
|
559
|
+
loadRawDownloadedFiles() {
|
|
560
|
+
const result = storage.load(this.DOWNLOADED_FILES_KEY);
|
|
561
|
+
return result.is_error() ? {} : result.value;
|
|
562
|
+
}
|
|
563
|
+
loadQuarantinedFiles() {
|
|
564
|
+
const result = storage.load(this.QUARANTINED_FILES_KEY);
|
|
565
|
+
return result.is_error() ? {} : result.value;
|
|
566
|
+
}
|
|
567
|
+
toPortableRelativePath(path) {
|
|
568
|
+
return toPortableGalleryPath(path, RNFS.DocumentDirectoryPath);
|
|
569
|
+
}
|
|
421
570
|
}
|
|
422
571
|
export const localStorageService = LocalStorageService.getInstance();
|
|
423
572
|
//# sourceMappingURL=localStorageService.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localStorageService.js","sourceRoot":"","sources":["../../../src/services/asg/localStorageService.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Local Storage Service for ASG Gallery\n * Manages downloaded files and sync state\n */\n\nimport * as RNFS from \"@dr.pogodin/react-native-fs\"\n\nimport {PhotoInfo} from \"../../types/asg\"\nimport {BgTimer} from \"../../utils/timers\"\nimport {storage, StorageValueNotFoundError} from \"../../utils/storage\"\n\nexport interface DownloadedFile {\n name: string\n filePath: string // Path to file on filesystem\n size: number\n modified: number\n mime_type: string\n is_video: boolean\n thumbnailPath?: string // Path to thumbnail file\n downloaded_at: number\n glassesModel?: string // Model of glasses that captured this media\n duration?: number // Video duration in milliseconds\n capture_id?: string // Capture folder name (when synced via capture-aware pipeline)\n}\n\ninterface SyncState {\n last_sync_time: number\n client_id: string\n total_downloaded: number\n total_size: number\n}\n\nexport interface SyncQueueData {\n files: PhotoInfo[]\n currentIndex: number\n startedAt: number\n hotspotInfo: {\n ssid: string\n password: string\n ip: string\n }\n}\n\nexport class LocalStorageService {\n private static instance: LocalStorageService\n private readonly DOWNLOADED_FILES_KEY = \"asg_downloaded_files\"\n private readonly SYNC_STATE_KEY = \"asg_sync_state\"\n private readonly CLIENT_ID_KEY = \"asg_client_id\"\n private readonly SYNC_QUEUE_KEY = \"asg_sync_queue\"\n private readonly ASG_PHOTOS_DIR = `${RNFS.DocumentDirectoryPath}/MentraPhotos`\n private readonly ASG_THUMBNAILS_DIR = `${RNFS.DocumentDirectoryPath}/MentraPhotos/thumbnails`\n\n private constructor() {\n this.initializeDirectories()\n }\n\n static getInstance(): LocalStorageService {\n if (!LocalStorageService.instance) {\n LocalStorageService.instance = new LocalStorageService()\n }\n return LocalStorageService.instance\n }\n\n /**\n * Initialize ASG photo directories\n */\n private async initializeDirectories(): Promise<void> {\n try {\n // Create main photos directory if it doesn't exist\n const photoDirExists = await RNFS.exists(this.ASG_PHOTOS_DIR)\n if (!photoDirExists) {\n await RNFS.mkdir(this.ASG_PHOTOS_DIR)\n console.log(`[LocalStorage] Created Mentra photos directory: ${this.ASG_PHOTOS_DIR}`)\n }\n\n // Create thumbnails directory if it doesn't exist\n const thumbDirExists = await RNFS.exists(this.ASG_THUMBNAILS_DIR)\n if (!thumbDirExists) {\n await RNFS.mkdir(this.ASG_THUMBNAILS_DIR)\n console.log(`[LocalStorage] Created Mentra thumbnails directory: ${this.ASG_THUMBNAILS_DIR}`)\n }\n } catch (error) {\n console.error(\"[LocalStorage] Error initializing directories:\", error)\n }\n }\n\n /**\n * Get the full file path for a photo\n */\n getPhotoFilePath(filename: string): string {\n return `${this.ASG_PHOTOS_DIR}/${filename}`\n }\n\n /**\n * Get the full file path for a thumbnail\n */\n getThumbnailFilePath(filename: string): string {\n return `${this.ASG_THUMBNAILS_DIR}/${filename}_thumb.jpg`\n }\n\n /**\n * Initialize client ID if not exists\n */\n async initializeClientId(): Promise<string> {\n let res = storage.load<string>(this.CLIENT_ID_KEY)\n let clientId\n if (res.is_error()) {\n clientId = `mobile_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`\n storage.save(this.CLIENT_ID_KEY, clientId)\n } else {\n clientId = res.value\n }\n return clientId\n }\n\n /**\n * Get current sync state\n */\n async getSyncState(): Promise<SyncState> {\n const clientId = await this.initializeClientId()\n const res = storage.load<SyncState>(this.SYNC_STATE_KEY)\n\n if (res.is_error()) {\n // A missing key is the expected first-sync state (fresh install / never\n // synced) — start from scratch quietly. Real storage failures still log.\n if (!(res.error instanceof StorageValueNotFoundError)) {\n console.error(\"Error getting sync state:\", res.error)\n }\n return {\n last_sync_time: 0,\n client_id: clientId,\n total_downloaded: 0,\n total_size: 0,\n }\n }\n\n const syncState = res.value\n return {...syncState, client_id: clientId}\n }\n\n /**\n * Update sync state\n */\n async updateSyncState(updates: Partial<SyncState>): Promise<void> {\n try {\n const currentState = await this.getSyncState()\n const newState = {...currentState, ...updates}\n await storage.save(this.SYNC_STATE_KEY, newState)\n } catch (error) {\n console.error(\"Error updating sync state:\", error)\n throw error\n }\n }\n\n /**\n * Save downloaded file (only metadata, file should already be written to filesystem)\n */\n async saveDownloadedFile(file: DownloadedFile): Promise<void> {\n try {\n const files = await this.getDownloadedFiles()\n\n // 🔍 DIAGNOSTIC: Check if file already exists\n // const existingFile = files[file.name]\n // if (existingFile) {\n // console.log(`[LocalStorage] ⚠️ WARNING: File ${file.name} ALREADY EXISTS - will be REPLACED!`)\n // console.log(`[LocalStorage] 📁 Existing file:`)\n // console.log(`[LocalStorage] - Downloaded at: ${new Date(existingFile.downloaded_at).toISOString()}`)\n // console.log(`[LocalStorage] - Modified: ${new Date(existingFile.modified).toISOString()}`)\n // console.log(`[LocalStorage] - Size: ${existingFile.size} bytes`)\n // console.log(`[LocalStorage] - Path: ${existingFile.filePath}`)\n // console.log(`[LocalStorage] 📁 New file:`)\n // console.log(`[LocalStorage] - Downloaded at: ${new Date(file.downloaded_at).toISOString()}`)\n // console.log(`[LocalStorage] - Modified: ${new Date(file.modified).toISOString()}`)\n // console.log(`[LocalStorage] - Size: ${file.size} bytes`)\n // console.log(`[LocalStorage] - Path: ${file.filePath}`)\n // console.log(`[LocalStorage] 🔄 This will OVERWRITE the existing entry!`)\n // } else {\n // console.log(`[LocalStorage] ✅ File ${file.name} is NEW - saving metadata`)\n // }\n\n // Store relative paths to handle iOS app container changes between launches\n // Convert absolute paths to relative (remove DocumentDirectoryPath prefix)\n const docPath = RNFS.DocumentDirectoryPath\n const relativePath = file.filePath.startsWith(docPath)\n ? file.filePath.substring(docPath.length + 1) // +1 for the slash\n : file.filePath\n const relativeThumbnailPath = file.thumbnailPath\n ? file.thumbnailPath.startsWith(docPath)\n ? file.thumbnailPath.substring(docPath.length + 1)\n : file.thumbnailPath\n : undefined\n\n files[file.name] = {\n ...file,\n // Store relative paths instead of absolute\n filePath: relativePath,\n thumbnailPath: relativeThumbnailPath,\n }\n await storage.save(this.DOWNLOADED_FILES_KEY, files)\n // console.log(`[LocalStorage] 💾 Saved metadata for ${file.name} with relative path: ${relativePath}`)\n } catch (error) {\n console.error(\"Error saving downloaded file metadata:\", error)\n throw error\n }\n }\n\n /**\n * Get all downloaded files\n */\n async getDownloadedFiles(): Promise<Record<string, DownloadedFile>> {\n const res = storage.load<Record<string, DownloadedFile>>(this.DOWNLOADED_FILES_KEY)\n if (res.is_error()) {\n // Not an error - just means no files have been downloaded yet (first use)\n // Only log as debug, not error, since this is expected on first launch\n console.log(\"[LocalStorage] No downloaded files found (first use or empty gallery)\")\n return {}\n }\n\n const files = res.value\n const reconstructedFiles: Record<string, DownloadedFile> = {}\n const docPath = RNFS.DocumentDirectoryPath\n\n // Reconstruct absolute paths from relative paths\n for (const [name, file] of Object.entries(files as Record<string, DownloadedFile>)) {\n // Check if path is already absolute (legacy data) or relative\n const absolutePath = file.filePath.startsWith(\"/\")\n ? file.filePath // Already absolute (legacy data)\n : `${docPath}/${file.filePath}` // Relative path, prepend DocumentDirectoryPath\n\n const absoluteThumbnailPath = file.thumbnailPath\n ? file.thumbnailPath.startsWith(\"/\")\n ? file.thumbnailPath // Already absolute (legacy data)\n : `${docPath}/${file.thumbnailPath}` // Relative path\n : undefined\n\n reconstructedFiles[name] = {\n ...file,\n filePath: absolutePath,\n thumbnailPath: absoluteThumbnailPath,\n }\n }\n\n return reconstructedFiles\n }\n\n /**\n * Get downloaded file by name\n */\n async getDownloadedFile(fileName: string): Promise<DownloadedFile | null> {\n try {\n const files = await this.getDownloadedFiles()\n return files[fileName] || null\n } catch (error) {\n console.error(\"Error getting downloaded file:\", error)\n return null\n }\n }\n\n /**\n * Delete downloaded file (both metadata and actual files)\n */\n async deleteDownloadedFile(fileName: string): Promise<boolean> {\n try {\n const files = await this.getDownloadedFiles()\n if (files[fileName]) {\n const file = files[fileName]\n\n // Delete actual file from filesystem\n if (file.filePath && (await RNFS.exists(file.filePath))) {\n await RNFS.unlink(file.filePath)\n console.log(`[LocalStorage] Deleted file: ${file.filePath}`)\n }\n\n // Delete thumbnail if exists\n if (file.thumbnailPath && (await RNFS.exists(file.thumbnailPath))) {\n await RNFS.unlink(file.thumbnailPath)\n console.log(`[LocalStorage] Deleted thumbnail: ${file.thumbnailPath}`)\n }\n\n // Delete metadata - need to get raw data to maintain relative paths\n const res = storage.load<Record<string, DownloadedFile>>(this.DOWNLOADED_FILES_KEY)\n if (res.is_error()) {\n console.error(\"Error loading downloaded files:\", res.error)\n return false\n }\n const rawFiles = res.value\n delete rawFiles[fileName]\n await storage.save(this.DOWNLOADED_FILES_KEY, rawFiles)\n return true\n }\n return false\n } catch (error) {\n console.error(\"Error deleting downloaded file:\", error)\n return false\n }\n }\n\n /**\n * Convert PhotoInfo to DownloadedFile (assumes files are already saved to filesystem)\n */\n convertToDownloadedFile(\n photoInfo: PhotoInfo,\n filePath: string,\n thumbnailPath?: string,\n glassesModel?: string,\n ): DownloadedFile {\n return {\n name: photoInfo.name,\n filePath: filePath,\n size: photoInfo.size,\n modified: new Date(photoInfo.modified).getTime(),\n mime_type: photoInfo.mime_type || (photoInfo.is_video ? \"video/mp4\" : \"image/jpeg\"),\n is_video: photoInfo.is_video || false,\n thumbnailPath: thumbnailPath,\n downloaded_at: Date.now(),\n glassesModel: glassesModel || photoInfo.glassesModel,\n duration: photoInfo.duration,\n }\n }\n\n /**\n * Convert DownloadedFile to PhotoInfo\n */\n convertToPhotoInfo(downloadedFile: DownloadedFile): PhotoInfo {\n // Use file:// URLs for local files\n // On iOS, ensure we have proper file:// URL format with correct number of slashes\n const fileUrl = downloadedFile.filePath.startsWith(\"file://\")\n ? downloadedFile.filePath\n : downloadedFile.filePath.startsWith(\"/\")\n ? `file://${downloadedFile.filePath}` // Path already has leading slash\n : `file:///${downloadedFile.filePath}` // Path needs leading slash\n\n const thumbnailUrl = downloadedFile.thumbnailPath\n ? downloadedFile.thumbnailPath.startsWith(\"file://\")\n ? downloadedFile.thumbnailPath\n : downloadedFile.thumbnailPath.startsWith(\"/\")\n ? `file://${downloadedFile.thumbnailPath}` // Path already has leading slash\n : `file:///${downloadedFile.thumbnailPath}` // Path needs leading slash\n : undefined\n\n return {\n name: downloadedFile.name,\n url: fileUrl,\n download: fileUrl,\n size: downloadedFile.size,\n modified: new Date(downloadedFile.modified).toISOString(),\n mime_type: downloadedFile.mime_type,\n is_video: downloadedFile.is_video,\n thumbnail_data: undefined,\n downloaded_at: downloadedFile.downloaded_at,\n filePath: downloadedFile.filePath,\n glassesModel: downloadedFile.glassesModel,\n thumbnailPath: thumbnailUrl, // Use the file:// URL version for thumbnailPath\n duration: downloadedFile.duration,\n }\n }\n\n /**\n * Get storage statistics\n */\n async getStorageStats(): Promise<{\n total_files: number\n total_size: number\n last_sync: number\n }> {\n try {\n const files = await this.getDownloadedFiles()\n const syncState = await this.getSyncState()\n\n const totalSize = Object.values(files).reduce((sum, file) => sum + file.size, 0)\n\n return {\n total_files: Object.keys(files).length,\n total_size: totalSize,\n last_sync: syncState.last_sync_time,\n }\n } catch (error) {\n console.error(\"Error getting storage stats:\", error)\n return {\n total_files: 0,\n total_size: 0,\n last_sync: 0,\n }\n }\n }\n\n /**\n * Clear all downloaded files (both metadata and actual files)\n */\n async clearAllFiles(): Promise<void> {\n // Nuke the entire photos directory (includes thumbnails subdirectory)\n // This is more reliable than deleting individual files, which can miss orphaned thumbnails\n try {\n if (await RNFS.exists(this.ASG_PHOTOS_DIR)) {\n await RNFS.unlink(this.ASG_PHOTOS_DIR)\n console.log(\"[LocalStorage] Deleted entire photos directory\")\n }\n } catch (error) {\n console.error(\"[LocalStorage] Error deleting photos directory:\", error)\n }\n\n // Recreate empty directories\n await this.initializeDirectories()\n\n // Clear metadata\n const res = await storage.remove(this.DOWNLOADED_FILES_KEY)\n if (res.is_error()) {\n console.error(\"[LocalStorage] Error clearing downloaded files:\", res.error)\n throw res.error\n }\n console.log(\"[LocalStorage] Cleared all downloaded files and thumbnails\")\n }\n\n // ============================================\n // Sync Queue Persistence (for background sync resume)\n // ============================================\n\n /**\n * Save sync queue for potential resume after app restart\n */\n async saveSyncQueue(queue: SyncQueueData): Promise<void> {\n try {\n await storage.save(this.SYNC_QUEUE_KEY, queue)\n console.log(`[LocalStorage] Saved sync queue: ${queue.files.length} files, index ${queue.currentIndex}`)\n } catch (error) {\n console.error(\"[LocalStorage] Error saving sync queue:\", error)\n throw error\n }\n }\n\n /**\n * Get saved sync queue (for resume on app restart)\n */\n async getSyncQueue(): Promise<SyncQueueData | null> {\n try {\n const res = storage.load<SyncQueueData>(this.SYNC_QUEUE_KEY)\n if (res.is_error()) {\n // No queue saved - this is normal\n return null\n }\n const queue = res.value\n console.log(`[LocalStorage] Loaded sync queue: ${queue.files.length} files, index ${queue.currentIndex}`)\n return queue\n } catch (error) {\n console.error(\"[LocalStorage] Error loading sync queue:\", error)\n return null\n }\n }\n\n /**\n * Update the current index of the sync queue (called after each file completes)\n */\n async updateSyncQueueIndex(newIndex: number): Promise<void> {\n // S6: Let errors propagate — caller uses .catch() for non-critical updates\n const queue = await this.getSyncQueue()\n if (queue) {\n queue.currentIndex = newIndex\n await this.saveSyncQueue(queue)\n }\n }\n\n /**\n * Clear sync queue (called on sync complete or cancel)\n */\n async clearSyncQueue(): Promise<void> {\n // S6: Retry up to 3 times to ensure queue is cleared\n for (let attempt = 1; attempt <= 3; attempt++) {\n try {\n const res = await storage.remove(this.SYNC_QUEUE_KEY)\n if (res.is_error()) {\n console.error(`[LocalStorage] Error clearing sync queue (attempt ${attempt}/3):`, res.error)\n if (attempt < 3) continue\n return\n }\n console.log(\"[LocalStorage] Cleared sync queue\")\n return\n } catch (error) {\n console.error(`[LocalStorage] Error clearing sync queue (attempt ${attempt}/3):`, error)\n if (attempt < 3) {\n await new Promise<void>((resolve) => BgTimer.setTimeout(() => resolve(), 100))\n }\n }\n }\n }\n\n /**\n * Check if there's a resumable sync queue\n */\n async hasResumableSyncQueue(): Promise<boolean> {\n const queue = await this.getSyncQueue()\n if (!queue) return false\n // Has resumable queue if there are still files to process\n return queue.currentIndex < queue.files.length\n }\n}\n\nexport const localStorageService = LocalStorageService.getInstance()\n"]}
|
|
1
|
+
{"version":3,"file":"localStorageService.js","sourceRoot":"","sources":["../../../src/services/asg/localStorageService.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Local Storage Service for ASG Gallery\n * Manages downloaded files and sync state\n */\n\nimport * as RNFS from \"@dr.pogodin/react-native-fs\"\n\nimport {PhotoInfo} from \"../../types/asg\"\nimport {BgTimer} from \"../../utils/timers\"\nimport {storage, StorageValueNotFoundError} from \"../../utils/storage\"\nimport {galleryTransferLedger, GalleryAssetReceipt} from \"./galleryTransferLedger\"\nimport {toPortableGalleryPath} from \"./galleryPathMigration\"\n\nexport interface DownloadedFile {\n name: string\n filePath: string // Path to file on filesystem\n size: number\n modified: number\n mime_type: string\n is_video: boolean\n thumbnailPath?: string // Path to thumbnail file\n downloaded_at: number\n glassesModel?: string // Model of glasses that captured this media\n duration?: number // Video duration in milliseconds\n capture_id?: string // Capture folder name (when synced via capture-aware pipeline)\n assetReceipt?: GalleryAssetReceipt\n}\n\ninterface SyncState {\n last_sync_time: number\n client_id: string\n total_downloaded: number\n total_size: number\n}\n\nexport interface SyncQueueData {\n files: PhotoInfo[]\n currentIndex: number\n startedAt: number\n hotspotInfo: {\n ssid: string\n password: string\n ip: string\n }\n}\n\nexport class LocalStorageService {\n private static instance: LocalStorageService\n private readonly DOWNLOADED_FILES_KEY = \"asg_downloaded_files\"\n private readonly SYNC_STATE_KEY = \"asg_sync_state\"\n private readonly CLIENT_ID_KEY = \"asg_client_id\"\n private readonly SYNC_QUEUE_KEY = \"asg_sync_queue\"\n private readonly QUARANTINED_FILES_KEY = \"asg_quarantined_downloaded_files_v1\"\n private readonly ASG_PHOTOS_DIR = `${RNFS.DocumentDirectoryPath}/MentraPhotos`\n private readonly ASG_THUMBNAILS_DIR = `${RNFS.DocumentDirectoryPath}/MentraPhotos/thumbnails`\n\n private constructor() {\n this.initializeDirectories()\n }\n\n static getInstance(): LocalStorageService {\n if (!LocalStorageService.instance) {\n LocalStorageService.instance = new LocalStorageService()\n }\n return LocalStorageService.instance\n }\n\n /**\n * Initialize ASG photo directories\n */\n private async initializeDirectories(): Promise<void> {\n try {\n // Create main photos directory if it doesn't exist\n const photoDirExists = await RNFS.exists(this.ASG_PHOTOS_DIR)\n if (!photoDirExists) {\n await RNFS.mkdir(this.ASG_PHOTOS_DIR)\n console.log(`[LocalStorage] Created Mentra photos directory: ${this.ASG_PHOTOS_DIR}`)\n }\n\n // Create thumbnails directory if it doesn't exist\n const thumbDirExists = await RNFS.exists(this.ASG_THUMBNAILS_DIR)\n if (!thumbDirExists) {\n await RNFS.mkdir(this.ASG_THUMBNAILS_DIR)\n console.log(`[LocalStorage] Created Mentra thumbnails directory: ${this.ASG_THUMBNAILS_DIR}`)\n }\n } catch (error) {\n console.error(\"[LocalStorage] Error initializing directories:\", error)\n }\n }\n\n /**\n * Get the full file path for a photo\n */\n getPhotoFilePath(filename: string): string {\n return `${this.ASG_PHOTOS_DIR}/${filename}`\n }\n\n /**\n * Get the full file path for a thumbnail\n */\n getThumbnailFilePath(filename: string): string {\n return `${this.ASG_THUMBNAILS_DIR}/${filename}_thumb.jpg`\n }\n\n /**\n * Initialize client ID if not exists\n */\n async initializeClientId(): Promise<string> {\n let res = storage.load<string>(this.CLIENT_ID_KEY)\n let clientId\n if (res.is_error()) {\n clientId = `mobile_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`\n storage.save(this.CLIENT_ID_KEY, clientId)\n } else {\n clientId = res.value\n }\n return clientId\n }\n\n /**\n * Get current sync state\n */\n async getSyncState(): Promise<SyncState> {\n const clientId = await this.initializeClientId()\n const res = storage.load<SyncState>(this.SYNC_STATE_KEY)\n\n if (res.is_error()) {\n // A missing key is the expected first-sync state (fresh install / never\n // synced) — start from scratch quietly. Real storage failures still log.\n if (!(res.error instanceof StorageValueNotFoundError)) {\n console.error(\"Error getting sync state:\", res.error)\n }\n return {\n last_sync_time: 0,\n client_id: clientId,\n total_downloaded: 0,\n total_size: 0,\n }\n }\n\n const syncState = res.value\n return {...syncState, client_id: clientId}\n }\n\n /**\n * Update sync state\n */\n async updateSyncState(updates: Partial<SyncState>): Promise<void> {\n try {\n const currentState = await this.getSyncState()\n const newState = {...currentState, ...updates}\n await storage.save(this.SYNC_STATE_KEY, newState)\n } catch (error) {\n console.error(\"Error updating sync state:\", error)\n throw error\n }\n }\n\n /**\n * Save downloaded file (only metadata, file should already be written to filesystem)\n */\n async saveDownloadedFile(file: DownloadedFile): Promise<void> {\n try {\n const rawFiles = this.loadRawDownloadedFiles()\n const files: Record<string, DownloadedFile> = {}\n const quarantined = this.loadQuarantinedFiles()\n const missingCaptureIds: string[] = []\n for (const [name, existing] of Object.entries(rawFiles)) {\n const existingPath = this.toPortableRelativePath(existing.filePath)\n const existingThumbnail = existing.thumbnailPath\n ? this.toPortableRelativePath(existing.thumbnailPath) || undefined\n : undefined\n if (!existingPath) {\n quarantined[name] = existing\n missingCaptureIds.push(name)\n continue\n }\n files[name] = {...existing, filePath: existingPath, thumbnailPath: existingThumbnail}\n }\n\n // 🔍 DIAGNOSTIC: Check if file already exists\n // const existingFile = files[file.name]\n // if (existingFile) {\n // console.log(`[LocalStorage] ⚠️ WARNING: File ${file.name} ALREADY EXISTS - will be REPLACED!`)\n // console.log(`[LocalStorage] 📁 Existing file:`)\n // console.log(`[LocalStorage] - Downloaded at: ${new Date(existingFile.downloaded_at).toISOString()}`)\n // console.log(`[LocalStorage] - Modified: ${new Date(existingFile.modified).toISOString()}`)\n // console.log(`[LocalStorage] - Size: ${existingFile.size} bytes`)\n // console.log(`[LocalStorage] - Path: ${existingFile.filePath}`)\n // console.log(`[LocalStorage] 📁 New file:`)\n // console.log(`[LocalStorage] - Downloaded at: ${new Date(file.downloaded_at).toISOString()}`)\n // console.log(`[LocalStorage] - Modified: ${new Date(file.modified).toISOString()}`)\n // console.log(`[LocalStorage] - Size: ${file.size} bytes`)\n // console.log(`[LocalStorage] - Path: ${file.filePath}`)\n // console.log(`[LocalStorage] 🔄 This will OVERWRITE the existing entry!`)\n // } else {\n // console.log(`[LocalStorage] ✅ File ${file.name} is NEW - saving metadata`)\n // }\n\n // Store relative paths to handle iOS app container changes between launches\n // Convert absolute paths to relative (remove DocumentDirectoryPath prefix)\n const relativePath = this.toPortableRelativePath(file.filePath)\n const relativeThumbnailPath = file.thumbnailPath\n ? this.toPortableRelativePath(file.thumbnailPath) || undefined\n : undefined\n\n if (!relativePath) {\n throw new Error(`Cannot persist non-portable gallery path: ${file.filePath}`)\n }\n\n files[file.name] = {\n ...file,\n // Store relative paths instead of absolute\n filePath: relativePath,\n thumbnailPath: relativeThumbnailPath,\n }\n const saveResult = storage.save(this.DOWNLOADED_FILES_KEY, files)\n if (saveResult.is_error()) throw saveResult.error\n const quarantineResult = storage.save(this.QUARANTINED_FILES_KEY, quarantined)\n if (quarantineResult.is_error()) throw quarantineResult.error\n for (const captureId of missingCaptureIds) {\n galleryTransferLedger.releaseMissingLocalCommit(captureId, true)\n }\n // console.log(`[LocalStorage] 💾 Saved metadata for ${file.name} with relative path: ${relativePath}`)\n } catch (error) {\n console.error(\"Error saving downloaded file metadata:\", error)\n throw error\n }\n }\n\n /**\n * Get all downloaded files\n */\n async getDownloadedFiles(): Promise<Record<string, DownloadedFile>> {\n const res = storage.load<Record<string, DownloadedFile>>(this.DOWNLOADED_FILES_KEY)\n if (res.is_error()) {\n // Not an error - just means no files have been downloaded yet (first use)\n // Only log as debug, not error, since this is expected on first launch\n console.log(\"[LocalStorage] No downloaded files found (first use or empty gallery)\")\n return {}\n }\n\n const files = res.value\n const reconstructedFiles: Record<string, DownloadedFile> = {}\n const normalizedFiles: Record<string, DownloadedFile> = {}\n const quarantined = this.loadQuarantinedFiles()\n const missingCaptureIds: string[] = []\n let didMigrate = false\n\n // Normalize every record before saving. This fixes the old read-absolute/write-one-relative\n // bug and migrates stale iOS container UUID paths via their Documents/MentraPhotos suffix.\n for (const [name, file] of Object.entries(files as Record<string, DownloadedFile>)) {\n const relativePath = this.toPortableRelativePath(file.filePath)\n const relativeThumbnailPath = file.thumbnailPath\n ? this.toPortableRelativePath(file.thumbnailPath) || undefined\n : undefined\n if (!relativePath) {\n quarantined[name] = {...file, downloaded_at: file.downloaded_at || Date.now()}\n missingCaptureIds.push(name)\n didMigrate = true\n continue\n }\n const absolutePath = `${RNFS.DocumentDirectoryPath}/${relativePath}`\n const absoluteThumbnailPath = relativeThumbnailPath\n ? `${RNFS.DocumentDirectoryPath}/${relativeThumbnailPath}`\n : undefined\n\n normalizedFiles[name] = {\n ...file,\n filePath: relativePath,\n thumbnailPath: relativeThumbnailPath,\n }\n\n reconstructedFiles[name] = {\n ...file,\n filePath: absolutePath,\n thumbnailPath: absoluteThumbnailPath,\n }\n if (file.filePath !== relativePath || file.thumbnailPath !== relativeThumbnailPath) didMigrate = true\n }\n\n if (didMigrate) {\n const saveResult = storage.save(this.DOWNLOADED_FILES_KEY, normalizedFiles)\n if (saveResult.is_error()) throw saveResult.error\n const quarantineResult = storage.save(this.QUARANTINED_FILES_KEY, quarantined)\n if (quarantineResult.is_error()) throw quarantineResult.error\n for (const captureId of missingCaptureIds) {\n galleryTransferLedger.releaseMissingLocalCommit(captureId, true)\n }\n }\n\n return reconstructedFiles\n }\n\n /**\n * Reconcile the remote manifest against the app-local gallery index before ledger filtering.\n * Android backup/restore and data-preserving reinstalls can restore MMKV ledger rows without\n * restoring app-private media. Only captures currently advertised by the glasses are released,\n * so acknowledged captures that remain in glasses trash are not resurrected unnecessarily.\n */\n async reconcileRemoteCaptures(\n captureIds: string[],\n downloadedFiles?: Record<string, DownloadedFile>,\n ): Promise<number> {\n const localFiles = downloadedFiles || (await this.getDownloadedFiles())\n let released = 0\n for (const captureId of captureIds) {\n const entry = galleryTransferLedger.get(captureId)\n if (!entry || !galleryTransferLedger.isLocallyCommitted(captureId)) continue\n const localFile = localFiles[captureId]\n const localFileExists = localFile?.filePath ? await RNFS.exists(localFile.filePath).catch(() => false) : false\n if (localFileExists) continue\n\n // The transfer ledger and gallery index are persisted independently. A crash can leave the\n // committed media in place after its index write was lost, so repair the index from the\n // ledger before deciding that the capture needs to be restored from the glasses.\n const committedPath = entry.finalPath?.replace(/^file:\\/\\//, \"\")\n const committedFileExists = committedPath ? await RNFS.exists(committedPath).catch(() => false) : false\n if (committedPath && committedFileExists) {\n try {\n const stat = await RNFS.stat(committedPath)\n const size = Number(stat.size)\n if (Number.isFinite(size) && size > 0) {\n const recovered = this.convertToDownloadedFile(\n {\n name: captureId,\n url: \"\",\n download: \"\",\n size,\n modified: entry.timestamp,\n mime_type: entry.captureType === \"video\" ? \"video/mp4\" : \"image/jpeg\",\n is_video: entry.captureType === \"video\",\n filePath: committedPath,\n },\n committedPath,\n entry.thumbnailPath,\n )\n recovered.capture_id = captureId\n recovered.assetReceipt = entry.assetReceipt\n await this.saveDownloadedFile(recovered)\n localFiles[captureId] = recovered\n continue\n }\n } catch (error) {\n console.warn(`[LocalStorage] Could not recover gallery index for ${captureId}:`, error)\n }\n }\n galleryTransferLedger.releaseMissingLocalCommit(captureId, true)\n released++\n }\n if (released > 0) {\n console.warn(`[LocalStorage] Released ${released} stale gallery ledger commit(s) missing local media`)\n }\n return released\n }\n\n /**\n * Get downloaded file by name\n */\n async getDownloadedFile(fileName: string): Promise<DownloadedFile | null> {\n try {\n const files = await this.getDownloadedFiles()\n return files[fileName] || null\n } catch (error) {\n console.error(\"Error getting downloaded file:\", error)\n return null\n }\n }\n\n /** Persist a durable camera-roll receipt without replacing the local-file generation. */\n async updateDownloadedFileAssetReceipt(fileName: string, assetReceipt: GalleryAssetReceipt): Promise<void> {\n const files = await this.getDownloadedFiles()\n const file = files[fileName]\n if (!file) throw new Error(`Downloaded file is missing: ${fileName}`)\n await this.saveDownloadedFile({...file, assetReceipt})\n }\n\n /**\n * Delete downloaded file (both metadata and actual files)\n */\n async deleteDownloadedFile(fileName: string): Promise<boolean> {\n try {\n const files = await this.getDownloadedFiles()\n if (files[fileName]) {\n const file = files[fileName]\n\n // Delete actual file from filesystem\n if (file.filePath && (await RNFS.exists(file.filePath))) {\n await RNFS.unlink(file.filePath)\n console.log(`[LocalStorage] Deleted file: ${file.filePath}`)\n }\n\n // Delete thumbnail if exists\n if (file.thumbnailPath && (await RNFS.exists(file.thumbnailPath))) {\n await RNFS.unlink(file.thumbnailPath)\n console.log(`[LocalStorage] Deleted thumbnail: ${file.thumbnailPath}`)\n }\n\n // Delete metadata - need to get raw data to maintain relative paths\n const res = storage.load<Record<string, DownloadedFile>>(this.DOWNLOADED_FILES_KEY)\n if (res.is_error()) {\n console.error(\"Error loading downloaded files:\", res.error)\n return false\n }\n const rawFiles = res.value\n delete rawFiles[fileName]\n await storage.save(this.DOWNLOADED_FILES_KEY, rawFiles)\n galleryTransferLedger.releaseMissingLocalCommit(fileName)\n return true\n }\n return false\n } catch (error) {\n console.error(\"Error deleting downloaded file:\", error)\n return false\n }\n }\n\n /** Preserve unresolved metadata for repair instead of silently deleting it from the gallery. */\n async quarantineDownloadedFile(fileName: string, reason: string): Promise<void> {\n const rawFiles = this.loadRawDownloadedFiles()\n const file = rawFiles[fileName]\n if (!file) return\n const quarantined = this.loadQuarantinedFiles()\n quarantined[fileName] = {...file, quarantineReason: reason} as DownloadedFile\n delete rawFiles[fileName]\n const quarantineResult = storage.save(this.QUARANTINED_FILES_KEY, quarantined)\n if (quarantineResult.is_error()) throw quarantineResult.error\n const filesResult = storage.save(this.DOWNLOADED_FILES_KEY, rawFiles)\n if (filesResult.is_error()) throw filesResult.error\n galleryTransferLedger.releaseMissingLocalCommit(fileName, true)\n }\n\n async getQuarantinedDownloadedFiles(): Promise<Record<string, DownloadedFile>> {\n return this.loadQuarantinedFiles()\n }\n\n /**\n * Convert PhotoInfo to DownloadedFile (assumes files are already saved to filesystem)\n */\n convertToDownloadedFile(\n photoInfo: PhotoInfo,\n filePath: string,\n thumbnailPath?: string,\n glassesModel?: string,\n ): DownloadedFile {\n return {\n name: photoInfo.name,\n filePath: filePath,\n size: photoInfo.size,\n modified: new Date(photoInfo.modified).getTime(),\n mime_type: photoInfo.mime_type || (photoInfo.is_video ? \"video/mp4\" : \"image/jpeg\"),\n is_video: photoInfo.is_video || false,\n thumbnailPath: thumbnailPath,\n downloaded_at: Date.now(),\n glassesModel: glassesModel || photoInfo.glassesModel,\n duration: photoInfo.duration,\n }\n }\n\n /**\n * Convert DownloadedFile to PhotoInfo\n */\n convertToPhotoInfo(downloadedFile: DownloadedFile): PhotoInfo {\n // Use file:// URLs for local files\n // On iOS, ensure we have proper file:// URL format with correct number of slashes\n const fileUrl = downloadedFile.filePath.startsWith(\"file://\")\n ? downloadedFile.filePath\n : downloadedFile.filePath.startsWith(\"/\")\n ? `file://${downloadedFile.filePath}` // Path already has leading slash\n : `file:///${downloadedFile.filePath}` // Path needs leading slash\n\n const thumbnailUrl = downloadedFile.thumbnailPath\n ? downloadedFile.thumbnailPath.startsWith(\"file://\")\n ? downloadedFile.thumbnailPath\n : downloadedFile.thumbnailPath.startsWith(\"/\")\n ? `file://${downloadedFile.thumbnailPath}` // Path already has leading slash\n : `file:///${downloadedFile.thumbnailPath}` // Path needs leading slash\n : undefined\n\n return {\n name: downloadedFile.name,\n url: fileUrl,\n download: fileUrl,\n size: downloadedFile.size,\n modified: new Date(downloadedFile.modified).toISOString(),\n mime_type: downloadedFile.mime_type,\n is_video: downloadedFile.is_video,\n thumbnail_data: undefined,\n downloaded_at: downloadedFile.downloaded_at,\n filePath: downloadedFile.filePath,\n glassesModel: downloadedFile.glassesModel,\n thumbnailPath: thumbnailUrl, // Use the file:// URL version for thumbnailPath\n duration: downloadedFile.duration,\n }\n }\n\n /**\n * Get storage statistics\n */\n async getStorageStats(): Promise<{\n total_files: number\n total_size: number\n last_sync: number\n }> {\n try {\n const files = await this.getDownloadedFiles()\n const syncState = await this.getSyncState()\n\n const totalSize = Object.values(files).reduce((sum, file) => sum + file.size, 0)\n\n return {\n total_files: Object.keys(files).length,\n total_size: totalSize,\n last_sync: syncState.last_sync_time,\n }\n } catch (error) {\n console.error(\"Error getting storage stats:\", error)\n return {\n total_files: 0,\n total_size: 0,\n last_sync: 0,\n }\n }\n }\n\n /**\n * Clear all downloaded files (both metadata and actual files)\n */\n async clearAllFiles(): Promise<void> {\n // Nuke the entire photos directory (includes thumbnails subdirectory)\n // This is more reliable than deleting individual files, which can miss orphaned thumbnails\n try {\n if (await RNFS.exists(this.ASG_PHOTOS_DIR)) {\n await RNFS.unlink(this.ASG_PHOTOS_DIR)\n console.log(\"[LocalStorage] Deleted entire photos directory\")\n }\n } catch (error) {\n console.error(\"[LocalStorage] Error deleting photos directory:\", error)\n }\n\n // Recreate empty directories\n await this.initializeDirectories()\n\n // Clear metadata\n const res = await storage.remove(this.DOWNLOADED_FILES_KEY)\n if (res.is_error()) {\n console.error(\"[LocalStorage] Error clearing downloaded files:\", res.error)\n throw res.error\n }\n storage.remove(this.QUARANTINED_FILES_KEY)\n galleryTransferLedger.releaseAllMissingLocalCommits()\n console.log(\"[LocalStorage] Cleared all downloaded files and thumbnails\")\n }\n\n // ============================================\n // Sync Queue Persistence (for background sync resume)\n // ============================================\n\n /**\n * Save sync queue for potential resume after app restart\n */\n async saveSyncQueue(queue: SyncQueueData): Promise<void> {\n try {\n await storage.save(this.SYNC_QUEUE_KEY, queue)\n console.log(`[LocalStorage] Saved sync queue: ${queue.files.length} files, index ${queue.currentIndex}`)\n } catch (error) {\n console.error(\"[LocalStorage] Error saving sync queue:\", error)\n throw error\n }\n }\n\n /**\n * Get saved sync queue (for resume on app restart)\n */\n async getSyncQueue(): Promise<SyncQueueData | null> {\n try {\n const res = storage.load<SyncQueueData>(this.SYNC_QUEUE_KEY)\n if (res.is_error()) {\n // No queue saved - this is normal\n return null\n }\n const queue = res.value\n console.log(`[LocalStorage] Loaded sync queue: ${queue.files.length} files, index ${queue.currentIndex}`)\n return queue\n } catch (error) {\n console.error(\"[LocalStorage] Error loading sync queue:\", error)\n return null\n }\n }\n\n /**\n * Update the current index of the sync queue (called after each file completes)\n */\n async updateSyncQueueIndex(newIndex: number): Promise<void> {\n // S6: Let errors propagate — caller uses .catch() for non-critical updates\n const queue = await this.getSyncQueue()\n if (queue) {\n queue.currentIndex = newIndex\n await this.saveSyncQueue(queue)\n }\n }\n\n /**\n * Clear sync queue (called on sync complete or cancel)\n */\n async clearSyncQueue(): Promise<void> {\n // S6: Retry up to 3 times to ensure queue is cleared\n for (let attempt = 1; attempt <= 3; attempt++) {\n try {\n const res = await storage.remove(this.SYNC_QUEUE_KEY)\n if (res.is_error()) {\n console.error(`[LocalStorage] Error clearing sync queue (attempt ${attempt}/3):`, res.error)\n if (attempt < 3) continue\n return\n }\n console.log(\"[LocalStorage] Cleared sync queue\")\n return\n } catch (error) {\n console.error(`[LocalStorage] Error clearing sync queue (attempt ${attempt}/3):`, error)\n if (attempt < 3) {\n await new Promise<void>((resolve) => BgTimer.setTimeout(() => resolve(), 100))\n }\n }\n }\n }\n\n /**\n * Check if there's a resumable sync queue\n */\n async hasResumableSyncQueue(): Promise<boolean> {\n const queue = await this.getSyncQueue()\n if (!queue) return false\n // Has resumable queue if there are still files to process\n return queue.currentIndex < queue.files.length\n }\n\n private loadRawDownloadedFiles(): Record<string, DownloadedFile> {\n const result = storage.load<Record<string, DownloadedFile>>(this.DOWNLOADED_FILES_KEY)\n return result.is_error() ? {} : result.value\n }\n\n private loadQuarantinedFiles(): Record<string, DownloadedFile> {\n const result = storage.load<Record<string, DownloadedFile>>(this.QUARANTINED_FILES_KEY)\n return result.is_error() ? {} : result.value\n }\n\n private toPortableRelativePath(path: string): string | null {\n return toPortableGalleryPath(path, RNFS.DocumentDirectoryPath)\n }\n}\n\nexport const localStorageService = LocalStorageService.getInstance()\n"]}
|
|
@@ -34,6 +34,8 @@ export interface ProcessingItem {
|
|
|
34
34
|
thumbnailPath?: string;
|
|
35
35
|
/** File names to delete from glasses after processing completes */
|
|
36
36
|
deleteFromGlasses?: string[];
|
|
37
|
+
/** Negotiated gallery protocol; absent entries are inferred from the transfer ledger. */
|
|
38
|
+
protocolVersion?: number;
|
|
37
39
|
}
|
|
38
40
|
declare class MediaProcessingQueue {
|
|
39
41
|
private queue;
|
|
@@ -50,10 +52,18 @@ declare class MediaProcessingQueue {
|
|
|
50
52
|
get hasPending(): boolean;
|
|
51
53
|
/** Returns a promise that resolves when the queue is fully drained, or rejects on timeout. */
|
|
52
54
|
waitUntilDrained(timeoutMs?: number): Promise<void>;
|
|
55
|
+
/** Retry durable export/ack work after an app restart without downloading media again. */
|
|
56
|
+
retryPending(): Promise<{
|
|
57
|
+
retried: number;
|
|
58
|
+
failed: number;
|
|
59
|
+
}>;
|
|
60
|
+
private acknowledgeEntry;
|
|
53
61
|
/** Process items one at a time. */
|
|
54
62
|
private processLoop;
|
|
55
63
|
/** Process a single item through the full pipeline. */
|
|
56
64
|
private processItem;
|
|
65
|
+
/** Rebuild a missing app-local index row from the durable transfer ledger. */
|
|
66
|
+
private recoverDownloadedFile;
|
|
57
67
|
}
|
|
58
68
|
export declare const mediaProcessingQueue: MediaProcessingQueue;
|
|
59
69
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mediaProcessingQueue.d.ts","sourceRoot":"","sources":["../../../src/services/asg/mediaProcessingQueue.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"mediaProcessingQueue.d.ts","sourceRoot":"","sources":["../../../src/services/asg/mediaProcessingQueue.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgBH,MAAM,WAAW,cAAc;IAC7B,oDAAoD;IACpD,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,OAAO,GAAG,OAAO,CAAA;IACvB,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAA;IACnB,kCAAkC;IAClC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,4BAA4B;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sBAAsB;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,oBAAoB;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,oDAAoD;IACpD,aAAa,EAAE,OAAO,CAAA;IACtB,0CAA0C;IAC1C,cAAc,EAAE,OAAO,CAAA;IACvB,qDAAqD;IACrD,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,mEAAmE;IACnE,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC5B,yFAAyF;IACzF,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,cAAM,oBAAoB;IACxB,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,UAAU,CAAI;IAEtB,qFAAqF;IACrF,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAenC,qCAAqC;IACrC,KAAK,IAAI,IAAI;IAMb,0CAA0C;IAC1C,KAAK,IAAI,IAAI;IAOb,sEAAsE;IACtE,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,8FAA8F;IAC9F,gBAAgB,CAAC,SAAS,GAAE,MAA2B,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBvE,0FAA0F;IACpF,YAAY,IAAI,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,CAAC;YAmDlD,gBAAgB;IAa9B,mCAAmC;YACrB,WAAW;IA4CzB,uDAAuD;YACzC,WAAW;IA8OzB,8EAA8E;YAChE,qBAAqB;CAgDpC;AAED,eAAO,MAAM,oBAAoB,sBAA6B,CAAA"}
|