@mentra/engine 0.1.0-dev.1 → 3.1.0-dev.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -24
- 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 +13 -13
- package/build/engine.d.ts.map +1 -1
- package/build/engine.js +2 -2
- package/build/engine.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/glasses.d.ts +3 -13
- package/build/facades/glasses.d.ts.map +1 -1
- package/build/facades/glasses.js +3 -3
- package/build/facades/glasses.js.map +1 -1
- package/build/facades/ota.d.ts +5 -16
- package/build/facades/ota.d.ts.map +1 -1
- package/build/facades/ota.js +3 -3
- package/build/facades/ota.js.map +1 -1
- package/build/facades/pairing.d.ts +4 -5
- package/build/facades/pairing.d.ts.map +1 -1
- package/build/facades/pairing.js +2 -2
- package/build/facades/pairing.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 +4 -5
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2 -3
- package/build/index.js.map +1 -1
- package/build/services/AppRegistry.d.ts +8 -0
- package/build/services/AppRegistry.d.ts.map +1 -1
- package/build/services/AppRegistry.js +15 -0
- package/build/services/AppRegistry.js.map +1 -1
- package/build/services/OtaInstallCoordinator.d.ts +1 -1
- package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
- package/build/services/OtaInstallCoordinator.js +3 -0
- package/build/services/OtaInstallCoordinator.js.map +1 -1
- package/build/services/OtaUpdateCheckService.d.ts +1 -1
- package/build/services/OtaUpdateCheckService.d.ts.map +1 -1
- package/build/services/OtaUpdateCheckService.js +12 -16
- package/build/services/OtaUpdateCheckService.js.map +1 -1
- package/build/services/glassesClockSync.d.ts.map +1 -1
- package/build/services/glassesClockSync.js +4 -0
- package/build/services/glassesClockSync.js.map +1 -1
- package/build/services/otaDisplayState.d.ts +1 -1
- package/build/services/otaDisplayState.d.ts.map +1 -1
- package/build/services/otaDisplayState.js.map +1 -1
- package/build/services/otaInstallPolicy.d.ts +1 -1
- package/build/services/otaInstallPolicy.d.ts.map +1 -1
- 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 +2 -1
- package/build/services/otaManifestUrl.d.ts.map +1 -1
- package/build/services/otaManifestUrl.js +24 -32
- package/build/services/otaManifestUrl.js.map +1 -1
- package/build/stores/settings.js +3 -3
- package/build/stores/settings.js.map +1 -1
- package/build/types/enums.d.ts +1 -25
- package/build/types/enums.d.ts.map +1 -1
- package/build/types/enums.js +1 -27
- package/build/types/enums.js.map +1 -1
- package/build/types/hardware.d.ts +3 -13
- package/build/types/hardware.d.ts.map +1 -1
- package/build/types/hardware.js +1 -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/package.json +40 -22
- 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 +2 -2
- package/src/facades/display.ts +1 -1
- package/src/facades/glasses.ts +4 -4
- package/src/facades/ota.ts +4 -4
- package/src/facades/pairing.ts +4 -4
- package/src/facades/speech.ts +21 -7
- package/src/generated/releaseMetadata.ts +20 -0
- package/src/index.ts +13 -11
- package/src/services/AppRegistry.ts +16 -0
- package/src/services/OtaInstallCoordinator.ts +4 -1
- package/src/services/OtaUpdateCheckService.ts +20 -20
- package/src/services/glassesClockSync.ts +4 -0
- package/src/services/otaDisplayState.ts +1 -1
- package/src/services/otaInstallPolicy.ts +1 -1
- package/src/services/otaLegacyMapping.ts +1 -1
- package/src/services/otaManifestPolicy.ts +42 -0
- package/src/services/otaManifestUrl.ts +27 -36
- package/src/stores/settings.ts +3 -3
- package/src/types/enums.ts +1 -27
- package/src/types/hardware.ts +3 -13
- package/src/types/index.ts +2 -6
- 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 -67
- package/build/internal.d.ts.map +0 -1
- package/build/internal.js +0 -90
- package/build/internal.js.map +0 -1
- package/src/devtools.ts +0 -13
- package/src/internal.ts +0 -160
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OtaUpdateCheckService.d.ts","sourceRoot":"","sources":["../../src/services/OtaUpdateCheckService.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"OtaUpdateCheckService.d.ts","sourceRoot":"","sources":["../../src/services/OtaUpdateCheckService.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,uBAAuB,CAAA;AAKxD;;;;;;;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;AAiDD,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,CAmChC;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,CA6JvC"}
|
|
@@ -1,8 +1,7 @@
|
|
|
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";
|
|
4
3
|
import { maybeFixGlassesClockFromVersionInfo } from "./glassesClockSync";
|
|
5
|
-
import { resolveOtaManifestUrl } from "./otaManifestUrl";
|
|
4
|
+
import { hasConfiguredModernOtaManifestPin, resolveOtaManifestUrl } from "./otaManifestUrl";
|
|
6
5
|
/**
|
|
7
6
|
* Phone-side mirror of ASG's `DOWNGRADE_FLOOR_VERSION_CODE`. Set to the versionCode of the first
|
|
8
7
|
* release shipping the shared media root (the first downgrade-safe build). A non-positive value
|
|
@@ -38,7 +37,10 @@ async function fetchVersionInfoDetailed(url) {
|
|
|
38
37
|
// 4xx: the manifest does not exist (or is gone) — permanent for this app
|
|
39
38
|
// build, retrying cannot help. Everything else is transient server/network
|
|
40
39
|
// trouble and retryable.
|
|
41
|
-
return {
|
|
40
|
+
return {
|
|
41
|
+
json: null,
|
|
42
|
+
failureReason: response.status >= 400 && response.status < 500 ? "pin_unavailable" : "network",
|
|
43
|
+
};
|
|
42
44
|
}
|
|
43
45
|
try {
|
|
44
46
|
return { json: await response.json() };
|
|
@@ -92,10 +94,7 @@ export function getApkUpdateDirection(currentBuildNumber, versionJson, floorVers
|
|
|
92
94
|
// Downgrades require an exact pin AND a target at/above the enabled floor. A non-positive floor
|
|
93
95
|
// disables downgrades entirely, matching ASG's fail-closed DowngradeGate — so the phone never
|
|
94
96
|
// offers what the glasses would refuse.
|
|
95
|
-
if (serverVersion < currentVersion &&
|
|
96
|
-
exactPin &&
|
|
97
|
-
floorVersionCode > 0 &&
|
|
98
|
-
serverVersion >= floorVersionCode) {
|
|
97
|
+
if (serverVersion < currentVersion && exactPin && floorVersionCode > 0 && serverVersion >= floorVersionCode) {
|
|
99
98
|
return "downgrade";
|
|
100
99
|
}
|
|
101
100
|
return null;
|
|
@@ -253,17 +252,10 @@ export async function checkCurrentGlassesForUpdate(options = {}) {
|
|
|
253
252
|
if (!glassesConnectedNow()) {
|
|
254
253
|
return emptyCheckResult("disconnected");
|
|
255
254
|
}
|
|
256
|
-
|
|
257
|
-
|
|
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");
|
|
255
|
+
if (!hasConfiguredModernOtaManifestPin()) {
|
|
256
|
+
console.log("OTA: check skipped - this app or Engine package has no embedded OTA manifest pin");
|
|
262
257
|
return emptyCheckResult("dev_build");
|
|
263
258
|
}
|
|
264
|
-
if (!embeddedManifestUrl) {
|
|
265
|
-
console.log("OTA: no embedded manifest pin, but super-mode manifest override is active - checking anyway");
|
|
266
|
-
}
|
|
267
259
|
if (refreshVersionInfo) {
|
|
268
260
|
void BluetoothSdk.requestVersionInfo().catch((error) => {
|
|
269
261
|
console.warn("OTA: Failed to request version_info from glasses:", error);
|
|
@@ -313,6 +305,10 @@ export async function checkCurrentGlassesForUpdate(options = {}) {
|
|
|
313
305
|
});
|
|
314
306
|
}
|
|
315
307
|
const manifestUrl = resolveOtaManifestUrl(useGlassesStore.getState().otaVersionUrl, buildNumber);
|
|
308
|
+
if (!manifestUrl) {
|
|
309
|
+
console.log("OTA: check skipped - no OTA manifest pin resolved");
|
|
310
|
+
return emptyCheckResult("dev_build");
|
|
311
|
+
}
|
|
316
312
|
const result = await checkForOtaUpdate(manifestUrl, buildNumber, mtkFirmwareVersion, besFirmwareVersion, floorVersionCode);
|
|
317
313
|
if (!result.hasCheckCompleted) {
|
|
318
314
|
return {
|
|
@@ -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 {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
|
+
{"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\"\nimport {getGlassesSystemTimeMs, isGlassesConnected, useGlassesStore, waitForGlassesState} from \"../stores/glasses\"\nimport {maybeFixGlassesClockFromVersionInfo} from \"./glassesClockSync\"\nimport {hasConfiguredModernOtaManifestPin, 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 {\n json: null,\n failureReason: response.status >= 400 && response.status < 500 ? \"pin_unavailable\" : \"network\",\n }\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 (serverVersion < currentVersion && exactPin && floorVersionCode > 0 && serverVersion >= floorVersionCode) {\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 if (!hasConfiguredModernOtaManifestPin()) {\n console.log(\"OTA: check skipped - this app or Engine package has no embedded OTA manifest pin\")\n return emptyCheckResult(\"dev_build\")\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 if (!manifestUrl) {\n console.log(\"OTA: check skipped - no OTA manifest pin resolved\")\n return emptyCheckResult(\"dev_build\")\n }\n const result = await checkForOtaUpdate(\n manifestUrl,\n buildNumber,\n mtkFirmwareVersion,\n besFirmwareVersion,\n floorVersionCode,\n )\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":"glassesClockSync.d.ts","sourceRoot":"","sources":["../../src/services/glassesClockSync.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH,eAAO,MAAM,eAAe,MAAM,CAAA;AASlC,0BAA0B;AAC1B,wBAAgB,gCAAgC,IAAI,IAAI,CAGvD;AAMD;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,iBAAiB,EAAE,MAAM,EAAE,YAAY,SAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAS3G;AAED;;;GAGG;AACH,wBAAsB,6BAA6B,CACjD,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"glassesClockSync.d.ts","sourceRoot":"","sources":["../../src/services/glassesClockSync.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH,eAAO,MAAM,eAAe,MAAM,CAAA;AASlC,0BAA0B;AAC1B,wBAAgB,gCAAgC,IAAI,IAAI,CAGvD;AAMD;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,iBAAiB,EAAE,MAAM,EAAE,YAAY,SAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAS3G;AAED;;;GAGG;AACH,wBAAsB,6BAA6B,CACjD,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,OAAO,CAAC,CAmDlB;AAED;;GAEG;AACH,wBAAsB,mCAAmC,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAW5G"}
|
|
@@ -71,6 +71,10 @@ export async function handleOtaClockSkewFromGlasses(errorCode, glassesTimeMs) {
|
|
|
71
71
|
lastOtaClockFixAt = Date.now();
|
|
72
72
|
const { buildNumber, otaVersionUrl } = useGlassesStore.getState();
|
|
73
73
|
const manifestUrl = resolveOtaManifestUrl(otaVersionUrl, buildNumber);
|
|
74
|
+
if (!manifestUrl) {
|
|
75
|
+
console.warn("[GlassesClockSync] OTA restart skipped because this build has no manifest pin");
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
74
78
|
console.log("[GlassesClockSync] ⏰ Restarting OTA with ota_start after clock fix");
|
|
75
79
|
await BluetoothSdk.startOtaUpdate(manifestUrl);
|
|
76
80
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glassesClockSync.js","sourceRoot":"","sources":["../../src/services/glassesClockSync.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Push phone time to glasses only when clock skew is detected (gallery sync, OTA, etc.).\n */\n\nimport BluetoothSdk from \"@mentra/bluetooth-sdk/internal\"\nimport {BgTimer} from \"../utils/timers\"\nimport {useGlassesStore} from \"../stores/glasses\"\n\nimport {resolveOtaManifestUrl} from \"./otaManifestUrl\"\nimport {detectClockSkew} from \"./gallerySyncClock\"\n\nexport const CLOCK_SETTLE_MS = 500\n\nconst OTA_CLOCK_FIX_COOLDOWN_MS = 30_000\nlet lastOtaClockFixAt = 0\n// Coalesce concurrent OTA clock-fix attempts. Glasses can emit two clock_skew events\n// back-to-back during BLE handshake; without this guard both would await the BLE fix\n// + retry pair before either updated `lastOtaClockFixAt`.\nlet inflightOtaClockFix: Promise<boolean> | null = null\n\n/** @internal test-only */\nexport function resetOtaClockFixCooldownForTests(): void {\n lastOtaClockFixAt = 0\n inflightOtaClockFix = null\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => BgTimer.setTimeout(resolve, ms))\n}\n\n/**\n * Set glasses system clock from phone when skew is detected.\n */\nexport async function fixGlassesClockIfSkewed(glassesServerTime: number, lastSyncTime = 0): Promise<boolean> {\n const {skewed, reason} = detectClockSkew(Date.now(), glassesServerTime, lastSyncTime)\n if (!skewed) {\n return false\n }\n console.log(`[GlassesClockSync] ⏰ Clock skew detected (${reason}) — setting glasses time from phone`)\n await BluetoothSdk.setSystemTime(Date.now())\n await delay(CLOCK_SETTLE_MS)\n return true\n}\n\n/**\n * After glasses report OTA failure due to clock skew, fix time and restart\n * through the normal phone-driven ota_start path.\n */\nexport async function handleOtaClockSkewFromGlasses(\n errorCode: string | undefined,\n glassesTimeMs?: number,\n): Promise<boolean> {\n if (Date.now() - lastOtaClockFixAt < OTA_CLOCK_FIX_COOLDOWN_MS) {\n return false\n }\n\n const hasGlassesTime = typeof glassesTimeMs === \"number\" && Number.isFinite(glassesTimeMs) && glassesTimeMs > 0\n\n if (errorCode === \"ssl_error\") {\n if (!hasGlassesTime) {\n return false\n }\n const {skewed} = detectClockSkew(Date.now(), glassesTimeMs, 0)\n if (!skewed) {\n return false\n }\n console.log(\"[GlassesClockSync] ⏰ OTA ssl_error with wall-clock drift — treating as clock skew\")\n } else if (errorCode !== \"clock_skew\") {\n return false\n }\n\n // Coalesce concurrent attempts: if a fix is already in flight, await its result instead\n // of racing it through the cooldown guard.\n if (inflightOtaClockFix) {\n return inflightOtaClockFix\n }\n\n const glassesTime = hasGlassesTime ? glassesTimeMs : Date.now() - 86_400_000\n\n inflightOtaClockFix = (async () => {\n try {\n const fixed = await fixGlassesClockIfSkewed(glassesTime, 0)\n if (!fixed) {\n return false\n }\n\n lastOtaClockFixAt = Date.now()\n const {buildNumber, otaVersionUrl} = useGlassesStore.getState()\n const manifestUrl = resolveOtaManifestUrl(otaVersionUrl, buildNumber)\n console.log(\"[GlassesClockSync] ⏰ Restarting OTA with ota_start after clock fix\")\n await BluetoothSdk.startOtaUpdate(manifestUrl)\n return true\n } finally {\n inflightOtaClockFix = null\n }\n })()\n\n return inflightOtaClockFix\n}\n\n/**\n * Proactive fix when version_info includes glasses system_time_ms before OTA manifest checks.\n */\nexport async function maybeFixGlassesClockFromVersionInfo(systemTimeMs: number | undefined): Promise<boolean> {\n if (typeof systemTimeMs !== \"number\" || systemTimeMs <= 0) {\n return false\n }\n\n const fixed = await fixGlassesClockIfSkewed(systemTimeMs, 0)\n if (!fixed) {\n return false\n }\n\n return true\n}\n"]}
|
|
1
|
+
{"version":3,"file":"glassesClockSync.js","sourceRoot":"","sources":["../../src/services/glassesClockSync.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Push phone time to glasses only when clock skew is detected (gallery sync, OTA, etc.).\n */\n\nimport BluetoothSdk from \"@mentra/bluetooth-sdk/internal\"\nimport {BgTimer} from \"../utils/timers\"\nimport {useGlassesStore} from \"../stores/glasses\"\n\nimport {resolveOtaManifestUrl} from \"./otaManifestUrl\"\nimport {detectClockSkew} from \"./gallerySyncClock\"\n\nexport const CLOCK_SETTLE_MS = 500\n\nconst OTA_CLOCK_FIX_COOLDOWN_MS = 30_000\nlet lastOtaClockFixAt = 0\n// Coalesce concurrent OTA clock-fix attempts. Glasses can emit two clock_skew events\n// back-to-back during BLE handshake; without this guard both would await the BLE fix\n// + retry pair before either updated `lastOtaClockFixAt`.\nlet inflightOtaClockFix: Promise<boolean> | null = null\n\n/** @internal test-only */\nexport function resetOtaClockFixCooldownForTests(): void {\n lastOtaClockFixAt = 0\n inflightOtaClockFix = null\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => BgTimer.setTimeout(resolve, ms))\n}\n\n/**\n * Set glasses system clock from phone when skew is detected.\n */\nexport async function fixGlassesClockIfSkewed(glassesServerTime: number, lastSyncTime = 0): Promise<boolean> {\n const {skewed, reason} = detectClockSkew(Date.now(), glassesServerTime, lastSyncTime)\n if (!skewed) {\n return false\n }\n console.log(`[GlassesClockSync] ⏰ Clock skew detected (${reason}) — setting glasses time from phone`)\n await BluetoothSdk.setSystemTime(Date.now())\n await delay(CLOCK_SETTLE_MS)\n return true\n}\n\n/**\n * After glasses report OTA failure due to clock skew, fix time and restart\n * through the normal phone-driven ota_start path.\n */\nexport async function handleOtaClockSkewFromGlasses(\n errorCode: string | undefined,\n glassesTimeMs?: number,\n): Promise<boolean> {\n if (Date.now() - lastOtaClockFixAt < OTA_CLOCK_FIX_COOLDOWN_MS) {\n return false\n }\n\n const hasGlassesTime = typeof glassesTimeMs === \"number\" && Number.isFinite(glassesTimeMs) && glassesTimeMs > 0\n\n if (errorCode === \"ssl_error\") {\n if (!hasGlassesTime) {\n return false\n }\n const {skewed} = detectClockSkew(Date.now(), glassesTimeMs, 0)\n if (!skewed) {\n return false\n }\n console.log(\"[GlassesClockSync] ⏰ OTA ssl_error with wall-clock drift — treating as clock skew\")\n } else if (errorCode !== \"clock_skew\") {\n return false\n }\n\n // Coalesce concurrent attempts: if a fix is already in flight, await its result instead\n // of racing it through the cooldown guard.\n if (inflightOtaClockFix) {\n return inflightOtaClockFix\n }\n\n const glassesTime = hasGlassesTime ? glassesTimeMs : Date.now() - 86_400_000\n\n inflightOtaClockFix = (async () => {\n try {\n const fixed = await fixGlassesClockIfSkewed(glassesTime, 0)\n if (!fixed) {\n return false\n }\n\n lastOtaClockFixAt = Date.now()\n const {buildNumber, otaVersionUrl} = useGlassesStore.getState()\n const manifestUrl = resolveOtaManifestUrl(otaVersionUrl, buildNumber)\n if (!manifestUrl) {\n console.warn(\"[GlassesClockSync] OTA restart skipped because this build has no manifest pin\")\n return false\n }\n console.log(\"[GlassesClockSync] ⏰ Restarting OTA with ota_start after clock fix\")\n await BluetoothSdk.startOtaUpdate(manifestUrl)\n return true\n } finally {\n inflightOtaClockFix = null\n }\n })()\n\n return inflightOtaClockFix\n}\n\n/**\n * Proactive fix when version_info includes glasses system_time_ms before OTA manifest checks.\n */\nexport async function maybeFixGlassesClockFromVersionInfo(systemTimeMs: number | undefined): Promise<boolean> {\n if (typeof systemTimeMs !== \"number\" || systemTimeMs <= 0) {\n return false\n }\n\n const fixed = await fixGlassesClockIfSkewed(systemTimeMs, 0)\n if (!fixed) {\n return false\n }\n\n return true\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { OtaProgress, OtaStatus } from "@mentra/bluetooth-sdk
|
|
1
|
+
import type { OtaProgress, OtaStatus } from "@mentra/bluetooth-sdk";
|
|
2
2
|
export type DisplayState = "starting" | "updating" | "complete" | "failed" | "disconnected" | "restarting";
|
|
3
3
|
/**
|
|
4
4
|
* Pure derivation of the OTA progress UI state from the glasses data in the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"otaDisplayState.d.ts","sourceRoot":"","sources":["../../src/services/otaDisplayState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,WAAW,EAAE,SAAS,EAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"otaDisplayState.d.ts","sourceRoot":"","sources":["../../src/services/otaDisplayState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,WAAW,EAAE,SAAS,EAAC,MAAM,uBAAuB,CAAA;AAIjE,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,QAAQ,GAAG,cAAc,GAAG,YAAY,CAAA;AAE1G;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAA;IAC3B,WAAW,EAAE,WAAW,GAAG,IAAI,CAAA;IAC/B,SAAS,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,gBAAgB,EAAE,OAAO,CAAA;IACzB,4FAA4F;IAC5F,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,uEAAuE;IACvE,4BAA4B,CAAC,EAAE,OAAO,CAAA;IACtC,2FAA2F;IAC3F,kBAAkB,CAAC,EAAE,UAAU,GAAG,UAAU,GAAG,IAAI,CAAA;IACnD,4FAA4F;IAC5F,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,6DAA6D;IAC7D,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B,GAAG,YAAY,CAqFf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"otaDisplayState.js","sourceRoot":"","sources":["../../src/services/otaDisplayState.ts"],"names":[],"mappings":"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","sourcesContent":["import type {OtaProgress, OtaStatus} from \"@mentra/bluetooth-sdk/internal\"\n\nimport {isLegacyShapedOtaStatus} from \"./otaInstallPolicy\"\n\nexport type DisplayState = \"starting\" | \"updating\" | \"complete\" | \"failed\" | \"disconnected\" | \"restarting\"\n\n/**\n * Pure derivation of the OTA progress UI state from the glasses data in the\n * Zustand store plus a couple of genuinely-local inputs. See\n * OtaInstallCoordinator.ts for the state machine that consumes this (the host\n * progress screen renders its snapshot).\n *\n * Legacy shape (WP 8C): old (< 37) ASG builds send `ota_progress`, which the SDK\n * maps to ota_status with sessionId \"\" and FINISHED→\"complete\" at ANY phase. For\n * those statuses a download-phase \"complete\" only means the download finished\n * (the install is still ahead), and an apk install \"complete\" may be held by the\n * coordinator's settle window — both stay \"updating\" instead of terminal.\n *\n * Priority-ordered rules (first match wins):\n * 1. errorMsg !== \"\" -> \"failed\"\n * 2. BES reboot recovery complete -> \"complete\"\n * 3. BES reboot recovery awaiting reconnect -> \"restarting\"\n * 4. BES terminal (any connection state) -> \"restarting\"\n * (legacy-shaped BES \"complete\" counts only in install phase)\n * 6. apkCompletedViaBuildIncrease (legacy build-number port) -> \"complete\"\n * 7. otaStatus.status === \"failed\" -> \"failed\"\n * 8. otaStatus.status === \"complete\" (non-BES) -> \"complete\"\n * (unless legacy-shaped download-complete or held apk settle -> in flight)\n * 9. !connected + legacy in-flight complete (held apk) -> \"updating\"\n * 10. !connected + APK step_complete with totalSteps > 1 -> \"starting\" (expected reboot)\n * 11. !connected + BES in flight -> \"restarting\" (defensive)\n * 12. !connected -> \"disconnected\"\n * 13. connected + in_progress | step_complete | legacy in-flight complete -> \"updating\"\n * 14. fallback -> \"starting\"\n */\nexport function deriveDisplayState(args: {\n otaStatus: OtaStatus | null\n otaProgress: OtaProgress | null\n connected: boolean\n errorMsg: string\n /**\n * Retained for host API compatibility. A session-wide reconnect edge is not\n * sufficient for BES completion because it may belong to an earlier APK step.\n */\n sawReconnectEdge: boolean\n /** Coordinator is holding a legacy apk install \"complete\" for the settle window (WP 8C). */\n legacyApkSettleHold?: boolean\n /** Legacy APK completion detected by build-number increase (WP 8C). */\n apkCompletedViaBuildIncrease?: boolean\n /** Phone-observed BES disconnect/reconnect recovery, independent of stale OTA progress. */\n besRestartRecovery?: \"awaiting\" | \"complete\" | null\n /** Downgrade detour: the reconnected glasses reported exactly the pinned target version. */\n versionChangeConverged?: boolean\n /** True for the whole downgrade (version-change) session. */\n versionChangeSession?: boolean\n}): DisplayState {\n const {\n otaStatus,\n otaProgress,\n connected,\n errorMsg,\n legacyApkSettleHold,\n apkCompletedViaBuildIncrease,\n besRestartRecovery,\n versionChangeConverged,\n versionChangeSession,\n } = args\n\n if (errorMsg) return \"failed\"\n\n // Downgrade detour completion: exact-version convergence after reconnect is the\n // only completion signal (the wipe destroys ASG's ota_session, and the target is\n // a LOWER build so no build-number increase fires). Outranks the stale install\n // status still sitting in the store from before the handoff.\n if (versionChangeConverged) return \"complete\"\n\n // A BES reboot destroys or strands the glasses-side OTA session on older\n // clients. Once the phone observed that reboot, stale pre-reboot progress must\n // not move the UI from restarting back to updating.\n if (besRestartRecovery === \"complete\") return \"complete\"\n if (besRestartRecovery === \"awaiting\") return \"restarting\"\n\n // In a version-change session, convergence (above) is the ONLY completion for the ASG\n // downgrade. A bare non-firmware \"complete\" before convergence — the glasses refusing\n // the downgrade (floor/gate) with no install, or a stale pre-handoff status — must never\n // present as success. Firmware-step completions (mtk/bes) DO pass through: a combined\n // downgrade+firmware manifest applies firmware first on its own pass, which must finish\n // so the phone re-checks and re-offers the now-firmware-free downgrade.\n const isFirmwareComplete = otaStatus?.stepType === \"mtk\" || otaStatus?.stepType === \"bes\"\n if (versionChangeSession && otaStatus?.status === \"complete\" && !isFirmwareComplete) {\n return connected ? \"updating\" : \"disconnected\"\n }\n\n const besTerminal = isBesTerminal(otaStatus, otaProgress)\n if (besTerminal) return \"restarting\"\n\n // Legacy build-number APK completion: the coordinator clears errorMsg when it fires,\n // and the flag outranks whatever stale legacy status is still in the store (the old\n // screen's last-write-wins completion from starting/failed/installing).\n if (apkCompletedViaBuildIncrease) return \"complete\"\n\n if (otaStatus?.status === \"failed\") return \"failed\"\n\n // Legacy-shaped \"complete\" that is still in flight: a download-phase FINISHED (the\n // install is still ahead), or an apk install FINISHED held by the settle window.\n const legacyInFlightComplete =\n isLegacyShapedOtaStatus(otaStatus) &&\n otaStatus?.status === \"complete\" &&\n (otaStatus.phase === \"download\" ||\n (!!legacyApkSettleHold && otaStatus.stepType === \"apk\" && otaStatus.phase === \"install\"))\n\n if (otaStatus?.status === \"complete\" && !legacyInFlightComplete) return \"complete\"\n\n if (!connected) {\n // The held apk install complete means the glasses are restarting into the new\n // build — the legacy screen kept showing \"installing\" through that restart.\n if (legacyInFlightComplete && otaStatus?.phase === \"install\") return \"updating\"\n\n // By here, the failed/complete rules already returned for terminal statuses.\n // For APK multi-step, \"step_complete\" means the current step ended and the\n // glasses are rebooting to start the next one.\n const apkRebootExpected =\n otaStatus?.stepType === \"apk\" && (otaStatus?.totalSteps ?? 0) > 1 && otaStatus.status === \"step_complete\"\n if (apkRebootExpected) return \"starting\"\n\n // Legacy-shaped BES download events do not mean a reboot is coming (the flash\n // has not started); the legacy screen treated that drop as a plain disconnect.\n const besStatusInFlight =\n otaStatus?.stepType === \"bes\" && !(isLegacyShapedOtaStatus(otaStatus) && otaStatus.phase === \"download\")\n const besInFlight = besStatusInFlight || (otaProgress?.currentUpdate === \"bes\" && otaProgress?.stage === \"install\")\n if (besInFlight) return \"restarting\"\n\n return \"disconnected\"\n }\n\n if (otaStatus?.status === \"in_progress\" || otaStatus?.status === \"step_complete\" || legacyInFlightComplete) {\n return \"updating\"\n }\n\n return \"starting\"\n}\n\nfunction isBesTerminal(otaStatus: OtaStatus | null, otaProgress: OtaProgress | null): boolean {\n if (otaStatus?.stepType === \"bes\" && (otaStatus.status === \"step_complete\" || otaStatus.status === \"complete\")) {\n // Legacy-shaped statuses map download FINISHED to \"complete\" too; only an\n // install-phase terminal means the BES flash actually ran (WP 8C).\n if (isLegacyShapedOtaStatus(otaStatus) && otaStatus.phase !== \"install\") {\n return false\n }\n return true\n }\n if (otaProgress?.currentUpdate === \"bes\" && otaProgress.stage === \"install\" && otaProgress.status === \"FINISHED\") {\n return true\n }\n return false\n}\n"]}
|
|
1
|
+
{"version":3,"file":"otaDisplayState.js","sourceRoot":"","sources":["../../src/services/otaDisplayState.ts"],"names":[],"mappings":"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","sourcesContent":["import type {OtaProgress, OtaStatus} from \"@mentra/bluetooth-sdk\"\n\nimport {isLegacyShapedOtaStatus} from \"./otaInstallPolicy\"\n\nexport type DisplayState = \"starting\" | \"updating\" | \"complete\" | \"failed\" | \"disconnected\" | \"restarting\"\n\n/**\n * Pure derivation of the OTA progress UI state from the glasses data in the\n * Zustand store plus a couple of genuinely-local inputs. See\n * OtaInstallCoordinator.ts for the state machine that consumes this (the host\n * progress screen renders its snapshot).\n *\n * Legacy shape (WP 8C): old (< 37) ASG builds send `ota_progress`, which the SDK\n * maps to ota_status with sessionId \"\" and FINISHED→\"complete\" at ANY phase. For\n * those statuses a download-phase \"complete\" only means the download finished\n * (the install is still ahead), and an apk install \"complete\" may be held by the\n * coordinator's settle window — both stay \"updating\" instead of terminal.\n *\n * Priority-ordered rules (first match wins):\n * 1. errorMsg !== \"\" -> \"failed\"\n * 2. BES reboot recovery complete -> \"complete\"\n * 3. BES reboot recovery awaiting reconnect -> \"restarting\"\n * 4. BES terminal (any connection state) -> \"restarting\"\n * (legacy-shaped BES \"complete\" counts only in install phase)\n * 6. apkCompletedViaBuildIncrease (legacy build-number port) -> \"complete\"\n * 7. otaStatus.status === \"failed\" -> \"failed\"\n * 8. otaStatus.status === \"complete\" (non-BES) -> \"complete\"\n * (unless legacy-shaped download-complete or held apk settle -> in flight)\n * 9. !connected + legacy in-flight complete (held apk) -> \"updating\"\n * 10. !connected + APK step_complete with totalSteps > 1 -> \"starting\" (expected reboot)\n * 11. !connected + BES in flight -> \"restarting\" (defensive)\n * 12. !connected -> \"disconnected\"\n * 13. connected + in_progress | step_complete | legacy in-flight complete -> \"updating\"\n * 14. fallback -> \"starting\"\n */\nexport function deriveDisplayState(args: {\n otaStatus: OtaStatus | null\n otaProgress: OtaProgress | null\n connected: boolean\n errorMsg: string\n /**\n * Retained for host API compatibility. A session-wide reconnect edge is not\n * sufficient for BES completion because it may belong to an earlier APK step.\n */\n sawReconnectEdge: boolean\n /** Coordinator is holding a legacy apk install \"complete\" for the settle window (WP 8C). */\n legacyApkSettleHold?: boolean\n /** Legacy APK completion detected by build-number increase (WP 8C). */\n apkCompletedViaBuildIncrease?: boolean\n /** Phone-observed BES disconnect/reconnect recovery, independent of stale OTA progress. */\n besRestartRecovery?: \"awaiting\" | \"complete\" | null\n /** Downgrade detour: the reconnected glasses reported exactly the pinned target version. */\n versionChangeConverged?: boolean\n /** True for the whole downgrade (version-change) session. */\n versionChangeSession?: boolean\n}): DisplayState {\n const {\n otaStatus,\n otaProgress,\n connected,\n errorMsg,\n legacyApkSettleHold,\n apkCompletedViaBuildIncrease,\n besRestartRecovery,\n versionChangeConverged,\n versionChangeSession,\n } = args\n\n if (errorMsg) return \"failed\"\n\n // Downgrade detour completion: exact-version convergence after reconnect is the\n // only completion signal (the wipe destroys ASG's ota_session, and the target is\n // a LOWER build so no build-number increase fires). Outranks the stale install\n // status still sitting in the store from before the handoff.\n if (versionChangeConverged) return \"complete\"\n\n // A BES reboot destroys or strands the glasses-side OTA session on older\n // clients. Once the phone observed that reboot, stale pre-reboot progress must\n // not move the UI from restarting back to updating.\n if (besRestartRecovery === \"complete\") return \"complete\"\n if (besRestartRecovery === \"awaiting\") return \"restarting\"\n\n // In a version-change session, convergence (above) is the ONLY completion for the ASG\n // downgrade. A bare non-firmware \"complete\" before convergence — the glasses refusing\n // the downgrade (floor/gate) with no install, or a stale pre-handoff status — must never\n // present as success. Firmware-step completions (mtk/bes) DO pass through: a combined\n // downgrade+firmware manifest applies firmware first on its own pass, which must finish\n // so the phone re-checks and re-offers the now-firmware-free downgrade.\n const isFirmwareComplete = otaStatus?.stepType === \"mtk\" || otaStatus?.stepType === \"bes\"\n if (versionChangeSession && otaStatus?.status === \"complete\" && !isFirmwareComplete) {\n return connected ? \"updating\" : \"disconnected\"\n }\n\n const besTerminal = isBesTerminal(otaStatus, otaProgress)\n if (besTerminal) return \"restarting\"\n\n // Legacy build-number APK completion: the coordinator clears errorMsg when it fires,\n // and the flag outranks whatever stale legacy status is still in the store (the old\n // screen's last-write-wins completion from starting/failed/installing).\n if (apkCompletedViaBuildIncrease) return \"complete\"\n\n if (otaStatus?.status === \"failed\") return \"failed\"\n\n // Legacy-shaped \"complete\" that is still in flight: a download-phase FINISHED (the\n // install is still ahead), or an apk install FINISHED held by the settle window.\n const legacyInFlightComplete =\n isLegacyShapedOtaStatus(otaStatus) &&\n otaStatus?.status === \"complete\" &&\n (otaStatus.phase === \"download\" ||\n (!!legacyApkSettleHold && otaStatus.stepType === \"apk\" && otaStatus.phase === \"install\"))\n\n if (otaStatus?.status === \"complete\" && !legacyInFlightComplete) return \"complete\"\n\n if (!connected) {\n // The held apk install complete means the glasses are restarting into the new\n // build — the legacy screen kept showing \"installing\" through that restart.\n if (legacyInFlightComplete && otaStatus?.phase === \"install\") return \"updating\"\n\n // By here, the failed/complete rules already returned for terminal statuses.\n // For APK multi-step, \"step_complete\" means the current step ended and the\n // glasses are rebooting to start the next one.\n const apkRebootExpected =\n otaStatus?.stepType === \"apk\" && (otaStatus?.totalSteps ?? 0) > 1 && otaStatus.status === \"step_complete\"\n if (apkRebootExpected) return \"starting\"\n\n // Legacy-shaped BES download events do not mean a reboot is coming (the flash\n // has not started); the legacy screen treated that drop as a plain disconnect.\n const besStatusInFlight =\n otaStatus?.stepType === \"bes\" && !(isLegacyShapedOtaStatus(otaStatus) && otaStatus.phase === \"download\")\n const besInFlight = besStatusInFlight || (otaProgress?.currentUpdate === \"bes\" && otaProgress?.stage === \"install\")\n if (besInFlight) return \"restarting\"\n\n return \"disconnected\"\n }\n\n if (otaStatus?.status === \"in_progress\" || otaStatus?.status === \"step_complete\" || legacyInFlightComplete) {\n return \"updating\"\n }\n\n return \"starting\"\n}\n\nfunction isBesTerminal(otaStatus: OtaStatus | null, otaProgress: OtaProgress | null): boolean {\n if (otaStatus?.stepType === \"bes\" && (otaStatus.status === \"step_complete\" || otaStatus.status === \"complete\")) {\n // Legacy-shaped statuses map download FINISHED to \"complete\" too; only an\n // install-phase terminal means the BES flash actually ran (WP 8C).\n if (isLegacyShapedOtaStatus(otaStatus) && otaStatus.phase !== \"install\") {\n return false\n }\n return true\n }\n if (otaProgress?.currentUpdate === \"bes\" && otaProgress.stage === \"install\" && otaProgress.status === \"FINISHED\") {\n return true\n }\n return false\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Shared OTA progress watchdog timings (see progress-legacy.tsx / progress.tsx). */
|
|
2
|
-
import type { OtaProgress, OtaStatus } from "@mentra/bluetooth-sdk
|
|
2
|
+
import type { OtaProgress, OtaStatus } from "@mentra/bluetooth-sdk";
|
|
3
3
|
/**
|
|
4
4
|
* First glasses `build_number` (ASG `versionCode`) that uses `progress.tsx` with unified
|
|
5
5
|
* `ota_status` session UI. Strictly lower builds use `/ota/progress-legacy` (routed from
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"otaInstallPolicy.d.ts","sourceRoot":"","sources":["../../src/services/otaInstallPolicy.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,OAAO,KAAK,EAAC,WAAW,EAAE,SAAS,EAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"otaInstallPolicy.d.ts","sourceRoot":"","sources":["../../src/services/otaInstallPolicy.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,OAAO,KAAK,EAAC,WAAW,EAAE,SAAS,EAAC,MAAM,uBAAuB,CAAA;AAEjE;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,KAAK,CAAA;AAE1C,eAAO,MAAM,WAAW,IAAI,CAAA;AAC5B,sFAAsF;AACtF,eAAO,MAAM,iBAAiB,OAAO,CAAA;AACrC,oEAAoE;AACpE,eAAO,MAAM,mBAAmB,SAAU,CAAA;AAC1C,kDAAkD;AAClD,eAAO,MAAM,yBAAyB,QAAS,CAAA;AAC/C,2DAA2D;AAC3D,eAAO,MAAM,sBAAsB,SAAU,CAAA;AAC7C,mCAAmC;AACnC,eAAO,MAAM,qBAAqB,QAAiB,CAAA;AACnD,+BAA+B;AAC/B,eAAO,MAAM,gBAAgB,QAAS,CAAA;AACtC;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,OAAO,CAAA;AAC1C,4FAA4F;AAC5F,eAAO,MAAM,uBAAuB,QAAS,CAAA;AAW7C,kFAAkF;AAClF,eAAO,MAAM,uBAAuB,QAAS,CAAA;AAC7C,eAAO,MAAM,wBAAwB,QAA8C,CAAA;AACnF,eAAO,MAAM,0BAA0B,QAAgD,CAAA;AACvF,eAAO,MAAM,gCAAgC,QAAsD,CAAA;AACnG,eAAO,MAAM,6BAA6B,QAAmD,CAAA;AAC7F,eAAO,MAAM,4BAA4B,QAAkD,CAAA;AAC3F,eAAO,MAAM,uBAAuB,QAA6C,CAAA;AACjF,eAAO,MAAM,8BAA8B,QAAoD,CAAA;AAC/F;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,QAAmC,CAAA;AAC/E;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,QAAmC,CAAA;AAC1E,eAAO,MAAM,sBAAsB,QAAmC,CAAA;AACtE,eAAO,MAAM,iCAAiC,KAAK,CAAA;AACnD,eAAO,MAAM,iCAAiC,KAAK,CAAA;AACnD,eAAO,MAAM,4BAA4B,KAAK,CAAA;AAC9C,eAAO,MAAM,0BAA0B,KAAK,CAAA;AAE5C,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,SAAS,CAAA;AAErD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,GAAG,OAAO,CAE5E;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,SAAS,GAAG,IAAI,EAC3B,WAAW,EAAE,WAAW,GAAG,IAAI,EAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACrC,OAAO,CAKT;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,SAAS,GAAG,IAAI,EAC3B,WAAW,EAAE,WAAW,GAAG,IAAI,EAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACrC,kBAAkB,GAAG,IAAI,CAQ3B;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;CAUtB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"otaInstallPolicy.js","sourceRoot":"","sources":["../../src/services/otaInstallPolicy.ts"],"names":[],"mappings":"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","sourcesContent":["/** Shared OTA progress watchdog timings (see progress-legacy.tsx / progress.tsx). */\nimport type {OtaProgress, OtaStatus} from \"@mentra/bluetooth-sdk/internal\"\n\n/**\n * First glasses `build_number` (ASG `versionCode`) that uses `progress.tsx` with unified\n * `ota_status` session UI. Strictly lower builds use `/ota/progress-legacy` (routed from\n * `check-for-updates.tsx` before navigation), and get the LEGACY_* padded policy below\n * in the unified OtaInstallCoordinator (WP 8C). Change only here.\n */\nexport const MINIMUM_OTA_STATUS_BUILD = 37\n\nexport const MAX_RETRIES = 3\n/** Wait between ended native ota_start requests; never overlaps a pending request. */\nexport const RETRY_INTERVAL_MS = 5000\n/** APK/BES and general install when progress events are expected */\nexport const PROGRESS_TIMEOUT_MS = 120_000\n/** Fail if still at 0% in starting/downloading */\nexport const DOWNLOAD_STUCK_TIMEOUT_MS = 70_000\n/** MTK system install often goes quiet for long periods */\nexport const MTK_INSTALL_TIMEOUT_MS = 300_000\n/** Whole multi-step session cap */\nexport const GLOBAL_OTA_TIMEOUT_MS = 20 * 60 * 1000\n/** BLE keepalive during OTA */\nexport const PING_INTERVAL_MS = 10_000\n/**\n * If we sent ota_query_status (e.g. on reconnect) and the glasses haven't\n * replied with an ota_status by then, fall back to ota_start. This recovers\n * from the case where the glasses process restarted between mount and\n * reconnect — the session is gone, ota_query_status returns nothing, and\n * the user would otherwise sit on the spinner forever.\n */\nexport const QUERY_REPLY_TIMEOUT_MS = 6000\n/** 15s lockout on the Continue button after a BES restart, to prevent an accidental tap. */\nexport const BES_CONTINUE_LOCKOUT_MS = 15_000\n\n// --- Legacy old-build (< MINIMUM_OTA_STATUS_BUILD) OTA policy (WP 8C) ---\n//\n// Ported verbatim from mobile/src/app/ota/progress-legacy.tsx, which padded EVERY\n// watchdog/timer by +20s for old ASG builds (\"Legacy OTA: +20s on every watchdog /\n// timer duration\"). Old builds respond slower on every path, so where the legacy\n// screen used a longer duration the coordinator applies the longer value whenever\n// the session is legacy-shaped (see isLegacyShapedOtaStatus / the coordinator's\n// session-shape check). Builds >= 37 keep the unpadded values above.\n\n/** The uniform pad progress-legacy.tsx added to every duration for old builds. */\nexport const LEGACY_EXTRA_TIMEOUT_MS = 20_000\nexport const LEGACY_RETRY_INTERVAL_MS = RETRY_INTERVAL_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_PROGRESS_TIMEOUT_MS = PROGRESS_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_DOWNLOAD_STUCK_TIMEOUT_MS = DOWNLOAD_STUCK_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_MTK_INSTALL_TIMEOUT_MS = MTK_INSTALL_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_GLOBAL_OTA_TIMEOUT_MS = GLOBAL_OTA_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_PING_INTERVAL_MS = PING_INTERVAL_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_BES_CONTINUE_LOCKOUT_MS = BES_CONTINUE_LOCKOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\n/**\n * After a legacy apk `install FINISHED` observed in-flight, the legacy screen held the\n * completed state for 12s (+20s pad) so the ASG process restart settles (and fresh\n * version_info lands) before the user can continue.\n */\nexport const LEGACY_APK_COMPLETION_SETTLE_MS = 12_000 + LEGACY_EXTRA_TIMEOUT_MS\n/**\n * Legacy MTK install stall simulation (display-only): the MTK system install typically\n * stalls around 49-50%. After LEGACY_MTK_STALL_DETECT_MS without a new event in the\n * [45, 55) zone, the legacy screen simulated +1% every LEGACY_MTK_SIM_TICK_MS starting\n * at max(stall+1, 51) and capped at 60%, purely to keep the user informed.\n */\nexport const LEGACY_MTK_STALL_DETECT_MS = 20_000 + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_MTK_SIM_TICK_MS = 15_000 + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_MTK_STALL_ZONE_MIN_PERCENT = 45\nexport const LEGACY_MTK_STALL_ZONE_MAX_PERCENT = 55\nexport const LEGACY_MTK_SIM_FLOOR_PERCENT = 51\nexport const LEGACY_MTK_SIM_CAP_PERCENT = 60\n\nexport type OtaProtocolProfile = \"legacy\" | \"unified\"\n\n/**\n * Legacy-shaped ota_status: old (< 37) ASG builds send `ota_progress`, which the SDK\n * (Android MentraLive.kt / iOS MentraLive.swift) maps to a unified ota_status with\n * sessionId \"\" and totalSteps 1, and FINISHED→\"complete\" regardless of phase. A real\n * (>= 37) session always carries a sessionId; an \"idle\" reply also has sessionId \"\" but\n * proves the glasses speak the unified protocol, so it is NOT legacy-shaped.\n */\nexport function isLegacyShapedOtaStatus(otaStatus: OtaStatus | null): boolean {\n return !!otaStatus && otaStatus.sessionId === \"\" && otaStatus.status !== \"idle\"\n}\n\n/**\n * Is the current install session legacy-shaped? Event shape wins when events exist\n * (per the WP 8C rule: key off legacy-shaped inputs, not a build flag, where possible);\n * before any event arrives only the glasses build number can tell.\n */\nexport function isLegacyShapedOtaSession(\n otaStatus: OtaStatus | null,\n otaProgress: OtaProgress | null,\n buildNumber: string | null | undefined,\n): boolean {\n if (otaStatus) return isLegacyShapedOtaStatus(otaStatus)\n if (otaProgress) return true\n const build = Number.parseInt(buildNumber ?? \"\", 10)\n return Number.isFinite(build) && build > 0 && build < MINIMUM_OTA_STATUS_BUILD\n}\n\n/**\n * Select the compatibility profile once at install-screen attach. The old split\n * routes made this decision from the pre-update build and kept it for the whole\n * mounted flow, even when an APK step restarted into a newer ASG build. Returning\n * null leaves the coordinator undecided until the first meaningful OTA event.\n */\nexport function selectOtaProtocolProfile(\n otaStatus: OtaStatus | null,\n otaProgress: OtaProgress | null,\n buildNumber: string | null | undefined,\n): OtaProtocolProfile | null {\n const build = Number.parseInt(buildNumber ?? \"\", 10)\n if (Number.isFinite(build) && build > 0) {\n return build < MINIMUM_OTA_STATUS_BUILD ? \"legacy\" : \"unified\"\n }\n if (otaStatus) return isLegacyShapedOtaStatus(otaStatus) ? \"legacy\" : \"unified\"\n if (otaProgress) return \"legacy\"\n return null\n}\n\nexport const OtaProgressMessages = {\n stalledOrStuck: \"Update may have failed. Ensure glasses have internet access and try again.\",\n globalTimeout: \"Update took too long. Please try again.\",\n sendOtaStartFailed: \"Failed to communicate with glasses.\",\n hotspotArtifactDownloadFailed: \"Could not download the update to your phone. Check phone internet and try again.\",\n hotspotArtifactVerifyFailed: \"The update package could not be verified. Please try again later.\",\n hotspotWifiPermissionDenied: \"Allow nearby devices access so the phone can connect to the glasses hotspot.\",\n hotspotStartFailed: \"Could not start the glasses hotspot. Please try again.\",\n hotspotJoinFailed: \"Could not connect the phone to the glasses hotspot. Please try again.\",\n hotspotServerFailed: \"Could not make the update available to the glasses. Please try again.\",\n} as const\n"]}
|
|
1
|
+
{"version":3,"file":"otaInstallPolicy.js","sourceRoot":"","sources":["../../src/services/otaInstallPolicy.ts"],"names":[],"mappings":"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","sourcesContent":["/** Shared OTA progress watchdog timings (see progress-legacy.tsx / progress.tsx). */\nimport type {OtaProgress, OtaStatus} from \"@mentra/bluetooth-sdk\"\n\n/**\n * First glasses `build_number` (ASG `versionCode`) that uses `progress.tsx` with unified\n * `ota_status` session UI. Strictly lower builds use `/ota/progress-legacy` (routed from\n * `check-for-updates.tsx` before navigation), and get the LEGACY_* padded policy below\n * in the unified OtaInstallCoordinator (WP 8C). Change only here.\n */\nexport const MINIMUM_OTA_STATUS_BUILD = 37\n\nexport const MAX_RETRIES = 3\n/** Wait between ended native ota_start requests; never overlaps a pending request. */\nexport const RETRY_INTERVAL_MS = 5000\n/** APK/BES and general install when progress events are expected */\nexport const PROGRESS_TIMEOUT_MS = 120_000\n/** Fail if still at 0% in starting/downloading */\nexport const DOWNLOAD_STUCK_TIMEOUT_MS = 70_000\n/** MTK system install often goes quiet for long periods */\nexport const MTK_INSTALL_TIMEOUT_MS = 300_000\n/** Whole multi-step session cap */\nexport const GLOBAL_OTA_TIMEOUT_MS = 20 * 60 * 1000\n/** BLE keepalive during OTA */\nexport const PING_INTERVAL_MS = 10_000\n/**\n * If we sent ota_query_status (e.g. on reconnect) and the glasses haven't\n * replied with an ota_status by then, fall back to ota_start. This recovers\n * from the case where the glasses process restarted between mount and\n * reconnect — the session is gone, ota_query_status returns nothing, and\n * the user would otherwise sit on the spinner forever.\n */\nexport const QUERY_REPLY_TIMEOUT_MS = 6000\n/** 15s lockout on the Continue button after a BES restart, to prevent an accidental tap. */\nexport const BES_CONTINUE_LOCKOUT_MS = 15_000\n\n// --- Legacy old-build (< MINIMUM_OTA_STATUS_BUILD) OTA policy (WP 8C) ---\n//\n// Ported verbatim from mobile/src/app/ota/progress-legacy.tsx, which padded EVERY\n// watchdog/timer by +20s for old ASG builds (\"Legacy OTA: +20s on every watchdog /\n// timer duration\"). Old builds respond slower on every path, so where the legacy\n// screen used a longer duration the coordinator applies the longer value whenever\n// the session is legacy-shaped (see isLegacyShapedOtaStatus / the coordinator's\n// session-shape check). Builds >= 37 keep the unpadded values above.\n\n/** The uniform pad progress-legacy.tsx added to every duration for old builds. */\nexport const LEGACY_EXTRA_TIMEOUT_MS = 20_000\nexport const LEGACY_RETRY_INTERVAL_MS = RETRY_INTERVAL_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_PROGRESS_TIMEOUT_MS = PROGRESS_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_DOWNLOAD_STUCK_TIMEOUT_MS = DOWNLOAD_STUCK_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_MTK_INSTALL_TIMEOUT_MS = MTK_INSTALL_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_GLOBAL_OTA_TIMEOUT_MS = GLOBAL_OTA_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_PING_INTERVAL_MS = PING_INTERVAL_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_BES_CONTINUE_LOCKOUT_MS = BES_CONTINUE_LOCKOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\n/**\n * After a legacy apk `install FINISHED` observed in-flight, the legacy screen held the\n * completed state for 12s (+20s pad) so the ASG process restart settles (and fresh\n * version_info lands) before the user can continue.\n */\nexport const LEGACY_APK_COMPLETION_SETTLE_MS = 12_000 + LEGACY_EXTRA_TIMEOUT_MS\n/**\n * Legacy MTK install stall simulation (display-only): the MTK system install typically\n * stalls around 49-50%. After LEGACY_MTK_STALL_DETECT_MS without a new event in the\n * [45, 55) zone, the legacy screen simulated +1% every LEGACY_MTK_SIM_TICK_MS starting\n * at max(stall+1, 51) and capped at 60%, purely to keep the user informed.\n */\nexport const LEGACY_MTK_STALL_DETECT_MS = 20_000 + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_MTK_SIM_TICK_MS = 15_000 + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_MTK_STALL_ZONE_MIN_PERCENT = 45\nexport const LEGACY_MTK_STALL_ZONE_MAX_PERCENT = 55\nexport const LEGACY_MTK_SIM_FLOOR_PERCENT = 51\nexport const LEGACY_MTK_SIM_CAP_PERCENT = 60\n\nexport type OtaProtocolProfile = \"legacy\" | \"unified\"\n\n/**\n * Legacy-shaped ota_status: old (< 37) ASG builds send `ota_progress`, which the SDK\n * (Android MentraLive.kt / iOS MentraLive.swift) maps to a unified ota_status with\n * sessionId \"\" and totalSteps 1, and FINISHED→\"complete\" regardless of phase. A real\n * (>= 37) session always carries a sessionId; an \"idle\" reply also has sessionId \"\" but\n * proves the glasses speak the unified protocol, so it is NOT legacy-shaped.\n */\nexport function isLegacyShapedOtaStatus(otaStatus: OtaStatus | null): boolean {\n return !!otaStatus && otaStatus.sessionId === \"\" && otaStatus.status !== \"idle\"\n}\n\n/**\n * Is the current install session legacy-shaped? Event shape wins when events exist\n * (per the WP 8C rule: key off legacy-shaped inputs, not a build flag, where possible);\n * before any event arrives only the glasses build number can tell.\n */\nexport function isLegacyShapedOtaSession(\n otaStatus: OtaStatus | null,\n otaProgress: OtaProgress | null,\n buildNumber: string | null | undefined,\n): boolean {\n if (otaStatus) return isLegacyShapedOtaStatus(otaStatus)\n if (otaProgress) return true\n const build = Number.parseInt(buildNumber ?? \"\", 10)\n return Number.isFinite(build) && build > 0 && build < MINIMUM_OTA_STATUS_BUILD\n}\n\n/**\n * Select the compatibility profile once at install-screen attach. The old split\n * routes made this decision from the pre-update build and kept it for the whole\n * mounted flow, even when an APK step restarted into a newer ASG build. Returning\n * null leaves the coordinator undecided until the first meaningful OTA event.\n */\nexport function selectOtaProtocolProfile(\n otaStatus: OtaStatus | null,\n otaProgress: OtaProgress | null,\n buildNumber: string | null | undefined,\n): OtaProtocolProfile | null {\n const build = Number.parseInt(buildNumber ?? \"\", 10)\n if (Number.isFinite(build) && build > 0) {\n return build < MINIMUM_OTA_STATUS_BUILD ? \"legacy\" : \"unified\"\n }\n if (otaStatus) return isLegacyShapedOtaStatus(otaStatus) ? \"legacy\" : \"unified\"\n if (otaProgress) return \"legacy\"\n return null\n}\n\nexport const OtaProgressMessages = {\n stalledOrStuck: \"Update may have failed. Ensure glasses have internet access and try again.\",\n globalTimeout: \"Update took too long. Please try again.\",\n sendOtaStartFailed: \"Failed to communicate with glasses.\",\n hotspotArtifactDownloadFailed: \"Could not download the update to your phone. Check phone internet and try again.\",\n hotspotArtifactVerifyFailed: \"The update package could not be verified. Please try again later.\",\n hotspotWifiPermissionDenied: \"Allow nearby devices access so the phone can connect to the glasses hotspot.\",\n hotspotStartFailed: \"Could not start the glasses hotspot. Please try again.\",\n hotspotJoinFailed: \"Could not connect the phone to the glasses hotspot. Please try again.\",\n hotspotServerFailed: \"Could not make the update available to the glasses. Please try again.\",\n} as const\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { OtaProgress, OtaStatus } from "@mentra/bluetooth-sdk
|
|
1
|
+
import type { OtaProgress, OtaStatus } from "@mentra/bluetooth-sdk";
|
|
2
2
|
/** Normalized ota_status fields (snake_case) after bridging Core/expo (snake or camel). */
|
|
3
3
|
export type NormalizedOtaStatusEvent = {
|
|
4
4
|
session_id: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"otaLegacyMapping.d.ts","sourceRoot":"","sources":["../../src/services/otaLegacyMapping.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,WAAW,EAAqB,SAAS,EAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"otaLegacyMapping.d.ts","sourceRoot":"","sources":["../../src/services/otaLegacyMapping.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,WAAW,EAAqB,SAAS,EAAC,MAAM,uBAAuB,CAAA;AAEpF,2FAA2F;AAC3F,MAAM,MAAM,wBAAwB,GAAG;IACrC,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,UAAU,GAAG,SAAS,CAAA;IAC7B,YAAY,EAAE,MAAM,CAAA;IACpB,eAAe,EAAE,MAAM,CAAA;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,wBAAwB,CAehG;AAED,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,wBAAwB,GAAG,SAAS,CAY9E;AAED,6GAA6G;AAC7G,wBAAgB,mCAAmC,CACjD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,wBAAwB,GACxD,WAAW,CAiBb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"otaLegacyMapping.js","sourceRoot":"","sources":["../../src/services/otaLegacyMapping.ts"],"names":[],"mappings":"AAeA;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAA8B;IACpE,MAAM,CAAC,GAAG,KAA4B,CAAA;IACtC,MAAM,KAAK,GAA2B,CAAC,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAA;IACrF,MAAM,GAAG,GAAG,CAAC,EAAE,aAAa,IAAI,CAAC,EAAE,YAAY,CAAA;IAC/C,OAAO;QACL,UAAU,EAAE,MAAM,CAAC,CAAC,EAAE,UAAU,IAAI,CAAC,EAAE,SAAS,IAAI,EAAE,CAAC;QACvD,WAAW,EAAE,MAAM,CAAC,CAAC,EAAE,WAAW,IAAI,CAAC,EAAE,UAAU,IAAI,CAAC,CAAC;QACzD,YAAY,EAAE,MAAM,CAAC,CAAC,EAAE,YAAY,IAAI,CAAC,EAAE,WAAW,IAAI,CAAC,CAAC;QAC5D,SAAS,EAAE,MAAM,CAAC,CAAC,EAAE,SAAS,IAAI,CAAC,EAAE,QAAQ,IAAI,KAAK,CAAC;QACvD,KAAK;QACL,YAAY,EAAE,MAAM,CAAC,CAAC,EAAE,YAAY,IAAI,CAAC,EAAE,WAAW,IAAI,CAAC,CAAC;QAC5D,eAAe,EAAE,MAAM,CAAC,CAAC,EAAE,eAAe,IAAI,CAAC,EAAE,cAAc,IAAI,CAAC,CAAC;QACrE,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,MAAM,IAAI,MAAM,CAAC;QACnC,aAAa,EAAE,GAAG,IAAI,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;KACnE,CAAA;AACH,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,CAA2B;IACjE,OAAO;QACL,SAAS,EAAE,CAAC,CAAC,UAAU;QACvB,UAAU,EAAE,CAAC,CAAC,WAAW;QACzB,WAAW,EAAE,CAAC,CAAC,YAAY;QAC3B,QAAQ,EAAE,CAAC,CAAC,SAAkC;QAC9C,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,WAAW,EAAE,CAAC,CAAC,YAAY;QAC3B,cAAc,EAAE,CAAC,CAAC,eAAe;QACjC,MAAM,EAAE,CAAC,CAAC,MAA6B;QACvC,KAAK,EAAE,CAAC,CAAC,aAAa;KACvB,CAAA;AACH,CAAC;AAED,6GAA6G;AAC7G,MAAM,UAAU,mCAAmC,CACjD,KAAyD;IAEzD,MAAM,CAAC,GAAG,uBAAuB,CAAC,KAAgC,CAAC,CAAA;IACnE,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,CAAC,YAAY,IAAI,CAAC,CAAW,CAAA;IAChE,IAAI,EAAE,GAAsB,UAAU,CAAA;IACtC,mHAAmH;IACnH,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,IAAI,CAAC,CAAC,MAAM,KAAK,eAAe;QAAE,EAAE,GAAG,UAAU,CAAA;SACvE,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ;QAAE,EAAE,GAAG,QAAQ,CAAA;SACxC,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;QAAE,EAAE,GAAG,SAAS,CAAA;IAC5C,OAAO;QACL,KAAK,EAAE,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU;QACrD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;QACzB,eAAe,EAAE,CAAC;QAClB,UAAU,EAAE,CAAC;QACb,aAAa,EAAE,CAAC,CAAC,SAAS,IAAI,KAAK;QACnC,YAAY,EAAE,CAAC,CAAC,aAAa;KAC9B,CAAA;AACH,CAAC","sourcesContent":["import type {OtaProgress, OtaProgressStatus, OtaStatus} from \"@mentra/bluetooth-sdk
|
|
1
|
+
{"version":3,"file":"otaLegacyMapping.js","sourceRoot":"","sources":["../../src/services/otaLegacyMapping.ts"],"names":[],"mappings":"AAeA;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAA8B;IACpE,MAAM,CAAC,GAAG,KAA4B,CAAA;IACtC,MAAM,KAAK,GAA2B,CAAC,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAA;IACrF,MAAM,GAAG,GAAG,CAAC,EAAE,aAAa,IAAI,CAAC,EAAE,YAAY,CAAA;IAC/C,OAAO;QACL,UAAU,EAAE,MAAM,CAAC,CAAC,EAAE,UAAU,IAAI,CAAC,EAAE,SAAS,IAAI,EAAE,CAAC;QACvD,WAAW,EAAE,MAAM,CAAC,CAAC,EAAE,WAAW,IAAI,CAAC,EAAE,UAAU,IAAI,CAAC,CAAC;QACzD,YAAY,EAAE,MAAM,CAAC,CAAC,EAAE,YAAY,IAAI,CAAC,EAAE,WAAW,IAAI,CAAC,CAAC;QAC5D,SAAS,EAAE,MAAM,CAAC,CAAC,EAAE,SAAS,IAAI,CAAC,EAAE,QAAQ,IAAI,KAAK,CAAC;QACvD,KAAK;QACL,YAAY,EAAE,MAAM,CAAC,CAAC,EAAE,YAAY,IAAI,CAAC,EAAE,WAAW,IAAI,CAAC,CAAC;QAC5D,eAAe,EAAE,MAAM,CAAC,CAAC,EAAE,eAAe,IAAI,CAAC,EAAE,cAAc,IAAI,CAAC,CAAC;QACrE,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,MAAM,IAAI,MAAM,CAAC;QACnC,aAAa,EAAE,GAAG,IAAI,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;KACnE,CAAA;AACH,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,CAA2B;IACjE,OAAO;QACL,SAAS,EAAE,CAAC,CAAC,UAAU;QACvB,UAAU,EAAE,CAAC,CAAC,WAAW;QACzB,WAAW,EAAE,CAAC,CAAC,YAAY;QAC3B,QAAQ,EAAE,CAAC,CAAC,SAAkC;QAC9C,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,WAAW,EAAE,CAAC,CAAC,YAAY;QAC3B,cAAc,EAAE,CAAC,CAAC,eAAe;QACjC,MAAM,EAAE,CAAC,CAAC,MAA6B;QACvC,KAAK,EAAE,CAAC,CAAC,aAAa;KACvB,CAAA;AACH,CAAC;AAED,6GAA6G;AAC7G,MAAM,UAAU,mCAAmC,CACjD,KAAyD;IAEzD,MAAM,CAAC,GAAG,uBAAuB,CAAC,KAAgC,CAAC,CAAA;IACnE,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,CAAC,YAAY,IAAI,CAAC,CAAW,CAAA;IAChE,IAAI,EAAE,GAAsB,UAAU,CAAA;IACtC,mHAAmH;IACnH,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,IAAI,CAAC,CAAC,MAAM,KAAK,eAAe;QAAE,EAAE,GAAG,UAAU,CAAA;SACvE,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ;QAAE,EAAE,GAAG,QAAQ,CAAA;SACxC,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;QAAE,EAAE,GAAG,SAAS,CAAA;IAC5C,OAAO;QACL,KAAK,EAAE,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU;QACrD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;QACzB,eAAe,EAAE,CAAC;QAClB,UAAU,EAAE,CAAC;QACb,aAAa,EAAE,CAAC,CAAC,SAAS,IAAI,KAAK;QACnC,YAAY,EAAE,CAAC,CAAC,aAAa;KAC9B,CAAA;AACH,CAAC","sourcesContent":["import type {OtaProgress, OtaProgressStatus, OtaStatus} from \"@mentra/bluetooth-sdk\"\n\n/** Normalized ota_status fields (snake_case) after bridging Core/expo (snake or camel). */\nexport type NormalizedOtaStatusEvent = {\n session_id: string\n total_steps: number\n current_step: number\n step_type: string\n phase: \"download\" | \"install\"\n step_percent: number\n overall_percent: number\n status: string\n error_message?: string\n}\n\n/**\n * Core may deliver ota_status with snake_case (Android) or camelCase (some bridge paths).\n * Use this for Mantle and legacy otaProgress mapping.\n */\nexport function normalizeOtaStatusEvent(event: Record<string, unknown>): NormalizedOtaStatusEvent {\n const e = event as Record<string, any>\n const phase: \"download\" | \"install\" = e?.phase === \"install\" ? \"install\" : \"download\"\n const err = e?.error_message ?? e?.errorMessage\n return {\n session_id: String(e?.session_id ?? e?.sessionId ?? \"\"),\n total_steps: Number(e?.total_steps ?? e?.totalSteps ?? 0),\n current_step: Number(e?.current_step ?? e?.currentStep ?? 0),\n step_type: String(e?.step_type ?? e?.stepType ?? \"apk\"),\n phase,\n step_percent: Number(e?.step_percent ?? e?.stepPercent ?? 0),\n overall_percent: Number(e?.overall_percent ?? e?.overallPercent ?? 0),\n status: String(e?.status ?? \"idle\"),\n error_message: err == null || err === \"\" ? undefined : String(err),\n }\n}\n\nexport function otaStatusFromNormalized(n: NormalizedOtaStatusEvent): OtaStatus {\n return {\n sessionId: n.session_id,\n totalSteps: n.total_steps,\n currentStep: n.current_step,\n stepType: n.step_type as OtaStatus[\"stepType\"],\n phase: n.phase,\n stepPercent: n.step_percent,\n overallPercent: n.overall_percent,\n status: n.status as OtaStatus[\"status\"],\n error: n.error_message,\n }\n}\n\n/** Maps unified ota_status from Core into the legacy otaProgress store shape (progress-legacy, settings). */\nexport function legacyOtaProgressFromOtaStatusEvent(\n event: Record<string, unknown> | NormalizedOtaStatusEvent,\n): OtaProgress {\n const n = normalizeOtaStatusEvent(event as Record<string, unknown>)\n const raw = (n.overall_percent ?? n.step_percent ?? 0) as number\n let st: OtaProgressStatus = \"PROGRESS\"\n // Native K900 BES OTA (sr_adota) sends step_complete, not complete, on success — map for progress-legacy FINISHED.\n if (n.status === \"complete\" || n.status === \"step_complete\") st = \"FINISHED\"\n else if (n.status === \"failed\") st = \"FAILED\"\n else if (n.status === \"idle\") st = \"STARTED\"\n return {\n stage: n.phase === \"install\" ? \"install\" : \"download\",\n status: st,\n progress: Math.round(raw),\n bytesDownloaded: 0,\n totalBytes: 0,\n currentUpdate: n.step_type || \"apk\",\n errorMessage: n.error_message,\n }\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function isLegacyAsgOtaStartBuild(glassesBuildNumber?: string | null): boolean;
|
|
2
|
+
export declare function selectModernOtaManifestPin({ developerOverride, hostReleasePin, engineReleasePin, }: {
|
|
3
|
+
developerOverride?: string | null;
|
|
4
|
+
hostReleasePin?: string | null;
|
|
5
|
+
engineReleasePin?: string | null;
|
|
6
|
+
}): string | null;
|
|
7
|
+
export declare function resolveOtaManifestPolicy({ glassesUrl, glassesBuildNumber, developerOverride, hostReleasePin, engineReleasePin, }: {
|
|
8
|
+
glassesUrl?: string | null;
|
|
9
|
+
glassesBuildNumber?: string | null;
|
|
10
|
+
developerOverride?: string | null;
|
|
11
|
+
hostReleasePin?: string | null;
|
|
12
|
+
engineReleasePin?: string | null;
|
|
13
|
+
}): string | null;
|
|
14
|
+
//# sourceMappingURL=otaManifestPolicy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otaManifestPolicy.d.ts","sourceRoot":"","sources":["../../src/services/otaManifestPolicy.ts"],"names":[],"mappings":"AAOA,wBAAgB,wBAAwB,CAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAGpF;AAED,wBAAgB,0BAA0B,CAAC,EACzC,iBAAiB,EACjB,cAAc,EACd,gBAAgB,GACjB,EAAE;IACD,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACjC,GAAG,MAAM,GAAG,IAAI,CAEhB;AAED,wBAAgB,wBAAwB,CAAC,EACvC,UAAU,EACV,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,gBAAgB,GACjB,EAAE;IACD,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACjC,GAAG,MAAM,GAAG,IAAI,CAKhB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const OTA_VERSION_URL_LEGACY_PROD = "https://ota.mentraglass.com/prod_live_version.json";
|
|
2
|
+
function trimmed(value) {
|
|
3
|
+
const result = value?.trim();
|
|
4
|
+
return result || null;
|
|
5
|
+
}
|
|
6
|
+
export function isLegacyAsgOtaStartBuild(glassesBuildNumber) {
|
|
7
|
+
const buildNumber = Number.parseInt(glassesBuildNumber ?? "", 10);
|
|
8
|
+
return Number.isFinite(buildNumber) && buildNumber < 39;
|
|
9
|
+
}
|
|
10
|
+
export function selectModernOtaManifestPin({ developerOverride, hostReleasePin, engineReleasePin, }) {
|
|
11
|
+
return trimmed(developerOverride) || trimmed(hostReleasePin) || trimmed(engineReleasePin);
|
|
12
|
+
}
|
|
13
|
+
export function resolveOtaManifestPolicy({ glassesUrl, glassesBuildNumber, developerOverride, hostReleasePin, engineReleasePin, }) {
|
|
14
|
+
if (isLegacyAsgOtaStartBuild(glassesBuildNumber)) {
|
|
15
|
+
return trimmed(glassesUrl) || OTA_VERSION_URL_LEGACY_PROD;
|
|
16
|
+
}
|
|
17
|
+
return selectModernOtaManifestPin({ developerOverride, hostReleasePin, engineReleasePin });
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=otaManifestPolicy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otaManifestPolicy.js","sourceRoot":"","sources":["../../src/services/otaManifestPolicy.ts"],"names":[],"mappings":"AAAA,MAAM,2BAA2B,GAAG,oDAAoD,CAAA;AAExF,SAAS,OAAO,CAAC,KAAqB;IACpC,MAAM,MAAM,GAAG,KAAK,EAAE,IAAI,EAAE,CAAA;IAC5B,OAAO,MAAM,IAAI,IAAI,CAAA;AACvB,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,kBAAkC;IACzE,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,kBAAkB,IAAI,EAAE,EAAE,EAAE,CAAC,CAAA;IACjE,OAAO,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,WAAW,GAAG,EAAE,CAAA;AACzD,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,EACzC,iBAAiB,EACjB,cAAc,EACd,gBAAgB,GAKjB;IACC,OAAO,OAAO,CAAC,iBAAiB,CAAC,IAAI,OAAO,CAAC,cAAc,CAAC,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAA;AAC3F,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,EACvC,UAAU,EACV,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,gBAAgB,GAOjB;IACC,IAAI,wBAAwB,CAAC,kBAAkB,CAAC,EAAE,CAAC;QACjD,OAAO,OAAO,CAAC,UAAU,CAAC,IAAI,2BAA2B,CAAA;IAC3D,CAAC;IACD,OAAO,0BAA0B,CAAC,EAAC,iBAAiB,EAAE,cAAc,EAAE,gBAAgB,EAAC,CAAC,CAAA;AAC1F,CAAC","sourcesContent":["const OTA_VERSION_URL_LEGACY_PROD = \"https://ota.mentraglass.com/prod_live_version.json\"\n\nfunction trimmed(value?: string | null): string | null {\n const result = value?.trim()\n return result || null\n}\n\nexport function isLegacyAsgOtaStartBuild(glassesBuildNumber?: string | null): boolean {\n const buildNumber = Number.parseInt(glassesBuildNumber ?? \"\", 10)\n return Number.isFinite(buildNumber) && buildNumber < 39\n}\n\nexport function selectModernOtaManifestPin({\n developerOverride,\n hostReleasePin,\n engineReleasePin,\n}: {\n developerOverride?: string | null\n hostReleasePin?: string | null\n engineReleasePin?: string | null\n}): string | null {\n return trimmed(developerOverride) || trimmed(hostReleasePin) || trimmed(engineReleasePin)\n}\n\nexport function resolveOtaManifestPolicy({\n glassesUrl,\n glassesBuildNumber,\n developerOverride,\n hostReleasePin,\n engineReleasePin,\n}: {\n glassesUrl?: string | null\n glassesBuildNumber?: string | null\n developerOverride?: string | null\n hostReleasePin?: string | null\n engineReleasePin?: string | null\n}): string | null {\n if (isLegacyAsgOtaStartBuild(glassesBuildNumber)) {\n return trimmed(glassesUrl) || OTA_VERSION_URL_LEGACY_PROD\n }\n return selectModernOtaManifestPin({developerOverride, hostReleasePin, engineReleasePin})\n}\n"]}
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export declare function
|
|
1
|
+
export declare function hasConfiguredModernOtaManifestPin(): boolean;
|
|
2
|
+
export declare function resolveOtaManifestUrl(glassesUrl?: string | null, glassesBuildNumber?: string | null): string | null;
|
|
2
3
|
//# sourceMappingURL=otaManifestUrl.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"otaManifestUrl.d.ts","sourceRoot":"","sources":["../../src/services/otaManifestUrl.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"otaManifestUrl.d.ts","sourceRoot":"","sources":["../../src/services/otaManifestUrl.ts"],"names":[],"mappings":"AAyBA,wBAAgB,iCAAiC,IAAI,OAAO,CAQ3D;AAED,wBAAgB,qBAAqB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAQnH"}
|