@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.
Files changed (103) hide show
  1. package/README.md +19 -5
  2. package/build/bluetooth-sdk/ota-transport.d.ts +2 -0
  3. package/build/bluetooth-sdk/ota-transport.d.ts.map +1 -0
  4. package/build/bluetooth-sdk/ota-transport.js +2 -0
  5. package/build/bluetooth-sdk/ota-transport.js.map +1 -0
  6. package/build/engine.d.ts +5 -2
  7. package/build/engine.d.ts.map +1 -1
  8. package/build/facades/ota.d.ts +9 -6
  9. package/build/facades/ota.d.ts.map +1 -1
  10. package/build/facades/ota.js +6 -4
  11. package/build/facades/ota.js.map +1 -1
  12. package/build/facades/pairing.d.ts +4 -0
  13. package/build/facades/pairing.d.ts.map +1 -1
  14. package/build/facades/pairing.js +81 -7
  15. package/build/facades/pairing.js.map +1 -1
  16. package/build/generated/releaseMetadata.js +5 -5
  17. package/build/generated/releaseMetadata.js.map +1 -1
  18. package/build/index.d.ts +1 -1
  19. package/build/index.d.ts.map +1 -1
  20. package/build/index.js.map +1 -1
  21. package/build/react/MentraLiveOtaFlow.d.ts +3 -2
  22. package/build/react/MentraLiveOtaFlow.d.ts.map +1 -1
  23. package/build/react/MentraLiveOtaFlow.js +113 -352
  24. package/build/react/MentraLiveOtaFlow.js.map +1 -1
  25. package/build/react/index.d.ts +1 -0
  26. package/build/react/index.d.ts.map +1 -1
  27. package/build/react/index.js +1 -0
  28. package/build/react/index.js.map +1 -1
  29. package/build/react/useMentraLiveOta.d.ts +80 -0
  30. package/build/react/useMentraLiveOta.d.ts.map +1 -0
  31. package/build/react/useMentraLiveOta.js +550 -0
  32. package/build/react/useMentraLiveOta.js.map +1 -0
  33. package/build/services/BlobStore.d.ts +2 -0
  34. package/build/services/BlobStore.d.ts.map +1 -1
  35. package/build/services/BlobStore.js +63 -10
  36. package/build/services/BlobStore.js.map +1 -1
  37. package/build/services/GlassesStatusProjection.d.ts +15 -2
  38. package/build/services/GlassesStatusProjection.d.ts.map +1 -1
  39. package/build/services/GlassesStatusProjection.js +3 -3
  40. package/build/services/GlassesStatusProjection.js.map +1 -1
  41. package/build/services/HotspotOtaTransport.d.ts.map +1 -1
  42. package/build/services/HotspotOtaTransport.js +8 -7
  43. package/build/services/HotspotOtaTransport.js.map +1 -1
  44. package/build/services/OtaAutoChain.d.ts +9 -2
  45. package/build/services/OtaAutoChain.d.ts.map +1 -1
  46. package/build/services/OtaAutoChain.js +10 -2
  47. package/build/services/OtaAutoChain.js.map +1 -1
  48. package/build/services/OtaInstallCoordinator.d.ts +24 -3
  49. package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
  50. package/build/services/OtaInstallCoordinator.js +14 -12
  51. package/build/services/OtaInstallCoordinator.js.map +1 -1
  52. package/build/services/OtaService.d.ts.map +1 -1
  53. package/build/services/OtaService.js +1 -1
  54. package/build/services/OtaService.js.map +1 -1
  55. package/build/services/OtaUpdateCheckService.d.ts +4 -1
  56. package/build/services/OtaUpdateCheckService.d.ts.map +1 -1
  57. package/build/services/OtaUpdateCheckService.js +21 -5
  58. package/build/services/OtaUpdateCheckService.js.map +1 -1
  59. package/build/services/asg/localNetworkTransport.d.ts.map +1 -1
  60. package/build/services/asg/localNetworkTransport.js +13 -12
  61. package/build/services/asg/localNetworkTransport.js.map +1 -1
  62. package/build/services/glassesClockSync.js +1 -1
  63. package/build/services/glassesClockSync.js.map +1 -1
  64. package/build/services/otaReleaseVersion.d.ts +10 -0
  65. package/build/services/otaReleaseVersion.d.ts.map +1 -0
  66. package/build/services/otaReleaseVersion.js +14 -0
  67. package/build/services/otaReleaseVersion.js.map +1 -0
  68. package/build/stores/appVisibility.d.ts +3 -0
  69. package/build/stores/appVisibility.d.ts.map +1 -0
  70. package/build/stores/appVisibility.js +3 -0
  71. package/build/stores/appVisibility.js.map +1 -0
  72. package/build/stores/apps.d.ts.map +1 -1
  73. package/build/stores/apps.js +7 -1
  74. package/build/stores/apps.js.map +1 -1
  75. package/build/stores/core.d.ts +3 -3
  76. package/build/stores/core.d.ts.map +1 -1
  77. package/build/stores/core.js.map +1 -1
  78. package/build/stores/glasses.d.ts +10 -4
  79. package/build/stores/glasses.d.ts.map +1 -1
  80. package/build/stores/glasses.js.map +1 -1
  81. package/package.json +12 -6
  82. package/src/bluetooth-sdk/ota-transport.ts +1 -0
  83. package/src/facades/ota.ts +16 -5
  84. package/src/facades/pairing.ts +88 -12
  85. package/src/generated/releaseMetadata.ts +5 -5
  86. package/src/index.ts +1 -0
  87. package/src/react/MentraLiveOtaFlow.tsx +178 -465
  88. package/src/react/index.ts +14 -0
  89. package/src/react/useMentraLiveOta.ts +707 -0
  90. package/src/services/BlobStore.ts +57 -10
  91. package/src/services/GlassesStatusProjection.ts +7 -6
  92. package/src/services/HotspotOtaTransport.ts +8 -7
  93. package/src/services/OtaAutoChain.ts +26 -2
  94. package/src/services/OtaInstallCoordinator.ts +16 -13
  95. package/src/services/OtaService.ts +1 -2
  96. package/src/services/OtaUpdateCheckService.ts +26 -8
  97. package/src/services/asg/localNetworkTransport.ts +20 -19
  98. package/src/services/glassesClockSync.ts +1 -1
  99. package/src/services/otaReleaseVersion.ts +22 -0
  100. package/src/stores/appVisibility.ts +3 -0
  101. package/src/stores/apps.ts +7 -1
  102. package/src/stores/core.ts +4 -4
  103. package/src/stores/glasses.ts +13 -6
package/README.md CHANGED
@@ -33,14 +33,14 @@ resolve live TypeScript source):
33
33
  OTA policy constants, hardware capability tables, `BgTimer`). Judgment rule:
34
34
  read models, commands, pure functions and types are main; anything that
35
35
  mutates runtime state or exposes a store/service is not.
36
- - **`@mentra/engine/ota`** (`src/react/index.ts`) — shared full-screen OTA
37
- Native experiences. `MentraLiveOtaFlow` owns the complete check, hotspot or
38
- Wi-Fi install, APK/MTK/BES progress, reboot, retry, and final verification
39
- flow so hosts do not implement their own OTA state machines.
36
+ - **`@mentra/engine/ota`** (`src/react/index.ts`) — the complete Mentra Live OTA
37
+ controller plus its stock full-screen renderer. `useMentraLiveOta` owns the
38
+ check, hotspot or Wi-Fi install, APK/MTK/BES progress, reboot, retry, and final
39
+ verification behavior. `MentraLiveOtaFlow` renders that same public hook.
40
40
  - **`@mentra/engine/bluetooth-sdk`** (`src/bluetooth-sdk/index.ts`) — the
41
41
  complete public Bluetooth SDK surface, re-exported without a wrapper so it
42
42
  has the same singleton identity as `@mentra/bluetooth-sdk`. The supported
43
- SDK `react`, `types`, `photo-receiver`, and `debug` subpaths are mirrored
43
+ SDK `react`, `types`, `photo-receiver`, `ota-transport`, and `debug` subpaths are mirrored
44
44
  below this path. The SDK's `internal` entrypoint is deliberately not exposed.
45
45
 
46
46
  See `cloud-v2/docs/issues/020-glasses-status-boundary/integration-review.md`
@@ -82,6 +82,20 @@ the flow after a Mentra Live connects. Hosts must provide `onOpenWifiSetup`;
82
82
  the flow invokes it only for older glasses that cannot provide the OTA hotspot
83
83
  transport.
84
84
 
85
+ Apps that need different pages can render the same controller directly:
86
+
87
+ ```tsx
88
+ import {useMentraLiveOta} from "@mentra/engine/ota"
89
+
90
+ const ota = useMentraLiveOta({onFinished, onOpenWifiSetup})
91
+ // Render ota.state.screen and invoke ota.install(), retryInstall(), finish(), etc.
92
+ ```
93
+
94
+ Customize presentation only. Engine must remain responsible for OTA ordering,
95
+ hotspot staging, restart recovery, retries, and verification. The canonical
96
+ stock and custom integration guide is
97
+ [Update Mentra Live](https://docs.mentraglass.com/mentra-live/software-update).
98
+
85
99
  Released Engine packages contain a literal immutable OTA manifest URL and
86
100
  SHA-256 generated by coordinated release CI. Modern-glasses manifest selection
87
101
  is developer override, host-app release pin, then Engine release pin. It does
@@ -0,0 +1,2 @@
1
+ export * from "@mentra/bluetooth-sdk/ota-transport";
2
+ //# sourceMappingURL=ota-transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ota-transport.d.ts","sourceRoot":"","sources":["../../src/bluetooth-sdk/ota-transport.ts"],"names":[],"mappings":"AAAA,cAAc,qCAAqC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export * from "@mentra/bluetooth-sdk/ota-transport";
2
+ //# sourceMappingURL=ota-transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ota-transport.js","sourceRoot":"","sources":["../../src/bluetooth-sdk/ota-transport.ts"],"names":[],"mappings":"AAAA,cAAc,qCAAqC,CAAA","sourcesContent":["export * from \"@mentra/bluetooth-sdk/ota-transport\"\n"]}
package/build/engine.d.ts CHANGED
@@ -144,6 +144,7 @@ export declare const engine: {
144
144
  install: (otaVersionUrl?: string | null) => Promise<import("@mentra/bluetooth-sdk").OtaStartAckEvent>;
145
145
  ping: () => Promise<void>;
146
146
  checkForUpdates: (options?: import(".").OtaCheckCurrentGlassesOptions) => Promise<import(".").OtaCheckCurrentGlassesResult>;
147
+ getReleaseChangelogs: (fromVersion?: string | null, toVersion?: string | null) => import("@mentra/bluetooth-sdk").ReleaseChangelog[];
147
148
  clearUpdateAvailable: () => void;
148
149
  clearProgress: () => void;
149
150
  replacePendingUpdateSequence: (updates: import("@mentra/bluetooth-sdk").OtaUpdateInfo["updates"]) => import("@mentra/bluetooth-sdk").OtaUpdateInfo | null;
@@ -154,8 +155,8 @@ export declare const engine: {
154
155
  attach: () => void;
155
156
  detach: () => void;
156
157
  retry: () => void;
157
- finish: () => void;
158
- discard: () => void;
158
+ finish: () => Promise<void>;
159
+ discard: () => Promise<void>;
159
160
  snapshot: () => import(".").OtaInstallSnapshot;
160
161
  onSnapshot: (cb: (snapshot: import(".").OtaInstallSnapshot) => void) => (() => void);
161
162
  };
@@ -201,6 +202,8 @@ export declare const engine: {
201
202
  pairing: {
202
203
  readiness: () => import("./facades/pairing").PairingReadinessSnapshot;
203
204
  onReadiness: (cb: (readiness: import("./facades/pairing").PairingReadinessSnapshot) => void) => (() => void);
205
+ targetReady: (options: Pick<import("./facades/pairing").PairingReadyWaitOptions, "deviceModel" | "deviceName">) => boolean;
206
+ onTargetReady: (options: Pick<import("./facades/pairing").PairingReadyWaitOptions, "deviceModel" | "deviceName">, cb: (ready: boolean) => void) => (() => void);
204
207
  identity: () => import(".").IdentitySnapshot;
205
208
  onIdentity: (cb: (identity: import(".").IdentitySnapshot) => void) => (() => void);
206
209
  markPendingSelection: (model: string) => import("typesafe-ts").AsyncResult<void, Error>;
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAC,SAAS,EAAkD,aAAa,EAAC,MAAM,qBAAqB,CAAA;AAmC5G,eAAO,MAAM,MAAM;IACjB,2EAA2E;;IAE3E,8EAA8E;;IAE9E;iDAC6C;;IA0E7C;;yCAEqC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA2BrC,mFAAmF;;;;;;;;IAEnF,sEAAsE;;;;;;;;;;;;IAEtE,qFAAqF;;;gBA7FlC,CAAC;mBAAiB,CAAC;;;gBAKhD,CAAC;mBAAiB,CAAC;;;;;;;;;;;;;;;;IA0FzC,qEAAqE;;;;IAErE,sFAAsF;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAEtF,6EAA6E;;;;;;;;;;;;IAE7E,iFAAiF;;;;;;;;;;;;;;;;;;;IAEjF,8CAA8C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAE9C,uDAAuD;;;;;;;;;;;;IAEvD,8EAA8E;;;;;;;IAE9E,qFAAqF;;;;;;;;;;;;;;CAGtF,CAAA"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAC,SAAS,EAAkD,aAAa,EAAC,MAAM,qBAAqB,CAAA;AAmC5G,eAAO,MAAM,MAAM;IACjB,2EAA2E;;IAE3E,8EAA8E;;IAE9E;iDAC6C;;IA0E7C;;yCAEqC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA2BrC,mFAAmF;;;;;;;;IAEnF,sEAAsE;;;;;;;;;;;;IAEtE,qFAAqF;;;gBA7FlC,CAAC;mBAAiB,CAAC;;;gBAKhD,CAAC;mBAAiB,CAAC;;;;;;;;;;;;;;;;IA0FzC,qEAAqE;;;;IAErE,sFAAsF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAEtF,6EAA6E;;;;;;;;;;;;IAE7E,iFAAiF;;;;;;;;;;;;;;;;;;;IAEjF,8CAA8C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAE9C,uDAAuD;;;;;;;;;;;;IAEvD,8EAA8E;;;;;;;IAE9E,qFAAqF;;;;;;;;;;;;;;CAGtF,CAAA"}
@@ -1,9 +1,10 @@
1
- import type { OtaProgress, OtaProgressStatus, OtaStartAckEvent, OtaStatus, OtaUpdateInfo } from "@mentra/bluetooth-sdk";
1
+ import type { OtaProgress, OtaProgressStatus, OtaStartAckEvent, OtaStatus, OtaUpdateInfo, ReleaseChangelog } from "@mentra/bluetooth-sdk";
2
2
  import { type OtaInstallSnapshot } from "../services/OtaInstallCoordinator";
3
3
  import { type OtaCheckCurrentGlassesOptions, type OtaCheckCurrentGlassesResult } from "../services/OtaUpdateCheckService";
4
4
  declare function projectSnapshot(): {
5
5
  connected: boolean;
6
6
  buildNumber: string | null;
7
+ appVersion: string | null;
7
8
  mtkFirmwareVersion: string | null;
8
9
  besFirmwareVersion: string | null;
9
10
  hotspotOtaVersion: number;
@@ -17,7 +18,7 @@ declare function projectSnapshot(): {
17
18
  mtkUpdatedThisSession: boolean;
18
19
  };
19
20
  export type OtaSnapshot = ReturnType<typeof projectSnapshot>;
20
- export type { OtaProgress, OtaProgressStatus, OtaStatus, OtaUpdateInfo, OtaInstallSnapshot, OtaCheckCurrentGlassesOptions, OtaCheckCurrentGlassesResult, };
21
+ export type { OtaProgress, OtaProgressStatus, OtaStatus, OtaUpdateInfo, ReleaseChangelog, OtaInstallSnapshot, OtaCheckCurrentGlassesOptions, OtaCheckCurrentGlassesResult, };
21
22
  export declare const ota: {
22
23
  /**
23
24
  * Start the device-status and OTA projections without starting the authenticated
@@ -39,6 +40,8 @@ export declare const ota: {
39
40
  ping: () => Promise<void>;
40
41
  /** Resolve and compare the current glasses against the OTA manifest, then update the OTA snapshot. */
41
42
  checkForUpdates: (options?: OtaCheckCurrentGlassesOptions) => Promise<OtaCheckCurrentGlassesResult>;
43
+ /** Return bundled release changelogs crossed between two coordinated product versions, newest first. */
44
+ getReleaseChangelogs: (fromVersion?: string | null, toVersion?: string | null) => ReleaseChangelog[];
42
45
  /** Clear the available-update prompt state. */
43
46
  clearUpdateAvailable: () => void;
44
47
  /** Clear active progress/status before entering a fresh install flow. */
@@ -76,10 +79,10 @@ export declare const ota: {
76
79
  detach: () => void;
77
80
  /** Retry after a failure: clear state and re-send ota_start (if connected). */
78
81
  retry: () => void;
79
- /** Terminal cleanup for Continue/Done (navigation stays in the screen). */
80
- finish: () => void;
81
- /** Abandon an interrupted session (super-mode skip): finish() + drop the session's status/progress. */
82
- discard: () => void;
82
+ /** Terminal cleanup for Continue/Done, including hotspot route teardown. */
83
+ finish: () => Promise<void>;
84
+ /** Abandon an interrupted session: await finish() then drop the session's status/progress. */
85
+ discard: () => Promise<void>;
83
86
  /** Current install read model (displayState/errorMsg/lockout + glasses OTA data). */
84
87
  snapshot: () => OtaInstallSnapshot;
85
88
  /** Subscribe to install snapshot changes (deduped on projected JSON). Returns an unsubscribe. */
@@ -1 +1 @@
1
- {"version":3,"file":"ota.d.ts","sourceRoot":"","sources":["../../src/facades/ota.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAC,WAAW,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,SAAS,EAAE,aAAa,EAAC,MAAM,uBAAuB,CAAA;AAGrH,OAAO,EAAwB,KAAK,kBAAkB,EAAC,MAAM,mCAAmC,CAAA;AAGhG,OAAO,EAEL,KAAK,6BAA6B,EAClC,KAAK,4BAA4B,EAClC,MAAM,mCAAmC,CAAA;AAE1C,iBAAS,eAAe;;;;;;;;;;;;;;EAiBvB;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAA;AAC5D,YAAY,EACV,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,aAAa,EACb,kBAAkB,EAClB,6BAA6B,EAC7B,4BAA4B,GAC7B,CAAA;AAED,eAAO,MAAM,GAAG;IAEd;;;;OAIG;;IAMH;;;;;OAKG;8BACuB,MAAM,GAAG,IAAI,KAAG,OAAO,CAAC,gBAAgB,CAAC;IAQnE;;;OAGG;;IAEH,sGAAsG;gCAC1E,6BAA6B;IACzD,+CAA+C;;IAE/C,yEAAyE;;IAMzE;;;;;OAKG;4CACqC,aAAa,CAAC,SAAS,CAAC,KAAG,aAAa,GAAG,IAAI;IAQvF;;;;;OAKG;;IAKH;;;OAGG;yCACkC,OAAO;IAE5C;;;;OAIG;;QAED,oFAAoF;0BAClE,4BAA4B;QAC9C,2FAA2F;;QAE3F,+EAA+E;;QAE/E,+EAA+E;;QAE/E,2EAA2E;;QAE3E,uGAAuG;;QAEvG,qFAAqF;wBACvE,kBAAkB;QAChC,iGAAiG;yBAChF,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC;;IAGxE,8EAA8E;2BACzD,aAAa,GAAG,IAAI;IACzC,iFAAiF;kBACrE,SAAS,GAAG,IAAI;IAC5B,iEAAiE;oBACnD,WAAW;IAEzB,iGAAiG;4BACzE,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,KAAK,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC;IAU3E,uEAAuE;mBACxD,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,KAAK,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC;IAUhE,iEAAiE;qBAChD,CAAC,QAAQ,EAAE,WAAW,KAAK,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC;CAUhE,CAAA"}
1
+ {"version":3,"file":"ota.d.ts","sourceRoot":"","sources":["../../src/facades/ota.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,gBAAgB,EACjB,MAAM,uBAAuB,CAAA;AAG9B,OAAO,EAAwB,KAAK,kBAAkB,EAAC,MAAM,mCAAmC,CAAA;AAGhG,OAAO,EAEL,KAAK,6BAA6B,EAClC,KAAK,4BAA4B,EAClC,MAAM,mCAAmC,CAAA;AAE1C,iBAAS,eAAe;;;;;;;;;;;;;;;EAkBvB;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAA;AAC5D,YAAY,EACV,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,6BAA6B,EAC7B,4BAA4B,GAC7B,CAAA;AAED,eAAO,MAAM,GAAG;IAEd;;;;OAIG;;IAMH;;;;;OAKG;8BACuB,MAAM,GAAG,IAAI,KAAG,OAAO,CAAC,gBAAgB,CAAC;IAQnE;;;OAGG;;IAEH,sGAAsG;gCAC1E,6BAA6B;IACzD,wGAAwG;yCACnE,MAAM,GAAG,IAAI,cAAc,MAAM,GAAG,IAAI,KAAG,gBAAgB,EAAE;IAElG,+CAA+C;;IAE/C,yEAAyE;;IAMzE;;;;;OAKG;4CACqC,aAAa,CAAC,SAAS,CAAC,KAAG,aAAa,GAAG,IAAI;IAQvF;;;;;OAKG;;IAIH;;;OAGG;yCACkC,OAAO;IAE5C;;;;OAIG;;QAED,oFAAoF;0BAClE,4BAA4B;QAC9C,2FAA2F;;QAE3F,+EAA+E;;QAE/E,+EAA+E;;QAE/E,4EAA4E;;QAE5E,8FAA8F;;QAE9F,qFAAqF;wBACvE,kBAAkB;QAChC,iGAAiG;yBAChF,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC;;IAGxE,8EAA8E;2BACzD,aAAa,GAAG,IAAI;IACzC,iFAAiF;kBACrE,SAAS,GAAG,IAAI;IAC5B,iEAAiE;oBACnD,WAAW;IAEzB,iGAAiG;4BACzE,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,KAAK,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC;IAU3E,uEAAuE;mBACxD,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,KAAK,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC;IAUhE,iEAAiE;qBAChD,CAAC,QAAQ,EAAE,WAAW,KAAK,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC;CAUhE,CAAA"}
@@ -8,7 +8,7 @@
8
8
  * `installSession` fronts the OtaInstallCoordinator state machine (WP 8B) — the host
9
9
  * progress screen is a pure renderer over its snapshot + attach/detach/retry/finish.
10
10
  */
11
- import BluetoothSdk from "@mentra/bluetooth-sdk/internal";
11
+ import BluetoothSdk from "@mentra/bluetooth-sdk";
12
12
  import { isGlassesConnected, useGlassesStore } from "../stores/glasses";
13
13
  import { resolveOtaManifestUrl } from "../services/otaManifestUrl";
14
14
  import { otaInstallCoordinator } from "../services/OtaInstallCoordinator";
@@ -20,6 +20,7 @@ function projectSnapshot() {
20
20
  return {
21
21
  connected: isGlassesConnected(s.connection),
22
22
  buildNumber: s.buildNumber || null,
23
+ appVersion: s.appVersion || null,
23
24
  mtkFirmwareVersion: s.mtkFirmwareVersion || null,
24
25
  besFirmwareVersion: s.besFirmwareVersion || null,
25
26
  hotspotOtaVersion: s.hotspotOtaVersion ?? 0,
@@ -66,6 +67,8 @@ export const ota = {
66
67
  ping: () => BluetoothSdk.ping(),
67
68
  /** Resolve and compare the current glasses against the OTA manifest, then update the OTA snapshot. */
68
69
  checkForUpdates: (options) => checkCurrentGlassesForUpdate(options),
70
+ /** Return bundled release changelogs crossed between two coordinated product versions, newest first. */
71
+ getReleaseChangelogs: (fromVersion, toVersion) => BluetoothSdk.getReleaseChangelogs(fromVersion, toVersion),
69
72
  /** Clear the available-update prompt state. */
70
73
  clearUpdateAvailable: () => useGlassesStore.getState().setOtaUpdateAvailable(null),
71
74
  /** Clear active progress/status before entering a fresh install flow. */
@@ -96,7 +99,6 @@ export const ota = {
96
99
  * @deprecated Legacy progress route (build < 37) only — removed with WP 8D.
97
100
  */
98
101
  clearBuildNumberForNextCheck: () => {
99
- BluetoothSdk.updateGlasses({ buildNumber: "" });
100
102
  useGlassesStore.getState().setGlassesInfo({ buildNumber: "" });
101
103
  },
102
104
  /**
@@ -118,9 +120,9 @@ export const ota = {
118
120
  detach: () => otaInstallCoordinator.detach(),
119
121
  /** Retry after a failure: clear state and re-send ota_start (if connected). */
120
122
  retry: () => otaInstallCoordinator.retry(),
121
- /** Terminal cleanup for Continue/Done (navigation stays in the screen). */
123
+ /** Terminal cleanup for Continue/Done, including hotspot route teardown. */
122
124
  finish: () => otaInstallCoordinator.finish(),
123
- /** Abandon an interrupted session (super-mode skip): finish() + drop the session's status/progress. */
125
+ /** Abandon an interrupted session: await finish() then drop the session's status/progress. */
124
126
  discard: () => otaInstallCoordinator.discard(),
125
127
  /** Current install read model (displayState/errorMsg/lockout + glasses OTA data). */
126
128
  snapshot: () => otaInstallCoordinator.snapshot(),
@@ -1 +1 @@
1
- {"version":3,"file":"ota.js","sourceRoot":"","sources":["../../src/facades/ota.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ota facade — `engine.ota`: the OEM-facing OTA read/observe surface. Engine's\n * OtaService projects the glasses' OTA BLE events into the engine store; this facade\n * exposes the snapshot + change subscriptions behind the shared OTA flow exported by\n * `@mentra/engine/ota`. Hosts retain only their surrounding navigation and theme/i18n adapters.\n *\n * Availability checks live in engine. Install orchestration lives in engine too:\n * `installSession` fronts the OtaInstallCoordinator state machine (WP 8B) — the host\n * progress screen is a pure renderer over its snapshot + attach/detach/retry/finish.\n */\nimport BluetoothSdk from \"@mentra/bluetooth-sdk/internal\"\nimport type {OtaProgress, OtaProgressStatus, OtaStartAckEvent, OtaStatus, OtaUpdateInfo} from \"@mentra/bluetooth-sdk\"\nimport {isGlassesConnected, useGlassesStore} from \"../stores/glasses\"\nimport {resolveOtaManifestUrl} from \"../services/otaManifestUrl\"\nimport {otaInstallCoordinator, type OtaInstallSnapshot} from \"../services/OtaInstallCoordinator\"\nimport {startGlassesStatusProjection} from \"../services/GlassesStatusProjection\"\nimport {startOtaService} from \"../services/OtaService\"\nimport {\n checkCurrentGlassesForUpdate,\n type OtaCheckCurrentGlassesOptions,\n type OtaCheckCurrentGlassesResult,\n} from \"../services/OtaUpdateCheckService\"\n\nfunction projectSnapshot() {\n const s = useGlassesStore.getState()\n return {\n connected: isGlassesConnected(s.connection),\n buildNumber: s.buildNumber || null,\n mtkFirmwareVersion: s.mtkFirmwareVersion || null,\n besFirmwareVersion: s.besFirmwareVersion || null,\n hotspotOtaVersion: s.hotspotOtaVersion ?? 0,\n wifiConnected: s.wifi.state === \"connected\",\n wifiStatusKnown: s.wifiStatusKnown,\n manifestUrl: resolveOtaManifestUrl(s.otaVersionUrl, s.buildNumber),\n updateAvailable: s.otaUpdateAvailable,\n status: s.otaStatus,\n legacyProgress: s.otaProgress,\n inProgress: s.otaInProgress,\n mtkUpdatedThisSession: s.mtkUpdatedThisSession,\n }\n}\n\nexport type OtaSnapshot = ReturnType<typeof projectSnapshot>\nexport type {\n OtaProgress,\n OtaProgressStatus,\n OtaStatus,\n OtaUpdateInfo,\n OtaInstallSnapshot,\n OtaCheckCurrentGlassesOptions,\n OtaCheckCurrentGlassesResult,\n}\n\nexport const ota = {\n // --- actions ---\n /**\n * Start the device-status and OTA projections without starting the authenticated\n * cloud/miniapp runtime. This is the explicit entry point for Bluetooth-only hosts.\n * Idempotent and safe when the full engine runtime is already running.\n */\n initialize: async () => {\n const hydrated = startGlassesStatusProjection()\n startOtaService()\n await hydrated\n },\n /**\n * Start the firmware install with the resolved OTA manifest URL. Progress lands on\n * `status()`/`onStatus()`. (The host resolves the manifest URL — developer override,\n * host pin, or Engine release pin resolution stays with the OTA config; the stuck/retry watchdog is its own\n * resilience layer on top of this command.)\n */\n install: (otaVersionUrl?: string | null): Promise<OtaStartAckEvent> => BluetoothSdk.startOtaUpdate(otaVersionUrl),\n // Deferred: this facade entry was intended to become the engine-owned retry/check\n // action, but BluetoothSdk.checkForOtaUpdate() only returns a boolean. Exposing it\n // here would make callers think the rich otaUpdateAvailable read model is refreshed,\n // while the original view still depends on the host-side manifest compare to build\n // versionName/updates/totalSize. Keep that behavior unchanged until the whole rich\n // availability check moves into engine.\n // retry: () => BluetoothSdk.checkForOtaUpdate(),\n /**\n * Keep glasses awake while an OTA session is actively progressing.\n * @deprecated Legacy progress route (build < 37) only — removed with WP 8D.\n */\n ping: () => BluetoothSdk.ping(),\n /** Resolve and compare the current glasses against the OTA manifest, then update the OTA snapshot. */\n checkForUpdates: (options?: OtaCheckCurrentGlassesOptions) => checkCurrentGlassesForUpdate(options),\n /** Clear the available-update prompt state. */\n clearUpdateAvailable: () => useGlassesStore.getState().setOtaUpdateAvailable(null),\n /** Clear active progress/status before entering a fresh install flow. */\n clearProgress: () => {\n const store = useGlassesStore.getState()\n store.setOtaProgress(null)\n store.setOtaStatus(null)\n },\n /**\n * Replace the pending update sequence after an in-flow firmware revalidation.\n * Kept as a named OTA policy operation so host screens do not mutate the raw\n * glasses store.\n * @deprecated Legacy progress route (build < 37) only — removed with WP 8D.\n */\n replacePendingUpdateSequence: (updates: OtaUpdateInfo[\"updates\"]): OtaUpdateInfo | null => {\n const store = useGlassesStore.getState()\n const current = store.otaUpdateAvailable\n if (!current) return null\n const next = {...current, updates}\n store.setOtaUpdateAvailable(next)\n return next\n },\n /**\n * Clear stale build metadata before returning to the update-check screen.\n * This forces the next version_info event through both the native observable\n * store and the engine projection after an APK reboot.\n * @deprecated Legacy progress route (build < 37) only — removed with WP 8D.\n */\n clearBuildNumberForNextCheck: () => {\n BluetoothSdk.updateGlasses({buildNumber: \"\"})\n useGlassesStore.getState().setGlassesInfo({buildNumber: \"\"})\n },\n /**\n * Mark MTK as already applied during this app session until the glasses reboot/disconnect.\n * @deprecated Legacy progress route (build < 37) only — removed with WP 8D.\n */\n markMtkUpdatedThisSession: (updated: boolean) => useGlassesStore.getState().setMtkUpdatedThisSession(updated),\n\n /**\n * The OTA install state machine (unified `ota_status` sessions, build >= 37).\n * The host progress screen attaches on mount, detaches on unmount, and renders\n * the snapshot; every watchdog/retry/reconnect rule lives in the coordinator.\n */\n installSession: {\n /** Select Wi-Fi or capability-gated hotspot transport for this checked manifest. */\n prepare: (result: OtaCheckCurrentGlassesResult) => otaInstallCoordinator.prepare(result),\n /** Bind the machine to the mounted progress screen. Idempotent per attach/detach cycle. */\n attach: () => otaInstallCoordinator.attach(),\n /** Unbind on unmount: clears all timers/listeners and resets session state. */\n detach: () => otaInstallCoordinator.detach(),\n /** Retry after a failure: clear state and re-send ota_start (if connected). */\n retry: () => otaInstallCoordinator.retry(),\n /** Terminal cleanup for Continue/Done (navigation stays in the screen). */\n finish: () => otaInstallCoordinator.finish(),\n /** Abandon an interrupted session (super-mode skip): finish() + drop the session's status/progress. */\n discard: () => otaInstallCoordinator.discard(),\n /** Current install read model (displayState/errorMsg/lockout + glasses OTA data). */\n snapshot: (): OtaInstallSnapshot => otaInstallCoordinator.snapshot(),\n /** Subscribe to install snapshot changes (deduped on projected JSON). Returns an unsubscribe. */\n onSnapshot: (cb: (snapshot: OtaInstallSnapshot) => void): (() => void) => otaInstallCoordinator.onSnapshot(cb),\n },\n\n /** Current available-update info (versionName/updates/totalSize), or null. */\n updateAvailable: (): OtaUpdateInfo | null => useGlassesStore.getState().otaUpdateAvailable,\n /** Current OTA install status (stepType/phase/percent/status/error), or null. */\n status: (): OtaStatus | null => useGlassesStore.getState().otaStatus,\n /** Current OTA read model for update prompt/progress screens. */\n snapshot: (): OtaSnapshot => projectSnapshot(),\n\n /** Subscribe to OTA availability changes (info or null when cleared). Returns an unsubscribe. */\n onUpdateAvailable: (cb: (info: OtaUpdateInfo | null) => void): (() => void) => {\n let last = useGlassesStore.getState().otaUpdateAvailable\n return useGlassesStore.subscribe(() => {\n const info = useGlassesStore.getState().otaUpdateAvailable\n if (info === last) return\n last = info\n cb(info)\n })\n },\n\n /** Subscribe to OTA install status changes. Returns an unsubscribe. */\n onStatus: (cb: (status: OtaStatus | null) => void): (() => void) => {\n let last = useGlassesStore.getState().otaStatus\n return useGlassesStore.subscribe(() => {\n const status = useGlassesStore.getState().otaStatus\n if (status === last) return\n last = status\n cb(status)\n })\n },\n\n /** Subscribe to OTA snapshot changes. Returns an unsubscribe. */\n onSnapshot: (cb: (snapshot: OtaSnapshot) => void): (() => void) => {\n let last = JSON.stringify(projectSnapshot())\n return useGlassesStore.subscribe(() => {\n const snap = projectSnapshot()\n const key = JSON.stringify(snap)\n if (key === last) return\n last = key\n cb(snap)\n })\n },\n}\n"]}
1
+ {"version":3,"file":"ota.js","sourceRoot":"","sources":["../../src/facades/ota.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ota facade — `engine.ota`: the OEM-facing OTA read/observe surface. Engine's\n * OtaService projects the glasses' OTA BLE events into the engine store; this facade\n * exposes the snapshot + change subscriptions behind the shared OTA flow exported by\n * `@mentra/engine/ota`. Hosts retain only their surrounding navigation and theme/i18n adapters.\n *\n * Availability checks live in engine. Install orchestration lives in engine too:\n * `installSession` fronts the OtaInstallCoordinator state machine (WP 8B) — the host\n * progress screen is a pure renderer over its snapshot + attach/detach/retry/finish.\n */\nimport BluetoothSdk from \"@mentra/bluetooth-sdk\"\nimport type {\n OtaProgress,\n OtaProgressStatus,\n OtaStartAckEvent,\n OtaStatus,\n OtaUpdateInfo,\n ReleaseChangelog,\n} from \"@mentra/bluetooth-sdk\"\nimport {isGlassesConnected, useGlassesStore} from \"../stores/glasses\"\nimport {resolveOtaManifestUrl} from \"../services/otaManifestUrl\"\nimport {otaInstallCoordinator, type OtaInstallSnapshot} from \"../services/OtaInstallCoordinator\"\nimport {startGlassesStatusProjection} from \"../services/GlassesStatusProjection\"\nimport {startOtaService} from \"../services/OtaService\"\nimport {\n checkCurrentGlassesForUpdate,\n type OtaCheckCurrentGlassesOptions,\n type OtaCheckCurrentGlassesResult,\n} from \"../services/OtaUpdateCheckService\"\n\nfunction projectSnapshot() {\n const s = useGlassesStore.getState()\n return {\n connected: isGlassesConnected(s.connection),\n buildNumber: s.buildNumber || null,\n appVersion: s.appVersion || null,\n mtkFirmwareVersion: s.mtkFirmwareVersion || null,\n besFirmwareVersion: s.besFirmwareVersion || null,\n hotspotOtaVersion: s.hotspotOtaVersion ?? 0,\n wifiConnected: s.wifi.state === \"connected\",\n wifiStatusKnown: s.wifiStatusKnown,\n manifestUrl: resolveOtaManifestUrl(s.otaVersionUrl, s.buildNumber),\n updateAvailable: s.otaUpdateAvailable,\n status: s.otaStatus,\n legacyProgress: s.otaProgress,\n inProgress: s.otaInProgress,\n mtkUpdatedThisSession: s.mtkUpdatedThisSession,\n }\n}\n\nexport type OtaSnapshot = ReturnType<typeof projectSnapshot>\nexport type {\n OtaProgress,\n OtaProgressStatus,\n OtaStatus,\n OtaUpdateInfo,\n ReleaseChangelog,\n OtaInstallSnapshot,\n OtaCheckCurrentGlassesOptions,\n OtaCheckCurrentGlassesResult,\n}\n\nexport const ota = {\n // --- actions ---\n /**\n * Start the device-status and OTA projections without starting the authenticated\n * cloud/miniapp runtime. This is the explicit entry point for Bluetooth-only hosts.\n * Idempotent and safe when the full engine runtime is already running.\n */\n initialize: async () => {\n const hydrated = startGlassesStatusProjection()\n startOtaService()\n await hydrated\n },\n /**\n * Start the firmware install with the resolved OTA manifest URL. Progress lands on\n * `status()`/`onStatus()`. (The host resolves the manifest URL — developer override,\n * host pin, or Engine release pin resolution stays with the OTA config; the stuck/retry watchdog is its own\n * resilience layer on top of this command.)\n */\n install: (otaVersionUrl?: string | null): Promise<OtaStartAckEvent> => BluetoothSdk.startOtaUpdate(otaVersionUrl),\n // Deferred: this facade entry was intended to become the engine-owned retry/check\n // action, but BluetoothSdk.checkForOtaUpdate() only returns a boolean. Exposing it\n // here would make callers think the rich otaUpdateAvailable read model is refreshed,\n // while the original view still depends on the host-side manifest compare to build\n // versionName/updates/totalSize. Keep that behavior unchanged until the whole rich\n // availability check moves into engine.\n // retry: () => BluetoothSdk.checkForOtaUpdate(),\n /**\n * Keep glasses awake while an OTA session is actively progressing.\n * @deprecated Legacy progress route (build < 37) only — removed with WP 8D.\n */\n ping: () => BluetoothSdk.ping(),\n /** Resolve and compare the current glasses against the OTA manifest, then update the OTA snapshot. */\n checkForUpdates: (options?: OtaCheckCurrentGlassesOptions) => checkCurrentGlassesForUpdate(options),\n /** Return bundled release changelogs crossed between two coordinated product versions, newest first. */\n getReleaseChangelogs: (fromVersion?: string | null, toVersion?: string | null): ReleaseChangelog[] =>\n BluetoothSdk.getReleaseChangelogs(fromVersion, toVersion),\n /** Clear the available-update prompt state. */\n clearUpdateAvailable: () => useGlassesStore.getState().setOtaUpdateAvailable(null),\n /** Clear active progress/status before entering a fresh install flow. */\n clearProgress: () => {\n const store = useGlassesStore.getState()\n store.setOtaProgress(null)\n store.setOtaStatus(null)\n },\n /**\n * Replace the pending update sequence after an in-flow firmware revalidation.\n * Kept as a named OTA policy operation so host screens do not mutate the raw\n * glasses store.\n * @deprecated Legacy progress route (build < 37) only — removed with WP 8D.\n */\n replacePendingUpdateSequence: (updates: OtaUpdateInfo[\"updates\"]): OtaUpdateInfo | null => {\n const store = useGlassesStore.getState()\n const current = store.otaUpdateAvailable\n if (!current) return null\n const next = {...current, updates}\n store.setOtaUpdateAvailable(next)\n return next\n },\n /**\n * Clear stale build metadata before returning to the update-check screen.\n * This forces the next version_info event through both the native observable\n * store and the engine projection after an APK reboot.\n * @deprecated Legacy progress route (build < 37) only — removed with WP 8D.\n */\n clearBuildNumberForNextCheck: () => {\n useGlassesStore.getState().setGlassesInfo({buildNumber: \"\"})\n },\n /**\n * Mark MTK as already applied during this app session until the glasses reboot/disconnect.\n * @deprecated Legacy progress route (build < 37) only — removed with WP 8D.\n */\n markMtkUpdatedThisSession: (updated: boolean) => useGlassesStore.getState().setMtkUpdatedThisSession(updated),\n\n /**\n * The OTA install state machine (unified `ota_status` sessions, build >= 37).\n * The host progress screen attaches on mount, detaches on unmount, and renders\n * the snapshot; every watchdog/retry/reconnect rule lives in the coordinator.\n */\n installSession: {\n /** Select Wi-Fi or capability-gated hotspot transport for this checked manifest. */\n prepare: (result: OtaCheckCurrentGlassesResult) => otaInstallCoordinator.prepare(result),\n /** Bind the machine to the mounted progress screen. Idempotent per attach/detach cycle. */\n attach: () => otaInstallCoordinator.attach(),\n /** Unbind on unmount: clears all timers/listeners and resets session state. */\n detach: () => otaInstallCoordinator.detach(),\n /** Retry after a failure: clear state and re-send ota_start (if connected). */\n retry: () => otaInstallCoordinator.retry(),\n /** Terminal cleanup for Continue/Done, including hotspot route teardown. */\n finish: () => otaInstallCoordinator.finish(),\n /** Abandon an interrupted session: await finish() then drop the session's status/progress. */\n discard: () => otaInstallCoordinator.discard(),\n /** Current install read model (displayState/errorMsg/lockout + glasses OTA data). */\n snapshot: (): OtaInstallSnapshot => otaInstallCoordinator.snapshot(),\n /** Subscribe to install snapshot changes (deduped on projected JSON). Returns an unsubscribe. */\n onSnapshot: (cb: (snapshot: OtaInstallSnapshot) => void): (() => void) => otaInstallCoordinator.onSnapshot(cb),\n },\n\n /** Current available-update info (versionName/updates/totalSize), or null. */\n updateAvailable: (): OtaUpdateInfo | null => useGlassesStore.getState().otaUpdateAvailable,\n /** Current OTA install status (stepType/phase/percent/status/error), or null. */\n status: (): OtaStatus | null => useGlassesStore.getState().otaStatus,\n /** Current OTA read model for update prompt/progress screens. */\n snapshot: (): OtaSnapshot => projectSnapshot(),\n\n /** Subscribe to OTA availability changes (info or null when cleared). Returns an unsubscribe. */\n onUpdateAvailable: (cb: (info: OtaUpdateInfo | null) => void): (() => void) => {\n let last = useGlassesStore.getState().otaUpdateAvailable\n return useGlassesStore.subscribe(() => {\n const info = useGlassesStore.getState().otaUpdateAvailable\n if (info === last) return\n last = info\n cb(info)\n })\n },\n\n /** Subscribe to OTA install status changes. Returns an unsubscribe. */\n onStatus: (cb: (status: OtaStatus | null) => void): (() => void) => {\n let last = useGlassesStore.getState().otaStatus\n return useGlassesStore.subscribe(() => {\n const status = useGlassesStore.getState().otaStatus\n if (status === last) return\n last = status\n cb(status)\n })\n },\n\n /** Subscribe to OTA snapshot changes. Returns an unsubscribe. */\n onSnapshot: (cb: (snapshot: OtaSnapshot) => void): (() => void) => {\n let last = JSON.stringify(projectSnapshot())\n return useGlassesStore.subscribe(() => {\n const snap = projectSnapshot()\n const key = JSON.stringify(snap)\n if (key === last) return\n last = key\n cb(snap)\n })\n },\n}\n"]}
@@ -29,6 +29,10 @@ declare function waitForBluetoothClassic(options?: Pick<PairingReadyWaitOptions,
29
29
  export declare const pairing: {
30
30
  readiness: () => PairingReadinessSnapshot;
31
31
  onReadiness: (cb: (readiness: PairingReadinessSnapshot) => void) => (() => void);
32
+ /** Whether the exact wearable or controller selected on the scan screen is ready. */
33
+ targetReady: (options: Pick<PairingReadyWaitOptions, "deviceModel" | "deviceName">) => boolean;
34
+ /** Subscribe to readiness for the exact selected target, excluding stale devices. */
35
+ onTargetReady: (options: Pick<PairingReadyWaitOptions, "deviceModel" | "deviceName">, cb: (ready: boolean) => void) => (() => void);
32
36
  /** The identity lifecycle snapshot: none | pending (chosen, never paired) | paired. */
33
37
  identity: () => IdentitySnapshot;
34
38
  /** Subscribe to identity changes; fires only when the projected snapshot changes.
@@ -1 +1 @@
1
- {"version":3,"file":"pairing.d.ts","sourceRoot":"","sources":["../../src/facades/pairing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pairing.d.ts","sourceRoot":"","sources":["../../src/facades/pairing.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,oBAAoB,EAAC,MAAM,uBAAuB,CAAA;AAKtH,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,6BAA6B,CAAA;AAEpC,OAAO,EAGL,KAAK,+BAA+B,EACrC,MAAM,mCAAmC,CAAA;AAK1C,YAAY,EAAC,gBAAgB,EAAC,MAAM,6BAA6B,CAAA;AAEjE,MAAM,WAAW,uBAAuB;IACtC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAOD,iBAAS,gBAAgB;;;;;;EASxB;AA8ED,MAAM,MAAM,wBAAwB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAE1E,wBAAsB,8BAA8B,CAAC,MAAM,EAAE;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,kBAAkB,EAAE,OAAO,CAAA;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,GAAG,OAAO,CAAC,+BAA+B,CAAC,CA8B3C;AAED,iBAAe,yBAAyB,CAAC,OAAO,GAAE,uBAA4B,GAAG,OAAO,CAAC,OAAO,CAAC,CA0BhG;AAED,iBAAe,uBAAuB,CACpC,OAAO,GAAE,IAAI,CAAC,uBAAuB,EAAE,WAAW,GAAG,QAAQ,CAAM,GAClE,OAAO,CAAC,OAAO,CAAC,CA4ClB;AAED,eAAO,MAAM,OAAO;qBACH,wBAAwB;sBACrB,CAAC,SAAS,EAAE,wBAAwB,KAAK,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC;IAU9E,qFAAqF;2BAC9D,IAAI,CAAC,uBAAuB,EAAE,aAAa,GAAG,YAAY,CAAC,KAAG,OAAO;IAE5F,qFAAqF;6BAE1E,IAAI,CAAC,uBAAuB,EAAE,aAAa,GAAG,YAAY,CAAC,MAChE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,KAC3B,CAAC,MAAM,IAAI,CAAC;IAIf,uFAAuF;oBACzE,gBAAgB;IAC9B;iCAC6B;qBACZ,CAAC,QAAQ,EAAE,gBAAgB,KAAK,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC;IACpE;gFAC4E;kCAC9C,MAAM;IAEpC,wFAAwF;kBAC1E,WAAW,KAAG,OAAO,CAAC,IAAI,CAAC;IACzC,+CAA+C;oBACjC,OAAO;IACrB,iGAAiG;qBAChF,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC;IAC3D,0DAA0D;8BAClC,OAAO;IAC/B,4GAA4G;+BACjF,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC;IAErE,sGAAsG;4BAChF,OAAO;IAC7B,iHAAiH;6BACxF,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC;IAEpE,2CAA2C;;;;;;;;;;;;IAI3C,6FAA6F;kBAC/E,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC;IAYxD;;;;;;OAMG;mBACkB,MAAM,YAAY,cAAc,KAAG,OAAO,CAAC,IAAI,CAAC;IAIrE,6EAA6E;yBACxD,MAAM,GAAG,IAAI,KAAG,OAAO,CAAC,IAAI,CAAC;IAClD;;;;;;;;OAQG;wCACiC,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;IAE1D;;;;;;;;;;;;;;;;;;OAkBG;0BACuB,OAAO,CAAC,IAAI,CAAC;IAmCvC,6DAA6D;wBACzC,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC;IAIpE,oFAAoF;4BAC5D,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC;IAI5E,sFAAsF;;IAEtF,uEAAuE;;CAExE,CAAA"}
@@ -12,11 +12,13 @@
12
12
  import BluetoothSdk from "@mentra/bluetooth-sdk/internal";
13
13
  import { useCoreStore } from "../stores/core";
14
14
  import { useGlassesStore } from "../stores/glasses";
15
+ import { SETTINGS, useSettingsStore } from "../stores/settings";
15
16
  import { hasDefaultDevice } from "../services/DeviceStoreHydration";
16
17
  import { markPendingSelection, projectPairingIdentity, subscribePairingIdentity, } from "../services/PairingIdentity";
17
- import { isGlassesConnected, isGlassesLinkLayerBusy, isGlassesReady, waitForGlassesReady, } from "../services/GlassesReadiness";
18
+ import { isGlassesConnected, isGlassesLinkLayerBusy, isGlassesReady } from "../services/GlassesReadiness";
18
19
  import { logAutomaticReportSubmissionStatus, toAutomaticReportSubmissionStatus, } from "../services/AutomaticReportResult";
19
20
  import { pushAllBluetoothSettings } from "../services/GlassesSettingsSync";
21
+ import { ControllerTypes } from "../types";
20
22
  import { submitAutomaticReport } from "./reports";
21
23
  const DEFAULT_PAIRING_BOOT_TIMEOUT_MS = 35_000;
22
24
  const DEFAULT_BT_CLASSIC_TIMEOUT_MS = 1_000;
@@ -32,6 +34,79 @@ function projectReadiness() {
32
34
  nativeLinkBusy: isGlassesLinkLayerBusy(s.connection),
33
35
  };
34
36
  }
37
+ function projectTargetReady(options) {
38
+ const { deviceModel, deviceName } = options;
39
+ const glasses = useGlassesStore.getState();
40
+ if (deviceModel === ControllerTypes.R1) {
41
+ if (!glasses.controllerConnected || !glasses.controllerFullyBooted)
42
+ return false;
43
+ const settings = useSettingsStore.getState();
44
+ const pairedModel = settings.getSetting(SETTINGS.default_controller.key);
45
+ const pairedName = settings.getSetting(SETTINGS.controller_device_name.key);
46
+ return (!deviceModel || pairedModel === deviceModel) && (!deviceName || pairedName === deviceName);
47
+ }
48
+ if (!isGlassesReady(glasses.connection))
49
+ return false;
50
+ const identity = projectPairingIdentity();
51
+ if (!deviceModel && !deviceName)
52
+ return true;
53
+ return (identity.kind === "paired" &&
54
+ (!deviceModel || identity.model === deviceModel) &&
55
+ (!deviceName || identity.name === deviceName));
56
+ }
57
+ function subscribeTargetReady(options, cb) {
58
+ let last = projectTargetReady(options);
59
+ const notify = () => {
60
+ const ready = projectTargetReady(options);
61
+ if (ready === last)
62
+ return;
63
+ last = ready;
64
+ cb(ready);
65
+ };
66
+ const unsubscribeGlasses = useGlassesStore.subscribe(notify);
67
+ const unsubscribeSettings = useSettingsStore.subscribe(notify);
68
+ return () => {
69
+ unsubscribeGlasses();
70
+ unsubscribeSettings();
71
+ };
72
+ }
73
+ async function waitForTargetReady(options, timeoutMs) {
74
+ return new Promise((resolve) => {
75
+ if (options.signal?.aborted) {
76
+ resolve(false);
77
+ return;
78
+ }
79
+ if (projectTargetReady(options)) {
80
+ resolve(true);
81
+ return;
82
+ }
83
+ let settled = false;
84
+ let timeout = null;
85
+ let unsubscribe = null;
86
+ let onAbort = null;
87
+ const finish = (ready) => {
88
+ if (settled)
89
+ return;
90
+ settled = true;
91
+ if (timeout)
92
+ clearTimeout(timeout);
93
+ if (unsubscribe)
94
+ unsubscribe();
95
+ if (onAbort && options.signal)
96
+ options.signal.removeEventListener("abort", onAbort);
97
+ resolve(ready);
98
+ };
99
+ unsubscribe = subscribeTargetReady(options, (ready) => {
100
+ if (ready)
101
+ finish(true);
102
+ });
103
+ if (options.signal) {
104
+ onAbort = () => finish(false);
105
+ options.signal.addEventListener("abort", onAbort);
106
+ }
107
+ timeout = setTimeout(() => finish(projectTargetReady(options)), timeoutMs);
108
+ });
109
+ }
35
110
  export async function submitPairingBootTimeoutReport(params) {
36
111
  const { deviceModel, deviceName, showGlassesBooting, elapsedMs, route = DEFAULT_PAIRING_ROUTE } = params;
37
112
  const result = await submitAutomaticReport({
@@ -65,12 +140,7 @@ async function waitForReadyDuringPairing(options = {}) {
65
140
  showGlassesBooting = true;
66
141
  });
67
142
  try {
68
- const ready = await waitForGlassesReady({
69
- getConnection: () => useGlassesStore.getState().connection,
70
- subscribe: (listener) => useGlassesStore.subscribe((state) => state.connection, listener),
71
- timeoutMs,
72
- signal: options.signal,
73
- });
143
+ const ready = await waitForTargetReady(options, timeoutMs);
74
144
  if (!ready && !options.signal?.aborted) {
75
145
  void submitPairingBootTimeoutReport({
76
146
  deviceModel: options.deviceModel,
@@ -142,6 +212,10 @@ export const pairing = {
142
212
  cb(snap);
143
213
  });
144
214
  },
215
+ /** Whether the exact wearable or controller selected on the scan screen is ready. */
216
+ targetReady: (options) => projectTargetReady(options),
217
+ /** Subscribe to readiness for the exact selected target, excluding stale devices. */
218
+ onTargetReady: (options, cb) => subscribeTargetReady(options, cb),
145
219
  // --- pairing-identity lifecycle (the PairingIdentity read-model + the JS-owned
146
220
  // identity writes; promotion to `paired` only ever happens natively) ---
147
221
  /** The identity lifecycle snapshot: none | pending (chosen, never paired) | paired. */
@@ -1 +1 @@
1
- {"version":3,"file":"pairing.js","sourceRoot":"","sources":["../../src/facades/pairing.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * pairing facade — `engine.pairing`: scan for nearby glasses + pair. Scan state\n * (searching + results) comes from the engine core store; scan/connect go over the\n * bluetooth-sdk; pair-failure / not-ready are the bluetooth-sdk events.\n *\n * (Connect-the-already-paired-default is `engine.glasses.connectDefault()`; this\n * facade is the first-time discovery + pair flow.)\n */\n// Internal btsdk surface — updateBluetoothSettings (the Bluetooth Classic\n// target hint) lives on the full surface, not the public entry (same reason\n// the glasses facade imports internal).\nimport BluetoothSdk from \"@mentra/bluetooth-sdk/internal\"\nimport type {ConnectOptions, Device, DeviceModel, PairFailureEvent, GlassesNotReadyEvent} from \"@mentra/bluetooth-sdk\"\nimport {useCoreStore} from \"../stores/core\"\nimport {useGlassesStore} from \"../stores/glasses\"\nimport {hasDefaultDevice} from \"../services/DeviceStoreHydration\"\nimport {\n markPendingSelection,\n projectPairingIdentity,\n subscribePairingIdentity,\n type IdentitySnapshot,\n} from \"../services/PairingIdentity\"\nimport {\n isGlassesConnected,\n isGlassesLinkLayerBusy,\n isGlassesReady,\n waitForGlassesReady,\n} from \"../services/GlassesReadiness\"\nimport {\n logAutomaticReportSubmissionStatus,\n toAutomaticReportSubmissionStatus,\n type AutomaticReportSubmissionStatus,\n} from \"../services/AutomaticReportResult\"\nimport {pushAllBluetoothSettings} from \"../services/GlassesSettingsSync\"\nimport {submitAutomaticReport} from \"./reports\"\n\nexport type {IdentitySnapshot} from \"../services/PairingIdentity\"\n\nexport interface PairingReadyWaitOptions {\n deviceModel?: string\n deviceName?: string\n timeoutMs?: number\n route?: string\n signal?: AbortSignal\n}\n\nconst DEFAULT_PAIRING_BOOT_TIMEOUT_MS = 35_000\nconst DEFAULT_BT_CLASSIC_TIMEOUT_MS = 1_000\nconst DEFAULT_PAIRING_ROUTE = \"/pairing/loading\"\nconst LOG_TAG = \"PairingTimeoutReport\"\n\nfunction projectReadiness() {\n const s = useGlassesStore.getState()\n return {\n state: s.connection.state,\n connected: s.connection.state === \"connected\",\n fullyBooted: isGlassesReady(s.connection),\n bluetoothClassicConnected: s.bluetoothClassicConnected,\n nativeLinkBusy: isGlassesLinkLayerBusy(s.connection),\n }\n}\n\nexport type PairingReadinessSnapshot = ReturnType<typeof projectReadiness>\n\nexport async function submitPairingBootTimeoutReport(params: {\n deviceModel?: string\n deviceName?: string\n showGlassesBooting: boolean\n elapsedMs: number\n route?: string\n}): Promise<AutomaticReportSubmissionStatus> {\n const {deviceModel, deviceName, showGlassesBooting, elapsedMs, route = DEFAULT_PAIRING_ROUTE} = params\n const result = await submitAutomaticReport({\n kind: \"automatic\",\n trigger: {\n type: \"automatic\",\n source: \"pairing_loading\",\n reason: \"glasses_connect_timeout\",\n },\n report: {\n expectedBehavior: `Glasses should connect successfully within ${Math.round(elapsedMs / 1000)} seconds.`,\n actualBehavior: JSON.stringify(\n {\n deviceModel,\n deviceName,\n showGlassesBooting,\n elapsedMs,\n route,\n },\n null,\n 2,\n ),\n systemPriority: \"medium\",\n },\n throttleKey: `pairing_timeout|${deviceModel || \"unknown\"}|${deviceName || \"unknown\"}`,\n })\n\n const status = toAutomaticReportSubmissionStatus(result)\n logAutomaticReportSubmissionStatus(LOG_TAG, status, deviceModel, deviceName)\n return status\n}\n\nasync function waitForReadyDuringPairing(options: PairingReadyWaitOptions = {}): Promise<boolean> {\n const timeoutMs = options.timeoutMs ?? DEFAULT_PAIRING_BOOT_TIMEOUT_MS\n let showGlassesBooting = false\n const notReadySub = BluetoothSdk.addListener(\"glasses_not_ready\", () => {\n showGlassesBooting = true\n })\n\n try {\n const ready = await waitForGlassesReady({\n getConnection: () => useGlassesStore.getState().connection,\n subscribe: (listener) => useGlassesStore.subscribe((state) => state.connection, listener),\n timeoutMs,\n signal: options.signal,\n })\n\n if (!ready && !options.signal?.aborted) {\n void submitPairingBootTimeoutReport({\n deviceModel: options.deviceModel,\n deviceName: options.deviceName,\n showGlassesBooting,\n elapsedMs: timeoutMs,\n route: options.route,\n }).catch((error) => {\n console.error(`[${LOG_TAG}] Unexpected error:`, error)\n })\n }\n\n return ready\n } finally {\n notReadySub.remove()\n }\n}\n\nasync function waitForBluetoothClassic(\n options: Pick<PairingReadyWaitOptions, \"timeoutMs\" | \"signal\"> = {},\n): Promise<boolean> {\n const timeoutMs = options.timeoutMs ?? DEFAULT_BT_CLASSIC_TIMEOUT_MS\n return new Promise((resolve) => {\n if (options.signal?.aborted) {\n resolve(false)\n return\n }\n\n const initial = useGlassesStore.getState().bluetoothClassicConnected\n if (initial) {\n resolve(true)\n return\n }\n\n let settled = false\n let timeout: ReturnType<typeof setTimeout> | null = null\n let unsubscribe: (() => void) | null = null\n let onAbort: (() => void) | null = null\n\n const finish = (value: boolean) => {\n if (settled) return\n settled = true\n if (timeout) clearTimeout(timeout)\n if (unsubscribe) unsubscribe()\n if (onAbort && options.signal) options.signal.removeEventListener(\"abort\", onAbort)\n resolve(value)\n }\n\n if (options.signal) {\n onAbort = () => finish(false)\n options.signal.addEventListener(\"abort\", onAbort)\n }\n\n unsubscribe = useGlassesStore.subscribe(\n (s) => s.bluetoothClassicConnected,\n (connected) => {\n if (connected) finish(true)\n },\n )\n\n timeout = setTimeout(() => {\n finish(useGlassesStore.getState().bluetoothClassicConnected)\n }, timeoutMs)\n })\n}\n\nexport const pairing = {\n readiness: (): PairingReadinessSnapshot => projectReadiness(),\n onReadiness: (cb: (readiness: PairingReadinessSnapshot) => void): (() => void) => {\n let last = JSON.stringify(projectReadiness())\n return useGlassesStore.subscribe(() => {\n const snap = projectReadiness()\n const key = JSON.stringify(snap)\n if (key === last) return\n last = key\n cb(snap)\n })\n },\n\n // --- pairing-identity lifecycle (the PairingIdentity read-model + the JS-owned\n // identity writes; promotion to `paired` only ever happens natively) ---\n /** The identity lifecycle snapshot: none | pending (chosen, never paired) | paired. */\n identity: (): IdentitySnapshot => projectPairingIdentity(),\n /** Subscribe to identity changes; fires only when the projected snapshot changes.\n * Returns an unsubscribe. */\n onIdentity: (cb: (identity: IdentitySnapshot) => void): (() => void) => subscribePairingIdentity(cb),\n /** Mark the chosen model as the pending selection (the scan-entry write); the\n * host renders it as a finish-pairing affordance until pairing succeeds. */\n markPendingSelection: (model: string) => markPendingSelection(model),\n\n /** Start scanning for nearby glasses. Results land on `searchResults()`/`onFound()`. */\n scan: (model: DeviceModel): Promise<void> => BluetoothSdk.startScan(model),\n /** Whether a scan is currently in progress. */\n scanning: (): boolean => useCoreStore.getState().searching,\n /** Subscribe to scan-in-progress changes; fires only when it changes. Returns an unsubscribe. */\n onScanning: (cb: (scanning: boolean) => void): (() => void) => useCoreStore.subscribe((s) => s.searching, cb),\n /** Whether a controller scan is currently in progress. */\n scanningController: (): boolean => useCoreStore.getState().searchingController,\n /** Subscribe to controller-scan-in-progress changes; fires only when it changes. Returns an unsubscribe. */\n onScanningController: (cb: (scanning: boolean) => void): (() => void) =>\n useCoreStore.subscribe((s) => s.searchingController, cb),\n /** Whether the phone has another Bluetooth (audio) device connected — the BT Classic pairing hint. */\n otherBtConnected: (): boolean => useCoreStore.getState().otherBtConnected,\n /** Subscribe to other-Bluetooth-device-connected changes; fires only when it changes. Returns an unsubscribe. */\n onOtherBtConnected: (cb: (connected: boolean) => void): (() => void) =>\n useCoreStore.subscribe((s) => s.otherBtConnected, cb),\n /** The current scan results (snapshot). */\n // Copy the array AND each entry: neither the list nor the Device objects may\n // leak as mutable references into the store.\n searchResults: () => useCoreStore.getState().searchResults.map((result) => ({...result})),\n /** Subscribe to scan-result changes; fires only when they change. Returns an unsubscribe. */\n onFound: (cb: (results: Device[]) => void): (() => void) => {\n let last = JSON.stringify(useCoreStore.getState().searchResults)\n return useCoreStore.subscribe(() => {\n const results = useCoreStore.getState().searchResults\n const key = JSON.stringify(results)\n if (key === last) return\n last = key\n // Copy like searchResults(): listeners must not mutate shared scan state.\n cb(results.map((result) => ({...result})))\n })\n },\n\n /**\n * Pair with (connect to) a discovered device. Two-phase identity: the connect\n * attempt only marks the device as pending (`saveAsDefault: false` — no eager\n * default-device write); the native layer promotes it to the default wearable\n * when pairing actually succeeds (handleDeviceReady), so an abandoned or\n * failed attempt can't leave a default identity with no paired device behind.\n */\n pair: async (device: Device, options?: ConnectOptions): Promise<void> => {\n await pushAllBluetoothSettings()\n return BluetoothSdk.connect(device, {...options, saveAsDefault: false})\n },\n /** Set a device as the default for subsequent `glasses.connectDefault()`. */\n setDefault: (device: Device | null): Promise<void> => BluetoothSdk.setDefaultDevice(device),\n /**\n * Prime the native Bluetooth Classic audio watcher with the picked device.\n * The iOS Mentra Live flow pairs Classic audio BEFORE any BLE connect\n * exists, and native detects the pairing by matching the connected audio\n * route against its device_name — which two-phase identity no longer sets\n * at selection time. This is native-only routing state (device_name has no\n * native→JS echo): the phone's persisted identity is untouched, and\n * promotion still happens only at pairing success.\n */\n setBluetoothClassicTarget: (device: Device): Promise<void> =>\n BluetoothSdk.updateBluetoothSettings({device_name: device.name}),\n /**\n * Abandon an in-flight pairing attempt (back-out, failure retry, conflict\n * retry) without destroying an existing pairing. The decision comes from the\n * LIVE hydrated default-device read — never from flow-entry state, because a\n * pairing can PROMOTE while the flow is open (the glasses finish pairing\n * even as the user backs out of the UI), and an entry snapshot would forget\n * that brand-new pairing:\n * - Default device exists and glasses are connected (nothing in flight — an\n * attempt drops the link first): stop the scan, touch nothing else.\n * - Default device exists with an attempt in flight: cancel it, then re-seed\n * the native identity from the phone's persisted settings — the attempt's\n * connect-by-name overwrote the native device_name, so a later\n * connectDefault() would otherwise target the abandoned device.\n * - No default device (genuinely unpaired attempt): also forget, clearing\n * the partial native pairing state.\n * The read fails OPEN to \"preserve\" — a transient failure must never wipe a\n * real pairing. The `pending_wearable` marker is deliberately left alone —\n * the host renders it as a finish-pairing affordance.\n */\n abandonAttempt: async (): Promise<void> => {\n const nativeHasDefault = await hasDefaultDevice().catch(() => true)\n if (nativeHasDefault && isGlassesConnected(useGlassesStore.getState().connection)) {\n // Still connected means no connect attempt is in flight (an attempt drops\n // the existing link first): the user browsed the scan and backed out.\n // Stop the scan and leave the live pairing untouched.\n console.log(\"PairingIdentity: abandonAttempt — pairing intact and connected; stopping scan only\")\n await BluetoothSdk.stopScan()\n return\n }\n if (projectPairingIdentity().kind === \"paired\") {\n // The persisted settings describe a COMPLETE pairing: restore it to\n // native (the attempt's connect-by-name overwrote the native\n // device_name; and if native somehow lost its default entirely, this\n // repairs the divergence instead of forgetting a real pairing).\n console.log(\"PairingIdentity: abandonAttempt — preserving pairing; attempt cancelled, native identity re-seeded\")\n await BluetoothSdk.disconnect()\n await pushAllBluetoothSettings()\n return\n }\n if (nativeHasDefault) {\n // Mid-relay: native promoted and its echoes are still landing — the\n // incomplete JS snapshot must not be pushed over the fresher native\n // identity (the on-connect replay's race). Native holds the truth.\n console.log(\"PairingIdentity: abandonAttempt — preserving pairing; JS identity mid-relay, native kept as-is\")\n await BluetoothSdk.disconnect()\n return\n }\n // Partial attempt: forget owns teardown. Do NOT disconnect() first — that\n // nulls the MentraLive SGC and used to skip Classic removeBond, leaving\n // IBRT ACL up so glasses never re-advertise for the next scan.\n console.log(\"PairingIdentity: abandonAttempt — no pairing on either layer; forgetting the partial attempt\")\n await BluetoothSdk.forget()\n },\n\n /** Subscribe to pairing failures; returns an unsubscribe. */\n onPairFailure: (cb: (event: PairFailureEvent) => void): (() => void) => {\n const sub = BluetoothSdk.addListener(\"pair_failure\", cb)\n return () => sub.remove()\n },\n /** Subscribe to glasses-not-ready events during pairing; returns an unsubscribe. */\n onGlassesNotReady: (cb: (event: GlassesNotReadyEvent) => void): (() => void) => {\n const sub = BluetoothSdk.addListener(\"glasses_not_ready\", cb)\n return () => sub.remove()\n },\n /** Wait for paired glasses to finish booting; engine files the timeout diagnostic. */\n waitForReady: waitForReadyDuringPairing,\n /** Wait briefly for Bluetooth Classic to come up after BLE pairing. */\n waitForBluetoothClassic,\n}\n"]}
1
+ {"version":3,"file":"pairing.js","sourceRoot":"","sources":["../../src/facades/pairing.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * pairing facade — `engine.pairing`: scan for nearby glasses + pair. Scan state\n * (searching + results) comes from the engine core store; scan/connect go over the\n * bluetooth-sdk; pair-failure / not-ready are the bluetooth-sdk events.\n *\n * (Connect-the-already-paired-default is `engine.glasses.connectDefault()`; this\n * facade is the first-time discovery + pair flow.)\n */\n// Internal btsdk surface — updateBluetoothSettings (the Bluetooth Classic\n// target hint) lives on the full surface, not the public entry (same reason\n// the glasses facade imports internal).\nimport BluetoothSdk from \"@mentra/bluetooth-sdk/internal\"\nimport type {ConnectOptions, Device, DeviceModel, PairFailureEvent, GlassesNotReadyEvent} from \"@mentra/bluetooth-sdk\"\nimport {useCoreStore} from \"../stores/core\"\nimport {useGlassesStore} from \"../stores/glasses\"\nimport {SETTINGS, useSettingsStore} from \"../stores/settings\"\nimport {hasDefaultDevice} from \"../services/DeviceStoreHydration\"\nimport {\n markPendingSelection,\n projectPairingIdentity,\n subscribePairingIdentity,\n type IdentitySnapshot,\n} from \"../services/PairingIdentity\"\nimport {isGlassesConnected, isGlassesLinkLayerBusy, isGlassesReady} from \"../services/GlassesReadiness\"\nimport {\n logAutomaticReportSubmissionStatus,\n toAutomaticReportSubmissionStatus,\n type AutomaticReportSubmissionStatus,\n} from \"../services/AutomaticReportResult\"\nimport {pushAllBluetoothSettings} from \"../services/GlassesSettingsSync\"\nimport {ControllerTypes} from \"../types\"\nimport {submitAutomaticReport} from \"./reports\"\n\nexport type {IdentitySnapshot} from \"../services/PairingIdentity\"\n\nexport interface PairingReadyWaitOptions {\n deviceModel?: string\n deviceName?: string\n timeoutMs?: number\n route?: string\n signal?: AbortSignal\n}\n\nconst DEFAULT_PAIRING_BOOT_TIMEOUT_MS = 35_000\nconst DEFAULT_BT_CLASSIC_TIMEOUT_MS = 1_000\nconst DEFAULT_PAIRING_ROUTE = \"/pairing/loading\"\nconst LOG_TAG = \"PairingTimeoutReport\"\n\nfunction projectReadiness() {\n const s = useGlassesStore.getState()\n return {\n state: s.connection.state,\n connected: s.connection.state === \"connected\",\n fullyBooted: isGlassesReady(s.connection),\n bluetoothClassicConnected: s.bluetoothClassicConnected,\n nativeLinkBusy: isGlassesLinkLayerBusy(s.connection),\n }\n}\n\nfunction projectTargetReady(options: Pick<PairingReadyWaitOptions, \"deviceModel\" | \"deviceName\">): boolean {\n const {deviceModel, deviceName} = options\n const glasses = useGlassesStore.getState()\n\n if (deviceModel === ControllerTypes.R1) {\n if (!glasses.controllerConnected || !glasses.controllerFullyBooted) return false\n const settings = useSettingsStore.getState()\n const pairedModel = settings.getSetting(SETTINGS.default_controller.key)\n const pairedName = settings.getSetting(SETTINGS.controller_device_name.key)\n return (!deviceModel || pairedModel === deviceModel) && (!deviceName || pairedName === deviceName)\n }\n\n if (!isGlassesReady(glasses.connection)) return false\n const identity = projectPairingIdentity()\n if (!deviceModel && !deviceName) return true\n return (\n identity.kind === \"paired\" &&\n (!deviceModel || identity.model === deviceModel) &&\n (!deviceName || identity.name === deviceName)\n )\n}\n\nfunction subscribeTargetReady(\n options: Pick<PairingReadyWaitOptions, \"deviceModel\" | \"deviceName\">,\n cb: (ready: boolean) => void,\n): () => void {\n let last = projectTargetReady(options)\n const notify = () => {\n const ready = projectTargetReady(options)\n if (ready === last) return\n last = ready\n cb(ready)\n }\n const unsubscribeGlasses = useGlassesStore.subscribe(notify)\n const unsubscribeSettings = useSettingsStore.subscribe(notify)\n return () => {\n unsubscribeGlasses()\n unsubscribeSettings()\n }\n}\n\nasync function waitForTargetReady(options: PairingReadyWaitOptions, timeoutMs: number): Promise<boolean> {\n return new Promise((resolve) => {\n if (options.signal?.aborted) {\n resolve(false)\n return\n }\n if (projectTargetReady(options)) {\n resolve(true)\n return\n }\n\n let settled = false\n let timeout: ReturnType<typeof setTimeout> | null = null\n let unsubscribe: (() => void) | null = null\n let onAbort: (() => void) | null = null\n const finish = (ready: boolean) => {\n if (settled) return\n settled = true\n if (timeout) clearTimeout(timeout)\n if (unsubscribe) unsubscribe()\n if (onAbort && options.signal) options.signal.removeEventListener(\"abort\", onAbort)\n resolve(ready)\n }\n\n unsubscribe = subscribeTargetReady(options, (ready) => {\n if (ready) finish(true)\n })\n if (options.signal) {\n onAbort = () => finish(false)\n options.signal.addEventListener(\"abort\", onAbort)\n }\n timeout = setTimeout(() => finish(projectTargetReady(options)), timeoutMs)\n })\n}\n\nexport type PairingReadinessSnapshot = ReturnType<typeof projectReadiness>\n\nexport async function submitPairingBootTimeoutReport(params: {\n deviceModel?: string\n deviceName?: string\n showGlassesBooting: boolean\n elapsedMs: number\n route?: string\n}): Promise<AutomaticReportSubmissionStatus> {\n const {deviceModel, deviceName, showGlassesBooting, elapsedMs, route = DEFAULT_PAIRING_ROUTE} = params\n const result = await submitAutomaticReport({\n kind: \"automatic\",\n trigger: {\n type: \"automatic\",\n source: \"pairing_loading\",\n reason: \"glasses_connect_timeout\",\n },\n report: {\n expectedBehavior: `Glasses should connect successfully within ${Math.round(elapsedMs / 1000)} seconds.`,\n actualBehavior: JSON.stringify(\n {\n deviceModel,\n deviceName,\n showGlassesBooting,\n elapsedMs,\n route,\n },\n null,\n 2,\n ),\n systemPriority: \"medium\",\n },\n throttleKey: `pairing_timeout|${deviceModel || \"unknown\"}|${deviceName || \"unknown\"}`,\n })\n\n const status = toAutomaticReportSubmissionStatus(result)\n logAutomaticReportSubmissionStatus(LOG_TAG, status, deviceModel, deviceName)\n return status\n}\n\nasync function waitForReadyDuringPairing(options: PairingReadyWaitOptions = {}): Promise<boolean> {\n const timeoutMs = options.timeoutMs ?? DEFAULT_PAIRING_BOOT_TIMEOUT_MS\n let showGlassesBooting = false\n const notReadySub = BluetoothSdk.addListener(\"glasses_not_ready\", () => {\n showGlassesBooting = true\n })\n\n try {\n const ready = await waitForTargetReady(options, timeoutMs)\n\n if (!ready && !options.signal?.aborted) {\n void submitPairingBootTimeoutReport({\n deviceModel: options.deviceModel,\n deviceName: options.deviceName,\n showGlassesBooting,\n elapsedMs: timeoutMs,\n route: options.route,\n }).catch((error) => {\n console.error(`[${LOG_TAG}] Unexpected error:`, error)\n })\n }\n\n return ready\n } finally {\n notReadySub.remove()\n }\n}\n\nasync function waitForBluetoothClassic(\n options: Pick<PairingReadyWaitOptions, \"timeoutMs\" | \"signal\"> = {},\n): Promise<boolean> {\n const timeoutMs = options.timeoutMs ?? DEFAULT_BT_CLASSIC_TIMEOUT_MS\n return new Promise((resolve) => {\n if (options.signal?.aborted) {\n resolve(false)\n return\n }\n\n const initial = useGlassesStore.getState().bluetoothClassicConnected\n if (initial) {\n resolve(true)\n return\n }\n\n let settled = false\n let timeout: ReturnType<typeof setTimeout> | null = null\n let unsubscribe: (() => void) | null = null\n let onAbort: (() => void) | null = null\n\n const finish = (value: boolean) => {\n if (settled) return\n settled = true\n if (timeout) clearTimeout(timeout)\n if (unsubscribe) unsubscribe()\n if (onAbort && options.signal) options.signal.removeEventListener(\"abort\", onAbort)\n resolve(value)\n }\n\n if (options.signal) {\n onAbort = () => finish(false)\n options.signal.addEventListener(\"abort\", onAbort)\n }\n\n unsubscribe = useGlassesStore.subscribe(\n (s) => s.bluetoothClassicConnected,\n (connected) => {\n if (connected) finish(true)\n },\n )\n\n timeout = setTimeout(() => {\n finish(useGlassesStore.getState().bluetoothClassicConnected)\n }, timeoutMs)\n })\n}\n\nexport const pairing = {\n readiness: (): PairingReadinessSnapshot => projectReadiness(),\n onReadiness: (cb: (readiness: PairingReadinessSnapshot) => void): (() => void) => {\n let last = JSON.stringify(projectReadiness())\n return useGlassesStore.subscribe(() => {\n const snap = projectReadiness()\n const key = JSON.stringify(snap)\n if (key === last) return\n last = key\n cb(snap)\n })\n },\n /** Whether the exact wearable or controller selected on the scan screen is ready. */\n targetReady: (options: Pick<PairingReadyWaitOptions, \"deviceModel\" | \"deviceName\">): boolean =>\n projectTargetReady(options),\n /** Subscribe to readiness for the exact selected target, excluding stale devices. */\n onTargetReady: (\n options: Pick<PairingReadyWaitOptions, \"deviceModel\" | \"deviceName\">,\n cb: (ready: boolean) => void,\n ): (() => void) => subscribeTargetReady(options, cb),\n\n // --- pairing-identity lifecycle (the PairingIdentity read-model + the JS-owned\n // identity writes; promotion to `paired` only ever happens natively) ---\n /** The identity lifecycle snapshot: none | pending (chosen, never paired) | paired. */\n identity: (): IdentitySnapshot => projectPairingIdentity(),\n /** Subscribe to identity changes; fires only when the projected snapshot changes.\n * Returns an unsubscribe. */\n onIdentity: (cb: (identity: IdentitySnapshot) => void): (() => void) => subscribePairingIdentity(cb),\n /** Mark the chosen model as the pending selection (the scan-entry write); the\n * host renders it as a finish-pairing affordance until pairing succeeds. */\n markPendingSelection: (model: string) => markPendingSelection(model),\n\n /** Start scanning for nearby glasses. Results land on `searchResults()`/`onFound()`. */\n scan: (model: DeviceModel): Promise<void> => BluetoothSdk.startScan(model),\n /** Whether a scan is currently in progress. */\n scanning: (): boolean => useCoreStore.getState().searching,\n /** Subscribe to scan-in-progress changes; fires only when it changes. Returns an unsubscribe. */\n onScanning: (cb: (scanning: boolean) => void): (() => void) => useCoreStore.subscribe((s) => s.searching, cb),\n /** Whether a controller scan is currently in progress. */\n scanningController: (): boolean => useCoreStore.getState().searchingController,\n /** Subscribe to controller-scan-in-progress changes; fires only when it changes. Returns an unsubscribe. */\n onScanningController: (cb: (scanning: boolean) => void): (() => void) =>\n useCoreStore.subscribe((s) => s.searchingController, cb),\n /** Whether the phone has another Bluetooth (audio) device connected — the BT Classic pairing hint. */\n otherBtConnected: (): boolean => useCoreStore.getState().otherBtConnected,\n /** Subscribe to other-Bluetooth-device-connected changes; fires only when it changes. Returns an unsubscribe. */\n onOtherBtConnected: (cb: (connected: boolean) => void): (() => void) =>\n useCoreStore.subscribe((s) => s.otherBtConnected, cb),\n /** The current scan results (snapshot). */\n // Copy the array AND each entry: neither the list nor the Device objects may\n // leak as mutable references into the store.\n searchResults: () => useCoreStore.getState().searchResults.map((result) => ({...result})),\n /** Subscribe to scan-result changes; fires only when they change. Returns an unsubscribe. */\n onFound: (cb: (results: Device[]) => void): (() => void) => {\n let last = JSON.stringify(useCoreStore.getState().searchResults)\n return useCoreStore.subscribe(() => {\n const results = useCoreStore.getState().searchResults\n const key = JSON.stringify(results)\n if (key === last) return\n last = key\n // Copy like searchResults(): listeners must not mutate shared scan state.\n cb(results.map((result) => ({...result})))\n })\n },\n\n /**\n * Pair with (connect to) a discovered device. Two-phase identity: the connect\n * attempt only marks the device as pending (`saveAsDefault: false` — no eager\n * default-device write); the native layer promotes it to the default wearable\n * when pairing actually succeeds (handleDeviceReady), so an abandoned or\n * failed attempt can't leave a default identity with no paired device behind.\n */\n pair: async (device: Device, options?: ConnectOptions): Promise<void> => {\n await pushAllBluetoothSettings()\n return BluetoothSdk.connect(device, {...options, saveAsDefault: false})\n },\n /** Set a device as the default for subsequent `glasses.connectDefault()`. */\n setDefault: (device: Device | null): Promise<void> => BluetoothSdk.setDefaultDevice(device),\n /**\n * Prime the native Bluetooth Classic audio watcher with the picked device.\n * The iOS Mentra Live flow pairs Classic audio BEFORE any BLE connect\n * exists, and native detects the pairing by matching the connected audio\n * route against its device_name — which two-phase identity no longer sets\n * at selection time. This is native-only routing state (device_name has no\n * native→JS echo): the phone's persisted identity is untouched, and\n * promotion still happens only at pairing success.\n */\n setBluetoothClassicTarget: (device: Device): Promise<void> =>\n BluetoothSdk.updateBluetoothSettings({device_name: device.name}),\n /**\n * Abandon an in-flight pairing attempt (back-out, failure retry, conflict\n * retry) without destroying an existing pairing. The decision comes from the\n * LIVE hydrated default-device read — never from flow-entry state, because a\n * pairing can PROMOTE while the flow is open (the glasses finish pairing\n * even as the user backs out of the UI), and an entry snapshot would forget\n * that brand-new pairing:\n * - Default device exists and glasses are connected (nothing in flight — an\n * attempt drops the link first): stop the scan, touch nothing else.\n * - Default device exists with an attempt in flight: cancel it, then re-seed\n * the native identity from the phone's persisted settings — the attempt's\n * connect-by-name overwrote the native device_name, so a later\n * connectDefault() would otherwise target the abandoned device.\n * - No default device (genuinely unpaired attempt): also forget, clearing\n * the partial native pairing state.\n * The read fails OPEN to \"preserve\" — a transient failure must never wipe a\n * real pairing. The `pending_wearable` marker is deliberately left alone —\n * the host renders it as a finish-pairing affordance.\n */\n abandonAttempt: async (): Promise<void> => {\n const nativeHasDefault = await hasDefaultDevice().catch(() => true)\n if (nativeHasDefault && isGlassesConnected(useGlassesStore.getState().connection)) {\n // Still connected means no connect attempt is in flight (an attempt drops\n // the existing link first): the user browsed the scan and backed out.\n // Stop the scan and leave the live pairing untouched.\n console.log(\"PairingIdentity: abandonAttempt — pairing intact and connected; stopping scan only\")\n await BluetoothSdk.stopScan()\n return\n }\n if (projectPairingIdentity().kind === \"paired\") {\n // The persisted settings describe a COMPLETE pairing: restore it to\n // native (the attempt's connect-by-name overwrote the native\n // device_name; and if native somehow lost its default entirely, this\n // repairs the divergence instead of forgetting a real pairing).\n console.log(\"PairingIdentity: abandonAttempt — preserving pairing; attempt cancelled, native identity re-seeded\")\n await BluetoothSdk.disconnect()\n await pushAllBluetoothSettings()\n return\n }\n if (nativeHasDefault) {\n // Mid-relay: native promoted and its echoes are still landing — the\n // incomplete JS snapshot must not be pushed over the fresher native\n // identity (the on-connect replay's race). Native holds the truth.\n console.log(\"PairingIdentity: abandonAttempt — preserving pairing; JS identity mid-relay, native kept as-is\")\n await BluetoothSdk.disconnect()\n return\n }\n // Partial attempt: forget owns teardown. Do NOT disconnect() first — that\n // nulls the MentraLive SGC and used to skip Classic removeBond, leaving\n // IBRT ACL up so glasses never re-advertise for the next scan.\n console.log(\"PairingIdentity: abandonAttempt — no pairing on either layer; forgetting the partial attempt\")\n await BluetoothSdk.forget()\n },\n\n /** Subscribe to pairing failures; returns an unsubscribe. */\n onPairFailure: (cb: (event: PairFailureEvent) => void): (() => void) => {\n const sub = BluetoothSdk.addListener(\"pair_failure\", cb)\n return () => sub.remove()\n },\n /** Subscribe to glasses-not-ready events during pairing; returns an unsubscribe. */\n onGlassesNotReady: (cb: (event: GlassesNotReadyEvent) => void): (() => void) => {\n const sub = BluetoothSdk.addListener(\"glasses_not_ready\", cb)\n return () => sub.remove()\n },\n /** Wait for paired glasses to finish booting; engine files the timeout diagnostic. */\n waitForReady: waitForReadyDuringPairing,\n /** Wait briefly for Bluetooth Classic to come up after BLE pairing. */\n waitForBluetoothClassic,\n}\n"]}
@@ -1,10 +1,10 @@
1
1
  export const ENGINE_RELEASE_METADATA = Object.freeze({
2
2
  "schemaVersion": 1,
3
3
  "familyBaseVersion": "3.1.0",
4
- "releaseIdentity": "3.1.0-dev.4",
5
- "releaseSetId": "mentra-3.1.0-dev.4",
6
- "sourceCommit": "43b81aea1c84675fade024077063e45fddde4861",
7
- "otaManifestUrl": "https://github.com/Mentra-Community/MentraOS/releases/download/mentra-v3.1.0-dev.4/mentra-live-ota-3.1.0-dev.4.json",
8
- "otaManifestSha256": "8fbea7589345658dc5dffcb394229ffc5c52fbe75352acb8f6827d83290ce750"
4
+ "releaseIdentity": "3.1.0-dev.40",
5
+ "releaseSetId": "mentra-3.1.0-dev.40",
6
+ "sourceCommit": "b23b9074e8c086564bf685494462e9c90c4da4eb",
7
+ "otaManifestUrl": "https://github.com/Mentra-Community/MentraOS/releases/download/mentra-builds-v3.1.0/mentra-live-ota-3.1.0-dev.40.json",
8
+ "otaManifestSha256": "0fdf4cd8e5aca0a8a2098a056aab0608f65ac76314debe4243fefc7804d04033"
9
9
  });
10
10
  //# sourceMappingURL=releaseMetadata.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,uBAAuB,GAAoC,MAAM,CAAC,MAAM,CAAC;IACpF,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,aAAa;IAChC,cAAc,EAAE,oBAAoB;IACpC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,qHAAqH;IACvI,mBAAmB,EAAE,kEAAkE;CACxF,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface EngineReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const ENGINE_RELEASE_METADATA: Readonly<EngineReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"3.1.0\",\n \"releaseIdentity\": \"3.1.0-dev.4\",\n \"releaseSetId\": \"mentra-3.1.0-dev.4\",\n \"sourceCommit\": \"43b81aea1c84675fade024077063e45fddde4861\",\n \"otaManifestUrl\": \"https://github.com/Mentra-Community/MentraOS/releases/download/mentra-v3.1.0-dev.4/mentra-live-ota-3.1.0-dev.4.json\",\n \"otaManifestSha256\": \"8fbea7589345658dc5dffcb394229ffc5c52fbe75352acb8f6827d83290ce750\"\n})\n"]}
1
+ {"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,uBAAuB,GAAoC,MAAM,CAAC,MAAM,CAAC;IACpF,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,cAAc;IACjC,cAAc,EAAE,qBAAqB;IACrC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,uHAAuH;IACzI,mBAAmB,EAAE,kEAAkE;CACxF,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface EngineReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const ENGINE_RELEASE_METADATA: Readonly<EngineReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"3.1.0\",\n \"releaseIdentity\": \"3.1.0-dev.40\",\n \"releaseSetId\": \"mentra-3.1.0-dev.40\",\n \"sourceCommit\": \"b23b9074e8c086564bf685494462e9c90c4da4eb\",\n \"otaManifestUrl\": \"https://github.com/Mentra-Community/MentraOS/releases/download/mentra-builds-v3.1.0/mentra-live-ota-3.1.0-dev.40.json\",\n \"otaManifestSha256\": \"0fdf4cd8e5aca0a8a2098a056aab0608f65ac76314debe4243fefc7804d04033\"\n})\n"]}
package/build/index.d.ts CHANGED
@@ -26,7 +26,7 @@ export type { VersionInfo, MtkPatch, BesFirmware, VersionJson, OtaCheckResult, O
26
26
  export { MINIMUM_OTA_STATUS_BUILD, MAX_RETRIES, RETRY_INTERVAL_MS, PROGRESS_TIMEOUT_MS, DOWNLOAD_STUCK_TIMEOUT_MS, MTK_INSTALL_TIMEOUT_MS, GLOBAL_OTA_TIMEOUT_MS, PING_INTERVAL_MS, QUERY_REPLY_TIMEOUT_MS, OtaProgressMessages, } from "./services/otaInstallPolicy";
27
27
  export { deriveDisplayState } from "./services/otaDisplayState";
28
28
  export type { DisplayState } from "./services/otaDisplayState";
29
- export type { OtaProgress, OtaProgressStatus, OtaStatus, OtaUpdateInfo, OtaSnapshot, OtaInstallSnapshot, } from "./facades/ota";
29
+ export type { OtaProgress, OtaProgressStatus, OtaStatus, OtaUpdateInfo, ReleaseChangelog, OtaSnapshot, OtaInstallSnapshot, } from "./facades/ota";
30
30
  export { beginOtaAutoChain, clearOtaAutoChainReconnectWait, isOtaAutoChainActive, otaAutoChainFingerprint, otaAutoChainReconnectWaitRemaining, stopOtaAutoChain, tryAdvanceOtaAutoChain, MAX_OTA_AUTO_CHAIN_PASSES, OTA_AUTO_CHAIN_RECONNECT_TIMEOUT_MS, } from "./services/OtaAutoChain";
31
31
  export type { OtaAutoChainAdvanceResult } from "./services/OtaAutoChain";
32
32
  export { BES_INSTALL_RESTART_MESSAGE, getOtaErrorMessage, shouldRequireGlassesRebootForBesFailure, shouldShowChangeWifiForOtaDownloadFailure, } from "./services/OtaErrorMapping";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}