@mentra/engine 0.1.0-beta.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.map +1 -1
- package/build/facades/dev.js +9 -5
- 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/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 +2 -2
- package/build/internal.d.ts.map +1 -1
- package/build/internal.js +1 -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 +18 -8
- package/build/services/AppRegistry.d.ts.map +1 -1
- package/build/services/AppRegistry.js +44 -45
- package/build/services/AppRegistry.js.map +1 -1
- package/build/services/AudioCloudUplink.d.ts +9 -3
- package/build/services/AudioCloudUplink.d.ts.map +1 -1
- package/build/services/AudioCloudUplink.js +9 -3
- package/build/services/AudioCloudUplink.js.map +1 -1
- package/build/services/AudioPlaybackService.d.ts +9 -1
- package/build/services/AudioPlaybackService.d.ts.map +1 -1
- package/build/services/AudioPlaybackService.js +77 -32
- 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 +75 -0
- package/build/services/CloudClientService.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 +67 -1
- package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
- package/build/services/LocalMiniappRuntime.js +486 -126
- 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/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/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/PhoneCalendarService.d.ts.map +1 -1
- package/build/services/PhoneCalendarService.js +22 -1
- package/build/services/PhoneCalendarService.js.map +1 -1
- package/build/services/PhoneCameraFovCoordinator.d.ts +2 -0
- package/build/services/PhoneCameraFovCoordinator.d.ts.map +1 -1
- package/build/services/PhoneCameraFovCoordinator.js +14 -0
- package/build/services/PhoneCameraFovCoordinator.js.map +1 -1
- 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 +10 -3
- package/build/services/PhonePhotoCoordinator.d.ts.map +1 -1
- package/build/services/PhonePhotoCoordinator.js +21 -3
- 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/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/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 +3 -0
- package/build/services/asg/asgCameraApi.d.ts.map +1 -1
- package/build/services/asg/asgCameraApi.js +72 -2
- package/build/services/asg/asgCameraApi.js.map +1 -1
- package/build/services/asg/gallerySyncService.d.ts.map +1 -1
- package/build/services/asg/gallerySyncService.js +26 -14
- package/build/services/asg/gallerySyncService.js.map +1 -1
- package/build/services/asg/localNetworkTransport.d.ts +2 -2
- package/build/services/asg/localNetworkTransport.d.ts.map +1 -1
- package/build/services/asg/localNetworkTransport.js +6 -6
- package/build/services/asg/localNetworkTransport.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/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 +152 -19
- 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/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/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 +27 -18
- package/src/assets/silence.wav +0 -0
- package/src/engine.ts +7 -2
- package/src/facades/dev.ts +9 -5
- 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/phoneNotifications.ts +4 -13
- package/src/index.ts +26 -2
- package/src/internal.ts +2 -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 +72 -48
- package/src/services/AudioCloudUplink.ts +9 -3
- package/src/services/AudioPlaybackService.ts +94 -34
- package/src/services/BlobStore.ts +22 -9
- package/src/services/CloudAudioSubscriptionSync.ts +13 -1
- package/src/services/CloudClientService.ts +74 -0
- 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 +576 -130
- package/src/services/LocalMiniappStorage.ts +82 -0
- package/src/services/LocalMiniappUserIdentity.ts +46 -0
- package/src/services/MicStateCoordinator.ts +169 -4
- package/src/services/MiniappLauncher.ts +30 -3
- package/src/services/MiniappLiveness.ts +24 -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/PhoneCalendarService.ts +27 -4
- package/src/services/PhoneCameraFovCoordinator.ts +15 -0
- package/src/services/PhoneNotificationsSync.ts +12 -10
- package/src/services/PhonePhotoCoordinator.ts +33 -7
- package/src/services/PhoneStreamCoordinator.ts +139 -25
- package/src/services/PhoneVideoCoordinator.ts +11 -0
- package/src/services/SceneRenderer.ts +16 -0
- package/src/services/SupportProfileSync.ts +218 -0
- package/src/services/TtsTextSanitizer.ts +66 -0
- package/src/services/WifiAdbRequest.ts +53 -0
- package/src/services/asg/asgCameraApi.ts +99 -8
- package/src/services/asg/gallerySyncService.ts +28 -19
- package/src/services/asg/localNetworkTransport.ts +7 -11
- package/src/services/audioPlaybackAssets.ts +8 -0
- 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 +174 -21
- package/src/types/applet.ts +2 -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/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
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import type { OtaUpdateInfo } from "@mentra/bluetooth-sdk/internal";
|
|
2
|
+
/**
|
|
3
|
+
* Phone-side mirror of ASG's `DOWNGRADE_FLOOR_VERSION_CODE`. Set to the versionCode of the first
|
|
4
|
+
* release shipping the shared media root (the first downgrade-safe build). A non-positive value
|
|
5
|
+
* means downgrades are disabled, so the phone must NOT offer them — offering a downgrade the
|
|
6
|
+
* glasses' `DowngradeGate` will refuse leaves the version-change session with no install and the
|
|
7
|
+
* glasses reporting a bare "complete", which would otherwise present as false success. Keep this
|
|
8
|
+
* in lockstep with the ASG/recovery constant at release time.
|
|
9
|
+
*/
|
|
10
|
+
export declare const DOWNGRADE_FLOOR_VERSION_CODE = 0;
|
|
2
11
|
export interface VersionInfo {
|
|
3
12
|
versionCode: number;
|
|
4
13
|
versionName: string;
|
|
@@ -12,10 +21,12 @@ export interface MtkPatch {
|
|
|
12
21
|
start_firmware: string;
|
|
13
22
|
end_firmware: string;
|
|
14
23
|
url: string;
|
|
24
|
+
sha256?: string;
|
|
15
25
|
}
|
|
16
26
|
export interface BesFirmware {
|
|
17
27
|
version: string;
|
|
18
28
|
url: string;
|
|
29
|
+
sha256?: string;
|
|
19
30
|
}
|
|
20
31
|
export interface VersionJson {
|
|
21
32
|
apps?: {
|
|
@@ -37,8 +48,22 @@ export interface OtaCheckResult {
|
|
|
37
48
|
updates: string[];
|
|
38
49
|
mtkPatch: MtkPatch | null;
|
|
39
50
|
besVersion: string | null;
|
|
51
|
+
/** True when the pending APK step installs an OLDER build than the glasses currently run. */
|
|
52
|
+
isApkDowngrade: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Raw manifest JSON (stringified) this check actually fetched, or null when the
|
|
55
|
+
* fetch failed. Lets change-watchers baseline on exactly what the check saw,
|
|
56
|
+
* instead of racing it with a second fetch of the same URL.
|
|
57
|
+
*/
|
|
58
|
+
manifestBody: string | null;
|
|
59
|
+
/**
|
|
60
|
+
* Why the check failed, when it did. "network" is retryable (connection/server
|
|
61
|
+
* trouble); "pin_unavailable" is permanent for this app build (manifest 404/gone,
|
|
62
|
+
* unparseable, or carrying no valid ASG pin) — the remedy is updating the app.
|
|
63
|
+
*/
|
|
64
|
+
checkFailureReason?: "network" | "pin_unavailable";
|
|
40
65
|
}
|
|
41
|
-
export type OtaCheckSkippedReason = "disconnected" | "missing_build";
|
|
66
|
+
export type OtaCheckSkippedReason = "disconnected" | "missing_build" | "dev_build";
|
|
42
67
|
export interface OtaCheckCurrentGlassesResult extends OtaCheckResult {
|
|
43
68
|
updateInfo: OtaUpdateInfo | null;
|
|
44
69
|
isRequired: boolean;
|
|
@@ -54,12 +79,22 @@ export interface OtaCheckCurrentGlassesOptions {
|
|
|
54
79
|
waitForMtkVersionMs?: number;
|
|
55
80
|
refreshVersionInfo?: boolean;
|
|
56
81
|
fixClockBeforeCheck?: boolean;
|
|
82
|
+
/** Downgrade floor override (defaults to DOWNGRADE_FLOOR_VERSION_CODE); for tests. */
|
|
83
|
+
floorVersionCode?: number;
|
|
57
84
|
}
|
|
58
85
|
export declare function fetchVersionInfo(url: string): Promise<VersionJson | null>;
|
|
59
|
-
export declare function checkVersionUpdateAvailable(currentBuildNumber: string | undefined, versionJson: VersionJson | null): boolean;
|
|
86
|
+
export declare function checkVersionUpdateAvailable(currentBuildNumber: string | undefined, versionJson: VersionJson | null, floorVersionCode?: number): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Direction of the pending APK change, or null when the glasses already match the manifest.
|
|
89
|
+
* Every apps-shaped manifest the phone drives is an exact pin, so both directions are
|
|
90
|
+
* actionable (mirroring the glasses-side `DowngradeGate`); the ancient top-level manifest
|
|
91
|
+
* shape stays upgrade-only, and zeroed rescue pins are never actionable.
|
|
92
|
+
*/
|
|
93
|
+
export declare function getApkUpdateDirection(currentBuildNumber: string | undefined, versionJson: VersionJson | null, floorVersionCode?: number): "upgrade" | "downgrade" | null;
|
|
60
94
|
export declare function getLatestVersionInfo(versionJson: VersionJson | null): VersionInfo | null;
|
|
61
95
|
export declare function findMatchingMtkPatch(patches: MtkPatch[] | undefined, currentVersion: string | undefined): MtkPatch | null;
|
|
62
96
|
export declare function checkBesUpdate(besFirmware: BesFirmware | undefined, currentVersion: string | undefined): boolean;
|
|
63
|
-
export declare function
|
|
97
|
+
export declare function compareVersions(version1: string, version2: string): number;
|
|
98
|
+
export declare function checkForOtaUpdate(otaVersionUrl: string, currentBuildNumber: string, currentMtkVersion?: string, currentBesVersion?: string, floorVersionCode?: number): Promise<OtaCheckResult>;
|
|
64
99
|
export declare function checkCurrentGlassesForUpdate(options?: OtaCheckCurrentGlassesOptions): Promise<OtaCheckCurrentGlassesResult>;
|
|
65
100
|
//# sourceMappingURL=OtaUpdateCheckService.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OtaUpdateCheckService.d.ts","sourceRoot":"","sources":["../../src/services/OtaUpdateCheckService.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,gCAAgC,CAAA;
|
|
1
|
+
{"version":3,"file":"OtaUpdateCheckService.d.ts","sourceRoot":"","sources":["../../src/services/OtaUpdateCheckService.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,gCAAgC,CAAA;AAMjE;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,IAAI,CAAA;AAE7C,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,MAAM,WAAW,QAAQ;IACvB,cAAc,EAAE,MAAM,CAAA;IACtB,YAAY,EAAE,MAAM,CAAA;IACpB,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE;QACL,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,CAAA;KACnC,CAAA;IACD,WAAW,CAAC,EAAE,QAAQ,EAAE,CAAA;IACxB,YAAY,CAAC,EAAE,WAAW,CAAA;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,iBAAiB,EAAE,OAAO,CAAA;IAC1B,eAAe,EAAE,OAAO,CAAA;IACxB,iBAAiB,EAAE,WAAW,GAAG,IAAI,CAAA;IACrC,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,6FAA6F;IAC7F,cAAc,EAAE,OAAO,CAAA;IACvB;;;;OAIG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,SAAS,GAAG,iBAAiB,CAAA;CACnD;AAED,MAAM,MAAM,qBAAqB,GAAG,cAAc,GAAG,eAAe,GAAG,WAAW,CAAA;AAElF,MAAM,WAAW,4BAA6B,SAAQ,cAAc;IAClE,UAAU,EAAE,aAAa,GAAG,IAAI,CAAA;IAChC,UAAU,EAAE,OAAO,CAAA;IACnB,aAAa,CAAC,EAAE,qBAAqB,CAAA;IACrC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED,MAAM,WAAW,6BAA6B;IAC5C,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,sFAAsF;IACtF,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AA8CD,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAE/E;AAED,wBAAgB,2BAA2B,CACzC,kBAAkB,EAAE,MAAM,GAAG,SAAS,EACtC,WAAW,EAAE,WAAW,GAAG,IAAI,EAC/B,gBAAgB,GAAE,MAAqC,GACtD,OAAO,CAET;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,kBAAkB,EAAE,MAAM,GAAG,SAAS,EACtC,WAAW,EAAE,WAAW,GAAG,IAAI,EAC/B,gBAAgB,GAAE,MAAqC,GACtD,SAAS,GAAG,WAAW,GAAG,IAAI,CAwChC;AAED,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAqBxF;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,QAAQ,EAAE,GAAG,SAAS,EAC/B,cAAc,EAAE,MAAM,GAAG,SAAS,GACjC,QAAQ,GAAG,IAAI,CAgBjB;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,WAAW,GAAG,SAAS,EAAE,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAUhH;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAiB1E;AAED,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,MAAM,EACrB,kBAAkB,EAAE,MAAM,EAC1B,iBAAiB,CAAC,EAAE,MAAM,EAC1B,iBAAiB,CAAC,EAAE,MAAM,EAC1B,gBAAgB,GAAE,MAAqC,GACtD,OAAO,CAAC,cAAc,CAAC,CAmGzB;AAED,wBAAsB,4BAA4B,CAChD,OAAO,GAAE,6BAAkC,GAC1C,OAAO,CAAC,4BAA4B,CAAC,CA0JvC"}
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import BluetoothSdk from "@mentra/bluetooth-sdk/internal";
|
|
2
2
|
import { getGlassesSystemTimeMs, isGlassesConnected, useGlassesStore, waitForGlassesState } from "../stores/glasses";
|
|
3
|
+
import { SETTINGS, useSettingsStore } from "../stores/settings";
|
|
3
4
|
import { maybeFixGlassesClockFromVersionInfo } from "./glassesClockSync";
|
|
4
|
-
import {
|
|
5
|
+
import { resolveOtaManifestUrl } from "./otaManifestUrl";
|
|
6
|
+
/**
|
|
7
|
+
* Phone-side mirror of ASG's `DOWNGRADE_FLOOR_VERSION_CODE`. Set to the versionCode of the first
|
|
8
|
+
* release shipping the shared media root (the first downgrade-safe build). A non-positive value
|
|
9
|
+
* means downgrades are disabled, so the phone must NOT offer them — offering a downgrade the
|
|
10
|
+
* glasses' `DowngradeGate` will refuse leaves the version-change session with no install and the
|
|
11
|
+
* glasses reporting a bare "complete", which would otherwise present as false success. Keep this
|
|
12
|
+
* in lockstep with the ASG/recovery constant at release time.
|
|
13
|
+
*/
|
|
14
|
+
export const DOWNGRADE_FLOOR_VERSION_CODE = 0;
|
|
5
15
|
function emptyCheckResult(skippedReason) {
|
|
6
16
|
return {
|
|
7
17
|
hasCheckCompleted: false,
|
|
@@ -10,6 +20,8 @@ function emptyCheckResult(skippedReason) {
|
|
|
10
20
|
updates: [],
|
|
11
21
|
mtkPatch: null,
|
|
12
22
|
besVersion: null,
|
|
23
|
+
isApkDowngrade: false,
|
|
24
|
+
manifestBody: null,
|
|
13
25
|
updateInfo: null,
|
|
14
26
|
isRequired: true,
|
|
15
27
|
skippedReason,
|
|
@@ -18,39 +30,75 @@ function emptyCheckResult(skippedReason) {
|
|
|
18
30
|
function glassesConnectedNow() {
|
|
19
31
|
return isGlassesConnected(useGlassesStore.getState().connection);
|
|
20
32
|
}
|
|
21
|
-
|
|
33
|
+
async function fetchVersionInfoDetailed(url) {
|
|
22
34
|
try {
|
|
23
35
|
const response = await fetch(url);
|
|
24
36
|
if (!response.ok) {
|
|
25
37
|
console.error("Failed to fetch version info:", response.status);
|
|
26
|
-
|
|
38
|
+
// 4xx: the manifest does not exist (or is gone) — permanent for this app
|
|
39
|
+
// build, retrying cannot help. Everything else is transient server/network
|
|
40
|
+
// trouble and retryable.
|
|
41
|
+
return { json: null, failureReason: response.status >= 400 && response.status < 500 ? "pin_unavailable" : "network" };
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
return { json: await response.json() };
|
|
45
|
+
}
|
|
46
|
+
catch (parseError) {
|
|
47
|
+
console.error("OTA: manifest is not valid JSON:", parseError);
|
|
48
|
+
return { json: null, failureReason: "pin_unavailable" };
|
|
27
49
|
}
|
|
28
|
-
return await response.json();
|
|
29
50
|
}
|
|
30
51
|
catch (error) {
|
|
31
52
|
console.error("OTA: Error fetching version info:", error);
|
|
32
|
-
return null;
|
|
53
|
+
return { json: null, failureReason: "network" };
|
|
33
54
|
}
|
|
34
55
|
}
|
|
35
|
-
export function
|
|
56
|
+
export async function fetchVersionInfo(url) {
|
|
57
|
+
return (await fetchVersionInfoDetailed(url)).json;
|
|
58
|
+
}
|
|
59
|
+
export function checkVersionUpdateAvailable(currentBuildNumber, versionJson, floorVersionCode = DOWNGRADE_FLOOR_VERSION_CODE) {
|
|
60
|
+
return getApkUpdateDirection(currentBuildNumber, versionJson, floorVersionCode) !== null;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Direction of the pending APK change, or null when the glasses already match the manifest.
|
|
64
|
+
* Every apps-shaped manifest the phone drives is an exact pin, so both directions are
|
|
65
|
+
* actionable (mirroring the glasses-side `DowngradeGate`); the ancient top-level manifest
|
|
66
|
+
* shape stays upgrade-only, and zeroed rescue pins are never actionable.
|
|
67
|
+
*/
|
|
68
|
+
export function getApkUpdateDirection(currentBuildNumber, versionJson, floorVersionCode = DOWNGRADE_FLOOR_VERSION_CODE) {
|
|
36
69
|
if (!currentBuildNumber || !versionJson) {
|
|
37
|
-
return
|
|
70
|
+
return null;
|
|
38
71
|
}
|
|
39
72
|
const currentVersion = parseInt(currentBuildNumber, 10);
|
|
40
73
|
if (isNaN(currentVersion)) {
|
|
41
|
-
return
|
|
74
|
+
return null;
|
|
42
75
|
}
|
|
43
76
|
let serverVersion;
|
|
44
|
-
|
|
45
|
-
|
|
77
|
+
let exactPin = false;
|
|
78
|
+
const appEntry = versionJson.apps?.["com.mentra.asg_client"];
|
|
79
|
+
if (appEntry) {
|
|
80
|
+
serverVersion = appEntry.versionCode;
|
|
81
|
+
exactPin = true;
|
|
46
82
|
}
|
|
47
83
|
else if (versionJson.versionCode) {
|
|
48
84
|
serverVersion = versionJson.versionCode;
|
|
49
85
|
}
|
|
50
86
|
if (!serverVersion || isNaN(serverVersion)) {
|
|
51
|
-
return
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
if (serverVersion > currentVersion) {
|
|
90
|
+
return "upgrade";
|
|
91
|
+
}
|
|
92
|
+
// Downgrades require an exact pin AND a target at/above the enabled floor. A non-positive floor
|
|
93
|
+
// disables downgrades entirely, matching ASG's fail-closed DowngradeGate — so the phone never
|
|
94
|
+
// offers what the glasses would refuse.
|
|
95
|
+
if (serverVersion < currentVersion &&
|
|
96
|
+
exactPin &&
|
|
97
|
+
floorVersionCode > 0 &&
|
|
98
|
+
serverVersion >= floorVersionCode) {
|
|
99
|
+
return "downgrade";
|
|
52
100
|
}
|
|
53
|
-
return
|
|
101
|
+
return null;
|
|
54
102
|
}
|
|
55
103
|
export function getLatestVersionInfo(versionJson) {
|
|
56
104
|
if (!versionJson) {
|
|
@@ -95,7 +143,7 @@ export function checkBesUpdate(besFirmware, currentVersion) {
|
|
|
95
143
|
}
|
|
96
144
|
return compareVersions(besFirmware.version, currentVersion) > 0;
|
|
97
145
|
}
|
|
98
|
-
function compareVersions(version1, version2) {
|
|
146
|
+
export function compareVersions(version1, version2) {
|
|
99
147
|
if (version1.includes(".") && version2.includes(".")) {
|
|
100
148
|
const parts1 = version1.split(".");
|
|
101
149
|
const parts2 = version2.split(".");
|
|
@@ -111,13 +159,53 @@ function compareVersions(version1, version2) {
|
|
|
111
159
|
}
|
|
112
160
|
return version1.localeCompare(version2);
|
|
113
161
|
}
|
|
114
|
-
export async function checkForOtaUpdate(otaVersionUrl, currentBuildNumber, currentMtkVersion, currentBesVersion) {
|
|
162
|
+
export async function checkForOtaUpdate(otaVersionUrl, currentBuildNumber, currentMtkVersion, currentBesVersion, floorVersionCode = DOWNGRADE_FLOOR_VERSION_CODE) {
|
|
115
163
|
try {
|
|
116
164
|
console.log("OTA: Checking for OTA update - URL: " + otaVersionUrl + ", current build: " + currentBuildNumber);
|
|
117
|
-
const
|
|
165
|
+
const fetched = await fetchVersionInfoDetailed(otaVersionUrl);
|
|
166
|
+
const versionJson = fetched.json;
|
|
167
|
+
if (!versionJson) {
|
|
168
|
+
return {
|
|
169
|
+
hasCheckCompleted: false,
|
|
170
|
+
updateAvailable: false,
|
|
171
|
+
latestVersionInfo: null,
|
|
172
|
+
updates: [],
|
|
173
|
+
mtkPatch: null,
|
|
174
|
+
besVersion: null,
|
|
175
|
+
isApkDowngrade: false,
|
|
176
|
+
manifestBody: null,
|
|
177
|
+
checkFailureReason: fetched.failureReason ?? "network",
|
|
178
|
+
};
|
|
179
|
+
}
|
|
118
180
|
const latestVersionInfo = getLatestVersionInfo(versionJson);
|
|
119
|
-
|
|
120
|
-
|
|
181
|
+
// A manifest whose ASG pin is missing/zeroed cannot verify anything for modern
|
|
182
|
+
// glasses (zeroed pins are only legitimate in the frozen legacy rescue manifests
|
|
183
|
+
// that pre-39 glasses are checked against). Report the check as FAILED rather
|
|
184
|
+
// than silently completing as "up to date" — an unverifiable state must never
|
|
185
|
+
// present as a verified one.
|
|
186
|
+
const currentVersionNumber = parseInt(currentBuildNumber, 10);
|
|
187
|
+
const pinnedEntry = versionJson?.apps?.["com.mentra.asg_client"];
|
|
188
|
+
const pinnedVersion = pinnedEntry?.versionCode ?? versionJson?.versionCode;
|
|
189
|
+
if (versionJson &&
|
|
190
|
+
Number.isFinite(currentVersionNumber) &&
|
|
191
|
+
currentVersionNumber >= 39 &&
|
|
192
|
+
!(typeof pinnedVersion === "number" && pinnedVersion > 0)) {
|
|
193
|
+
console.error(`OTA: manifest at ${otaVersionUrl} has no valid ASG pin (versionCode=${String(pinnedVersion)}) - treating check as failed`);
|
|
194
|
+
return {
|
|
195
|
+
hasCheckCompleted: false,
|
|
196
|
+
updateAvailable: false,
|
|
197
|
+
latestVersionInfo: null,
|
|
198
|
+
updates: [],
|
|
199
|
+
mtkPatch: null,
|
|
200
|
+
besVersion: null,
|
|
201
|
+
isApkDowngrade: false,
|
|
202
|
+
manifestBody: null,
|
|
203
|
+
checkFailureReason: "pin_unavailable",
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
const apkDirection = getApkUpdateDirection(currentBuildNumber, versionJson, floorVersionCode);
|
|
207
|
+
const apkUpdateAvailable = apkDirection !== null;
|
|
208
|
+
console.log(`OTA: APK update available: ${apkUpdateAvailable} (current: ${currentBuildNumber}, direction: ${apkDirection ?? "none"})`);
|
|
121
209
|
const mtkPatch = findMatchingMtkPatch(versionJson?.mtk_patches, currentMtkVersion);
|
|
122
210
|
const mtkUpdateAvailable = mtkPatch !== null;
|
|
123
211
|
if (!currentMtkVersion && versionJson?.mtk_patches?.length) {
|
|
@@ -141,6 +229,8 @@ export async function checkForOtaUpdate(otaVersionUrl, currentBuildNumber, curre
|
|
|
141
229
|
updates,
|
|
142
230
|
mtkPatch,
|
|
143
231
|
besVersion: versionJson?.bes_firmware?.version || null,
|
|
232
|
+
isApkDowngrade: apkDirection === "downgrade",
|
|
233
|
+
manifestBody: versionJson ? JSON.stringify(versionJson) : null,
|
|
144
234
|
};
|
|
145
235
|
}
|
|
146
236
|
catch (error) {
|
|
@@ -152,14 +242,28 @@ export async function checkForOtaUpdate(otaVersionUrl, currentBuildNumber, curre
|
|
|
152
242
|
updates: [],
|
|
153
243
|
mtkPatch: null,
|
|
154
244
|
besVersion: null,
|
|
245
|
+
isApkDowngrade: false,
|
|
246
|
+
manifestBody: null,
|
|
247
|
+
checkFailureReason: "network",
|
|
155
248
|
};
|
|
156
249
|
}
|
|
157
250
|
}
|
|
158
251
|
export async function checkCurrentGlassesForUpdate(options = {}) {
|
|
159
|
-
const { waitForBuildNumberMs = 0, waitForBesVersionMs = 5000, waitForMtkVersionMs = 2000, refreshVersionInfo = true, fixClockBeforeCheck = true, } = options;
|
|
252
|
+
const { waitForBuildNumberMs = 0, waitForBesVersionMs = 5000, waitForMtkVersionMs = 2000, refreshVersionInfo = true, fixClockBeforeCheck = true, floorVersionCode = DOWNGRADE_FLOOR_VERSION_CODE, } = options;
|
|
160
253
|
if (!glassesConnectedNow()) {
|
|
161
254
|
return emptyCheckResult("disconnected");
|
|
162
255
|
}
|
|
256
|
+
const embeddedManifestUrl = process.env.EXPO_PUBLIC_ASG_OTA_VERSION_URL?.trim();
|
|
257
|
+
const superMode = useSettingsStore.getState().getSetting(SETTINGS.super_mode.key);
|
|
258
|
+
const overrideUrl = useSettingsStore.getState().getSetting(SETTINGS.ota_version_url.key);
|
|
259
|
+
const overrideActive = superMode && typeof overrideUrl === "string" && overrideUrl.trim() !== "";
|
|
260
|
+
if (!embeddedManifestUrl && !overrideActive) {
|
|
261
|
+
console.log("OTA: check skipped - mobile app has no embedded OTA manifest pin");
|
|
262
|
+
return emptyCheckResult("dev_build");
|
|
263
|
+
}
|
|
264
|
+
if (!embeddedManifestUrl) {
|
|
265
|
+
console.log("OTA: no embedded manifest pin, but super-mode manifest override is active - checking anyway");
|
|
266
|
+
}
|
|
163
267
|
if (refreshVersionInfo) {
|
|
164
268
|
void BluetoothSdk.requestVersionInfo().catch((error) => {
|
|
165
269
|
console.warn("OTA: Failed to request version_info from glasses:", error);
|
|
@@ -170,7 +274,10 @@ export async function checkCurrentGlassesForUpdate(options = {}) {
|
|
|
170
274
|
await waitForGlassesState("buildNumber", (value) => !!value, waitForBuildNumberMs);
|
|
171
275
|
buildNumber = useGlassesStore.getState().buildNumber;
|
|
172
276
|
}
|
|
173
|
-
if (!buildNumber) {
|
|
277
|
+
if (!buildNumber || !(parseInt(buildNumber, 10) > 0)) {
|
|
278
|
+
// Covers absent, non-numeric, and zero build numbers: a glasses version we
|
|
279
|
+
// cannot parse means nothing is verifiable, so skip rather than ghost an
|
|
280
|
+
// "up to date" result from a comparison that never really ran.
|
|
174
281
|
return emptyCheckResult("missing_build");
|
|
175
282
|
}
|
|
176
283
|
if (!glassesConnectedNow()) {
|
|
@@ -205,8 +312,8 @@ export async function checkCurrentGlassesForUpdate(options = {}) {
|
|
|
205
312
|
console.warn("OTA: clock fix attempt failed; continuing OTA check", error);
|
|
206
313
|
});
|
|
207
314
|
}
|
|
208
|
-
const manifestUrl =
|
|
209
|
-
const result = await checkForOtaUpdate(manifestUrl, buildNumber, mtkFirmwareVersion, besFirmwareVersion);
|
|
315
|
+
const manifestUrl = resolveOtaManifestUrl(useGlassesStore.getState().otaVersionUrl, buildNumber);
|
|
316
|
+
const result = await checkForOtaUpdate(manifestUrl, buildNumber, mtkFirmwareVersion, besFirmwareVersion, floorVersionCode);
|
|
210
317
|
if (!result.hasCheckCompleted) {
|
|
211
318
|
return {
|
|
212
319
|
...result,
|
|
@@ -235,6 +342,7 @@ export async function checkCurrentGlassesForUpdate(options = {}) {
|
|
|
235
342
|
"reporting no update (legacy behavior)");
|
|
236
343
|
}
|
|
237
344
|
const updateAvailable = filteredUpdates.length > 0 && !!result.latestVersionInfo;
|
|
345
|
+
const isApkDowngrade = result.isApkDowngrade && filteredUpdates.includes("apk");
|
|
238
346
|
const updateInfo = updateAvailable
|
|
239
347
|
? {
|
|
240
348
|
available: true,
|
|
@@ -242,6 +350,8 @@ export async function checkCurrentGlassesForUpdate(options = {}) {
|
|
|
242
350
|
versionName: result.latestVersionInfo?.versionName || "",
|
|
243
351
|
updates: filteredUpdates,
|
|
244
352
|
totalSize: 0,
|
|
353
|
+
...(filteredUpdates.includes("bes") && result.besVersion ? { besVersion: result.besVersion } : {}),
|
|
354
|
+
isDowngrade: isApkDowngrade,
|
|
245
355
|
}
|
|
246
356
|
: null;
|
|
247
357
|
useGlassesStore.getState().setOtaUpdateAvailable(updateInfo);
|
|
@@ -249,8 +359,18 @@ export async function checkCurrentGlassesForUpdate(options = {}) {
|
|
|
249
359
|
...result,
|
|
250
360
|
updateAvailable,
|
|
251
361
|
updates: filteredUpdates,
|
|
362
|
+
isApkDowngrade,
|
|
252
363
|
updateInfo,
|
|
253
|
-
|
|
364
|
+
// Required-update policy: an EXPLICIT isRequired in the manifest is the
|
|
365
|
+
// release-engineering escape hatch and wins in both directions. When absent,
|
|
366
|
+
// upgrades keep the historical forced default, but downgrades are always
|
|
367
|
+
// skippable — a version change that resets glasses settings must be
|
|
368
|
+
// declinable unless someone explicitly forced it.
|
|
369
|
+
isRequired: result.latestVersionInfo?.isRequired === true
|
|
370
|
+
? true
|
|
371
|
+
: result.latestVersionInfo?.isRequired === false
|
|
372
|
+
? false
|
|
373
|
+
: !isApkDowngrade,
|
|
254
374
|
manifestUrl,
|
|
255
375
|
buildNumber,
|
|
256
376
|
mtkFirmwareVersion,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OtaUpdateCheckService.js","sourceRoot":"","sources":["../../src/services/OtaUpdateCheckService.ts"],"names":[],"mappings":"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","sourcesContent":["import BluetoothSdk from \"@mentra/bluetooth-sdk/internal\"\nimport type {OtaUpdateInfo} from \"@mentra/bluetooth-sdk/internal\"\nimport {getGlassesSystemTimeMs, isGlassesConnected, useGlassesStore, waitForGlassesState} from \"../stores/glasses\"\nimport {maybeFixGlassesClockFromVersionInfo} from \"./glassesClockSync\"\nimport {getAsgOtaVersionUrl} from \"./asgOtaVersionUrl\"\n\nexport interface VersionInfo {\n versionCode: number\n versionName: string\n downloadUrl: string\n apkSize: number\n sha256: string\n releaseNotes: string\n isRequired?: boolean\n}\n\nexport interface MtkPatch {\n start_firmware: string\n end_firmware: string\n url: string\n}\n\nexport interface BesFirmware {\n version: string\n url: string\n}\n\nexport interface VersionJson {\n apps?: {\n [packageName: string]: VersionInfo\n }\n mtk_patches?: MtkPatch[]\n bes_firmware?: BesFirmware\n versionCode?: number\n versionName?: string\n downloadUrl?: string\n apkSize?: number\n sha256?: string\n releaseNotes?: string\n}\n\nexport interface OtaCheckResult {\n hasCheckCompleted: boolean\n updateAvailable: boolean\n latestVersionInfo: VersionInfo | null\n updates: string[]\n mtkPatch: MtkPatch | null\n besVersion: string | null\n}\n\nexport type OtaCheckSkippedReason = \"disconnected\" | \"missing_build\"\n\nexport interface OtaCheckCurrentGlassesResult extends OtaCheckResult {\n updateInfo: OtaUpdateInfo | null\n isRequired: boolean\n skippedReason?: OtaCheckSkippedReason\n manifestUrl?: string\n buildNumber?: string\n mtkFirmwareVersion?: string\n besFirmwareVersion?: string\n}\n\nexport interface OtaCheckCurrentGlassesOptions {\n waitForBuildNumberMs?: number\n waitForBesVersionMs?: number\n waitForMtkVersionMs?: number\n refreshVersionInfo?: boolean\n fixClockBeforeCheck?: boolean\n}\n\nfunction emptyCheckResult(skippedReason?: OtaCheckSkippedReason): OtaCheckCurrentGlassesResult {\n return {\n hasCheckCompleted: false,\n updateAvailable: false,\n latestVersionInfo: null,\n updates: [],\n mtkPatch: null,\n besVersion: null,\n updateInfo: null,\n isRequired: true,\n skippedReason,\n }\n}\n\nfunction glassesConnectedNow(): boolean {\n return isGlassesConnected(useGlassesStore.getState().connection)\n}\n\nexport async function fetchVersionInfo(url: string): Promise<VersionJson | null> {\n try {\n const response = await fetch(url)\n if (!response.ok) {\n console.error(\"Failed to fetch version info:\", response.status)\n return null\n }\n return await response.json()\n } catch (error) {\n console.error(\"OTA: Error fetching version info:\", error)\n return null\n }\n}\n\nexport function checkVersionUpdateAvailable(\n currentBuildNumber: string | undefined,\n versionJson: VersionJson | null,\n): boolean {\n if (!currentBuildNumber || !versionJson) {\n return false\n }\n\n const currentVersion = parseInt(currentBuildNumber, 10)\n if (isNaN(currentVersion)) {\n return false\n }\n\n let serverVersion: number | undefined\n\n if (versionJson.apps?.[\"com.mentra.asg_client\"]) {\n serverVersion = versionJson.apps[\"com.mentra.asg_client\"].versionCode\n } else if (versionJson.versionCode) {\n serverVersion = versionJson.versionCode\n }\n\n if (!serverVersion || isNaN(serverVersion)) {\n return false\n }\n\n return serverVersion > currentVersion\n}\n\nexport function getLatestVersionInfo(versionJson: VersionJson | null): VersionInfo | null {\n if (!versionJson) {\n return null\n }\n\n if (versionJson.apps?.[\"com.mentra.asg_client\"]) {\n return versionJson.apps[\"com.mentra.asg_client\"]\n }\n\n if (versionJson.versionCode) {\n return {\n versionCode: versionJson.versionCode,\n versionName: versionJson.versionName || \"\",\n downloadUrl: versionJson.downloadUrl || \"\",\n apkSize: versionJson.apkSize || 0,\n sha256: versionJson.sha256 || \"\",\n releaseNotes: versionJson.releaseNotes || \"\",\n }\n }\n\n return null\n}\n\nexport function findMatchingMtkPatch(\n patches: MtkPatch[] | undefined,\n currentVersion: string | undefined,\n): MtkPatch | null {\n if (!patches || !currentVersion) {\n return null\n }\n\n return (\n patches.find((patch) => {\n if (patch.start_firmware === currentVersion) {\n return true\n }\n const serverDate = patch.start_firmware.includes(\"_\")\n ? patch.start_firmware.split(\"_\").pop()\n : patch.start_firmware\n return serverDate === currentVersion\n }) || null\n )\n}\n\nexport function checkBesUpdate(besFirmware: BesFirmware | undefined, currentVersion: string | undefined): boolean {\n if (!besFirmware) {\n return false\n }\n\n if (!currentVersion) {\n console.log(`📱 BES current version unknown - assuming update needed (server: ${besFirmware.version})`)\n return true\n }\n return compareVersions(besFirmware.version, currentVersion) > 0\n}\n\nfunction compareVersions(version1: string, version2: string): number {\n if (version1.includes(\".\") && version2.includes(\".\")) {\n const parts1 = version1.split(\".\")\n const parts2 = version2.split(\".\")\n const maxLen = Math.max(parts1.length, parts2.length)\n\n for (let i = 0; i < maxLen; i++) {\n const v1 = i < parts1.length ? parseInt(parts1[i], 10) : 0\n const v2 = i < parts2.length ? parseInt(parts2[i], 10) : 0\n if (v1 !== v2) {\n return v1 - v2\n }\n }\n return 0\n }\n\n return version1.localeCompare(version2)\n}\n\nexport async function checkForOtaUpdate(\n otaVersionUrl: string,\n currentBuildNumber: string,\n currentMtkVersion?: string,\n currentBesVersion?: string,\n): Promise<OtaCheckResult> {\n try {\n console.log(\"OTA: Checking for OTA update - URL: \" + otaVersionUrl + \", current build: \" + currentBuildNumber)\n const versionJson = await fetchVersionInfo(otaVersionUrl)\n const latestVersionInfo = getLatestVersionInfo(versionJson)\n\n const apkUpdateAvailable = checkVersionUpdateAvailable(currentBuildNumber, versionJson)\n console.log(`OTA: APK update available: ${apkUpdateAvailable} (current: ${currentBuildNumber})`)\n\n const mtkPatch = findMatchingMtkPatch(versionJson?.mtk_patches, currentMtkVersion)\n const mtkUpdateAvailable = mtkPatch !== null\n if (!currentMtkVersion && versionJson?.mtk_patches?.length) {\n console.log(`OTA: MTK current version unknown - skipping MTK patch check`)\n }\n console.log(\n `OTA: MTK patch available: ${mtkUpdateAvailable ? \"yes\" : \"no\"} (current MTK: ${currentMtkVersion || \"unknown\"})`,\n )\n\n const besUpdateAvailable = checkBesUpdate(versionJson?.bes_firmware, currentBesVersion)\n console.log(`OTA: BES update available: ${besUpdateAvailable} (current BES: ${currentBesVersion || \"unknown\"})`)\n\n const updates: string[] = []\n if (apkUpdateAvailable) updates.push(\"apk\")\n if (mtkUpdateAvailable) updates.push(\"mtk\")\n if (besUpdateAvailable) updates.push(\"bes\")\n\n console.log(`OTA: OTA check result - updates available: ${updates.length > 0}, updates: [${updates.join(\", \")}]`)\n\n return {\n hasCheckCompleted: true,\n updateAvailable: updates.length > 0,\n latestVersionInfo,\n updates,\n mtkPatch,\n besVersion: versionJson?.bes_firmware?.version || null,\n }\n } catch (error) {\n console.error(\"Error checking for OTA update:\", error)\n return {\n hasCheckCompleted: false,\n updateAvailable: false,\n latestVersionInfo: null,\n updates: [],\n mtkPatch: null,\n besVersion: null,\n }\n }\n}\n\nexport async function checkCurrentGlassesForUpdate(\n options: OtaCheckCurrentGlassesOptions = {},\n): Promise<OtaCheckCurrentGlassesResult> {\n const {\n waitForBuildNumberMs = 0,\n waitForBesVersionMs = 5000,\n waitForMtkVersionMs = 2000,\n refreshVersionInfo = true,\n fixClockBeforeCheck = true,\n } = options\n\n if (!glassesConnectedNow()) {\n return emptyCheckResult(\"disconnected\")\n }\n\n if (refreshVersionInfo) {\n void BluetoothSdk.requestVersionInfo().catch((error) => {\n console.warn(\"OTA: Failed to request version_info from glasses:\", error)\n })\n }\n\n let buildNumber = useGlassesStore.getState().buildNumber\n if (!buildNumber && waitForBuildNumberMs > 0) {\n await waitForGlassesState(\"buildNumber\", (value) => !!value, waitForBuildNumberMs)\n buildNumber = useGlassesStore.getState().buildNumber\n }\n\n if (!buildNumber) {\n return emptyCheckResult(\"missing_build\")\n }\n\n if (!glassesConnectedNow()) {\n return emptyCheckResult(\"disconnected\")\n }\n\n let besFirmwareVersion = useGlassesStore.getState().besFirmwareVersion\n if (!besFirmwareVersion && waitForBesVersionMs > 0) {\n console.log(\"OTA: BES version still unknown - waiting up to 5s for it to arrive...\")\n await waitForGlassesState(\"besFirmwareVersion\", (value) => !!value, waitForBesVersionMs)\n besFirmwareVersion = useGlassesStore.getState().besFirmwareVersion\n if (besFirmwareVersion) {\n console.log(`OTA: BES version arrived: ${besFirmwareVersion}`)\n } else {\n console.log(\"OTA: BES version still unknown after extended wait - will assume BES update if published\")\n }\n }\n\n if (!glassesConnectedNow()) {\n return emptyCheckResult(\"disconnected\")\n }\n\n let mtkFirmwareVersion = useGlassesStore.getState().mtkFirmwareVersion\n if (!mtkFirmwareVersion && waitForMtkVersionMs > 0) {\n await waitForGlassesState(\"mtkFirmwareVersion\", (value) => !!value, waitForMtkVersionMs)\n mtkFirmwareVersion = useGlassesStore.getState().mtkFirmwareVersion\n }\n\n if (!glassesConnectedNow()) {\n return emptyCheckResult(\"disconnected\")\n }\n\n if (fixClockBeforeCheck) {\n const systemTimeMs = getGlassesSystemTimeMs()\n await maybeFixGlassesClockFromVersionInfo(systemTimeMs > 0 ? systemTimeMs : undefined).catch((error) => {\n console.warn(\"OTA: clock fix attempt failed; continuing OTA check\", error)\n })\n }\n\n const manifestUrl = getAsgOtaVersionUrl(useGlassesStore.getState().otaVersionUrl, buildNumber)\n const result = await checkForOtaUpdate(manifestUrl, buildNumber, mtkFirmwareVersion, besFirmwareVersion)\n\n if (!result.hasCheckCompleted) {\n return {\n ...result,\n updateInfo: null,\n isRequired: true,\n manifestUrl,\n buildNumber,\n mtkFirmwareVersion,\n besFirmwareVersion,\n }\n }\n\n const mtkUpdatedThisSession = useGlassesStore.getState().mtkUpdatedThisSession\n let filteredUpdates = result.updates\n if (mtkUpdatedThisSession && filteredUpdates.includes(\"mtk\")) {\n console.log(\"OTA: Filtering out MTK - already updated this session (pending reboot)\")\n filteredUpdates = filteredUpdates.filter((update) => update !== \"mtk\")\n }\n\n // Pre-migration parity: an update is only surfaced when the manifest also\n // carries APK version metadata. A firmware-only manifest (mtk_patches /\n // bes_firmware with no APK entry) is therefore dropped here — same as the\n // legacy host check. Loud-log it so the case is visible in the field;\n // surfacing firmware-only updates is a deliberate behavior change to make\n // separately, not silently inside the boundary migration.\n if (filteredUpdates.length > 0 && !result.latestVersionInfo) {\n console.warn(\n `OTA: manifest lists updates [${filteredUpdates.join(\", \")}] but has no APK version metadata - ` +\n \"reporting no update (legacy behavior)\",\n )\n }\n const updateAvailable = filteredUpdates.length > 0 && !!result.latestVersionInfo\n const updateInfo = updateAvailable\n ? {\n available: true,\n versionCode: result.latestVersionInfo?.versionCode || 0,\n versionName: result.latestVersionInfo?.versionName || \"\",\n updates: filteredUpdates,\n totalSize: 0,\n }\n : null\n\n useGlassesStore.getState().setOtaUpdateAvailable(updateInfo)\n\n return {\n ...result,\n updateAvailable,\n updates: filteredUpdates,\n updateInfo,\n isRequired: result.latestVersionInfo?.isRequired !== false,\n manifestUrl,\n buildNumber,\n mtkFirmwareVersion,\n besFirmwareVersion,\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"OtaUpdateCheckService.js","sourceRoot":"","sources":["../../src/services/OtaUpdateCheckService.ts"],"names":[],"mappings":"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","sourcesContent":["import BluetoothSdk from \"@mentra/bluetooth-sdk/internal\"\nimport type {OtaUpdateInfo} from \"@mentra/bluetooth-sdk/internal\"\nimport {getGlassesSystemTimeMs, isGlassesConnected, useGlassesStore, waitForGlassesState} from \"../stores/glasses\"\nimport {SETTINGS, useSettingsStore} from \"../stores/settings\"\nimport {maybeFixGlassesClockFromVersionInfo} from \"./glassesClockSync\"\nimport {resolveOtaManifestUrl} from \"./otaManifestUrl\"\n\n/**\n * Phone-side mirror of ASG's `DOWNGRADE_FLOOR_VERSION_CODE`. Set to the versionCode of the first\n * release shipping the shared media root (the first downgrade-safe build). A non-positive value\n * means downgrades are disabled, so the phone must NOT offer them — offering a downgrade the\n * glasses' `DowngradeGate` will refuse leaves the version-change session with no install and the\n * glasses reporting a bare \"complete\", which would otherwise present as false success. Keep this\n * in lockstep with the ASG/recovery constant at release time.\n */\nexport const DOWNGRADE_FLOOR_VERSION_CODE = 0\n\nexport interface VersionInfo {\n versionCode: number\n versionName: string\n downloadUrl: string\n apkSize: number\n sha256: string\n releaseNotes: string\n isRequired?: boolean\n}\n\nexport interface MtkPatch {\n start_firmware: string\n end_firmware: string\n url: string\n sha256?: string\n}\n\nexport interface BesFirmware {\n version: string\n url: string\n sha256?: string\n}\n\nexport interface VersionJson {\n apps?: {\n [packageName: string]: VersionInfo\n }\n mtk_patches?: MtkPatch[]\n bes_firmware?: BesFirmware\n versionCode?: number\n versionName?: string\n downloadUrl?: string\n apkSize?: number\n sha256?: string\n releaseNotes?: string\n}\n\nexport interface OtaCheckResult {\n hasCheckCompleted: boolean\n updateAvailable: boolean\n latestVersionInfo: VersionInfo | null\n updates: string[]\n mtkPatch: MtkPatch | null\n besVersion: string | null\n /** True when the pending APK step installs an OLDER build than the glasses currently run. */\n isApkDowngrade: boolean\n /**\n * Raw manifest JSON (stringified) this check actually fetched, or null when the\n * fetch failed. Lets change-watchers baseline on exactly what the check saw,\n * instead of racing it with a second fetch of the same URL.\n */\n manifestBody: string | null\n /**\n * Why the check failed, when it did. \"network\" is retryable (connection/server\n * trouble); \"pin_unavailable\" is permanent for this app build (manifest 404/gone,\n * unparseable, or carrying no valid ASG pin) — the remedy is updating the app.\n */\n checkFailureReason?: \"network\" | \"pin_unavailable\"\n}\n\nexport type OtaCheckSkippedReason = \"disconnected\" | \"missing_build\" | \"dev_build\"\n\nexport interface OtaCheckCurrentGlassesResult extends OtaCheckResult {\n updateInfo: OtaUpdateInfo | null\n isRequired: boolean\n skippedReason?: OtaCheckSkippedReason\n manifestUrl?: string\n buildNumber?: string\n mtkFirmwareVersion?: string\n besFirmwareVersion?: string\n}\n\nexport interface OtaCheckCurrentGlassesOptions {\n waitForBuildNumberMs?: number\n waitForBesVersionMs?: number\n waitForMtkVersionMs?: number\n refreshVersionInfo?: boolean\n fixClockBeforeCheck?: boolean\n /** Downgrade floor override (defaults to DOWNGRADE_FLOOR_VERSION_CODE); for tests. */\n floorVersionCode?: number\n}\n\nfunction emptyCheckResult(skippedReason?: OtaCheckSkippedReason): OtaCheckCurrentGlassesResult {\n return {\n hasCheckCompleted: false,\n updateAvailable: false,\n latestVersionInfo: null,\n updates: [],\n mtkPatch: null,\n besVersion: null,\n isApkDowngrade: false,\n manifestBody: null,\n updateInfo: null,\n isRequired: true,\n skippedReason,\n }\n}\n\nfunction glassesConnectedNow(): boolean {\n return isGlassesConnected(useGlassesStore.getState().connection)\n}\n\ntype ManifestFetchResult = {json: VersionJson | null; failureReason?: \"network\" | \"pin_unavailable\"}\n\nasync function fetchVersionInfoDetailed(url: string): Promise<ManifestFetchResult> {\n try {\n const response = await fetch(url)\n if (!response.ok) {\n console.error(\"Failed to fetch version info:\", response.status)\n // 4xx: the manifest does not exist (or is gone) — permanent for this app\n // build, retrying cannot help. Everything else is transient server/network\n // trouble and retryable.\n return {json: null, failureReason: response.status >= 400 && response.status < 500 ? \"pin_unavailable\" : \"network\"}\n }\n try {\n return {json: await response.json()}\n } catch (parseError) {\n console.error(\"OTA: manifest is not valid JSON:\", parseError)\n return {json: null, failureReason: \"pin_unavailable\"}\n }\n } catch (error) {\n console.error(\"OTA: Error fetching version info:\", error)\n return {json: null, failureReason: \"network\"}\n }\n}\n\nexport async function fetchVersionInfo(url: string): Promise<VersionJson | null> {\n return (await fetchVersionInfoDetailed(url)).json\n}\n\nexport function checkVersionUpdateAvailable(\n currentBuildNumber: string | undefined,\n versionJson: VersionJson | null,\n floorVersionCode: number = DOWNGRADE_FLOOR_VERSION_CODE,\n): boolean {\n return getApkUpdateDirection(currentBuildNumber, versionJson, floorVersionCode) !== null\n}\n\n/**\n * Direction of the pending APK change, or null when the glasses already match the manifest.\n * Every apps-shaped manifest the phone drives is an exact pin, so both directions are\n * actionable (mirroring the glasses-side `DowngradeGate`); the ancient top-level manifest\n * shape stays upgrade-only, and zeroed rescue pins are never actionable.\n */\nexport function getApkUpdateDirection(\n currentBuildNumber: string | undefined,\n versionJson: VersionJson | null,\n floorVersionCode: number = DOWNGRADE_FLOOR_VERSION_CODE,\n): \"upgrade\" | \"downgrade\" | null {\n if (!currentBuildNumber || !versionJson) {\n return null\n }\n\n const currentVersion = parseInt(currentBuildNumber, 10)\n if (isNaN(currentVersion)) {\n return null\n }\n\n let serverVersion: number | undefined\n let exactPin = false\n\n const appEntry = versionJson.apps?.[\"com.mentra.asg_client\"]\n if (appEntry) {\n serverVersion = appEntry.versionCode\n exactPin = true\n } else if (versionJson.versionCode) {\n serverVersion = versionJson.versionCode\n }\n\n if (!serverVersion || isNaN(serverVersion)) {\n return null\n }\n\n if (serverVersion > currentVersion) {\n return \"upgrade\"\n }\n // Downgrades require an exact pin AND a target at/above the enabled floor. A non-positive floor\n // disables downgrades entirely, matching ASG's fail-closed DowngradeGate — so the phone never\n // offers what the glasses would refuse.\n if (\n serverVersion < currentVersion &&\n exactPin &&\n floorVersionCode > 0 &&\n serverVersion >= floorVersionCode\n ) {\n return \"downgrade\"\n }\n return null\n}\n\nexport function getLatestVersionInfo(versionJson: VersionJson | null): VersionInfo | null {\n if (!versionJson) {\n return null\n }\n\n if (versionJson.apps?.[\"com.mentra.asg_client\"]) {\n return versionJson.apps[\"com.mentra.asg_client\"]\n }\n\n if (versionJson.versionCode) {\n return {\n versionCode: versionJson.versionCode,\n versionName: versionJson.versionName || \"\",\n downloadUrl: versionJson.downloadUrl || \"\",\n apkSize: versionJson.apkSize || 0,\n sha256: versionJson.sha256 || \"\",\n releaseNotes: versionJson.releaseNotes || \"\",\n }\n }\n\n return null\n}\n\nexport function findMatchingMtkPatch(\n patches: MtkPatch[] | undefined,\n currentVersion: string | undefined,\n): MtkPatch | null {\n if (!patches || !currentVersion) {\n return null\n }\n\n return (\n patches.find((patch) => {\n if (patch.start_firmware === currentVersion) {\n return true\n }\n const serverDate = patch.start_firmware.includes(\"_\")\n ? patch.start_firmware.split(\"_\").pop()\n : patch.start_firmware\n return serverDate === currentVersion\n }) || null\n )\n}\n\nexport function checkBesUpdate(besFirmware: BesFirmware | undefined, currentVersion: string | undefined): boolean {\n if (!besFirmware) {\n return false\n }\n\n if (!currentVersion) {\n console.log(`📱 BES current version unknown - assuming update needed (server: ${besFirmware.version})`)\n return true\n }\n return compareVersions(besFirmware.version, currentVersion) > 0\n}\n\nexport function compareVersions(version1: string, version2: string): number {\n if (version1.includes(\".\") && version2.includes(\".\")) {\n const parts1 = version1.split(\".\")\n const parts2 = version2.split(\".\")\n const maxLen = Math.max(parts1.length, parts2.length)\n\n for (let i = 0; i < maxLen; i++) {\n const v1 = i < parts1.length ? parseInt(parts1[i], 10) : 0\n const v2 = i < parts2.length ? parseInt(parts2[i], 10) : 0\n if (v1 !== v2) {\n return v1 - v2\n }\n }\n return 0\n }\n\n return version1.localeCompare(version2)\n}\n\nexport async function checkForOtaUpdate(\n otaVersionUrl: string,\n currentBuildNumber: string,\n currentMtkVersion?: string,\n currentBesVersion?: string,\n floorVersionCode: number = DOWNGRADE_FLOOR_VERSION_CODE,\n): Promise<OtaCheckResult> {\n try {\n console.log(\"OTA: Checking for OTA update - URL: \" + otaVersionUrl + \", current build: \" + currentBuildNumber)\n const fetched = await fetchVersionInfoDetailed(otaVersionUrl)\n const versionJson = fetched.json\n if (!versionJson) {\n return {\n hasCheckCompleted: false,\n updateAvailable: false,\n latestVersionInfo: null,\n updates: [],\n mtkPatch: null,\n besVersion: null,\n isApkDowngrade: false,\n manifestBody: null,\n checkFailureReason: fetched.failureReason ?? \"network\",\n }\n }\n const latestVersionInfo = getLatestVersionInfo(versionJson)\n\n // A manifest whose ASG pin is missing/zeroed cannot verify anything for modern\n // glasses (zeroed pins are only legitimate in the frozen legacy rescue manifests\n // that pre-39 glasses are checked against). Report the check as FAILED rather\n // than silently completing as \"up to date\" — an unverifiable state must never\n // present as a verified one.\n const currentVersionNumber = parseInt(currentBuildNumber, 10)\n const pinnedEntry = versionJson?.apps?.[\"com.mentra.asg_client\"]\n const pinnedVersion = pinnedEntry?.versionCode ?? versionJson?.versionCode\n if (\n versionJson &&\n Number.isFinite(currentVersionNumber) &&\n currentVersionNumber >= 39 &&\n !(typeof pinnedVersion === \"number\" && pinnedVersion > 0)\n ) {\n console.error(\n `OTA: manifest at ${otaVersionUrl} has no valid ASG pin (versionCode=${String(pinnedVersion)}) - treating check as failed`,\n )\n return {\n hasCheckCompleted: false,\n updateAvailable: false,\n latestVersionInfo: null,\n updates: [],\n mtkPatch: null,\n besVersion: null,\n isApkDowngrade: false,\n manifestBody: null,\n checkFailureReason: \"pin_unavailable\",\n }\n }\n\n const apkDirection = getApkUpdateDirection(currentBuildNumber, versionJson, floorVersionCode)\n const apkUpdateAvailable = apkDirection !== null\n console.log(\n `OTA: APK update available: ${apkUpdateAvailable} (current: ${currentBuildNumber}, direction: ${apkDirection ?? \"none\"})`,\n )\n\n const mtkPatch = findMatchingMtkPatch(versionJson?.mtk_patches, currentMtkVersion)\n const mtkUpdateAvailable = mtkPatch !== null\n if (!currentMtkVersion && versionJson?.mtk_patches?.length) {\n console.log(`OTA: MTK current version unknown - skipping MTK patch check`)\n }\n console.log(\n `OTA: MTK patch available: ${mtkUpdateAvailable ? \"yes\" : \"no\"} (current MTK: ${currentMtkVersion || \"unknown\"})`,\n )\n\n const besUpdateAvailable = checkBesUpdate(versionJson?.bes_firmware, currentBesVersion)\n console.log(`OTA: BES update available: ${besUpdateAvailable} (current BES: ${currentBesVersion || \"unknown\"})`)\n\n const updates: string[] = []\n if (apkUpdateAvailable) updates.push(\"apk\")\n if (mtkUpdateAvailable) updates.push(\"mtk\")\n if (besUpdateAvailable) updates.push(\"bes\")\n\n console.log(`OTA: OTA check result - updates available: ${updates.length > 0}, updates: [${updates.join(\", \")}]`)\n\n return {\n hasCheckCompleted: true,\n updateAvailable: updates.length > 0,\n latestVersionInfo,\n updates,\n mtkPatch,\n besVersion: versionJson?.bes_firmware?.version || null,\n isApkDowngrade: apkDirection === \"downgrade\",\n manifestBody: versionJson ? JSON.stringify(versionJson) : null,\n }\n } catch (error) {\n console.error(\"Error checking for OTA update:\", error)\n return {\n hasCheckCompleted: false,\n updateAvailable: false,\n latestVersionInfo: null,\n updates: [],\n mtkPatch: null,\n besVersion: null,\n isApkDowngrade: false,\n manifestBody: null,\n checkFailureReason: \"network\",\n }\n }\n}\n\nexport async function checkCurrentGlassesForUpdate(\n options: OtaCheckCurrentGlassesOptions = {},\n): Promise<OtaCheckCurrentGlassesResult> {\n const {\n waitForBuildNumberMs = 0,\n waitForBesVersionMs = 5000,\n waitForMtkVersionMs = 2000,\n refreshVersionInfo = true,\n fixClockBeforeCheck = true,\n floorVersionCode = DOWNGRADE_FLOOR_VERSION_CODE,\n } = options\n\n if (!glassesConnectedNow()) {\n return emptyCheckResult(\"disconnected\")\n }\n\n const embeddedManifestUrl = process.env.EXPO_PUBLIC_ASG_OTA_VERSION_URL?.trim()\n const superMode = useSettingsStore.getState().getSetting(SETTINGS.super_mode.key)\n const overrideUrl = useSettingsStore.getState().getSetting(SETTINGS.ota_version_url.key)\n const overrideActive = superMode && typeof overrideUrl === \"string\" && overrideUrl.trim() !== \"\"\n if (!embeddedManifestUrl && !overrideActive) {\n console.log(\"OTA: check skipped - mobile app has no embedded OTA manifest pin\")\n return emptyCheckResult(\"dev_build\")\n }\n if (!embeddedManifestUrl) {\n console.log(\"OTA: no embedded manifest pin, but super-mode manifest override is active - checking anyway\")\n }\n\n if (refreshVersionInfo) {\n void BluetoothSdk.requestVersionInfo().catch((error) => {\n console.warn(\"OTA: Failed to request version_info from glasses:\", error)\n })\n }\n\n let buildNumber = useGlassesStore.getState().buildNumber\n if (!buildNumber && waitForBuildNumberMs > 0) {\n await waitForGlassesState(\"buildNumber\", (value) => !!value, waitForBuildNumberMs)\n buildNumber = useGlassesStore.getState().buildNumber\n }\n\n if (!buildNumber || !(parseInt(buildNumber, 10) > 0)) {\n // Covers absent, non-numeric, and zero build numbers: a glasses version we\n // cannot parse means nothing is verifiable, so skip rather than ghost an\n // \"up to date\" result from a comparison that never really ran.\n return emptyCheckResult(\"missing_build\")\n }\n\n if (!glassesConnectedNow()) {\n return emptyCheckResult(\"disconnected\")\n }\n\n let besFirmwareVersion = useGlassesStore.getState().besFirmwareVersion\n if (!besFirmwareVersion && waitForBesVersionMs > 0) {\n console.log(\"OTA: BES version still unknown - waiting up to 5s for it to arrive...\")\n await waitForGlassesState(\"besFirmwareVersion\", (value) => !!value, waitForBesVersionMs)\n besFirmwareVersion = useGlassesStore.getState().besFirmwareVersion\n if (besFirmwareVersion) {\n console.log(`OTA: BES version arrived: ${besFirmwareVersion}`)\n } else {\n console.log(\"OTA: BES version still unknown after extended wait - will assume BES update if published\")\n }\n }\n\n if (!glassesConnectedNow()) {\n return emptyCheckResult(\"disconnected\")\n }\n\n let mtkFirmwareVersion = useGlassesStore.getState().mtkFirmwareVersion\n if (!mtkFirmwareVersion && waitForMtkVersionMs > 0) {\n await waitForGlassesState(\"mtkFirmwareVersion\", (value) => !!value, waitForMtkVersionMs)\n mtkFirmwareVersion = useGlassesStore.getState().mtkFirmwareVersion\n }\n\n if (!glassesConnectedNow()) {\n return emptyCheckResult(\"disconnected\")\n }\n\n if (fixClockBeforeCheck) {\n const systemTimeMs = getGlassesSystemTimeMs()\n await maybeFixGlassesClockFromVersionInfo(systemTimeMs > 0 ? systemTimeMs : undefined).catch((error) => {\n console.warn(\"OTA: clock fix attempt failed; continuing OTA check\", error)\n })\n }\n\n const manifestUrl = resolveOtaManifestUrl(useGlassesStore.getState().otaVersionUrl, buildNumber)\n const result = await checkForOtaUpdate(manifestUrl, buildNumber, mtkFirmwareVersion, besFirmwareVersion, floorVersionCode)\n\n if (!result.hasCheckCompleted) {\n return {\n ...result,\n updateInfo: null,\n isRequired: true,\n manifestUrl,\n buildNumber,\n mtkFirmwareVersion,\n besFirmwareVersion,\n }\n }\n\n const mtkUpdatedThisSession = useGlassesStore.getState().mtkUpdatedThisSession\n let filteredUpdates = result.updates\n if (mtkUpdatedThisSession && filteredUpdates.includes(\"mtk\")) {\n console.log(\"OTA: Filtering out MTK - already updated this session (pending reboot)\")\n filteredUpdates = filteredUpdates.filter((update) => update !== \"mtk\")\n }\n\n // Pre-migration parity: an update is only surfaced when the manifest also\n // carries APK version metadata. A firmware-only manifest (mtk_patches /\n // bes_firmware with no APK entry) is therefore dropped here — same as the\n // legacy host check. Loud-log it so the case is visible in the field;\n // surfacing firmware-only updates is a deliberate behavior change to make\n // separately, not silently inside the boundary migration.\n if (filteredUpdates.length > 0 && !result.latestVersionInfo) {\n console.warn(\n `OTA: manifest lists updates [${filteredUpdates.join(\", \")}] but has no APK version metadata - ` +\n \"reporting no update (legacy behavior)\",\n )\n }\n const updateAvailable = filteredUpdates.length > 0 && !!result.latestVersionInfo\n const isApkDowngrade = result.isApkDowngrade && filteredUpdates.includes(\"apk\")\n const updateInfo = updateAvailable\n ? {\n available: true,\n versionCode: result.latestVersionInfo?.versionCode || 0,\n versionName: result.latestVersionInfo?.versionName || \"\",\n updates: filteredUpdates,\n totalSize: 0,\n ...(filteredUpdates.includes(\"bes\") && result.besVersion ? {besVersion: result.besVersion} : {}),\n isDowngrade: isApkDowngrade,\n }\n : null\n\n useGlassesStore.getState().setOtaUpdateAvailable(updateInfo)\n\n return {\n ...result,\n updateAvailable,\n updates: filteredUpdates,\n isApkDowngrade,\n updateInfo,\n // Required-update policy: an EXPLICIT isRequired in the manifest is the\n // release-engineering escape hatch and wins in both directions. When absent,\n // upgrades keep the historical forced default, but downgrades are always\n // skippable — a version change that resets glasses settings must be\n // declinable unless someone explicitly forced it.\n isRequired:\n result.latestVersionInfo?.isRequired === true\n ? true\n : result.latestVersionInfo?.isRequired === false\n ? false\n : !isApkDowngrade,\n manifestUrl,\n buildNumber,\n mtkFirmwareVersion,\n besFirmwareVersion,\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PhoneCalendarService.d.ts","sourceRoot":"","sources":["../../src/services/PhoneCalendarService.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PhoneCalendarService.d.ts","sourceRoot":"","sources":["../../src/services/PhoneCalendarService.ts"],"names":[],"mappings":"AAIA,OAAO,EAAmB,KAAK,kBAAkB,EAAC,MAAM,iBAAiB,CAAA;AAEzE,OAAO,EAEL,KAAK,mBAAmB,EAIzB,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EAAC,kBAAkB,EAAC,MAAM,wBAAwB,CAAA;AA0BzD,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAwBvG"}
|
|
@@ -1,12 +1,33 @@
|
|
|
1
1
|
import * as Calendar from "expo-calendar";
|
|
2
|
+
import { Platform } from "react-native";
|
|
3
|
+
import { check, PERMISSIONS, RESULTS } from "react-native-permissions";
|
|
2
4
|
import { MiniappErrorCode } from "@mentra/miniapp";
|
|
3
5
|
import { calendarEventOverlapsWindow, normalizeCalendarEvent, PhoneCalendarError, validateCalendarListRequest, } from "./PhoneCalendarHelpers";
|
|
4
6
|
export { PhoneCalendarError } from "./PhoneCalendarHelpers";
|
|
7
|
+
/**
|
|
8
|
+
* expo-calendar reports anything below EventKit full access as not granted,
|
|
9
|
+
* so distinguish the states the user can actually fix. "Reopen the miniapp"
|
|
10
|
+
* is only true while the permission is undetermined — once iOS has resolved
|
|
11
|
+
* it (denied or write-only/limited), only Settings can change it.
|
|
12
|
+
*/
|
|
13
|
+
async function calendarPermissionMessage(status) {
|
|
14
|
+
if (status === "undetermined") {
|
|
15
|
+
return "Calendar permission has not been granted yet. Reopen the miniapp and allow calendar access.";
|
|
16
|
+
}
|
|
17
|
+
if (Platform.OS === "ios") {
|
|
18
|
+
const writeOnly = await check(PERMISSIONS.IOS.CALENDARS_WRITE_ONLY).catch(() => null);
|
|
19
|
+
if (writeOnly === RESULTS.GRANTED || writeOnly === RESULTS.LIMITED) {
|
|
20
|
+
return 'Calendar access is limited to write-only. Enable "Full Access" for Mentra in Settings › Privacy & Security › Calendars.';
|
|
21
|
+
}
|
|
22
|
+
return "Calendar access is denied. Enable it for Mentra in Settings › Privacy & Security › Calendars.";
|
|
23
|
+
}
|
|
24
|
+
return "Calendar access is denied. Enable the Calendar permission for Mentra in your phone's app settings.";
|
|
25
|
+
}
|
|
5
26
|
export async function listPhoneCalendarEvents(request) {
|
|
6
27
|
const { startsAt, endsAt, limit } = validateCalendarListRequest(request);
|
|
7
28
|
const permission = await Calendar.getCalendarPermissionsAsync();
|
|
8
29
|
if (permission.status !== "granted") {
|
|
9
|
-
throw new PhoneCalendarError(MiniappErrorCode.PERMISSION_DENIED,
|
|
30
|
+
throw new PhoneCalendarError(MiniappErrorCode.PERMISSION_DENIED, await calendarPermissionMessage(permission.status));
|
|
10
31
|
}
|
|
11
32
|
const calendars = await Calendar.getCalendarsAsync(Calendar.EntityTypes.EVENT);
|
|
12
33
|
if (calendars.length === 0)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PhoneCalendarService.js","sourceRoot":"","sources":["../../src/services/PhoneCalendarService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"PhoneCalendarService.js","sourceRoot":"","sources":["../../src/services/PhoneCalendarService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,EAAC,QAAQ,EAAC,MAAM,cAAc,CAAA;AACrC,OAAO,EAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAC,MAAM,0BAA0B,CAAA;AAEpE,OAAO,EAAC,gBAAgB,EAA0B,MAAM,iBAAiB,CAAA;AAEzE,OAAO,EACL,2BAA2B,EAE3B,sBAAsB,EACtB,kBAAkB,EAClB,2BAA2B,GAC5B,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EAAC,kBAAkB,EAAC,MAAM,wBAAwB,CAAA;AAMzD;;;;;GAKG;AACH,KAAK,UAAU,yBAAyB,CAAC,MAAgC;IACvE,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;QAC9B,OAAO,6FAA6F,CAAA;IACtG,CAAC;IACD,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;QAC1B,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;QACrF,IAAI,SAAS,KAAK,OAAO,CAAC,OAAO,IAAI,SAAS,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC;YACnE,OAAO,yHAAyH,CAAA;QAClI,CAAC;QACD,OAAO,+FAA+F,CAAA;IACxG,CAAC;IACD,OAAO,oGAAoG,CAAA;AAC7G,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,OAA4B;IACxE,MAAM,EAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAC,GAAG,2BAA2B,CAAC,OAAO,CAAC,CAAA;IACtE,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,2BAA2B,EAAE,CAAA;IAC/D,IAAI,UAAU,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QACpC,MAAM,IAAI,kBAAkB,CAAC,gBAAgB,CAAC,iBAAiB,EAAE,MAAM,yBAAyB,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAA;IACtH,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,iBAAiB,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;IAC9E,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAC,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAC,CAAA;IAEjE,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,cAAc,CAC7C,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,EACxC,QAAQ,EACR,MAAM,CACP,CAAA;IACD,MAAM,MAAM,GAAG,SAAS;SACrB,GAAG,CAAC,sBAAsB,CAAC;SAC3B,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,2BAA2B,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;SACvE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;IAEjH,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;QAC9B,SAAS,EAAE,MAAM,CAAC,MAAM,GAAG,KAAK;KACjC,CAAA;AACH,CAAC","sourcesContent":["import * as Calendar from \"expo-calendar\"\nimport {Platform} from \"react-native\"\nimport {check, PERMISSIONS, RESULTS} from \"react-native-permissions\"\n\nimport {MiniappErrorCode, type CalendarListResult} from \"@mentra/miniapp\"\n\nimport {\n calendarEventOverlapsWindow,\n type CalendarListRequest,\n normalizeCalendarEvent,\n PhoneCalendarError,\n validateCalendarListRequest,\n} from \"./PhoneCalendarHelpers\"\n\nexport {PhoneCalendarError} from \"./PhoneCalendarHelpers\"\n\ntype CalendarPermissionStatus = Awaited<\n ReturnType<typeof Calendar.getCalendarPermissionsAsync>\n>[\"status\"]\n\n/**\n * expo-calendar reports anything below EventKit full access as not granted,\n * so distinguish the states the user can actually fix. \"Reopen the miniapp\"\n * is only true while the permission is undetermined — once iOS has resolved\n * it (denied or write-only/limited), only Settings can change it.\n */\nasync function calendarPermissionMessage(status: CalendarPermissionStatus): Promise<string> {\n if (status === \"undetermined\") {\n return \"Calendar permission has not been granted yet. Reopen the miniapp and allow calendar access.\"\n }\n if (Platform.OS === \"ios\") {\n const writeOnly = await check(PERMISSIONS.IOS.CALENDARS_WRITE_ONLY).catch(() => null)\n if (writeOnly === RESULTS.GRANTED || writeOnly === RESULTS.LIMITED) {\n return 'Calendar access is limited to write-only. Enable \"Full Access\" for Mentra in Settings › Privacy & Security › Calendars.'\n }\n return \"Calendar access is denied. Enable it for Mentra in Settings › Privacy & Security › Calendars.\"\n }\n return \"Calendar access is denied. Enable the Calendar permission for Mentra in your phone's app settings.\"\n}\n\nexport async function listPhoneCalendarEvents(request: CalendarListRequest): Promise<CalendarListResult> {\n const {startsAt, endsAt, limit} = validateCalendarListRequest(request)\n const permission = await Calendar.getCalendarPermissionsAsync()\n if (permission.status !== \"granted\") {\n throw new PhoneCalendarError(MiniappErrorCode.PERMISSION_DENIED, await calendarPermissionMessage(permission.status))\n }\n\n const calendars = await Calendar.getCalendarsAsync(Calendar.EntityTypes.EVENT)\n if (calendars.length === 0) return {events: [], truncated: false}\n\n const rawEvents = await Calendar.getEventsAsync(\n calendars.map((calendar) => calendar.id),\n startsAt,\n endsAt,\n )\n const events = rawEvents\n .map(normalizeCalendarEvent)\n .filter((event) => calendarEventOverlapsWindow(event, startsAt, endsAt))\n .sort((a, b) => Date.parse(a.startsAt) - Date.parse(b.startsAt) || Date.parse(a.endsAt) - Date.parse(b.endsAt))\n\n return {\n events: events.slice(0, limit),\n truncated: events.length > limit,\n }\n}\n"]}
|
|
@@ -15,6 +15,8 @@ export declare class PhoneCameraFovCoordinator {
|
|
|
15
15
|
private refreshTimer;
|
|
16
16
|
private legacyMode;
|
|
17
17
|
constructor(legacyRestartSettleMs?: number);
|
|
18
|
+
/** Report-safe FOV ownership snapshot for incident diagnostics. */
|
|
19
|
+
getDiagnosticSnapshot(): Record<string, unknown>;
|
|
18
20
|
setOverride(packageName: string, request: CameraFovRequest): Promise<CameraFovResult>;
|
|
19
21
|
releaseForApp(packageName: string): Promise<void>;
|
|
20
22
|
private scheduleRefresh;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PhoneCameraFovCoordinator.d.ts","sourceRoot":"","sources":["../../src/services/PhoneCameraFovCoordinator.ts"],"names":[],"mappings":"AAAA,OAAqB,EAAC,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAC,MAAM,gCAAgC,CAAA;AAExG,eAAO,MAAM,0BAA0B,SAAU,CAAA;AACjD,eAAO,MAAM,8BAA8B,SAAU,CAAA;AAyBrD;;;;GAIG;AACH,qBAAa,yBAAyB;IAQxB,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IAPlD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmC;IAC7D,OAAO,CAAC,gBAAgB,CAAoB;IAC5C,OAAO,CAAC,QAAQ,CAAI;IACpB,OAAO,CAAC,KAAK,CAAsC;IACnD,OAAO,CAAC,YAAY,CAA2C;IAC/D,OAAO,CAAC,UAAU,CAAQ;gBAEG,qBAAqB,SAAkC;IAEpF,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAkCrF,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDjD,OAAO,CAAC,eAAe;IAqBvB,OAAO,CAAC,YAAY;YAKN,iBAAiB;YAkBjB,cAAc;IAM5B,OAAO,CAAC,0BAA0B;IAKlC,OAAO,CAAC,OAAO;CAQhB;AAED,eAAO,MAAM,yBAAyB,2BAAkC,CAAA"}
|
|
1
|
+
{"version":3,"file":"PhoneCameraFovCoordinator.d.ts","sourceRoot":"","sources":["../../src/services/PhoneCameraFovCoordinator.ts"],"names":[],"mappings":"AAAA,OAAqB,EAAC,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAC,MAAM,gCAAgC,CAAA;AAExG,eAAO,MAAM,0BAA0B,SAAU,CAAA;AACjD,eAAO,MAAM,8BAA8B,SAAU,CAAA;AAyBrD;;;;GAIG;AACH,qBAAa,yBAAyB;IAQxB,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IAPlD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmC;IAC7D,OAAO,CAAC,gBAAgB,CAAoB;IAC5C,OAAO,CAAC,QAAQ,CAAI;IACpB,OAAO,CAAC,KAAK,CAAsC;IACnD,OAAO,CAAC,YAAY,CAA2C;IAC/D,OAAO,CAAC,UAAU,CAAQ;gBAEG,qBAAqB,SAAkC;IAEpF,mEAAmE;IACnE,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAchD,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAkCrF,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDjD,OAAO,CAAC,eAAe;IAqBvB,OAAO,CAAC,YAAY;YAKN,iBAAiB;YAkBjB,cAAc;IAM5B,OAAO,CAAC,0BAA0B;IAKlC,OAAO,CAAC,OAAO;CAQhB;AAED,eAAO,MAAM,yBAAyB,2BAAkC,CAAA"}
|
|
@@ -30,6 +30,20 @@ export class PhoneCameraFovCoordinator {
|
|
|
30
30
|
constructor(legacyRestartSettleMs = LEGACY_CAMERA_RESTART_SETTLE_MS) {
|
|
31
31
|
this.legacyRestartSettleMs = legacyRestartSettleMs;
|
|
32
32
|
}
|
|
33
|
+
/** Report-safe FOV ownership snapshot for incident diagnostics. */
|
|
34
|
+
getDiagnosticSnapshot() {
|
|
35
|
+
return {
|
|
36
|
+
owners: [...this.overrides.entries()]
|
|
37
|
+
.sort(([, a], [, b]) => b.order - a.order)
|
|
38
|
+
.map(([packageName, entry]) => ({
|
|
39
|
+
packageName,
|
|
40
|
+
effective: entry.leaseId === this.effectiveLeaseId,
|
|
41
|
+
fov: entry.fov,
|
|
42
|
+
roiPosition: entry.roiPosition,
|
|
43
|
+
})),
|
|
44
|
+
legacyMode: this.legacyMode,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
33
47
|
setOverride(packageName, request) {
|
|
34
48
|
return this.enqueue(async () => {
|
|
35
49
|
const previous = this.overrides.get(packageName);
|