@mentra/engine 0.1.0-dev.0 → 3.1.0-dev.10
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
|
@@ -17,14 +17,28 @@
|
|
|
17
17
|
* short-circuit our long-poll with a typed error (CAMERA_BUSY, BATTERY_LOW,
|
|
18
18
|
* etc.) instead of waiting 30s for cloud's timeout.
|
|
19
19
|
*/
|
|
20
|
+
import type { PhotoTransferMethod } from "@mentra/bluetooth-sdk/internal";
|
|
20
21
|
export interface PhotoOpts {
|
|
21
22
|
/** Legacy cloud size names are normalized before the native take_photo command. */
|
|
22
23
|
size?: "low" | "medium" | "high" | "max" | "small" | "large" | "full";
|
|
23
24
|
mode?: "photo" | "text";
|
|
25
|
+
/** Select direct-only, phone-relayed BLE, or the default Wi-Fi/BLE fallback policy. */
|
|
26
|
+
transferMethod?: PhotoTransferMethod;
|
|
24
27
|
compress?: "none" | "low" | "medium" | "high";
|
|
25
28
|
sound?: boolean;
|
|
26
29
|
saveToGallery?: boolean;
|
|
27
30
|
exposureTimeNs?: number;
|
|
31
|
+
iso?: number | null;
|
|
32
|
+
aeExposureDivisor?: number;
|
|
33
|
+
isoCap?: number;
|
|
34
|
+
noiseReduction?: boolean;
|
|
35
|
+
edgeEnhancement?: boolean;
|
|
36
|
+
/** ZSL preview buffering. */
|
|
37
|
+
zsl?: boolean;
|
|
38
|
+
/** MFNR still capture. */
|
|
39
|
+
mfnr?: boolean;
|
|
40
|
+
ispDigitalGain?: number;
|
|
41
|
+
ispAnalogGain?: string;
|
|
28
42
|
}
|
|
29
43
|
export interface PhotoTaken {
|
|
30
44
|
photoUrl: string;
|
|
@@ -53,25 +67,35 @@ export declare class PhotoError extends Error {
|
|
|
53
67
|
* rejected successful captures while their upload was still in progress.
|
|
54
68
|
*/
|
|
55
69
|
export declare const CAPTURE_PIPELINE_TIMEOUT_MS = 45000;
|
|
70
|
+
export declare const CAMERA_WARM_UP_DEFAULT_DURATION_MS = 15000;
|
|
71
|
+
export declare const CAMERA_WARM_UP_MAX_DURATION_MS = 60000;
|
|
56
72
|
export declare class PhonePhotoCoordinator {
|
|
57
73
|
private readonly activeRequests;
|
|
58
74
|
/** Short BLE correlation id (4-char hex) → full cloud requestId. */
|
|
59
75
|
private readonly bleIdToCloud;
|
|
76
|
+
private readonly activeWarmUps;
|
|
77
|
+
/** Report-safe camera ownership snapshot for incident diagnostics. */
|
|
78
|
+
getDiagnosticSnapshot(): Record<string, unknown>;
|
|
60
79
|
takePhoto(packageName: string, opts: PhotoOpts): Promise<PhotoTaken>;
|
|
61
80
|
/** Map a short BLE requestId from photo_response back to the cloud requestId. */
|
|
62
81
|
resolveCloudRequestId(bleOrCloudId: string): string;
|
|
63
82
|
/**
|
|
64
83
|
* Pre-warm the glasses camera so the next takePhoto() is near-instant.
|
|
65
84
|
*
|
|
66
|
-
* Pure BLE — NO cloud presign, NO upload, NO long-poll. The
|
|
67
|
-
* requestId, sends the warm-up command, and resolves when the camera reports
|
|
85
|
+
* Pure BLE — NO cloud presign, NO upload, NO long-poll. The phone mints and owns
|
|
86
|
+
* the requestId, sends the warm-up command, and resolves when the camera reports
|
|
68
87
|
* ready (the native promise resolves on the ready status event).
|
|
69
88
|
*/
|
|
70
89
|
warmUpCamera(packageName: string, opts: {
|
|
71
90
|
size?: "low" | "medium" | "high" | "max";
|
|
91
|
+
mode?: "photo" | "text";
|
|
72
92
|
exposureTimeNs?: number;
|
|
73
93
|
durationMs?: number;
|
|
94
|
+
zsl?: boolean;
|
|
95
|
+
mfnr?: boolean;
|
|
74
96
|
}): Promise<void>;
|
|
97
|
+
/** Release a miniapp's warm-up even if its original warmUpCamera promise is still opening. */
|
|
98
|
+
stopWarmUpForApp(packageName: string): Promise<void>;
|
|
75
99
|
/** True iff this requestId (short BLE id or cloud id) is one we're currently waiting on. */
|
|
76
100
|
owns(requestId: string): boolean;
|
|
77
101
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PhonePhotoCoordinator.d.ts","sourceRoot":"","sources":["../../src/services/PhonePhotoCoordinator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;
|
|
1
|
+
{"version":3,"file":"PhonePhotoCoordinator.d.ts","sourceRoot":"","sources":["../../src/services/PhonePhotoCoordinator.ts"],"names":[],"mappings":"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"}
|
|
@@ -48,6 +48,13 @@ export class PhotoError extends Error {
|
|
|
48
48
|
this.name = "PhotoError";
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
+
function parsePhotoTransferMethod(value) {
|
|
52
|
+
if (value === undefined)
|
|
53
|
+
return undefined;
|
|
54
|
+
if (value === "auto" || value === "direct" || value === "ble")
|
|
55
|
+
return value;
|
|
56
|
+
throw new PhotoError("INVALID_ARGUMENT", `Invalid transferMethod ${JSON.stringify(value)}. Expected "auto", "direct", or "ble".`);
|
|
57
|
+
}
|
|
51
58
|
/**
|
|
52
59
|
* Last-resort ceiling for the complete capture + encode + transfer + upload
|
|
53
60
|
* pipeline. This must exceed the managed-photo service's 30s ready-push
|
|
@@ -58,6 +65,8 @@ export class PhotoError extends Error {
|
|
|
58
65
|
* rejected successful captures while their upload was still in progress.
|
|
59
66
|
*/
|
|
60
67
|
export const CAPTURE_PIPELINE_TIMEOUT_MS = 45_000;
|
|
68
|
+
export const CAMERA_WARM_UP_DEFAULT_DURATION_MS = 15_000;
|
|
69
|
+
export const CAMERA_WARM_UP_MAX_DURATION_MS = 60_000;
|
|
61
70
|
let bleRequestCounter = 0;
|
|
62
71
|
/** Short 4-hex-char correlation id sent over BLE instead of the full cloud
|
|
63
72
|
* requestId UUID (wire v2 keeps BLE JSON small). */
|
|
@@ -79,7 +88,17 @@ export class PhonePhotoCoordinator {
|
|
|
79
88
|
activeRequests = new Map();
|
|
80
89
|
/** Short BLE correlation id (4-char hex) → full cloud requestId. */
|
|
81
90
|
bleIdToCloud = new Map();
|
|
91
|
+
activeWarmUps = new Map();
|
|
92
|
+
/** Report-safe camera ownership snapshot for incident diagnostics. */
|
|
93
|
+
getDiagnosticSnapshot() {
|
|
94
|
+
return {
|
|
95
|
+
captureOwners: [...new Set([...this.activeRequests.values()].map((request) => request.packageName))].sort(),
|
|
96
|
+
warmUpOwners: [...this.activeWarmUps.keys()].sort(),
|
|
97
|
+
activeCaptureCount: this.activeRequests.size,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
82
100
|
async takePhoto(packageName, opts) {
|
|
101
|
+
const transferMethod = parsePhotoTransferMethod(opts.transferMethod);
|
|
83
102
|
// Pre-check: if glasses aren't even connected, the BLE photo command
|
|
84
103
|
// would be sent into the void and we'd wait 30s for the cloud long-poll
|
|
85
104
|
// to time out. Fail fast with a typed error.
|
|
@@ -94,6 +113,9 @@ export class PhonePhotoCoordinator {
|
|
|
94
113
|
if (!isGlassesConnected(useGlassesStore.getState().connection)) {
|
|
95
114
|
throw new PhotoError("GLASSES_NOT_CONNECTED", "Glasses are not connected", "command", "ble");
|
|
96
115
|
}
|
|
116
|
+
// Text-mode sensor resolution is owned by ASG constants; keep cloud metadata on a stable
|
|
117
|
+
// high-capacity tier and let the glasses ignore the public size when mode=text.
|
|
118
|
+
const captureSize = opts.size ?? "medium";
|
|
97
119
|
// 1) Presign via the cloud-v2 managed-photo service. Local miniapps use
|
|
98
120
|
// ONLY the cloud-v2 path: the runtime presigns upload+read URLs and the
|
|
99
121
|
// phone (as the device controller) delivers the bytes; the legacy
|
|
@@ -104,10 +126,12 @@ export class PhonePhotoCoordinator {
|
|
|
104
126
|
const flowStarted = performance.now();
|
|
105
127
|
try {
|
|
106
128
|
const presignStarted = performance.now();
|
|
107
|
-
const r = await cloudClientService.startManagedPhoto({
|
|
129
|
+
const r = await cloudClientService.startManagedPhoto({
|
|
130
|
+
size: opts.mode === "text" ? "max" : captureSize,
|
|
131
|
+
});
|
|
108
132
|
const presignMs = Math.round(performance.now() - presignStarted);
|
|
109
133
|
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
110
|
-
console.debug(`[PhonePhotoCoordinator] presign ${presignMs}ms size=${opts.
|
|
134
|
+
console.debug(`[PhonePhotoCoordinator] presign ${presignMs}ms size=${opts.mode === "text" ? "max" : captureSize} mode=${opts.mode ?? "photo"}`);
|
|
111
135
|
}
|
|
112
136
|
requestId = r.requestId;
|
|
113
137
|
uploadUrl = r.uploadUrl;
|
|
@@ -151,21 +175,30 @@ export class PhonePhotoCoordinator {
|
|
|
151
175
|
void outcome.then(clearWatchdog, clearWatchdog);
|
|
152
176
|
// 3) Drive glasses over BLE. requestPhoto now resolves at terminal
|
|
153
177
|
// photo_response success, so run it beside the cloud poll instead of
|
|
154
|
-
// awaiting it before polling.
|
|
155
|
-
// (
|
|
178
|
+
// awaiting it before polling. Native defaults transferMethod to "auto"
|
|
179
|
+
// (Wi-Fi direct with BLE fallback) unless the miniapp forces BLE.
|
|
156
180
|
try {
|
|
157
181
|
void BluetoothSdk.requestPhoto({
|
|
158
182
|
requestId: bleRequestId,
|
|
159
183
|
appId: packageName,
|
|
160
|
-
size: normalizePhotoSize(
|
|
184
|
+
size: normalizePhotoSize(captureSize),
|
|
161
185
|
mode: opts.mode ?? "photo",
|
|
162
186
|
webhookUrl: uploadUrl,
|
|
163
187
|
authToken: null,
|
|
164
|
-
...(isLoopbackUpload ? { transferMethod: "ble" } : {}),
|
|
188
|
+
...(isLoopbackUpload ? { transferMethod: "ble" } : transferMethod ? { transferMethod } : {}),
|
|
165
189
|
compress: toNativeCompression(opts.compress),
|
|
166
190
|
save: opts.saveToGallery ?? false,
|
|
167
191
|
sound: opts.sound ?? true,
|
|
168
192
|
exposureTimeNs: opts.exposureTimeNs ?? null,
|
|
193
|
+
iso: opts.iso,
|
|
194
|
+
aeExposureDivisor: opts.aeExposureDivisor,
|
|
195
|
+
isoCap: opts.isoCap,
|
|
196
|
+
noiseReduction: opts.noiseReduction,
|
|
197
|
+
edgeEnhancement: opts.edgeEnhancement,
|
|
198
|
+
...(opts.zsl != null ? { zsl: opts.zsl } : {}),
|
|
199
|
+
...(opts.mfnr != null ? { mfnr: opts.mfnr } : {}),
|
|
200
|
+
ispDigitalGain: opts.ispDigitalGain,
|
|
201
|
+
ispAnalogGain: opts.ispAnalogGain,
|
|
169
202
|
}).catch((err) => {
|
|
170
203
|
const e = this.activeRequests.get(requestId);
|
|
171
204
|
if (!e)
|
|
@@ -219,8 +252,8 @@ export class PhonePhotoCoordinator {
|
|
|
219
252
|
/**
|
|
220
253
|
* Pre-warm the glasses camera so the next takePhoto() is near-instant.
|
|
221
254
|
*
|
|
222
|
-
* Pure BLE — NO cloud presign, NO upload, NO long-poll. The
|
|
223
|
-
* requestId, sends the warm-up command, and resolves when the camera reports
|
|
255
|
+
* Pure BLE — NO cloud presign, NO upload, NO long-poll. The phone mints and owns
|
|
256
|
+
* the requestId, sends the warm-up command, and resolves when the camera reports
|
|
224
257
|
* ready (the native promise resolves on the ready status event).
|
|
225
258
|
*/
|
|
226
259
|
async warmUpCamera(packageName, opts) {
|
|
@@ -229,17 +262,54 @@ export class PhonePhotoCoordinator {
|
|
|
229
262
|
if (!isGlassesConnected(useGlassesStore.getState().connection)) {
|
|
230
263
|
throw new PhotoError("GLASSES_NOT_CONNECTED", "Glasses are not connected", "command", "ble");
|
|
231
264
|
}
|
|
265
|
+
let lease;
|
|
232
266
|
try {
|
|
267
|
+
await this.stopWarmUpForApp(packageName);
|
|
268
|
+
const requestId = mintBleRequestId();
|
|
269
|
+
const requestedDuration = typeof opts.durationMs === "number" && Number.isFinite(opts.durationMs) && opts.durationMs > 0
|
|
270
|
+
? Math.round(opts.durationMs)
|
|
271
|
+
: CAMERA_WARM_UP_DEFAULT_DURATION_MS;
|
|
272
|
+
const durationMs = Math.min(requestedDuration, CAMERA_WARM_UP_MAX_DURATION_MS);
|
|
273
|
+
lease = { requestId, durationMs };
|
|
274
|
+
this.activeWarmUps.set(packageName, lease);
|
|
233
275
|
await BluetoothSdk.warmUpCamera({
|
|
276
|
+
requestId,
|
|
234
277
|
size: normalizePhotoSize(opts.size ?? "medium"),
|
|
278
|
+
mode: opts.mode ?? "photo",
|
|
235
279
|
exposureTimeNs: opts.exposureTimeNs ?? null,
|
|
236
|
-
durationMs
|
|
280
|
+
durationMs,
|
|
281
|
+
...(opts.zsl != null ? { zsl: opts.zsl } : {}),
|
|
282
|
+
...(opts.mfnr != null ? { mfnr: opts.mfnr } : {}),
|
|
237
283
|
});
|
|
284
|
+
if (this.activeWarmUps.get(packageName) === lease) {
|
|
285
|
+
lease.expiryTimer = setTimeout(() => {
|
|
286
|
+
if (this.activeWarmUps.get(packageName) === lease) {
|
|
287
|
+
this.activeWarmUps.delete(packageName);
|
|
288
|
+
}
|
|
289
|
+
}, durationMs);
|
|
290
|
+
}
|
|
238
291
|
}
|
|
239
292
|
catch (err) {
|
|
293
|
+
if (lease && this.activeWarmUps.get(packageName) === lease) {
|
|
294
|
+
if (lease.expiryTimer)
|
|
295
|
+
clearTimeout(lease.expiryTimer);
|
|
296
|
+
this.activeWarmUps.delete(packageName);
|
|
297
|
+
}
|
|
240
298
|
throw this.toPhotoError(err, "WARM_UP_FAILED", "command", "ble");
|
|
241
299
|
}
|
|
242
300
|
}
|
|
301
|
+
/** Release a miniapp's warm-up even if its original warmUpCamera promise is still opening. */
|
|
302
|
+
async stopWarmUpForApp(packageName) {
|
|
303
|
+
const active = this.activeWarmUps.get(packageName);
|
|
304
|
+
if (!active)
|
|
305
|
+
return;
|
|
306
|
+
await BluetoothSdk.stopCameraWarmUp(active.requestId);
|
|
307
|
+
if (this.activeWarmUps.get(packageName) === active) {
|
|
308
|
+
this.activeWarmUps.delete(packageName);
|
|
309
|
+
if (active.expiryTimer)
|
|
310
|
+
clearTimeout(active.expiryTimer);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
243
313
|
/** True iff this requestId (short BLE id or cloud id) is one we're currently waiting on. */
|
|
244
314
|
owns(requestId) {
|
|
245
315
|
const cloudId = this.resolveCloudRequestId(requestId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PhonePhotoCoordinator.js","sourceRoot":"","sources":["../../src/services/PhonePhotoCoordinator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * PhonePhotoCoordinator — owns local-miniapp takePhoto() end-to-end.\n *\n * Architecture:\n * miniapp → SDK → LocalMiniappRuntime → photo runtime hook\n * → coordinator.takePhoto(packageName, opts)\n * ├── (precheck) glasses connected + hasCamera\n * ├── cloudClientService.startManagedPhoto → {requestId, uploadUrl, readUrl} (cloud-v2 runtime presign)\n * ├── BluetoothSdk.requestPhoto(requestId, size, uploadUrl, compress, sound)\n * └── race:\n * - cloudClientService.awaitManagedPhotoReady(requestId) resolves on photo.ready push\n * - BluetoothSdk.requestPhoto rejects if terminal photo_response is an error\n * - handlePhotoError(requestId, code, message) rejects if MantleManager observes\n * the same BLE photo_response error before the native promise crosses the bridge\n *\n * `activeRequests` lets MantleManager's gated `photo_response` listener\n * short-circuit our long-poll with a typed error (CAMERA_BUSY, BATTERY_LOW,\n * etc.) instead of waiting 30s for cloud's timeout.\n */\n\nimport BluetoothSdk from \"@mentra/bluetooth-sdk/internal\"\nimport type {PhotoSize} from \"@mentra/bluetooth-sdk/internal\"\nimport {cloudClientService} from \"./CloudClientService\"\nimport {isGlassesConnected} from \"./GlassesReadiness\"\nimport {useGlassesStore} from \"../stores/glasses\"\n\ninterface PhotoResult {\n photoUrl: string\n mimeType: string\n size: number\n}\n\n/** Map legacy/cloud size names onto the native take_photo enum. */\nfunction normalizePhotoSize(value: unknown): PhotoSize {\n if (typeof value !== \"string\") return \"medium\"\n switch (value) {\n case \"small\":\n return \"low\"\n case \"large\":\n return \"high\"\n case \"full\":\n return \"max\"\n default:\n return ([\"low\", \"medium\", \"high\", \"max\"] as const).includes(value as PhotoSize) ? (value as PhotoSize) : \"medium\"\n }\n}\n\nexport interface PhotoOpts {\n /** Legacy cloud size names are normalized before the native take_photo command. */\n size?: \"low\" | \"medium\" | \"high\" | \"max\" | \"small\" | \"large\" | \"full\"\n mode?: \"photo\" | \"text\"\n compress?: \"none\" | \"low\" | \"medium\" | \"high\"\n sound?: boolean\n saveToGallery?: boolean\n exposureTimeNs?: number\n}\n\nexport interface PhotoTaken {\n photoUrl: string\n mimeType: string\n size: number\n requestId: string\n}\n\n/** Pipeline stage a photo request failed at — surfaced to the miniapp so a dev\n * sees exactly where it broke, not just a flattened message. */\nexport type PhotoStage = \"presign\" | \"command\" | \"capture\" | \"upload\" | \"push\"\n/** Transport in play at the point of failure. */\nexport type PhotoTransport = \"cloud-rest\" | \"ble\" | \"wifi\" | \"ws\"\n\nexport class PhotoError extends Error {\n constructor(\n public readonly code: string,\n message: string,\n public readonly stage?: PhotoStage,\n public readonly transport?: PhotoTransport,\n ) {\n super(message)\n this.name = \"PhotoError\"\n }\n}\n\ninterface ActiveRequest {\n packageName: string\n abort: AbortController\n resolve: (r: PhotoResult) => void\n reject: (err: Error) => void\n}\n\n/**\n * Last-resort ceiling for the complete capture + encode + transfer + upload\n * pipeline. This must exceed the managed-photo service's 30s ready-push\n * timeout so the cloud can return its more specific failure first.\n *\n * Text mode commonly spends several seconds detecting/cropping the region and\n * can take another 10s+ to transfer over BLE. A 15s ceiling incorrectly\n * rejected successful captures while their upload was still in progress.\n */\nexport const CAPTURE_PIPELINE_TIMEOUT_MS = 45_000\n\nlet bleRequestCounter = 0\n\n/** Short 4-hex-char correlation id sent over BLE instead of the full cloud\n * requestId UUID (wire v2 keeps BLE JSON small). */\nfunction mintBleRequestId(): string {\n bleRequestCounter = (bleRequestCounter + 1) & 0xffff\n return bleRequestCounter.toString(16).padStart(4, \"0\")\n}\n\nfunction toNativeCompression(compress: PhotoOpts[\"compress\"]): \"none\" | \"medium\" | \"heavy\" {\n if (compress === \"high\") return \"heavy\"\n if (compress === \"low\" || compress === \"medium\") return \"medium\"\n return \"none\"\n}\n\nexport class PhonePhotoCoordinator {\n // Cloud requestId → in-flight slot. The gated photo_response listener\n // (DeviceEventRouter) resolves short BLE ids via bleIdToCloud before calling\n // owns() / handlePhotoError().\n private readonly activeRequests = new Map<string, ActiveRequest>()\n /** Short BLE correlation id (4-char hex) → full cloud requestId. */\n private readonly bleIdToCloud = new Map<string, string>()\n\n async takePhoto(packageName: string, opts: PhotoOpts): Promise<PhotoTaken> {\n // Pre-check: if glasses aren't even connected, the BLE photo command\n // would be sent into the void and we'd wait 30s for the cloud long-poll\n // to time out. Fail fast with a typed error.\n //\n // We DON'T pre-check `hasCamera` here — the canonical capability data\n // lives in `getModelCapabilities(deviceModel)` from @mentra/types and\n // pulling that into this file would add a cross-package import. If a\n // cameraless device receives the BLE photo command, the glasses-side\n // handler will return a photo_response error within ~1s and the gated\n // photo_response listener in MantleManager will short-circuit our\n // long-poll. Slower but correct.\n if (!isGlassesConnected(useGlassesStore.getState().connection)) {\n throw new PhotoError(\"GLASSES_NOT_CONNECTED\", \"Glasses are not connected\", \"command\", \"ble\")\n }\n\n // 1) Presign via the cloud-v2 managed-photo service. Local miniapps use\n // ONLY the cloud-v2 path: the runtime presigns upload+read URLs and the\n // phone (as the device controller) delivers the bytes; the legacy\n // backend_url mint is gone from this flow.\n let requestId: string\n let uploadUrl: string\n let readUrl: string\n const flowStarted = performance.now()\n try {\n const presignStarted = performance.now()\n const r = await cloudClientService.startManagedPhoto({size: opts.size ?? \"medium\"})\n const presignMs = Math.round(performance.now() - presignStarted)\n if (typeof __DEV__ !== \"undefined\" && __DEV__) {\n console.debug(`[PhonePhotoCoordinator] presign ${presignMs}ms size=${opts.size ?? \"medium\"}`)\n }\n requestId = r.requestId\n uploadUrl = r.uploadUrl\n readUrl = r.readUrl\n } catch (err) {\n throw this.toPhotoError(err, \"PHOTO_REQUEST_FAILED\", \"presign\", \"cloud-rest\")\n }\n\n // 2) Build the outcome Promise FIRST so both resolve+reject handles\n // are wired into activeRequests BEFORE any code path can produce\n // an error. Without this, a fast BLE photo_response (BATTERY_LOW\n // etc.) racing with the Promise constructor could fire\n // handlePhotoError() against a no-op rejectFn and silently drop\n // the error.\n // When the managed-photo upload URL is loopback (the local storage provider\n // reached over `adb reverse`), the glasses cannot reach it over WiFi —\n // localhost on the glasses is the glasses. Force BLE transfer so the phone\n // (which CAN reach the reversed runtime) relays the bytes; a public r2/s3\n // presigned URL stays on \"auto\".\n const isLoopbackUpload = /^https?:\\/\\/(localhost|127\\.0\\.0\\.1|10\\.0\\.2\\.2)\\b/.test(uploadUrl)\n\n const abort = new AbortController()\n const bleRequestId = mintBleRequestId()\n this.bleIdToCloud.set(bleRequestId, requestId)\n\n const outcome = new Promise<PhotoResult>((resolve, reject) => {\n this.activeRequests.set(requestId, {packageName, abort, resolve, reject})\n })\n\n // Last-resort watchdog for a wedged pipeline. The managed-photo ready push\n // normally resolves or rejects first; this only prevents an indefinite hang\n // if both the native terminal response and cloud push disappear.\n const captureWatchdog = setTimeout(() => {\n const e = this.activeRequests.get(requestId)\n if (!e) return\n e.abort.abort()\n e.reject(\n new PhotoError(\n \"CAPTURE_TIMEOUT\",\n \"Photo capture did not complete. The take_photo command, media processing, transfer, or upload may have stalled.\",\n \"capture\",\n isLoopbackUpload ? \"ble\" : \"wifi\",\n ),\n )\n }, CAPTURE_PIPELINE_TIMEOUT_MS)\n // Clear the watchdog on BOTH arms. Not `.finally()`: that would mint a new\n // promise that re-rejects unobserved whenever the photo fails (the caller\n // only awaits `outcome` itself), i.e. an unhandled rejection per failure.\n const clearWatchdog = () => clearTimeout(captureWatchdog)\n void outcome.then(clearWatchdog, clearWatchdog)\n\n // 3) Drive glasses over BLE. requestPhoto now resolves at terminal\n // photo_response success, so run it beside the cloud poll instead of\n // awaiting it before polling. iOS auto-injects transferMethod: \"auto\"\n // (WiFi direct with BLE fallback) — see MentraLive.swift.\n try {\n void BluetoothSdk.requestPhoto({\n requestId: bleRequestId,\n appId: packageName,\n size: normalizePhotoSize(opts.size ?? \"medium\"),\n mode: opts.mode ?? \"photo\",\n webhookUrl: uploadUrl,\n authToken: null,\n ...(isLoopbackUpload ? {transferMethod: \"ble\" as const} : {}),\n compress: toNativeCompression(opts.compress),\n save: opts.saveToGallery ?? false,\n sound: opts.sound ?? true,\n exposureTimeNs: opts.exposureTimeNs ?? null,\n }).catch((err) => {\n const e = this.activeRequests.get(requestId)\n if (!e) return\n e.abort.abort()\n e.reject(this.toPhotoError(err, \"BLE_SEND_FAILED\", \"command\", \"ble\"))\n })\n } catch (err) {\n this.activeRequests.delete(requestId)\n this.bleIdToCloud.delete(bleRequestId)\n throw this.toPhotoError(err, \"BLE_SEND_FAILED\", \"command\", \"ble\")\n }\n\n // 4) Await the runtime's photo.ready push (replaces the legacy long-poll).\n // handlePhotoError races against it and uses the same entry to reject\n // first.\n cloudClientService\n .awaitManagedPhotoReady(requestId)\n .then((res) => {\n const e = this.activeRequests.get(requestId)\n if (!e) return // already settled by handlePhotoError\n e.resolve({photoUrl: res.readUrl ?? readUrl, mimeType: \"image/jpeg\", size: -1})\n })\n .catch((err) => {\n const e = this.activeRequests.get(requestId)\n if (e) e.reject(this.toPhotoError(err, \"POLL_FAILED\", \"push\", \"ws\"))\n })\n\n try {\n const result = await outcome\n if (typeof __DEV__ !== \"undefined\" && __DEV__) {\n console.debug(\n `[PhonePhotoCoordinator] takePhoto complete ${Math.round(performance.now() - flowStarted)}ms requestId=${requestId}`,\n )\n }\n return {\n photoUrl: result.photoUrl,\n mimeType: result.mimeType,\n size: result.size,\n requestId,\n }\n } finally {\n this.activeRequests.delete(requestId)\n this.bleIdToCloud.delete(bleRequestId)\n }\n }\n\n /** Map a short BLE requestId from photo_response back to the cloud requestId. */\n resolveCloudRequestId(bleOrCloudId: string): string {\n return this.bleIdToCloud.get(bleOrCloudId) ?? bleOrCloudId\n }\n\n /**\n * Pre-warm the glasses camera so the next takePhoto() is near-instant.\n *\n * Pure BLE — NO cloud presign, NO upload, NO long-poll. The SDK mints the\n * requestId, sends the warm-up command, and resolves when the camera reports\n * ready (the native promise resolves on the ready status event).\n */\n async warmUpCamera(\n packageName: string,\n opts: {size?: \"low\" | \"medium\" | \"high\" | \"max\"; exposureTimeNs?: number; durationMs?: number},\n ): Promise<void> {\n // Pre-check: if glasses aren't connected, the BLE warm-up command would be\n // sent into the void. Fail fast with a typed error.\n if (!isGlassesConnected(useGlassesStore.getState().connection)) {\n throw new PhotoError(\"GLASSES_NOT_CONNECTED\", \"Glasses are not connected\", \"command\", \"ble\")\n }\n\n try {\n await BluetoothSdk.warmUpCamera({\n size: normalizePhotoSize(opts.size ?? \"medium\"),\n exposureTimeNs: opts.exposureTimeNs ?? null,\n durationMs: opts.durationMs ?? 15000,\n })\n } catch (err) {\n throw this.toPhotoError(err, \"WARM_UP_FAILED\", \"command\", \"ble\")\n }\n }\n\n /** True iff this requestId (short BLE id or cloud id) is one we're currently waiting on. */\n owns(requestId: string): boolean {\n const cloudId = this.resolveCloudRequestId(requestId)\n return this.activeRequests.has(cloudId)\n }\n\n /**\n * Called by MantleManager's gated photo_response listener when glasses\n * report an error (BATTERY_LOW, CAMERA_BUSY, etc.) for a phone-owned\n * requestId. Rejects the in-flight takePhoto Promise immediately.\n */\n handlePhotoError(requestId: string, errorCode: string, errorMessage: string): void {\n const cloudId = this.resolveCloudRequestId(requestId)\n const entry = this.activeRequests.get(cloudId)\n if (!entry) return\n this.bleIdToCloud.delete(requestId)\n // Abort the in-flight long-poll first so we don't double-resolve.\n entry.abort.abort()\n entry.reject(new PhotoError(errorCode || \"GLASSES_ERROR\", errorMessage || \"Glasses error\", \"capture\", \"ble\"))\n // cloud-v2 pending photo requests TTL out on their own; nothing to free.\n }\n\n private toPhotoError(\n err: unknown,\n fallbackCode: string,\n stage?: PhotoStage,\n transport?: PhotoTransport,\n ): PhotoError {\n if (err instanceof PhotoError) return err\n const code = (err as {code?: string})?.code\n const message = err instanceof Error ? err.message : String(err)\n return new PhotoError(code || fallbackCode, message, stage, transport)\n }\n}\n\n// Singleton — coordinator state is process-wide (mirrors phoneStreamCoordinator).\nexport const phonePhotoCoordinator = new PhonePhotoCoordinator()\n"]}
|
|
1
|
+
{"version":3,"file":"PhonePhotoCoordinator.js","sourceRoot":"","sources":["../../src/services/PhonePhotoCoordinator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * PhonePhotoCoordinator — owns local-miniapp takePhoto() end-to-end.\n *\n * Architecture:\n * miniapp → SDK → LocalMiniappRuntime → photo runtime hook\n * → coordinator.takePhoto(packageName, opts)\n * ├── (precheck) glasses connected + hasCamera\n * ├── cloudClientService.startManagedPhoto → {requestId, uploadUrl, readUrl} (cloud-v2 runtime presign)\n * ├── BluetoothSdk.requestPhoto(requestId, size, uploadUrl, compress, sound)\n * └── race:\n * - cloudClientService.awaitManagedPhotoReady(requestId) resolves on photo.ready push\n * - BluetoothSdk.requestPhoto rejects if terminal photo_response is an error\n * - handlePhotoError(requestId, code, message) rejects if MantleManager observes\n * the same BLE photo_response error before the native promise crosses the bridge\n *\n * `activeRequests` lets MantleManager's gated `photo_response` listener\n * short-circuit our long-poll with a typed error (CAMERA_BUSY, BATTERY_LOW,\n * etc.) instead of waiting 30s for cloud's timeout.\n */\n\nimport BluetoothSdk from \"@mentra/bluetooth-sdk/internal\"\nimport type {PhotoSize, PhotoTransferMethod} from \"@mentra/bluetooth-sdk/internal\"\nimport {cloudClientService} from \"./CloudClientService\"\nimport {isGlassesConnected} from \"./GlassesReadiness\"\nimport {useGlassesStore} from \"../stores/glasses\"\n\ninterface PhotoResult {\n photoUrl: string\n mimeType: string\n size: number\n}\n\n/** Map legacy/cloud size names onto the native take_photo enum. */\nfunction normalizePhotoSize(value: unknown): PhotoSize {\n if (typeof value !== \"string\") return \"medium\"\n switch (value) {\n case \"small\":\n return \"low\"\n case \"large\":\n return \"high\"\n case \"full\":\n return \"max\"\n default:\n return ([\"low\", \"medium\", \"high\", \"max\"] as const).includes(value as PhotoSize) ? (value as PhotoSize) : \"medium\"\n }\n}\n\nexport interface PhotoOpts {\n /** Legacy cloud size names are normalized before the native take_photo command. */\n size?: \"low\" | \"medium\" | \"high\" | \"max\" | \"small\" | \"large\" | \"full\"\n mode?: \"photo\" | \"text\"\n /** Select direct-only, phone-relayed BLE, or the default Wi-Fi/BLE fallback policy. */\n transferMethod?: PhotoTransferMethod\n compress?: \"none\" | \"low\" | \"medium\" | \"high\"\n sound?: boolean\n saveToGallery?: boolean\n exposureTimeNs?: number\n iso?: number | null\n aeExposureDivisor?: number\n isoCap?: number\n noiseReduction?: boolean\n edgeEnhancement?: boolean\n /** ZSL preview buffering. */\n zsl?: boolean\n /** MFNR still capture. */\n mfnr?: boolean\n ispDigitalGain?: number\n ispAnalogGain?: string\n}\n\nexport interface PhotoTaken {\n photoUrl: string\n mimeType: string\n size: number\n requestId: string\n}\n\n/** Pipeline stage a photo request failed at — surfaced to the miniapp so a dev\n * sees exactly where it broke, not just a flattened message. */\nexport type PhotoStage = \"presign\" | \"command\" | \"capture\" | \"upload\" | \"push\"\n/** Transport in play at the point of failure. */\nexport type PhotoTransport = \"cloud-rest\" | \"ble\" | \"wifi\" | \"ws\"\n\nexport class PhotoError extends Error {\n constructor(\n public readonly code: string,\n message: string,\n public readonly stage?: PhotoStage,\n public readonly transport?: PhotoTransport,\n ) {\n super(message)\n this.name = \"PhotoError\"\n }\n}\n\nfunction parsePhotoTransferMethod(value: unknown): PhotoTransferMethod | undefined {\n if (value === undefined) return undefined\n if (value === \"auto\" || value === \"direct\" || value === \"ble\") return value\n throw new PhotoError(\n \"INVALID_ARGUMENT\",\n `Invalid transferMethod ${JSON.stringify(value)}. Expected \"auto\", \"direct\", or \"ble\".`,\n )\n}\n\ninterface ActiveRequest {\n packageName: string\n abort: AbortController\n resolve: (r: PhotoResult) => void\n reject: (err: Error) => void\n}\n\n/**\n * Last-resort ceiling for the complete capture + encode + transfer + upload\n * pipeline. This must exceed the managed-photo service's 30s ready-push\n * timeout so the cloud can return its more specific failure first.\n *\n * Text mode commonly spends several seconds detecting/cropping the region and\n * can take another 10s+ to transfer over BLE. A 15s ceiling incorrectly\n * rejected successful captures while their upload was still in progress.\n */\nexport const CAPTURE_PIPELINE_TIMEOUT_MS = 45_000\nexport const CAMERA_WARM_UP_DEFAULT_DURATION_MS = 15_000\nexport const CAMERA_WARM_UP_MAX_DURATION_MS = 60_000\n\nlet bleRequestCounter = 0\n\n/** Short 4-hex-char correlation id sent over BLE instead of the full cloud\n * requestId UUID (wire v2 keeps BLE JSON small). */\nfunction mintBleRequestId(): string {\n bleRequestCounter = (bleRequestCounter + 1) & 0xffff\n return bleRequestCounter.toString(16).padStart(4, \"0\")\n}\n\nfunction toNativeCompression(compress: PhotoOpts[\"compress\"]): \"none\" | \"medium\" | \"heavy\" {\n if (compress === \"high\") return \"heavy\"\n if (compress === \"low\" || compress === \"medium\") return \"medium\"\n return \"none\"\n}\n\nexport class PhonePhotoCoordinator {\n // Cloud requestId → in-flight slot. The gated photo_response listener\n // (DeviceEventRouter) resolves short BLE ids via bleIdToCloud before calling\n // owns() / handlePhotoError().\n private readonly activeRequests = new Map<string, ActiveRequest>()\n /** Short BLE correlation id (4-char hex) → full cloud requestId. */\n private readonly bleIdToCloud = new Map<string, string>()\n private readonly activeWarmUps = new Map<\n string,\n {requestId: string; durationMs: number; expiryTimer?: ReturnType<typeof setTimeout>}\n >()\n\n /** Report-safe camera ownership snapshot for incident diagnostics. */\n getDiagnosticSnapshot(): Record<string, unknown> {\n return {\n captureOwners: [...new Set([...this.activeRequests.values()].map((request) => request.packageName))].sort(),\n warmUpOwners: [...this.activeWarmUps.keys()].sort(),\n activeCaptureCount: this.activeRequests.size,\n }\n }\n\n async takePhoto(packageName: string, opts: PhotoOpts): Promise<PhotoTaken> {\n const transferMethod = parsePhotoTransferMethod(opts.transferMethod)\n\n // Pre-check: if glasses aren't even connected, the BLE photo command\n // would be sent into the void and we'd wait 30s for the cloud long-poll\n // to time out. Fail fast with a typed error.\n //\n // We DON'T pre-check `hasCamera` here — the canonical capability data\n // lives in `getModelCapabilities(deviceModel)` from @mentra/types and\n // pulling that into this file would add a cross-package import. If a\n // cameraless device receives the BLE photo command, the glasses-side\n // handler will return a photo_response error within ~1s and the gated\n // photo_response listener in MantleManager will short-circuit our\n // long-poll. Slower but correct.\n if (!isGlassesConnected(useGlassesStore.getState().connection)) {\n throw new PhotoError(\"GLASSES_NOT_CONNECTED\", \"Glasses are not connected\", \"command\", \"ble\")\n }\n\n // Text-mode sensor resolution is owned by ASG constants; keep cloud metadata on a stable\n // high-capacity tier and let the glasses ignore the public size when mode=text.\n const captureSize = opts.size ?? \"medium\"\n\n // 1) Presign via the cloud-v2 managed-photo service. Local miniapps use\n // ONLY the cloud-v2 path: the runtime presigns upload+read URLs and the\n // phone (as the device controller) delivers the bytes; the legacy\n // backend_url mint is gone from this flow.\n let requestId: string\n let uploadUrl: string\n let readUrl: string\n const flowStarted = performance.now()\n try {\n const presignStarted = performance.now()\n const r = await cloudClientService.startManagedPhoto({\n size: opts.mode === \"text\" ? \"max\" : captureSize,\n })\n const presignMs = Math.round(performance.now() - presignStarted)\n if (typeof __DEV__ !== \"undefined\" && __DEV__) {\n console.debug(\n `[PhonePhotoCoordinator] presign ${presignMs}ms size=${opts.mode === \"text\" ? \"max\" : captureSize} mode=${\n opts.mode ?? \"photo\"\n }`,\n )\n }\n requestId = r.requestId\n uploadUrl = r.uploadUrl\n readUrl = r.readUrl\n } catch (err) {\n throw this.toPhotoError(err, \"PHOTO_REQUEST_FAILED\", \"presign\", \"cloud-rest\")\n }\n\n // 2) Build the outcome Promise FIRST so both resolve+reject handles\n // are wired into activeRequests BEFORE any code path can produce\n // an error. Without this, a fast BLE photo_response (BATTERY_LOW\n // etc.) racing with the Promise constructor could fire\n // handlePhotoError() against a no-op rejectFn and silently drop\n // the error.\n // When the managed-photo upload URL is loopback (the local storage provider\n // reached over `adb reverse`), the glasses cannot reach it over WiFi —\n // localhost on the glasses is the glasses. Force BLE transfer so the phone\n // (which CAN reach the reversed runtime) relays the bytes; a public r2/s3\n // presigned URL stays on \"auto\".\n const isLoopbackUpload = /^https?:\\/\\/(localhost|127\\.0\\.0\\.1|10\\.0\\.2\\.2)\\b/.test(uploadUrl)\n\n const abort = new AbortController()\n const bleRequestId = mintBleRequestId()\n this.bleIdToCloud.set(bleRequestId, requestId)\n\n const outcome = new Promise<PhotoResult>((resolve, reject) => {\n this.activeRequests.set(requestId, {packageName, abort, resolve, reject})\n })\n\n // Last-resort watchdog for a wedged pipeline. The managed-photo ready push\n // normally resolves or rejects first; this only prevents an indefinite hang\n // if both the native terminal response and cloud push disappear.\n const captureWatchdog = setTimeout(() => {\n const e = this.activeRequests.get(requestId)\n if (!e) return\n e.abort.abort()\n e.reject(\n new PhotoError(\n \"CAPTURE_TIMEOUT\",\n \"Photo capture did not complete. The take_photo command, media processing, transfer, or upload may have stalled.\",\n \"capture\",\n isLoopbackUpload ? \"ble\" : \"wifi\",\n ),\n )\n }, CAPTURE_PIPELINE_TIMEOUT_MS)\n // Clear the watchdog on BOTH arms. Not `.finally()`: that would mint a new\n // promise that re-rejects unobserved whenever the photo fails (the caller\n // only awaits `outcome` itself), i.e. an unhandled rejection per failure.\n const clearWatchdog = () => clearTimeout(captureWatchdog)\n void outcome.then(clearWatchdog, clearWatchdog)\n\n // 3) Drive glasses over BLE. requestPhoto now resolves at terminal\n // photo_response success, so run it beside the cloud poll instead of\n // awaiting it before polling. Native defaults transferMethod to \"auto\"\n // (Wi-Fi direct with BLE fallback) unless the miniapp forces BLE.\n try {\n void BluetoothSdk.requestPhoto({\n requestId: bleRequestId,\n appId: packageName,\n size: normalizePhotoSize(captureSize),\n mode: opts.mode ?? \"photo\",\n webhookUrl: uploadUrl,\n authToken: null,\n ...(isLoopbackUpload ? {transferMethod: \"ble\" as const} : transferMethod ? {transferMethod} : {}),\n compress: toNativeCompression(opts.compress),\n save: opts.saveToGallery ?? false,\n sound: opts.sound ?? true,\n exposureTimeNs: opts.exposureTimeNs ?? null,\n iso: opts.iso,\n aeExposureDivisor: opts.aeExposureDivisor,\n isoCap: opts.isoCap,\n noiseReduction: opts.noiseReduction,\n edgeEnhancement: opts.edgeEnhancement,\n ...(opts.zsl != null ? {zsl: opts.zsl} : {}),\n ...(opts.mfnr != null ? {mfnr: opts.mfnr} : {}),\n ispDigitalGain: opts.ispDigitalGain,\n ispAnalogGain: opts.ispAnalogGain,\n }).catch((err) => {\n const e = this.activeRequests.get(requestId)\n if (!e) return\n e.abort.abort()\n e.reject(this.toPhotoError(err, \"BLE_SEND_FAILED\", \"command\", \"ble\"))\n })\n } catch (err) {\n this.activeRequests.delete(requestId)\n this.bleIdToCloud.delete(bleRequestId)\n throw this.toPhotoError(err, \"BLE_SEND_FAILED\", \"command\", \"ble\")\n }\n\n // 4) Await the runtime's photo.ready push (replaces the legacy long-poll).\n // handlePhotoError races against it and uses the same entry to reject\n // first.\n cloudClientService\n .awaitManagedPhotoReady(requestId)\n .then((res) => {\n const e = this.activeRequests.get(requestId)\n if (!e) return // already settled by handlePhotoError\n e.resolve({photoUrl: res.readUrl ?? readUrl, mimeType: \"image/jpeg\", size: -1})\n })\n .catch((err) => {\n const e = this.activeRequests.get(requestId)\n if (e) e.reject(this.toPhotoError(err, \"POLL_FAILED\", \"push\", \"ws\"))\n })\n\n try {\n const result = await outcome\n if (typeof __DEV__ !== \"undefined\" && __DEV__) {\n console.debug(\n `[PhonePhotoCoordinator] takePhoto complete ${Math.round(\n performance.now() - flowStarted,\n )}ms requestId=${requestId}`,\n )\n }\n return {\n photoUrl: result.photoUrl,\n mimeType: result.mimeType,\n size: result.size,\n requestId,\n }\n } finally {\n this.activeRequests.delete(requestId)\n this.bleIdToCloud.delete(bleRequestId)\n }\n }\n\n /** Map a short BLE requestId from photo_response back to the cloud requestId. */\n resolveCloudRequestId(bleOrCloudId: string): string {\n return this.bleIdToCloud.get(bleOrCloudId) ?? bleOrCloudId\n }\n\n /**\n * Pre-warm the glasses camera so the next takePhoto() is near-instant.\n *\n * Pure BLE — NO cloud presign, NO upload, NO long-poll. The phone mints and owns\n * the requestId, sends the warm-up command, and resolves when the camera reports\n * ready (the native promise resolves on the ready status event).\n */\n async warmUpCamera(\n packageName: string,\n opts: {\n size?: \"low\" | \"medium\" | \"high\" | \"max\"\n mode?: \"photo\" | \"text\"\n exposureTimeNs?: number\n durationMs?: number\n zsl?: boolean\n mfnr?: boolean\n },\n ): Promise<void> {\n // Pre-check: if glasses aren't connected, the BLE warm-up command would be\n // sent into the void. Fail fast with a typed error.\n if (!isGlassesConnected(useGlassesStore.getState().connection)) {\n throw new PhotoError(\"GLASSES_NOT_CONNECTED\", \"Glasses are not connected\", \"command\", \"ble\")\n }\n\n let lease: {requestId: string; durationMs: number; expiryTimer?: ReturnType<typeof setTimeout>} | undefined\n try {\n await this.stopWarmUpForApp(packageName)\n const requestId = mintBleRequestId()\n const requestedDuration =\n typeof opts.durationMs === \"number\" && Number.isFinite(opts.durationMs) && opts.durationMs > 0\n ? Math.round(opts.durationMs)\n : CAMERA_WARM_UP_DEFAULT_DURATION_MS\n const durationMs = Math.min(requestedDuration, CAMERA_WARM_UP_MAX_DURATION_MS)\n lease = {requestId, durationMs}\n this.activeWarmUps.set(packageName, lease)\n await BluetoothSdk.warmUpCamera({\n requestId,\n size: normalizePhotoSize(opts.size ?? \"medium\"),\n mode: opts.mode ?? \"photo\",\n exposureTimeNs: opts.exposureTimeNs ?? null,\n durationMs,\n ...(opts.zsl != null ? {zsl: opts.zsl} : {}),\n ...(opts.mfnr != null ? {mfnr: opts.mfnr} : {}),\n })\n if (this.activeWarmUps.get(packageName) === lease) {\n lease.expiryTimer = setTimeout(() => {\n if (this.activeWarmUps.get(packageName) === lease) {\n this.activeWarmUps.delete(packageName)\n }\n }, durationMs)\n }\n } catch (err) {\n if (lease && this.activeWarmUps.get(packageName) === lease) {\n if (lease.expiryTimer) clearTimeout(lease.expiryTimer)\n this.activeWarmUps.delete(packageName)\n }\n throw this.toPhotoError(err, \"WARM_UP_FAILED\", \"command\", \"ble\")\n }\n }\n\n /** Release a miniapp's warm-up even if its original warmUpCamera promise is still opening. */\n async stopWarmUpForApp(packageName: string): Promise<void> {\n const active = this.activeWarmUps.get(packageName)\n if (!active) return\n await BluetoothSdk.stopCameraWarmUp(active.requestId)\n if (this.activeWarmUps.get(packageName) === active) {\n this.activeWarmUps.delete(packageName)\n if (active.expiryTimer) clearTimeout(active.expiryTimer)\n }\n }\n\n /** True iff this requestId (short BLE id or cloud id) is one we're currently waiting on. */\n owns(requestId: string): boolean {\n const cloudId = this.resolveCloudRequestId(requestId)\n return this.activeRequests.has(cloudId)\n }\n\n /**\n * Called by MantleManager's gated photo_response listener when glasses\n * report an error (BATTERY_LOW, CAMERA_BUSY, etc.) for a phone-owned\n * requestId. Rejects the in-flight takePhoto Promise immediately.\n */\n handlePhotoError(requestId: string, errorCode: string, errorMessage: string): void {\n const cloudId = this.resolveCloudRequestId(requestId)\n const entry = this.activeRequests.get(cloudId)\n if (!entry) return\n this.bleIdToCloud.delete(requestId)\n // Abort the in-flight long-poll first so we don't double-resolve.\n entry.abort.abort()\n entry.reject(new PhotoError(errorCode || \"GLASSES_ERROR\", errorMessage || \"Glasses error\", \"capture\", \"ble\"))\n // cloud-v2 pending photo requests TTL out on their own; nothing to free.\n }\n\n private toPhotoError(err: unknown, fallbackCode: string, stage?: PhotoStage, transport?: PhotoTransport): PhotoError {\n if (err instanceof PhotoError) return err\n const code = (err as {code?: string})?.code\n const message = err instanceof Error ? err.message : String(err)\n return new PhotoError(code || fallbackCode, message, stage, transport)\n }\n}\n\n// Singleton — coordinator state is process-wide (mirrors phoneStreamCoordinator).\nexport const phonePhotoCoordinator = new PhonePhotoCoordinator()\n"]}
|
|
@@ -38,6 +38,7 @@ declare const DEFAULT_TIMINGS: {
|
|
|
38
38
|
readonly ackTimeoutMs: 10000;
|
|
39
39
|
readonly maxMissedAcks: 3;
|
|
40
40
|
readonly cloudflareStatusPollMs: 5000;
|
|
41
|
+
readonly cloudflareStartupPollInitialMs: 500;
|
|
41
42
|
readonly hlsReadinessInitialDelayMs: 5000;
|
|
42
43
|
readonly hlsReadinessPollMs: 2000;
|
|
43
44
|
readonly hlsReadinessMaxAttempts: 30;
|
|
@@ -51,6 +52,8 @@ export interface StartUnmanagedOptions {
|
|
|
51
52
|
video?: StreamStartRequest["video"];
|
|
52
53
|
audio?: StreamStartRequest["audio"];
|
|
53
54
|
sound?: boolean;
|
|
55
|
+
/** Optional Bearer token for WHIP Authorization (custom authenticated endpoints). */
|
|
56
|
+
authToken?: string;
|
|
54
57
|
}
|
|
55
58
|
export interface StartManagedOptions {
|
|
56
59
|
restreamDestinations?: RestreamDestinationInput[];
|
|
@@ -64,8 +67,10 @@ export interface StartManagedOptions {
|
|
|
64
67
|
* - "whip": WebRTC ingest -> WHEP playback (<1s glass-to-screen), but NO
|
|
65
68
|
* HLS/DASH playback and NO recording (Cloudflare limitation; the returned
|
|
66
69
|
* hlsUrl will serve 204 forever).
|
|
70
|
+
* - "rtmp": RTMPS ingest over TCP 443 -> HLS playback. Survives networks
|
|
71
|
+
* that drop WHIP/SRT UDP.
|
|
67
72
|
*/
|
|
68
|
-
ingest?: "srt" | "whip";
|
|
73
|
+
ingest?: "srt" | "whip" | "rtmp";
|
|
69
74
|
}
|
|
70
75
|
export interface StreamPublisherStartResult {
|
|
71
76
|
streamId: string;
|
|
@@ -139,6 +144,8 @@ export declare class PhoneStreamCoordinator {
|
|
|
139
144
|
* check covers the multi-subscriber case.
|
|
140
145
|
*/
|
|
141
146
|
owns(streamId: string): boolean;
|
|
147
|
+
/** Report-safe stream ownership snapshot for incident diagnostics. */
|
|
148
|
+
getDiagnosticSnapshot(): Record<string, unknown>;
|
|
142
149
|
startUnmanaged(packageName: string, opts: StartUnmanagedOptions): Promise<StreamPublisherStartResult>;
|
|
143
150
|
startManaged(packageName: string, opts: StartManagedOptions): Promise<ManagedStartResult>;
|
|
144
151
|
stop(packageName: string, streamId?: string): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PhoneStreamCoordinator.d.ts","sourceRoot":"","sources":["../../src/services/PhoneStreamCoordinator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAGH,OAAO,KAAK,EACV,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,gCAAgC,CAAA;AAMvC,OAAO,EAML,KAAK,wBAAwB,EAC9B,MAAM,kBAAkB,CAAA;AAEzB;;;GAGG;AACH,QAAA,MAAM,eAAe
|
|
1
|
+
{"version":3,"file":"PhoneStreamCoordinator.d.ts","sourceRoot":"","sources":["../../src/services/PhoneStreamCoordinator.ts"],"names":[],"mappings":"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"}
|