@mentra/engine 3.1.0-dev.4 → 3.1.0-dev.40
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 +19 -5
- package/build/bluetooth-sdk/ota-transport.d.ts +2 -0
- package/build/bluetooth-sdk/ota-transport.d.ts.map +1 -0
- package/build/bluetooth-sdk/ota-transport.js +2 -0
- package/build/bluetooth-sdk/ota-transport.js.map +1 -0
- package/build/engine.d.ts +5 -2
- package/build/engine.d.ts.map +1 -1
- package/build/facades/ota.d.ts +9 -6
- package/build/facades/ota.d.ts.map +1 -1
- package/build/facades/ota.js +6 -4
- package/build/facades/ota.js.map +1 -1
- package/build/facades/pairing.d.ts +4 -0
- package/build/facades/pairing.d.ts.map +1 -1
- package/build/facades/pairing.js +81 -7
- package/build/facades/pairing.js.map +1 -1
- package/build/generated/releaseMetadata.js +5 -5
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js.map +1 -1
- package/build/react/MentraLiveOtaFlow.d.ts +3 -2
- package/build/react/MentraLiveOtaFlow.d.ts.map +1 -1
- package/build/react/MentraLiveOtaFlow.js +113 -352
- package/build/react/MentraLiveOtaFlow.js.map +1 -1
- package/build/react/index.d.ts +1 -0
- package/build/react/index.d.ts.map +1 -1
- package/build/react/index.js +1 -0
- package/build/react/index.js.map +1 -1
- package/build/react/useMentraLiveOta.d.ts +80 -0
- package/build/react/useMentraLiveOta.d.ts.map +1 -0
- package/build/react/useMentraLiveOta.js +550 -0
- package/build/react/useMentraLiveOta.js.map +1 -0
- package/build/services/BlobStore.d.ts +2 -0
- package/build/services/BlobStore.d.ts.map +1 -1
- package/build/services/BlobStore.js +63 -10
- package/build/services/BlobStore.js.map +1 -1
- package/build/services/GlassesStatusProjection.d.ts +15 -2
- package/build/services/GlassesStatusProjection.d.ts.map +1 -1
- package/build/services/GlassesStatusProjection.js +3 -3
- package/build/services/GlassesStatusProjection.js.map +1 -1
- package/build/services/HotspotOtaTransport.d.ts.map +1 -1
- package/build/services/HotspotOtaTransport.js +8 -7
- package/build/services/HotspotOtaTransport.js.map +1 -1
- package/build/services/OtaAutoChain.d.ts +9 -2
- package/build/services/OtaAutoChain.d.ts.map +1 -1
- package/build/services/OtaAutoChain.js +10 -2
- package/build/services/OtaAutoChain.js.map +1 -1
- package/build/services/OtaInstallCoordinator.d.ts +24 -3
- package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
- package/build/services/OtaInstallCoordinator.js +14 -12
- package/build/services/OtaInstallCoordinator.js.map +1 -1
- package/build/services/OtaService.d.ts.map +1 -1
- package/build/services/OtaService.js +1 -1
- package/build/services/OtaService.js.map +1 -1
- package/build/services/OtaUpdateCheckService.d.ts +4 -1
- package/build/services/OtaUpdateCheckService.d.ts.map +1 -1
- package/build/services/OtaUpdateCheckService.js +21 -5
- package/build/services/OtaUpdateCheckService.js.map +1 -1
- package/build/services/asg/localNetworkTransport.d.ts.map +1 -1
- package/build/services/asg/localNetworkTransport.js +13 -12
- package/build/services/asg/localNetworkTransport.js.map +1 -1
- package/build/services/glassesClockSync.js +1 -1
- package/build/services/glassesClockSync.js.map +1 -1
- package/build/services/otaReleaseVersion.d.ts +10 -0
- package/build/services/otaReleaseVersion.d.ts.map +1 -0
- package/build/services/otaReleaseVersion.js +14 -0
- package/build/services/otaReleaseVersion.js.map +1 -0
- package/build/stores/appVisibility.d.ts +3 -0
- package/build/stores/appVisibility.d.ts.map +1 -0
- package/build/stores/appVisibility.js +3 -0
- package/build/stores/appVisibility.js.map +1 -0
- package/build/stores/apps.d.ts.map +1 -1
- package/build/stores/apps.js +7 -1
- package/build/stores/apps.js.map +1 -1
- package/build/stores/core.d.ts +3 -3
- package/build/stores/core.d.ts.map +1 -1
- package/build/stores/core.js.map +1 -1
- package/build/stores/glasses.d.ts +10 -4
- package/build/stores/glasses.d.ts.map +1 -1
- package/build/stores/glasses.js.map +1 -1
- package/package.json +12 -6
- package/src/bluetooth-sdk/ota-transport.ts +1 -0
- package/src/facades/ota.ts +16 -5
- package/src/facades/pairing.ts +88 -12
- package/src/generated/releaseMetadata.ts +5 -5
- package/src/index.ts +1 -0
- package/src/react/MentraLiveOtaFlow.tsx +178 -465
- package/src/react/index.ts +14 -0
- package/src/react/useMentraLiveOta.ts +707 -0
- package/src/services/BlobStore.ts +57 -10
- package/src/services/GlassesStatusProjection.ts +7 -6
- package/src/services/HotspotOtaTransport.ts +8 -7
- package/src/services/OtaAutoChain.ts +26 -2
- package/src/services/OtaInstallCoordinator.ts +16 -13
- package/src/services/OtaService.ts +1 -2
- package/src/services/OtaUpdateCheckService.ts +26 -8
- package/src/services/asg/localNetworkTransport.ts +20 -19
- package/src/services/glassesClockSync.ts +1 -1
- package/src/services/otaReleaseVersion.ts +22 -0
- package/src/stores/appVisibility.ts +3 -0
- package/src/stores/apps.ts +7 -1
- package/src/stores/core.ts +4 -4
- package/src/stores/glasses.ts +13 -6
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import type { OtaCheckCurrentGlassesResult } from "./OtaUpdateCheckService";
|
|
2
2
|
export declare const MAX_OTA_AUTO_CHAIN_PASSES = 8;
|
|
3
3
|
export declare const OTA_AUTO_CHAIN_RECONNECT_TIMEOUT_MS = 120000;
|
|
4
|
+
export type OtaAutoChainReleaseRange = {
|
|
5
|
+
fromVersion: string | null;
|
|
6
|
+
toVersion: string | null;
|
|
7
|
+
/** Exact coordinated release identity for the OTA pin, absent for legacy manifests. */
|
|
8
|
+
releaseVersion?: string | null;
|
|
9
|
+
};
|
|
4
10
|
export type OtaAutoChainAdvanceResult = {
|
|
5
11
|
advance: true;
|
|
6
12
|
passCount: number;
|
|
@@ -15,8 +21,9 @@ export type OtaAutoChainAdvanceResult = {
|
|
|
15
21
|
*/
|
|
16
22
|
export declare function otaAutoChainFingerprint(result: OtaCheckCurrentGlassesResult): string;
|
|
17
23
|
/** Start a chain after the user explicitly approves its first update pass. */
|
|
18
|
-
export declare function beginOtaAutoChain(initialFingerprint: string, approvedDowngrade: boolean): void;
|
|
24
|
+
export declare function beginOtaAutoChain(initialFingerprint: string, approvedDowngrade: boolean, releaseRange: OtaAutoChainReleaseRange): void;
|
|
19
25
|
export declare function isOtaAutoChainActive(): boolean;
|
|
26
|
+
export declare function otaAutoChainReleaseRange(): OtaAutoChainReleaseRange | null;
|
|
20
27
|
/** End the current chain. Safe to call when no chain is active. */
|
|
21
28
|
export declare function stopOtaAutoChain(): void;
|
|
22
29
|
/**
|
|
@@ -30,5 +37,5 @@ export declare function clearOtaAutoChainReconnectWait(): void;
|
|
|
30
37
|
* Admit the next pass of an active chain. Repeated offers, unexpectedly
|
|
31
38
|
* destructive downgrades, and runaway chains fail closed and end automation.
|
|
32
39
|
*/
|
|
33
|
-
export declare function tryAdvanceOtaAutoChain(fingerprint: string, isDowngrade: boolean): OtaAutoChainAdvanceResult;
|
|
40
|
+
export declare function tryAdvanceOtaAutoChain(fingerprint: string, isDowngrade: boolean, targetVersion: string | null, releaseVersion?: string | null): OtaAutoChainAdvanceResult;
|
|
34
41
|
//# sourceMappingURL=OtaAutoChain.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OtaAutoChain.d.ts","sourceRoot":"","sources":["../../src/services/OtaAutoChain.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,4BAA4B,EAAC,MAAM,yBAAyB,CAAA;AAEzE,eAAO,MAAM,yBAAyB,IAAI,CAAA;AAC1C,eAAO,MAAM,mCAAmC,SAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"OtaAutoChain.d.ts","sourceRoot":"","sources":["../../src/services/OtaAutoChain.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,4BAA4B,EAAC,MAAM,yBAAyB,CAAA;AAEzE,eAAO,MAAM,yBAAyB,IAAI,CAAA;AAC1C,eAAO,MAAM,mCAAmC,SAAU,CAAA;AAU1D,MAAM,MAAM,wBAAwB,GAAG;IACrC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,uFAAuF;IACvF,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC/B,CAAA;AAED,MAAM,MAAM,yBAAyB,GACjC;IAAC,OAAO,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAC,GAClC;IAAC,OAAO,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,UAAU,GAAG,WAAW,GAAG,YAAY,GAAG,wBAAwB,CAAA;CAAC,CAAA;AAIhG;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,4BAA4B,GAAG,MAAM,CAkBpF;AAED,8EAA8E;AAC9E,wBAAgB,iBAAiB,CAC/B,kBAAkB,EAAE,MAAM,EAC1B,iBAAiB,EAAE,OAAO,EAC1B,YAAY,EAAE,wBAAwB,GACrC,IAAI,CAQN;AAED,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AAED,wBAAgB,wBAAwB,IAAI,wBAAwB,GAAG,IAAI,CAE1E;AAED,mEAAmE;AACnE,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;AAED;;;GAGG;AACH,wBAAgB,kCAAkC,CAAC,GAAG,SAAoB,GAAG,MAAM,GAAG,IAAI,CAKzF;AAED,6EAA6E;AAC7E,wBAAgB,8BAA8B,IAAI,IAAI,CAErD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,OAAO,EACpB,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,cAAc,GAAE,MAAM,GAAG,IAAW,GACnC,yBAAyB,CAyB3B"}
|
|
@@ -26,10 +26,11 @@ export function otaAutoChainFingerprint(result) {
|
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
28
|
/** Start a chain after the user explicitly approves its first update pass. */
|
|
29
|
-
export function beginOtaAutoChain(initialFingerprint, approvedDowngrade) {
|
|
29
|
+
export function beginOtaAutoChain(initialFingerprint, approvedDowngrade, releaseRange) {
|
|
30
30
|
session = {
|
|
31
31
|
approvedDowngrade,
|
|
32
32
|
passCount: 1,
|
|
33
|
+
releaseRange: { ...releaseRange },
|
|
33
34
|
reconnectDeadline: null,
|
|
34
35
|
seenFingerprints: new Set([initialFingerprint]),
|
|
35
36
|
};
|
|
@@ -37,6 +38,9 @@ export function beginOtaAutoChain(initialFingerprint, approvedDowngrade) {
|
|
|
37
38
|
export function isOtaAutoChainActive() {
|
|
38
39
|
return session !== null;
|
|
39
40
|
}
|
|
41
|
+
export function otaAutoChainReleaseRange() {
|
|
42
|
+
return session ? { ...session.releaseRange } : null;
|
|
43
|
+
}
|
|
40
44
|
/** End the current chain. Safe to call when no chain is active. */
|
|
41
45
|
export function stopOtaAutoChain() {
|
|
42
46
|
session = null;
|
|
@@ -60,7 +64,7 @@ export function clearOtaAutoChainReconnectWait() {
|
|
|
60
64
|
* Admit the next pass of an active chain. Repeated offers, unexpectedly
|
|
61
65
|
* destructive downgrades, and runaway chains fail closed and end automation.
|
|
62
66
|
*/
|
|
63
|
-
export function tryAdvanceOtaAutoChain(fingerprint, isDowngrade) {
|
|
67
|
+
export function tryAdvanceOtaAutoChain(fingerprint, isDowngrade, targetVersion, releaseVersion = null) {
|
|
64
68
|
if (!session) {
|
|
65
69
|
return { advance: false, reason: "inactive" };
|
|
66
70
|
}
|
|
@@ -78,6 +82,10 @@ export function tryAdvanceOtaAutoChain(fingerprint, isDowngrade) {
|
|
|
78
82
|
}
|
|
79
83
|
session.seenFingerprints.add(fingerprint);
|
|
80
84
|
session.passCount += 1;
|
|
85
|
+
if (targetVersion)
|
|
86
|
+
session.releaseRange.toVersion = targetVersion;
|
|
87
|
+
if (releaseVersion)
|
|
88
|
+
session.releaseRange.releaseVersion = releaseVersion;
|
|
81
89
|
return { advance: true, passCount: session.passCount };
|
|
82
90
|
}
|
|
83
91
|
//# sourceMappingURL=OtaAutoChain.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OtaAutoChain.js","sourceRoot":"","sources":["../../src/services/OtaAutoChain.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAA;AAC1C,MAAM,CAAC,MAAM,mCAAmC,GAAG,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"OtaAutoChain.js","sourceRoot":"","sources":["../../src/services/OtaAutoChain.ts"],"names":[],"mappings":"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","sourcesContent":["import type {OtaCheckCurrentGlassesResult} from \"./OtaUpdateCheckService\"\n\nexport const MAX_OTA_AUTO_CHAIN_PASSES = 8\nexport const OTA_AUTO_CHAIN_RECONNECT_TIMEOUT_MS = 120_000\n\ntype OtaAutoChainSession = {\n approvedDowngrade: boolean\n passCount: number\n releaseRange: OtaAutoChainReleaseRange\n reconnectDeadline: number | null\n seenFingerprints: Set<string>\n}\n\nexport type OtaAutoChainReleaseRange = {\n fromVersion: string | null\n toVersion: string | null\n /** Exact coordinated release identity for the OTA pin, absent for legacy manifests. */\n releaseVersion?: string | null\n}\n\nexport type OtaAutoChainAdvanceResult =\n | {advance: true; passCount: number}\n | {advance: false; reason: \"inactive\" | \"duplicate\" | \"max_passes\" | \"downgrade_not_approved\"}\n\nlet session: OtaAutoChainSession | null = null\n\n/**\n * Identify the exact update offer that produced one OTA pass. Including the\n * observed versions and manifest body lets a changed manifest advance while a\n * stale post-install version_info response is rejected as a duplicate.\n */\nexport function otaAutoChainFingerprint(result: OtaCheckCurrentGlassesResult): string {\n return JSON.stringify({\n manifestUrl: result.manifestUrl ?? \"\",\n manifestBody: result.manifestBody ?? \"\",\n buildNumber: result.buildNumber ?? \"\",\n mtkFirmwareVersion: result.mtkFirmwareVersion ?? \"\",\n besFirmwareVersion: result.besFirmwareVersion ?? \"\",\n updates: result.updates,\n targetBuildNumber: result.updateInfo?.versionCode ?? result.latestVersionInfo?.versionCode ?? 0,\n targetBesVersion: result.besVersion ?? \"\",\n mtkPatch: result.mtkPatch\n ? {\n startFirmware: result.mtkPatch.start_firmware,\n endFirmware: result.mtkPatch.end_firmware,\n url: result.mtkPatch.url,\n }\n : null,\n })\n}\n\n/** Start a chain after the user explicitly approves its first update pass. */\nexport function beginOtaAutoChain(\n initialFingerprint: string,\n approvedDowngrade: boolean,\n releaseRange: OtaAutoChainReleaseRange,\n): void {\n session = {\n approvedDowngrade,\n passCount: 1,\n releaseRange: {...releaseRange},\n reconnectDeadline: null,\n seenFingerprints: new Set([initialFingerprint]),\n }\n}\n\nexport function isOtaAutoChainActive(): boolean {\n return session !== null\n}\n\nexport function otaAutoChainReleaseRange(): OtaAutoChainReleaseRange | null {\n return session ? {...session.releaseRange} : null\n}\n\n/** End the current chain. Safe to call when no chain is active. */\nexport function stopOtaAutoChain(): void {\n session = null\n}\n\n/**\n * Start (or continue) the bounded wait for glasses that are rebooting between\n * passes. Re-renders must not extend the original deadline indefinitely.\n */\nexport function otaAutoChainReconnectWaitRemaining(now = performance.now()): number | null {\n if (!session) return null\n\n session.reconnectDeadline ??= now + OTA_AUTO_CHAIN_RECONNECT_TIMEOUT_MS\n return Math.max(0, session.reconnectDeadline - now)\n}\n\n/** A successful reconnect allows a future pass to establish a fresh wait. */\nexport function clearOtaAutoChainReconnectWait(): void {\n if (session) session.reconnectDeadline = null\n}\n\n/**\n * Admit the next pass of an active chain. Repeated offers, unexpectedly\n * destructive downgrades, and runaway chains fail closed and end automation.\n */\nexport function tryAdvanceOtaAutoChain(\n fingerprint: string,\n isDowngrade: boolean,\n targetVersion: string | null,\n releaseVersion: string | null = null,\n): OtaAutoChainAdvanceResult {\n if (!session) {\n return {advance: false, reason: \"inactive\"}\n }\n\n if (isDowngrade && !session.approvedDowngrade) {\n stopOtaAutoChain()\n return {advance: false, reason: \"downgrade_not_approved\"}\n }\n\n if (session.seenFingerprints.has(fingerprint)) {\n stopOtaAutoChain()\n return {advance: false, reason: \"duplicate\"}\n }\n\n if (session.passCount >= MAX_OTA_AUTO_CHAIN_PASSES) {\n stopOtaAutoChain()\n return {advance: false, reason: \"max_passes\"}\n }\n\n session.seenFingerprints.add(fingerprint)\n session.passCount += 1\n if (targetVersion) session.releaseRange.toVersion = targetVersion\n if (releaseVersion) session.releaseRange.releaseVersion = releaseVersion\n return {advance: true, passCount: session.passCount}\n}\n"]}
|
|
@@ -1,4 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* OtaInstallCoordinator — engine-owned OTA install state machine (WP 8B).
|
|
3
|
+
*
|
|
4
|
+
* Owns every timer/retry/sequencing rule that used to live in the host screen
|
|
5
|
+
* `mobile/src/app/ota/progress.tsx`: the global session timeout, serialized
|
|
6
|
+
* ota_start retries, the stuck-at-zero watchdog, the progress-stall watchdog keyed
|
|
7
|
+
* on a staleness signature, connect-edge arbitration (initial mount vs
|
|
8
|
+
* reconnect vs post-APK reboot), the ota_query_status reply fallback, the ping
|
|
9
|
+
* keepalive, the ota_start_ack / mtk_update_complete listeners, and terminal
|
|
10
|
+
* cleanup. The host progress screen is a pure renderer over
|
|
11
|
+
* `snapshot()`/`onSnapshot()` plus the `attach()/detach()/retry()/finish()`
|
|
12
|
+
* commands (exposed as `engine.ota.installSession`).
|
|
13
|
+
*
|
|
14
|
+
* The reaction pass mirrors the old component's effect ordering: a
|
|
15
|
+
* pass diffs the store-derived inputs (connected / otaStatus / otaProgress /
|
|
16
|
+
* displayState / stall signature) exactly like the old effect dep arrays, and
|
|
17
|
+
* state written mid-pass queues a follow-up pass — the same way a setState
|
|
18
|
+
* during React effects scheduled a re-render after the current effect batch.
|
|
19
|
+
*/
|
|
20
|
+
import { type OtaProgress, type OtaStatus } from "@mentra/bluetooth-sdk";
|
|
2
21
|
import { type HotspotOtaPhase } from "./HotspotOtaTransport";
|
|
3
22
|
import type { OtaCheckCurrentGlassesResult } from "./OtaUpdateCheckService";
|
|
4
23
|
import { type DisplayState } from "./otaDisplayState";
|
|
@@ -30,6 +49,8 @@ export interface OtaInstallSnapshot {
|
|
|
30
49
|
/** Pre-ota_start phone staging/join state for a hotspot attempt. */
|
|
31
50
|
hotspotPhase: HotspotOtaPhase;
|
|
32
51
|
hotspotArtifactPercent: number | null;
|
|
52
|
+
/** Transport selected from the checked glasses capabilities and Wi-Fi state. */
|
|
53
|
+
transport: "wifi" | "hotspot";
|
|
33
54
|
}
|
|
34
55
|
declare class OtaInstallCoordinator {
|
|
35
56
|
private attached;
|
|
@@ -106,14 +127,14 @@ declare class OtaInstallCoordinator {
|
|
|
106
127
|
* stays in the screen): clear the selected update, and after an APK step
|
|
107
128
|
* clear the stale build number so the next check re-reads version_info.
|
|
108
129
|
*/
|
|
109
|
-
finish(): void
|
|
130
|
+
finish(): Promise<void>;
|
|
110
131
|
/**
|
|
111
132
|
* Abandon an interrupted session (the super-mode skip): terminal cleanup
|
|
112
133
|
* plus dropping the session's status/progress read-state, so
|
|
113
134
|
* deriveDisplayState doesn't resurrect the stale install when the host
|
|
114
135
|
* navigates away and back through /ota routes.
|
|
115
136
|
*/
|
|
116
|
-
discard(): void
|
|
137
|
+
discard(): Promise<void>;
|
|
117
138
|
snapshot(): OtaInstallSnapshot;
|
|
118
139
|
/**
|
|
119
140
|
* True while the recovery worker owns the downgrade transaction (after the apk install
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OtaInstallCoordinator.d.ts","sourceRoot":"","sources":["../../src/services/OtaInstallCoordinator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"OtaInstallCoordinator.d.ts","sourceRoot":"","sources":["../../src/services/OtaInstallCoordinator.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* state written mid-pass queues a follow-up pass — the same way a setState
|
|
18
18
|
* during React effects scheduled a re-render after the current effect batch.
|
|
19
19
|
*/
|
|
20
|
-
import BluetoothSdk from "@mentra/bluetooth-sdk
|
|
20
|
+
import BluetoothSdk from "@mentra/bluetooth-sdk";
|
|
21
21
|
import GlobalEventEmitter from "../utils/GlobalEventEmitter";
|
|
22
22
|
import { isGlassesConnected, useGlassesStore } from "../stores/glasses";
|
|
23
23
|
import { resolveOtaManifestUrl } from "./otaManifestUrl";
|
|
@@ -306,7 +306,7 @@ class OtaInstallCoordinator {
|
|
|
306
306
|
void this.sendOtaStartWithWatchdogs();
|
|
307
307
|
}
|
|
308
308
|
else {
|
|
309
|
-
void BluetoothSdk.
|
|
309
|
+
void BluetoothSdk.queryOtaStatus().catch(() => { });
|
|
310
310
|
this.armQueryReplyFallback("retry");
|
|
311
311
|
}
|
|
312
312
|
}
|
|
@@ -349,16 +349,17 @@ class OtaInstallCoordinator {
|
|
|
349
349
|
* stays in the screen): clear the selected update, and after an APK step
|
|
350
350
|
* clear the stale build number so the next check re-reads version_info.
|
|
351
351
|
*/
|
|
352
|
-
finish() {
|
|
352
|
+
async finish() {
|
|
353
353
|
if (this.otaStartOwnership?.outcome !== "pending") {
|
|
354
354
|
this.otaStartOwnership = null;
|
|
355
355
|
}
|
|
356
356
|
useGlassesStore.getState().setOtaUpdateAvailable(null);
|
|
357
357
|
if (this.apkStepSeen) {
|
|
358
|
-
BluetoothSdk.updateGlasses({ buildNumber: "" });
|
|
359
358
|
useGlassesStore.getState().setGlassesInfo({ buildNumber: "" });
|
|
360
359
|
}
|
|
361
|
-
|
|
360
|
+
// The post-install check needs internet again. Do not let callers leave the
|
|
361
|
+
// terminal screen while Android still owns the no-internet hotspot route.
|
|
362
|
+
await this.teardownHotspotTransport();
|
|
362
363
|
}
|
|
363
364
|
/**
|
|
364
365
|
* Abandon an interrupted session (the super-mode skip): terminal cleanup
|
|
@@ -366,8 +367,8 @@ class OtaInstallCoordinator {
|
|
|
366
367
|
* deriveDisplayState doesn't resurrect the stale install when the host
|
|
367
368
|
* navigates away and back through /ota routes.
|
|
368
369
|
*/
|
|
369
|
-
discard() {
|
|
370
|
-
this.finish();
|
|
370
|
+
async discard() {
|
|
371
|
+
await this.finish();
|
|
371
372
|
const store = useGlassesStore.getState();
|
|
372
373
|
store.setOtaStatus(null);
|
|
373
374
|
store.setOtaProgress(null);
|
|
@@ -403,6 +404,7 @@ class OtaInstallCoordinator {
|
|
|
403
404
|
versionChangePhase: this.deriveVersionChangePhase(connected),
|
|
404
405
|
hotspotPhase: this.hotspotPhase,
|
|
405
406
|
hotspotArtifactPercent: this.hotspotArtifactPercent,
|
|
407
|
+
transport: this.selectedTransport,
|
|
406
408
|
};
|
|
407
409
|
}
|
|
408
410
|
/**
|
|
@@ -908,7 +910,7 @@ class OtaInstallCoordinator {
|
|
|
908
910
|
if (this.otaStartOwnership?.outcome === "pending") {
|
|
909
911
|
void this.sendOtaStartWithWatchdogs();
|
|
910
912
|
}
|
|
911
|
-
void BluetoothSdk.
|
|
913
|
+
void BluetoothSdk.queryOtaStatus().catch(() => { });
|
|
912
914
|
this.armQueryReplyFallback("reconnect");
|
|
913
915
|
return true;
|
|
914
916
|
}
|
|
@@ -946,7 +948,7 @@ class OtaInstallCoordinator {
|
|
|
946
948
|
if (noSessionYet) {
|
|
947
949
|
if (!isIdleStatus && this.otaStartOwnership?.outcome === "acknowledged") {
|
|
948
950
|
console.log("[OTA_PROGRESS] initial mount, acknowledged session has no cached status — reconciling");
|
|
949
|
-
void BluetoothSdk.
|
|
951
|
+
void BluetoothSdk.queryOtaStatus().catch(() => { });
|
|
950
952
|
this.armQueryReplyFallback("initial-mount");
|
|
951
953
|
return;
|
|
952
954
|
}
|
|
@@ -961,7 +963,7 @@ class OtaInstallCoordinator {
|
|
|
961
963
|
}
|
|
962
964
|
else {
|
|
963
965
|
console.log("[OTA_PROGRESS] initial mount, session exists, sending ota_query_status");
|
|
964
|
-
void BluetoothSdk.
|
|
966
|
+
void BluetoothSdk.queryOtaStatus().catch(() => { });
|
|
965
967
|
this.armQueryReplyFallback("initial-mount");
|
|
966
968
|
}
|
|
967
969
|
}
|
|
@@ -988,7 +990,7 @@ class OtaInstallCoordinator {
|
|
|
988
990
|
this.clearProgressTimeout();
|
|
989
991
|
this.onFirstActivity();
|
|
990
992
|
this.onFirstNonZeroProgress();
|
|
991
|
-
void BluetoothSdk.
|
|
993
|
+
void BluetoothSdk.queryOtaStatus().catch(() => { });
|
|
992
994
|
useGlassesStore.getState().setMtkUpdatedThisSession(true);
|
|
993
995
|
};
|
|
994
996
|
// --- legacy (< 37) compatibility, ported from progress-legacy.tsx (WP 8C) ---
|
|
@@ -1148,7 +1150,7 @@ class OtaInstallCoordinator {
|
|
|
1148
1150
|
const s = useGlassesStore.getState().otaStatus;
|
|
1149
1151
|
if (s?.stepType === "apk" && s.phase === "install" && s.status === "in_progress") {
|
|
1150
1152
|
this.apkInstallPollInFlight = true;
|
|
1151
|
-
void BluetoothSdk.
|
|
1153
|
+
void BluetoothSdk.queryOtaStatus()
|
|
1152
1154
|
.catch(() => { })
|
|
1153
1155
|
.finally(() => {
|
|
1154
1156
|
this.apkInstallPollInFlight = false;
|