@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,12 +12,27 @@
|
|
|
12
12
|
* get it in the same round trip — no second fetch.
|
|
13
13
|
*
|
|
14
14
|
* Pre-flighting at the call site keeps /applet/local a pure mount route.
|
|
15
|
+
*
|
|
16
|
+
* When the laptop's Wi-Fi IP changes, the URL stored from the last QR scan
|
|
17
|
+
* goes stale. We then retry alternate hosts (Metro / EXPO_PUBLIC_LOCAL_MINIAPP_HOST,
|
|
18
|
+
* plus an mDNS name captured at scan time) and persist the working URL so
|
|
19
|
+
* the next launch doesn't need a re-scan.
|
|
15
20
|
*/
|
|
16
21
|
|
|
22
|
+
import {configuredDevHost} from "./configuredDevHost"
|
|
17
23
|
import {storage} from "./storage/storage"
|
|
18
24
|
|
|
19
25
|
const REACHABILITY_TIMEOUT_MS = 1500
|
|
20
26
|
|
|
27
|
+
// A single dropped DNS lookup or momentary Wi-Fi blip (AP roam, DHCP renewal,
|
|
28
|
+
// phone hopping to cellular for a beat) looks identical to a dead dev server —
|
|
29
|
+
// both throw out of fetch(). Retrying once absorbs that transient case instead
|
|
30
|
+
// of bouncing straight to the offline screen. We do NOT retry a real HTTP
|
|
31
|
+
// response (res.ok === false): that's the server telling us something
|
|
32
|
+
// definitive, not a network-layer hiccup.
|
|
33
|
+
const REACHABILITY_MAX_ATTEMPTS = 2
|
|
34
|
+
const REACHABILITY_RETRY_DELAY_MS = 400
|
|
35
|
+
|
|
21
36
|
export type DevManifest = {
|
|
22
37
|
packageName?: string
|
|
23
38
|
name?: string
|
|
@@ -29,40 +44,153 @@ export type DevManifest = {
|
|
|
29
44
|
}
|
|
30
45
|
|
|
31
46
|
export type DevLaunchResult =
|
|
32
|
-
| {decision: "live"; manifest: DevManifest}
|
|
33
|
-
| {decision: "offline"; manifest: null}
|
|
47
|
+
| {decision: "live"; manifest: DevManifest; resolvedUrl: string}
|
|
48
|
+
| {decision: "offline"; manifest: null; resolvedUrl?: undefined}
|
|
49
|
+
|
|
50
|
+
export type DecideDevLaunchOptions = {
|
|
51
|
+
/** Extra hostnames / IPs to try if `devUrl` is unreachable (no scheme/port). */
|
|
52
|
+
alternateHosts?: string[]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function delay(ms: number): Promise<void> {
|
|
56
|
+
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Single GET <devUrl>/miniapp.json attempt with a hard timeout. */
|
|
60
|
+
async function fetchManifestOnce(devUrl: string): Promise<DevManifest | null> {
|
|
61
|
+
const controller = new AbortController()
|
|
62
|
+
const timer = setTimeout(() => controller.abort(), REACHABILITY_TIMEOUT_MS)
|
|
63
|
+
try {
|
|
64
|
+
const res = await fetch(`${devUrl.replace(/\/$/, "")}/miniapp.json`, {
|
|
65
|
+
method: "GET",
|
|
66
|
+
signal: controller.signal,
|
|
67
|
+
})
|
|
68
|
+
if (!res.ok) return null
|
|
69
|
+
return (await res.json()) as DevManifest
|
|
70
|
+
} finally {
|
|
71
|
+
clearTimeout(timer)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function rewriteHost(devUrl: string, host: string): string | null {
|
|
76
|
+
const trimmed = host.trim()
|
|
77
|
+
if (!trimmed) return null
|
|
78
|
+
try {
|
|
79
|
+
const url = new URL(devUrl)
|
|
80
|
+
if (url.hostname === trimmed) return null
|
|
81
|
+
url.hostname = trimmed
|
|
82
|
+
return url.toString().replace(/\/$/, "")
|
|
83
|
+
} catch {
|
|
84
|
+
return null
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Point an http(s) icon at the host that actually answered. Cached dev icons are
|
|
90
|
+
* local `file://` paths and third-party icons live on unrelated hosts, so only
|
|
91
|
+
* icons still served by the stale dev host are rewritten.
|
|
92
|
+
*/
|
|
93
|
+
function rewriteIconHost(iconUrl: string, staleDevUrl: string, resolvedDevUrl: string): string | null {
|
|
94
|
+
try {
|
|
95
|
+
const icon = new URL(iconUrl)
|
|
96
|
+
if (icon.protocol !== "http:" && icon.protocol !== "https:") return null
|
|
97
|
+
const stale = new URL(staleDevUrl)
|
|
98
|
+
const resolved = new URL(resolvedDevUrl)
|
|
99
|
+
// Compare host (hostname+port) so an icon on the same hostname but a
|
|
100
|
+
// different service port is left alone.
|
|
101
|
+
if (icon.host !== stale.host) return null
|
|
102
|
+
icon.host = resolved.host
|
|
103
|
+
return icon.toString()
|
|
104
|
+
} catch {
|
|
105
|
+
return null
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function collectAlternateHosts(packageName: string, extra?: string[]): string[] {
|
|
110
|
+
const hosts: string[] = []
|
|
111
|
+
const push = (h: string | undefined | null) => {
|
|
112
|
+
const v = h?.trim()
|
|
113
|
+
if (v && !hosts.includes(v)) hosts.push(v)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
push(configuredDevHost())
|
|
117
|
+
|
|
118
|
+
if (packageName) {
|
|
119
|
+
const mdns = storage.load<string>(`${packageName}_dev_mdns`)
|
|
120
|
+
if (mdns.is_ok()) push(mdns.value)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
for (const h of extra ?? []) push(h)
|
|
124
|
+
return hosts
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function probeUrl(devUrl: string): Promise<DevManifest | null | "network-error"> {
|
|
128
|
+
for (let attempt = 1; attempt <= REACHABILITY_MAX_ATTEMPTS; attempt++) {
|
|
129
|
+
try {
|
|
130
|
+
const manifest = await fetchManifestOnce(devUrl)
|
|
131
|
+
// Definitive HTTP failure — do not retry this URL further.
|
|
132
|
+
if (!manifest) return null
|
|
133
|
+
return manifest
|
|
134
|
+
} catch {
|
|
135
|
+
if (attempt < REACHABILITY_MAX_ATTEMPTS) {
|
|
136
|
+
await delay(REACHABILITY_RETRY_DELAY_MS)
|
|
137
|
+
continue
|
|
138
|
+
}
|
|
139
|
+
return "network-error"
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return "network-error"
|
|
143
|
+
}
|
|
34
144
|
|
|
35
145
|
/**
|
|
36
|
-
* GET <devUrl>/miniapp.json with a hard timeout
|
|
146
|
+
* GET <devUrl>/miniapp.json with a hard timeout, retrying once on a
|
|
147
|
+
* network-layer failure (DNS/connection/abort) before trying alternate
|
|
148
|
+
* hosts (Metro laptop IP, mDNS name from the QR). Returns the parsed
|
|
37
149
|
* manifest on success ("live") or null ("offline").
|
|
38
150
|
*
|
|
39
|
-
* Side
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* The fetch doubles as the reachability probe AND the manifest source —
|
|
44
|
-
* one request per launch attempt instead of two.
|
|
151
|
+
* Side effects on success:
|
|
152
|
+
* - writes <packageName>_dev_last_reachable
|
|
153
|
+
* - if an alternate host worked, rewrites <packageName>_dev_url so the
|
|
154
|
+
* next launch skips the stale IP
|
|
45
155
|
*/
|
|
46
156
|
export async function decideDevLaunchRoute(
|
|
47
157
|
packageName: string,
|
|
48
158
|
devUrl: string,
|
|
159
|
+
options?: DecideDevLaunchOptions,
|
|
49
160
|
): Promise<DevLaunchResult> {
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
161
|
+
const candidates: string[] = [devUrl]
|
|
162
|
+
for (const host of collectAlternateHosts(packageName, options?.alternateHosts)) {
|
|
163
|
+
const rewritten = rewriteHost(devUrl, host)
|
|
164
|
+
if (rewritten && !candidates.includes(rewritten)) candidates.push(rewritten)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
for (const candidate of candidates) {
|
|
168
|
+
const result = await probeUrl(candidate)
|
|
169
|
+
if (result === "network-error" || result === null) continue
|
|
170
|
+
|
|
59
171
|
if (packageName) {
|
|
60
172
|
storage.save(`${packageName}_dev_last_reachable`, Date.now())
|
|
173
|
+
if (candidate !== devUrl) {
|
|
174
|
+
storage.save(`${packageName}_dev_url`, candidate)
|
|
175
|
+
// Keep _dev_meta.devUrl in sync when present so home-tile reads match.
|
|
176
|
+
const metaRes = storage.load<string>(`${packageName}_dev_meta`)
|
|
177
|
+
if (metaRes.is_ok()) {
|
|
178
|
+
try {
|
|
179
|
+
const meta = JSON.parse(metaRes.value) as {devUrl?: string; iconUrl?: string}
|
|
180
|
+
meta.devUrl = candidate
|
|
181
|
+
if (typeof meta.iconUrl === "string") {
|
|
182
|
+
const rewritten = rewriteIconHost(meta.iconUrl, devUrl, candidate)
|
|
183
|
+
if (rewritten) meta.iconUrl = rewritten
|
|
184
|
+
}
|
|
185
|
+
storage.save(`${packageName}_dev_meta`, JSON.stringify(meta))
|
|
186
|
+
} catch {
|
|
187
|
+
/* ignore malformed meta */
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
61
191
|
}
|
|
62
|
-
return {decision: "live", manifest}
|
|
63
|
-
} catch {
|
|
64
|
-
return {decision: "offline", manifest: null}
|
|
65
|
-
} finally {
|
|
66
|
-
clearTimeout(timer)
|
|
192
|
+
return {decision: "live", manifest: result, resolvedUrl: candidate}
|
|
67
193
|
}
|
|
194
|
+
|
|
195
|
+
return {decision: "offline", manifest: null}
|
|
68
196
|
}
|
|
@@ -4,11 +4,14 @@ import * as Location from "expo-location"
|
|
|
4
4
|
import {Platform} from "react-native"
|
|
5
5
|
import type {ReportContext} from "@mentra/cloud-client"
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import appRegistry from "../services/AppRegistry"
|
|
8
|
+
import localMiniappRuntime from "../services/LocalMiniappRuntime"
|
|
9
|
+
import {getLastOpenTime, useAppStatusStore} from "../stores/apps"
|
|
8
10
|
import {useConnectionStore} from "../stores/connection"
|
|
9
11
|
import {useCoreStore} from "../stores/core"
|
|
10
12
|
import {useGlassesStore} from "../stores/glasses"
|
|
11
13
|
import {SETTINGS, useSettingsStore} from "../stores/settings"
|
|
14
|
+
import {buildMiniappDiagnosticContext} from "./miniappDiagnostics"
|
|
12
15
|
|
|
13
16
|
const SENSITIVE_SETTINGS_KEYS = ["core_token", "auth_token", "auth_email"] as const
|
|
14
17
|
const SENSITIVE_GLASSES_KEYS = ["hotspotPassword"] as const
|
|
@@ -108,17 +111,17 @@ export async function collectDiagnosticContext(extra?: Partial<ReportContext>):
|
|
|
108
111
|
|
|
109
112
|
const offlineMode = await useSettingsStore.getState().getSetting(SETTINGS.offline_mode.key)
|
|
110
113
|
const defaultWearable = await useSettingsStore.getState().getSetting(SETTINGS.default_wearable.key)
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
})
|
|
114
|
+
const miniappRuntime = localMiniappRuntime.getDiagnosticSnapshot()
|
|
115
|
+
const miniapps = buildMiniappDiagnosticContext({
|
|
116
|
+
apps: appletState.apps,
|
|
117
|
+
foregroundedPackage: appletState.foregroundedPackage,
|
|
118
|
+
runtime: miniappRuntime,
|
|
119
|
+
getLastOpenedAtMs: (app) => getLastOpenTime(app.packageName),
|
|
120
|
+
getManifest: (app) =>
|
|
121
|
+
app.local && app.version ? appRegistry.getMiniappManifest(app.packageName, app.version) : undefined,
|
|
122
|
+
getReleaseIdentity: (app) =>
|
|
123
|
+
app.local && app.version ? appRegistry.getReleaseIdentity(app.packageName, app.version) : undefined,
|
|
124
|
+
})
|
|
122
125
|
|
|
123
126
|
return {
|
|
124
127
|
app: {
|
|
@@ -139,12 +142,9 @@ export async function collectDiagnosticContext(extra?: Partial<ReportContext>):
|
|
|
139
142
|
runtime: {
|
|
140
143
|
core: coreState,
|
|
141
144
|
connection: connectionState,
|
|
145
|
+
miniapps: miniappRuntime,
|
|
142
146
|
},
|
|
143
|
-
apps:
|
|
144
|
-
apps,
|
|
145
|
-
installed: apps.map((app) => app.packageName),
|
|
146
|
-
running: apps.filter((app) => app.running).map((app) => app.packageName),
|
|
147
|
-
},
|
|
147
|
+
apps: miniapps,
|
|
148
148
|
settings: {
|
|
149
149
|
...filteredSettings,
|
|
150
150
|
offlineMode: !!offlineMode,
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Capabilities,
|
|
3
|
-
HardwareRequirement,
|
|
4
|
-
HardwareType,
|
|
5
|
-
HardwareRequirementLevel,
|
|
6
|
-
DeviceTypes,
|
|
7
|
-
} from "../../types"
|
|
8
|
-
import {simulatedGlasses} from "../../types"
|
|
1
|
+
import {Capabilities, DeviceTypes, HardwareRequirement, HardwareRequirementLevel, HardwareType, simulatedGlasses} from "../../types"
|
|
9
2
|
|
|
10
3
|
/**
|
|
11
4
|
* Result of a hardware compatibility check
|
|
@@ -86,7 +79,12 @@ export class HardwareCompatibility {
|
|
|
86
79
|
return capabilities.hasDisplay
|
|
87
80
|
|
|
88
81
|
case HardwareType.MICROPHONE:
|
|
89
|
-
|
|
82
|
+
// MentraOS always provides an audio-input path. When the connected
|
|
83
|
+
// glasses do not have an onboard microphone, the engine falls back to
|
|
84
|
+
// the phone microphone. Keep `capabilities.hasMicrophone` reserved for
|
|
85
|
+
// physical-device/source selection; app compatibility is about whether
|
|
86
|
+
// the requested input is available to the miniapp.
|
|
87
|
+
return true
|
|
90
88
|
|
|
91
89
|
case HardwareType.SPEAKER:
|
|
92
90
|
return capabilities.hasSpeaker
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import type {ClientApp} from "../types/applet"
|
|
2
|
+
|
|
3
|
+
const MAX_DIAGNOSTIC_STRING_LENGTH = 512
|
|
4
|
+
const MAX_DIAGNOSTIC_LIST_ITEMS = 100
|
|
5
|
+
const MAX_RECENT_MINIAPPS = 20
|
|
6
|
+
|
|
7
|
+
export interface MiniappManifestSnapshot {
|
|
8
|
+
packageName: string
|
|
9
|
+
name?: string
|
|
10
|
+
version?: string
|
|
11
|
+
sdkVersion?: string
|
|
12
|
+
minHostVersion?: string
|
|
13
|
+
type?: string
|
|
14
|
+
entry?: {
|
|
15
|
+
background?: string
|
|
16
|
+
ui?: string
|
|
17
|
+
}
|
|
18
|
+
permissions: Array<{type: string; required?: boolean}>
|
|
19
|
+
hardwareRequirements: Array<{type: string; level: string}>
|
|
20
|
+
actionIds: string[]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface MiniappRuntimeAppSnapshot {
|
|
24
|
+
packageName: string
|
|
25
|
+
handshakeComplete: boolean
|
|
26
|
+
subscriptions: string[]
|
|
27
|
+
lastMessageAgeMs: number
|
|
28
|
+
requestedLocationRate: string | null
|
|
29
|
+
hasActiveSpeakerStream: boolean
|
|
30
|
+
manifest?: MiniappManifestSnapshot
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface MiniappRuntimeDiagnosticSnapshot {
|
|
34
|
+
connectedApps: MiniappRuntimeAppSnapshot[]
|
|
35
|
+
subscriptionsByStream: Record<string, string[]>
|
|
36
|
+
resources: {
|
|
37
|
+
display: Record<string, unknown>
|
|
38
|
+
camera: Record<string, unknown>
|
|
39
|
+
video: Record<string, unknown>
|
|
40
|
+
stream: Record<string, unknown>
|
|
41
|
+
cameraFov: Record<string, unknown>
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
type ManifestFallback = {
|
|
46
|
+
packageName: string
|
|
47
|
+
name?: string
|
|
48
|
+
version?: string
|
|
49
|
+
type?: string
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function boundedString(value: unknown): string | undefined {
|
|
53
|
+
if (typeof value !== "string") return undefined
|
|
54
|
+
const trimmed = value.trim()
|
|
55
|
+
if (!trimmed) return undefined
|
|
56
|
+
return trimmed.slice(0, MAX_DIAGNOSTIC_STRING_LENGTH)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function recordValue(value: unknown): Record<string, unknown> | null {
|
|
60
|
+
return value && typeof value === "object" && !Array.isArray(value) ? (value as Record<string, unknown>) : null
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function diagnosticPermissions(value: unknown): Array<{type: string; required?: boolean}> {
|
|
64
|
+
if (!Array.isArray(value)) return []
|
|
65
|
+
const permissions: Array<{type: string; required?: boolean}> = []
|
|
66
|
+
for (const raw of value) {
|
|
67
|
+
if (typeof raw === "string") {
|
|
68
|
+
const type = boundedString(raw)
|
|
69
|
+
if (type) permissions.push({type})
|
|
70
|
+
continue
|
|
71
|
+
}
|
|
72
|
+
const permission = recordValue(raw)
|
|
73
|
+
const type = boundedString(permission?.type)
|
|
74
|
+
if (!type) continue
|
|
75
|
+
permissions.push({
|
|
76
|
+
type,
|
|
77
|
+
...(typeof permission?.required === "boolean" ? {required: permission.required} : {}),
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
return permissions.slice(0, MAX_DIAGNOSTIC_LIST_ITEMS)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function diagnosticHardwareRequirements(value: unknown): Array<{type: string; level: string}> {
|
|
84
|
+
if (!Array.isArray(value)) return []
|
|
85
|
+
const requirements: Array<{type: string; level: string}> = []
|
|
86
|
+
for (const raw of value) {
|
|
87
|
+
const requirement = recordValue(raw)
|
|
88
|
+
const type = boundedString(requirement?.type)
|
|
89
|
+
const level = boundedString(requirement?.level)
|
|
90
|
+
if (type && level) requirements.push({type, level})
|
|
91
|
+
}
|
|
92
|
+
return requirements.slice(0, MAX_DIAGNOSTIC_LIST_ITEMS)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function diagnosticActionIds(value: unknown): string[] {
|
|
96
|
+
if (!Array.isArray(value)) return []
|
|
97
|
+
return value
|
|
98
|
+
.map((raw) => boundedString(typeof raw === "string" ? raw : recordValue(raw)?.id))
|
|
99
|
+
.filter((id): id is string => id !== undefined)
|
|
100
|
+
.sort()
|
|
101
|
+
.slice(0, MAX_DIAGNOSTIC_LIST_ITEMS)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Keep the routing/build fields from miniapp.json while excluding arbitrary
|
|
106
|
+
* free-form manifest content from reports. Descriptions, URLs, and unknown
|
|
107
|
+
* extension fields are intentionally omitted.
|
|
108
|
+
*/
|
|
109
|
+
export function buildMiniappManifestSnapshot(raw: unknown, fallback: ManifestFallback): MiniappManifestSnapshot {
|
|
110
|
+
const manifest = recordValue(raw)
|
|
111
|
+
const entry = recordValue(manifest?.entry)
|
|
112
|
+
const packageName = boundedString(manifest?.packageName) ?? boundedString(fallback.packageName) ?? "unknown"
|
|
113
|
+
const name = boundedString(manifest?.name) ?? boundedString(fallback.name)
|
|
114
|
+
const version = boundedString(manifest?.version) ?? boundedString(fallback.version)
|
|
115
|
+
const type = boundedString(manifest?.type) ?? boundedString(fallback.type)
|
|
116
|
+
const background = boundedString(entry?.background)
|
|
117
|
+
const ui = boundedString(entry?.ui)
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
packageName,
|
|
121
|
+
...(name ? {name} : {}),
|
|
122
|
+
...(version ? {version} : {}),
|
|
123
|
+
...(boundedString(manifest?.sdkVersion) ? {sdkVersion: boundedString(manifest?.sdkVersion)} : {}),
|
|
124
|
+
...(boundedString(manifest?.minHostVersion) ? {minHostVersion: boundedString(manifest?.minHostVersion)} : {}),
|
|
125
|
+
...(type ? {type} : {}),
|
|
126
|
+
...(background || ui ? {entry: {...(background ? {background} : {}), ...(ui ? {ui} : {})}} : {}),
|
|
127
|
+
permissions: diagnosticPermissions(manifest?.permissions),
|
|
128
|
+
hardwareRequirements: diagnosticHardwareRequirements(manifest?.hardwareRequirements),
|
|
129
|
+
actionIds: diagnosticActionIds(manifest?.actions ?? manifest?.actionIds),
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function executionMode(app: ClientApp): "built_in" | "dev_server" | "dev_snapshot" | "installed_bundle" {
|
|
134
|
+
if (app.offline) return "built_in"
|
|
135
|
+
if (app.isMiniappDev && app.devUrl && !app.version) return "dev_server"
|
|
136
|
+
if (app.isMiniappDev) return "dev_snapshot"
|
|
137
|
+
return "installed_bundle"
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function safeReleaseIdentity(value: unknown): Record<string, string> | undefined {
|
|
141
|
+
const identity = recordValue(value)
|
|
142
|
+
if (!identity) return undefined
|
|
143
|
+
const out: Record<string, string> = {}
|
|
144
|
+
for (const key of ["source", "releaseId", "bundleSha256", "channel"] as const) {
|
|
145
|
+
const field = boundedString(identity[key])
|
|
146
|
+
if (field) out[key] = field
|
|
147
|
+
}
|
|
148
|
+
return Object.keys(out).length > 0 ? out : undefined
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function buildMiniappDiagnosticContext(input: {
|
|
152
|
+
apps: ClientApp[]
|
|
153
|
+
foregroundedPackage: string | null
|
|
154
|
+
runtime: MiniappRuntimeDiagnosticSnapshot
|
|
155
|
+
getLastOpenedAtMs: (app: ClientApp) => number
|
|
156
|
+
getManifest: (app: ClientApp) => unknown
|
|
157
|
+
getReleaseIdentity: (app: ClientApp) => unknown
|
|
158
|
+
}): Record<string, unknown> {
|
|
159
|
+
const runtimeByPackage = new Map(input.runtime.connectedApps.map((app) => [app.packageName, app]))
|
|
160
|
+
const appSnapshots = input.apps.map((app) => {
|
|
161
|
+
const lastOpenedAtMs = input.getLastOpenedAtMs(app)
|
|
162
|
+
const packageName = boundedString(app.packageName) ?? "unknown"
|
|
163
|
+
return {
|
|
164
|
+
packageName,
|
|
165
|
+
name: boundedString(app.name) ?? packageName,
|
|
166
|
+
version: boundedString(app.version) ?? null,
|
|
167
|
+
executionMode: executionMode(app),
|
|
168
|
+
running: app.running,
|
|
169
|
+
foregrounded: app.packageName === input.foregroundedPackage,
|
|
170
|
+
loading: app.loading,
|
|
171
|
+
healthy: app.healthy,
|
|
172
|
+
hidden: app.hidden,
|
|
173
|
+
type: app.type,
|
|
174
|
+
offline: app.offline,
|
|
175
|
+
local: app.local,
|
|
176
|
+
lastOpenedAtMs: Number.isFinite(lastOpenedAtMs) ? lastOpenedAtMs : 0,
|
|
177
|
+
}
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
const recentlyInteracted = [...appSnapshots]
|
|
181
|
+
.filter((app) => app.lastOpenedAtMs > 0)
|
|
182
|
+
.sort((a, b) => b.lastOpenedAtMs - a.lastOpenedAtMs)
|
|
183
|
+
.slice(0, MAX_RECENT_MINIAPPS)
|
|
184
|
+
.map((app) => ({packageName: app.packageName, lastOpenedAtMs: app.lastOpenedAtMs}))
|
|
185
|
+
|
|
186
|
+
const runningMiniapps = input.apps
|
|
187
|
+
.filter((app) => app.running)
|
|
188
|
+
.map((app) => {
|
|
189
|
+
const runtime = runtimeByPackage.get(app.packageName)
|
|
190
|
+
const releaseIdentity = safeReleaseIdentity(input.getReleaseIdentity(app))
|
|
191
|
+
const packageName = boundedString(app.packageName) ?? "unknown"
|
|
192
|
+
const manifest = buildMiniappManifestSnapshot(input.getManifest(app) ?? runtime?.manifest, {
|
|
193
|
+
packageName,
|
|
194
|
+
name: app.name,
|
|
195
|
+
version: app.version,
|
|
196
|
+
type: app.type,
|
|
197
|
+
})
|
|
198
|
+
return {
|
|
199
|
+
packageName,
|
|
200
|
+
version: boundedString(app.version) ?? manifest.version ?? null,
|
|
201
|
+
executionMode: executionMode(app),
|
|
202
|
+
foregrounded: app.packageName === input.foregroundedPackage,
|
|
203
|
+
manifest,
|
|
204
|
+
...(releaseIdentity ? {releaseIdentity} : {}),
|
|
205
|
+
runtime: runtime
|
|
206
|
+
? {
|
|
207
|
+
handshakeComplete: runtime.handshakeComplete,
|
|
208
|
+
subscriptions: runtime.subscriptions,
|
|
209
|
+
lastMessageAgeMs: runtime.lastMessageAgeMs,
|
|
210
|
+
requestedLocationRate: runtime.requestedLocationRate,
|
|
211
|
+
hasActiveSpeakerStream: runtime.hasActiveSpeakerStream,
|
|
212
|
+
}
|
|
213
|
+
: null,
|
|
214
|
+
}
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
apps: appSnapshots,
|
|
219
|
+
installed: appSnapshots.map((app) => app.packageName),
|
|
220
|
+
running: runningMiniapps.map((app) => app.packageName),
|
|
221
|
+
foregroundedPackage: boundedString(input.foregroundedPackage) ?? null,
|
|
222
|
+
mostRecentlyInteractedPackage: recentlyInteracted[0]?.packageName ?? null,
|
|
223
|
+
recentlyInteracted,
|
|
224
|
+
runningMiniapps,
|
|
225
|
+
}
|
|
226
|
+
}
|
|
@@ -5,6 +5,14 @@ import CrustModule from "@mentra/crust"
|
|
|
5
5
|
|
|
6
6
|
import {deriveGalleryDisplayName} from "./galleryDisplayName"
|
|
7
7
|
|
|
8
|
+
export interface MediaLibrarySaveReceipt {
|
|
9
|
+
success: boolean
|
|
10
|
+
platform: "ios" | "android" | "unknown"
|
|
11
|
+
uri?: string
|
|
12
|
+
identifier?: string
|
|
13
|
+
error?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
8
16
|
/**
|
|
9
17
|
* MediaLibraryPermissions - Handles save-only permissions for camera roll
|
|
10
18
|
*
|
|
@@ -14,6 +22,18 @@ import {deriveGalleryDisplayName} from "./galleryDisplayName"
|
|
|
14
22
|
* - Android 9-: Uses WRITE_EXTERNAL_STORAGE (legacy)
|
|
15
23
|
*/
|
|
16
24
|
export class MediaLibraryPermissions {
|
|
25
|
+
/** Limited iOS access cannot see historical, unselected assets for duplicate reconciliation. */
|
|
26
|
+
static async hasLimitedAccess(): Promise<boolean> {
|
|
27
|
+
if (Platform.OS !== "ios") return false
|
|
28
|
+
try {
|
|
29
|
+
return (await check(PERMISSIONS.IOS.PHOTO_LIBRARY)) === RESULTS.LIMITED
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error("[MediaLibrary] Error checking limited-library access:", error)
|
|
32
|
+
// Conservatively block legacy reconciliation when the scope cannot be verified.
|
|
33
|
+
return true
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
17
37
|
/**
|
|
18
38
|
* Check if we have permission to save to the camera roll
|
|
19
39
|
* Note: On Android 10+, this always returns true since no permission is needed
|
|
@@ -85,6 +105,12 @@ export class MediaLibraryPermissions {
|
|
|
85
105
|
* @param creationTime - Optional creation/capture time in milliseconds (Unix timestamp)
|
|
86
106
|
*/
|
|
87
107
|
static async saveToLibrary(filePath: string, creationTime?: number): Promise<boolean> {
|
|
108
|
+
return (await this.saveToLibraryWithReceipt(filePath, creationTime)).success
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Save and return the durable MediaStore/PhotoKit identifier used as the export receipt. */
|
|
112
|
+
static async saveToLibraryWithReceipt(filePath: string, creationTime?: number): Promise<MediaLibrarySaveReceipt> {
|
|
113
|
+
const platform = Platform.OS === "ios" || Platform.OS === "android" ? Platform.OS : "unknown"
|
|
88
114
|
try {
|
|
89
115
|
// On Android 10+, we can save without permission
|
|
90
116
|
// On iOS and older Android, check permission first
|
|
@@ -95,7 +121,7 @@ export class MediaLibraryPermissions {
|
|
|
95
121
|
const granted = await this.requestPermission()
|
|
96
122
|
if (!granted) {
|
|
97
123
|
console.warn("[MediaLibrary] No permission to save to library - photos saved to app storage only")
|
|
98
|
-
return false
|
|
124
|
+
return {success: false, platform, error: "permission denied"}
|
|
99
125
|
}
|
|
100
126
|
}
|
|
101
127
|
}
|
|
@@ -117,14 +143,19 @@ export class MediaLibraryPermissions {
|
|
|
117
143
|
} else {
|
|
118
144
|
console.log(`[MediaLibrary] Saved to camera roll: ${cleanPath}`)
|
|
119
145
|
}
|
|
120
|
-
return
|
|
146
|
+
return {
|
|
147
|
+
success: true,
|
|
148
|
+
platform,
|
|
149
|
+
uri: result.uri,
|
|
150
|
+
identifier: result.identifier,
|
|
151
|
+
}
|
|
121
152
|
} else {
|
|
122
153
|
console.error(`[MediaLibrary] Failed to save to library: ${result.error}`)
|
|
123
|
-
return false
|
|
154
|
+
return {success: false, platform, error: result.error || "native export failed"}
|
|
124
155
|
}
|
|
125
156
|
} catch (error) {
|
|
126
157
|
console.error("[MediaLibrary] Error saving to library:", error)
|
|
127
|
-
return false
|
|
158
|
+
return {success: false, platform, error: error instanceof Error ? error.message : String(error)}
|
|
128
159
|
}
|
|
129
160
|
}
|
|
130
161
|
}
|