@mentra/engine 3.1.0-dev.10 → 3.1.0-dev.102

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 (185) hide show
  1. package/README.md +24 -6
  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 +12 -7
  9. package/build/facades/ota.d.ts.map +1 -1
  10. package/build/facades/ota.js +10 -6
  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 +3 -3
  19. package/build/index.d.ts.map +1 -1
  20. package/build/index.js +2 -2
  21. package/build/index.js.map +1 -1
  22. package/build/react/MentraLiveOtaFlow.d.ts +8 -2
  23. package/build/react/MentraLiveOtaFlow.d.ts.map +1 -1
  24. package/build/react/MentraLiveOtaFlow.js +256 -354
  25. package/build/react/MentraLiveOtaFlow.js.map +1 -1
  26. package/build/react/index.d.ts +1 -0
  27. package/build/react/index.d.ts.map +1 -1
  28. package/build/react/index.js +1 -0
  29. package/build/react/index.js.map +1 -1
  30. package/build/react/useMentraLiveOta.d.ts +84 -0
  31. package/build/react/useMentraLiveOta.d.ts.map +1 -0
  32. package/build/react/useMentraLiveOta.js +627 -0
  33. package/build/react/useMentraLiveOta.js.map +1 -0
  34. package/build/services/BlobStore.d.ts +2 -0
  35. package/build/services/BlobStore.d.ts.map +1 -1
  36. package/build/services/BlobStore.js +63 -10
  37. package/build/services/BlobStore.js.map +1 -1
  38. package/build/services/DisplayProcessor.d.ts +3 -3
  39. package/build/services/DisplayProcessor.js +3 -3
  40. package/build/services/DisplayProcessor.js.map +1 -1
  41. package/build/services/GlassesStatusProjection.d.ts +15 -2
  42. package/build/services/GlassesStatusProjection.d.ts.map +1 -1
  43. package/build/services/GlassesStatusProjection.js +3 -3
  44. package/build/services/GlassesStatusProjection.js.map +1 -1
  45. package/build/services/HotspotOtaTransport.d.ts.map +1 -1
  46. package/build/services/HotspotOtaTransport.js +8 -7
  47. package/build/services/HotspotOtaTransport.js.map +1 -1
  48. package/build/services/LocalDisplayManager.d.ts +2 -3
  49. package/build/services/LocalDisplayManager.d.ts.map +1 -1
  50. package/build/services/LocalDisplayManager.js +2 -3
  51. package/build/services/LocalDisplayManager.js.map +1 -1
  52. package/build/services/OtaAutoChain.d.ts +9 -2
  53. package/build/services/OtaAutoChain.d.ts.map +1 -1
  54. package/build/services/OtaAutoChain.js +10 -2
  55. package/build/services/OtaAutoChain.js.map +1 -1
  56. package/build/services/OtaInstallCoordinator.d.ts +26 -3
  57. package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
  58. package/build/services/OtaInstallCoordinator.js +35 -13
  59. package/build/services/OtaInstallCoordinator.js.map +1 -1
  60. package/build/services/OtaService.d.ts.map +1 -1
  61. package/build/services/OtaService.js +1 -1
  62. package/build/services/OtaService.js.map +1 -1
  63. package/build/services/OtaUpdateCheckService.d.ts +4 -1
  64. package/build/services/OtaUpdateCheckService.d.ts.map +1 -1
  65. package/build/services/OtaUpdateCheckService.js +21 -5
  66. package/build/services/OtaUpdateCheckService.js.map +1 -1
  67. package/build/services/PhonePhotoCoordinator.js +1 -1
  68. package/build/services/PhonePhotoCoordinator.js.map +1 -1
  69. package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
  70. package/build/services/PhoneStreamCoordinator.js +9 -6
  71. package/build/services/PhoneStreamCoordinator.js.map +1 -1
  72. package/build/services/StreamLifecycleController.d.ts +3 -3
  73. package/build/services/StreamLifecycleController.js +3 -3
  74. package/build/services/StreamLifecycleController.js.map +1 -1
  75. package/build/services/asg/localNetworkTransport.d.ts.map +1 -1
  76. package/build/services/asg/localNetworkTransport.js +13 -12
  77. package/build/services/asg/localNetworkTransport.js.map +1 -1
  78. package/build/services/glassesClockSync.js +1 -1
  79. package/build/services/glassesClockSync.js.map +1 -1
  80. package/build/services/otaInstallPolicy.d.ts +4 -0
  81. package/build/services/otaInstallPolicy.d.ts.map +1 -1
  82. package/build/services/otaInstallPolicy.js +4 -0
  83. package/build/services/otaInstallPolicy.js.map +1 -1
  84. package/build/services/otaReleaseVersion.d.ts +10 -0
  85. package/build/services/otaReleaseVersion.d.ts.map +1 -0
  86. package/build/services/otaReleaseVersion.js +14 -0
  87. package/build/services/otaReleaseVersion.js.map +1 -0
  88. package/build/stores/appVisibility.d.ts +3 -0
  89. package/build/stores/appVisibility.d.ts.map +1 -0
  90. package/build/stores/appVisibility.js +3 -0
  91. package/build/stores/appVisibility.js.map +1 -0
  92. package/build/stores/apps.d.ts.map +1 -1
  93. package/build/stores/apps.js +7 -1
  94. package/build/stores/apps.js.map +1 -1
  95. package/build/stores/core.d.ts +3 -3
  96. package/build/stores/core.d.ts.map +1 -1
  97. package/build/stores/core.js.map +1 -1
  98. package/build/stores/glasses.d.ts +10 -4
  99. package/build/stores/glasses.d.ts.map +1 -1
  100. package/build/stores/glasses.js.map +1 -1
  101. package/build/types/applet.d.ts +1 -1
  102. package/build/types/applet.js +1 -1
  103. package/build/types/applet.js.map +1 -1
  104. package/build/types/capabilities/even-realities-g1.d.ts.map +1 -1
  105. package/build/types/capabilities/even-realities-g1.js +2 -0
  106. package/build/types/capabilities/even-realities-g1.js.map +1 -1
  107. package/build/types/capabilities/even-realities-g2.d.ts.map +1 -1
  108. package/build/types/capabilities/even-realities-g2.js +2 -0
  109. package/build/types/capabilities/even-realities-g2.js.map +1 -1
  110. package/build/types/capabilities/mentra-display.d.ts.map +1 -1
  111. package/build/types/capabilities/mentra-display.js +2 -0
  112. package/build/types/capabilities/mentra-display.js.map +1 -1
  113. package/build/types/capabilities/mentra-live.d.ts.map +1 -1
  114. package/build/types/capabilities/mentra-live.js +2 -0
  115. package/build/types/capabilities/mentra-live.js.map +1 -1
  116. package/build/types/capabilities/nimo.d.ts +9 -0
  117. package/build/types/capabilities/nimo.d.ts.map +1 -0
  118. package/build/types/capabilities/nimo.js +57 -0
  119. package/build/types/capabilities/nimo.js.map +1 -0
  120. package/build/types/capabilities/none.d.ts.map +1 -1
  121. package/build/types/capabilities/none.js +2 -0
  122. package/build/types/capabilities/none.js.map +1 -1
  123. package/build/types/capabilities/simulated-glasses.d.ts.map +1 -1
  124. package/build/types/capabilities/simulated-glasses.js +2 -0
  125. package/build/types/capabilities/simulated-glasses.js.map +1 -1
  126. package/build/types/capabilities/vuzix-z100.d.ts.map +1 -1
  127. package/build/types/capabilities/vuzix-z100.js +2 -0
  128. package/build/types/capabilities/vuzix-z100.js.map +1 -1
  129. package/build/types/enums.d.ts +2 -1
  130. package/build/types/enums.d.ts.map +1 -1
  131. package/build/types/enums.js +1 -0
  132. package/build/types/enums.js.map +1 -1
  133. package/build/types/hardware.d.ts +3 -2
  134. package/build/types/hardware.d.ts.map +1 -1
  135. package/build/types/hardware.js +3 -1
  136. package/build/types/hardware.js.map +1 -1
  137. package/build/types/index.d.ts +1 -1
  138. package/build/types/index.d.ts.map +1 -1
  139. package/build/types/index.js +1 -1
  140. package/build/types/index.js.map +1 -1
  141. package/build/utils/display/composer/ColumnComposer.d.ts +1 -1
  142. package/build/utils/display/composer/ColumnComposer.js +1 -1
  143. package/build/utils/display/composer/ColumnComposer.js.map +1 -1
  144. package/package.json +13 -6
  145. package/src/bluetooth-sdk/ota-transport.ts +1 -0
  146. package/src/facades/ota.ts +20 -7
  147. package/src/facades/pairing.ts +88 -12
  148. package/src/generated/releaseMetadata.ts +5 -5
  149. package/src/index.ts +3 -0
  150. package/src/react/MentraLiveOtaFlow.tsx +378 -480
  151. package/src/react/index.ts +14 -0
  152. package/src/react/useMentraLiveOta.ts +793 -0
  153. package/src/services/BlobStore.ts +57 -10
  154. package/src/services/DisplayProcessor.ts +3 -3
  155. package/src/services/GlassesStatusProjection.ts +7 -6
  156. package/src/services/HotspotOtaTransport.ts +8 -7
  157. package/src/services/LocalDisplayManager.ts +2 -3
  158. package/src/services/OtaAutoChain.ts +26 -2
  159. package/src/services/OtaInstallCoordinator.ts +37 -13
  160. package/src/services/OtaService.ts +1 -2
  161. package/src/services/OtaUpdateCheckService.ts +26 -8
  162. package/src/services/PhonePhotoCoordinator.ts +1 -1
  163. package/src/services/PhoneStreamCoordinator.ts +10 -6
  164. package/src/services/StreamLifecycleController.ts +3 -3
  165. package/src/services/asg/localNetworkTransport.ts +20 -19
  166. package/src/services/glassesClockSync.ts +1 -1
  167. package/src/services/otaInstallPolicy.ts +4 -0
  168. package/src/services/otaReleaseVersion.ts +22 -0
  169. package/src/stores/appVisibility.ts +3 -0
  170. package/src/stores/apps.ts +7 -1
  171. package/src/stores/core.ts +4 -4
  172. package/src/stores/glasses.ts +13 -6
  173. package/src/types/applet.ts +1 -1
  174. package/src/types/capabilities/even-realities-g1.ts +3 -0
  175. package/src/types/capabilities/even-realities-g2.ts +3 -0
  176. package/src/types/capabilities/mentra-display.ts +3 -0
  177. package/src/types/capabilities/mentra-live.ts +3 -0
  178. package/src/types/capabilities/nimo.ts +59 -0
  179. package/src/types/capabilities/none.ts +3 -0
  180. package/src/types/capabilities/simulated-glasses.ts +3 -0
  181. package/src/types/capabilities/vuzix-z100.ts +3 -0
  182. package/src/types/enums.ts +1 -0
  183. package/src/types/hardware.ts +4 -2
  184. package/src/types/index.ts +1 -0
  185. package/src/utils/display/composer/ColumnComposer.ts +1 -1
@@ -1,5 +1,5 @@
1
1
  import * as RNFS from "@dr.pogodin/react-native-fs"
2
- import {MentraLocalNetwork, type LocalNetworkDownloadProgress} from "@mentra/bluetooth-sdk/internal"
2
+ import {otaLocalNetwork, type OtaLocalNetworkDownloadProgress} from "@mentra/bluetooth-sdk/ota-transport"
3
3
  import {Buffer} from "buffer"
4
4
  import {Platform} from "react-native"
5
5
  import WifiManager from "react-native-wifi-reborn"
@@ -17,7 +17,7 @@ export function shouldUseScopedLocalNetwork(os: string, moduleAvailable: boolean
17
17
  }
18
18
 
19
19
  function supportsScopedConnection(): boolean {
20
- return shouldUseScopedLocalNetwork(Platform.OS, MentraLocalNetwork != null)
20
+ return shouldUseScopedLocalNetwork(Platform.OS, otaLocalNetwork.isAvailable())
21
21
  }
22
22
 
23
23
  function normalizeHeaders(headers?: HeadersInit): Record<string, string> {
@@ -48,25 +48,25 @@ export const localNetworkTransport = {
48
48
  await WifiManager.connectToProtectedSSID(ssid, password, false, false)
49
49
  return undefined
50
50
  }
51
- const result = await MentraLocalNetwork!.connect(ssid, password)
51
+ const result = await otaLocalNetwork.connect(ssid, password)
52
52
  scopedConnectionActive = true
53
53
  return result.localAddress
54
54
  },
55
55
 
56
56
  async disconnect(): Promise<void> {
57
57
  if (supportsScopedConnection()) {
58
- await MentraLocalNetwork!.disconnect().catch(() => {})
58
+ await otaLocalNetwork.disconnect().catch(() => {})
59
59
  }
60
60
  scopedConnectionActive = false
61
61
  nativeJobs.clear()
62
62
  },
63
63
 
64
64
  async fetch(url: string | URL | Request, init?: RequestInit, timeoutMs = 30_000): Promise<Response> {
65
- if (!scopedConnectionActive || !MentraLocalNetwork || typeof url !== "string") {
65
+ if (!scopedConnectionActive || !otaLocalNetwork.isAvailable() || typeof url !== "string") {
66
66
  return globalThis.fetch(url, init)
67
67
  }
68
68
 
69
- const nativeModule = MentraLocalNetwork
69
+ const nativeModule = otaLocalNetwork
70
70
  const id = requestId("request")
71
71
  const signal = init?.signal
72
72
  const cancel = () => void nativeModule.cancel(id)
@@ -92,13 +92,13 @@ export const localNetworkTransport = {
92
92
  },
93
93
 
94
94
  downloadFile(options: DownloadOptions): DownloadHandle {
95
- if (!scopedConnectionActive || !MentraLocalNetwork) return RNFS.downloadFile(options)
95
+ if (!scopedConnectionActive || !otaLocalNetwork.isAvailable()) return RNFS.downloadFile(options)
96
96
 
97
97
  const jobId = nextJobId++
98
98
  const id = requestId("download")
99
99
  let began = false
100
100
  nativeJobs.set(jobId, id)
101
- const subscription = MentraLocalNetwork.addListener("downloadProgress", (event: LocalNetworkDownloadProgress) => {
101
+ const subscription = otaLocalNetwork.onDownloadProgress((event: OtaLocalNetworkDownloadProgress) => {
102
102
  if (event.requestId !== id) return
103
103
  if (!began) {
104
104
  began = true
@@ -116,14 +116,15 @@ export const localNetworkTransport = {
116
116
  })
117
117
  })
118
118
 
119
- const promise = MentraLocalNetwork.download(
120
- id,
121
- options.fromUrl,
122
- options.toFile,
123
- options.headers || {},
124
- options.connectionTimeout || 30_000,
125
- options.readTimeout || 30_000,
126
- )
119
+ const promise = otaLocalNetwork
120
+ .download(
121
+ id,
122
+ options.fromUrl,
123
+ options.toFile,
124
+ options.headers || {},
125
+ options.connectionTimeout || 30_000,
126
+ options.readTimeout || 30_000,
127
+ )
127
128
  .then((result) => {
128
129
  if (!began) {
129
130
  options.begin?.({
@@ -154,16 +155,16 @@ export const localNetworkTransport = {
154
155
 
155
156
  stopDownload(jobId: number): void {
156
157
  const nativeId = nativeJobs.get(jobId)
157
- if (nativeId && MentraLocalNetwork) {
158
+ if (nativeId && otaLocalNetwork.isAvailable()) {
158
159
  cancelledNativeJobs.add(jobId)
159
- void MentraLocalNetwork.cancel(nativeId)
160
+ void otaLocalNetwork.cancel(nativeId)
160
161
  return
161
162
  }
162
163
  RNFS.stopDownload(jobId)
163
164
  },
164
165
  }
165
166
 
166
- MentraLocalNetwork?.addListener("networkLost", () => {
167
+ otaLocalNetwork.onNetworkLost(() => {
167
168
  scopedConnectionActive = false
168
169
  nativeJobs.clear()
169
170
  })
@@ -2,7 +2,7 @@
2
2
  * Push phone time to glasses only when clock skew is detected (gallery sync, OTA, etc.).
3
3
  */
4
4
 
5
- import BluetoothSdk from "@mentra/bluetooth-sdk/internal"
5
+ import BluetoothSdk from "@mentra/bluetooth-sdk"
6
6
  import {BgTimer} from "../utils/timers"
7
7
  import {useGlassesStore} from "../stores/glasses"
8
8
 
@@ -32,6 +32,8 @@ export const PING_INTERVAL_MS = 10_000
32
32
  export const QUERY_REPLY_TIMEOUT_MS = 6000
33
33
  /** 15s lockout on the Continue button after a BES restart, to prevent an accidental tap. */
34
34
  export const BES_CONTINUE_LOCKOUT_MS = 15_000
35
+ /** Fail closed if a BES reboot never reconnects; normal restarts complete in a fraction of this window. */
36
+ export const BES_RESTART_TIMEOUT_MS = 120_000
35
37
 
36
38
  // --- Legacy old-build (< MINIMUM_OTA_STATUS_BUILD) OTA policy (WP 8C) ---
37
39
  //
@@ -51,6 +53,7 @@ export const LEGACY_MTK_INSTALL_TIMEOUT_MS = MTK_INSTALL_TIMEOUT_MS + LEGACY_EXT
51
53
  export const LEGACY_GLOBAL_OTA_TIMEOUT_MS = GLOBAL_OTA_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS
52
54
  export const LEGACY_PING_INTERVAL_MS = PING_INTERVAL_MS + LEGACY_EXTRA_TIMEOUT_MS
53
55
  export const LEGACY_BES_CONTINUE_LOCKOUT_MS = BES_CONTINUE_LOCKOUT_MS + LEGACY_EXTRA_TIMEOUT_MS
56
+ export const LEGACY_BES_RESTART_TIMEOUT_MS = BES_RESTART_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS
54
57
  /**
55
58
  * After a legacy apk `install FINISHED` observed in-flight, the legacy screen held the
56
59
  * completed state for 12s (+20s pad) so the ASG process restart settles (and fresh
@@ -122,6 +125,7 @@ export function selectOtaProtocolProfile(
122
125
  export const OtaProgressMessages = {
123
126
  stalledOrStuck: "Update may have failed. Ensure glasses have internet access and try again.",
124
127
  globalTimeout: "Update took too long. Please try again.",
128
+ restartTimeout: "Glasses did not finish restarting. Restart them before trying the update again.",
125
129
  sendOtaStartFailed: "Failed to communicate with glasses.",
126
130
  hotspotArtifactDownloadFailed: "Could not download the update to your phone. Check phone internet and try again.",
127
131
  hotspotArtifactVerifyFailed: "The update package could not be verified. Please try again later.",
@@ -0,0 +1,22 @@
1
+ const COORDINATED_RELEASE_VERSION = /^\d+\.\d+\.\d+(?:-(?:dev|beta)\.[1-9]\d*)?$/
2
+
3
+ type OtaReleaseVersionInput = {
4
+ manifestReleaseVersion?: string | null
5
+ manifestUrl: string
6
+ packagedManifestUrl?: string | null
7
+ packagedReleaseIdentity?: string | null
8
+ }
9
+
10
+ function validReleaseVersion(version: string | null | undefined): string | null {
11
+ const trimmed = version?.trim()
12
+ return trimmed && COORDINATED_RELEASE_VERSION.test(trimmed) ? trimmed : null
13
+ }
14
+
15
+ /** Resolve the label for the selected OTA pin, including stable promotion of exact beta OTA bytes. */
16
+ export function resolveOtaReleaseVersion(input: OtaReleaseVersionInput): string | null {
17
+ const packagedRelease = validReleaseVersion(input.packagedReleaseIdentity)
18
+ if (packagedRelease && input.packagedManifestUrl?.trim() === input.manifestUrl.trim()) {
19
+ return packagedRelease
20
+ }
21
+ return validReleaseVersion(input.manifestReleaseVersion)
22
+ }
@@ -0,0 +1,3 @@
1
+ /** Combine registry-enforced visibility with the user's home-screen choice. */
2
+ export const resolveHiddenStatus = (registryHidden: boolean, userHidden: boolean): boolean =>
3
+ registryHidden || userHidden
@@ -25,6 +25,7 @@ import {islandNotifications} from "../services/NotificationsEmitter"
25
25
  import sttModelManager from "../services/STTModelManager"
26
26
  import {miniappLauncher} from "../services/MiniappLauncher"
27
27
  import {miniappRunningRegistry} from "../services/MiniappRunningRegistry"
28
+ import {resolveHiddenStatus} from "./appVisibility"
28
29
  import {SETTINGS, useSettingsStore} from "./settings"
29
30
  import BluetoothSdk from "@mentra/bluetooth-sdk"
30
31
 
@@ -221,7 +222,12 @@ function projectApps(previousState: AppStatusState, localApps: ClientApp[]): Cli
221
222
  ...app,
222
223
  screenshot: previousByPackage.get(app.packageName)?.screenshot ?? app.screenshot,
223
224
  compatibility: HardwareCompatibility.checkCompatibility(app.hardwareRequirements, capabilities),
224
- hidden: previousState.getHiddenStatus(app.packageName),
225
+ // A registry source can force an app off the primary home screen (for
226
+ // example, Miniapp Developer while its home-screen setting is disabled).
227
+ // Compose that gate with the user's persisted home-screen layout instead
228
+ // of replacing it, otherwise a default-false persisted value makes a
229
+ // source-hidden app visible again during projection.
230
+ hidden: resolveHiddenStatus(app.hidden, previousState.getHiddenStatus(app.packageName)),
225
231
  // Derive the foreground flag from the store's single source of truth
226
232
  // (`foregroundedPackage`), NOT from the previous snapshot. Carrying it over
227
233
  // per-app meant a refresh that momentarily omitted an app (e.g. the
@@ -1,13 +1,13 @@
1
1
  import {create} from "zustand"
2
2
  import {subscribeWithSelector} from "zustand/middleware"
3
- import type {BluetoothStatus} from "@mentra/bluetooth-sdk/internal"
3
+ import type {PublicBluetoothStatus} from "@mentra/bluetooth-sdk"
4
4
 
5
- export interface CoreState extends BluetoothStatus {
6
- setCoreInfo: (info: Partial<BluetoothStatus>) => void
5
+ export interface CoreState extends PublicBluetoothStatus {
6
+ setCoreInfo: (info: Partial<PublicBluetoothStatus>) => void
7
7
  reset: () => void
8
8
  }
9
9
 
10
- const initialState: BluetoothStatus = {
10
+ const initialState: PublicBluetoothStatus = {
11
11
  // state:
12
12
  searching: false,
13
13
  searchingController: false,
@@ -1,12 +1,12 @@
1
1
  import type {
2
2
  GlassesConnectionStatus,
3
- GlassesStatus,
4
3
  HotspotStatus,
5
4
  OtaProgress,
6
5
  OtaStatus,
7
6
  OtaUpdateInfo,
7
+ PublicGlassesStatus,
8
8
  WifiStatus,
9
- } from "@mentra/bluetooth-sdk/internal"
9
+ } from "@mentra/bluetooth-sdk"
10
10
  import {isGlassesConnected, isGlassesLinkLayerBusy, isGlassesReady} from "../services/GlassesReadiness"
11
11
  import {create} from "zustand"
12
12
  import {subscribeWithSelector} from "zustand/middleware"
@@ -20,7 +20,14 @@ export const selectGlassesConnected = (state: {connection: GlassesConnectionStat
20
20
 
21
21
  export const selectGlassesReady = (state: {connection: GlassesConnectionStatus}) => isGlassesReady(state.connection)
22
22
 
23
- export interface GlassesState extends GlassesStatus {
23
+ type EngineGlassesStatus = PublicGlassesStatus & {
24
+ otaUpdateAvailable: OtaUpdateInfo | null
25
+ otaProgress: OtaProgress | null
26
+ otaInProgress: boolean
27
+ otaVersionUrl: string
28
+ }
29
+
30
+ export interface GlassesState extends EngineGlassesStatus {
24
31
  systemTimeMs: number
25
32
  wifiStatusKnown: boolean
26
33
  setGlassesInfo: (info: GlassesInfoUpdate) => void
@@ -53,7 +60,7 @@ type LegacyHotspotFields = {
53
60
  hotspotLocalIp?: string
54
61
  }
55
62
 
56
- type GlassesInfoUpdate = Partial<GlassesStatus> & LegacyWifiFields & LegacyHotspotFields
63
+ type GlassesInfoUpdate = Partial<EngineGlassesStatus> & LegacyWifiFields & LegacyHotspotFields
57
64
 
58
65
  function wifiFromLegacyFields(info: LegacyWifiFields): WifiStatus | null {
59
66
  if (info.wifiConnected === true) {
@@ -80,7 +87,7 @@ function hotspotFromLegacyFields(info: LegacyHotspotFields): HotspotStatus | nul
80
87
  return null
81
88
  }
82
89
 
83
- export const getGlasesInfoPartial = (state: GlassesStatus) => {
90
+ export const getGlasesInfoPartial = (state: EngineGlassesStatus) => {
84
91
  const wifi = state.wifi
85
92
  const connected = isGlassesConnected(state.connection)
86
93
  return {
@@ -98,7 +105,7 @@ export const getGlasesInfoPartial = (state: GlassesStatus) => {
98
105
  }
99
106
  }
100
107
 
101
- interface GlassesStore extends GlassesStatus {
108
+ interface GlassesStore extends EngineGlassesStatus {
102
109
  systemTimeMs: number
103
110
  mtkUpdatedThisSession: boolean
104
111
  wifiStatusKnown: boolean
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mentra/types - App/Applet types for client interfaces
2
+ * App and miniapp types owned by @mentra/engine.
3
3
  */
4
4
 
5
5
  import type {ReactNode} from "react"
@@ -64,4 +64,7 @@ export const evenRealitiesG1: Capabilities = {
64
64
 
65
65
  // WiFi capabilities - G1 does not support WiFi
66
66
  hasWifi: false,
67
+
68
+ // OTA capabilities - G1 firmware updates are not driven by the ASG OTA flow
69
+ hasOta: false,
67
70
  };
@@ -82,6 +82,9 @@ export const evenRealitiesG2: Capabilities = {
82
82
  // WiFi capabilities - G2 does not support WiFi
83
83
  hasWifi: false,
84
84
 
85
+ // OTA capabilities - G2 firmware updates are not driven by the ASG OTA flow
86
+ hasOta: false,
87
+
85
88
  // Dashboard - G2 renders Even Realities' native dashboard in firmware, so
86
89
  // MentraOS does not manage the dashboard or expose dashboard settings for it
87
90
  hasNativeDashboard: true,
@@ -72,4 +72,7 @@ export const mentraDisplay: Capabilities = {
72
72
 
73
73
  // WiFi capabilities - Mentra Display does not support WiFi
74
74
  hasWifi: false,
75
+
76
+ // OTA capabilities - Mentra Display firmware updates are not driven by the ASG OTA flow
77
+ hasOta: false,
75
78
  };
@@ -100,4 +100,7 @@ export const mentraLive: Capabilities = {
100
100
 
101
101
  // WiFi capabilities - Mentra Live supports WiFi
102
102
  hasWifi: true,
103
+
104
+ // OTA capabilities - Mentra Live supports ASG/BES/MTK OTA updates
105
+ hasOta: true,
103
106
  };
@@ -0,0 +1,59 @@
1
+ /**
2
+ * @fileoverview NIMO hardware capabilities.
3
+ *
4
+ * NIMO uses framed UART-over-BLE for widget content and a separate Opus
5
+ * microphone channel.
6
+ */
7
+
8
+ import type {Capabilities} from "../hardware"
9
+
10
+ export const nimo: Capabilities = {
11
+ modelName: "NIMO",
12
+ hasCamera: false,
13
+ camera: null,
14
+ hasDisplay: true,
15
+ display: {
16
+ count: 2,
17
+ isColor: false,
18
+ color: "green",
19
+ canDisplayBitmap: true,
20
+ // Bitmaps render into the 160x160 2bpp navigation widget. The resolution
21
+ // below remains the existing text-display placeholder until hardware
22
+ // screen information is available.
23
+ resolution: {width: 640, height: 400},
24
+ maxTextLines: 5,
25
+ adjustBrightness: true,
26
+ },
27
+ hasMicrophone: true,
28
+ microphone: {
29
+ count: 2,
30
+ hasVAD: false,
31
+ },
32
+ hasSpeaker: false,
33
+ speaker: null,
34
+ hasIMU: true,
35
+ imu: null,
36
+ hasButton: true,
37
+ button: {
38
+ count: 2,
39
+ buttons: [
40
+ {
41
+ type: "press",
42
+ events: ["press", "double_press", "long_press"],
43
+ isCapacitive: true,
44
+ },
45
+ {
46
+ type: "press",
47
+ events: ["press", "double_press", "long_press"],
48
+ isCapacitive: true,
49
+ },
50
+ ],
51
+ },
52
+ hasLight: false,
53
+ light: null,
54
+ power: {
55
+ hasExternalBattery: false,
56
+ },
57
+ hasWifi: false,
58
+ hasOta: false,
59
+ }
@@ -73,4 +73,7 @@ export const none: Capabilities = {
73
73
 
74
74
  // WiFi capabilities - does not support WiFi
75
75
  hasWifi: false,
76
+
77
+ // OTA capabilities - none profile does not support OTA
78
+ hasOta: false,
76
79
  };
@@ -73,4 +73,7 @@ export const simulatedGlasses: Capabilities = {
73
73
 
74
74
  // WiFi capabilities - does not support WiFi
75
75
  hasWifi: false,
76
+
77
+ // OTA capabilities - simulated glasses do not support OTA
78
+ hasOta: false,
76
79
  };
@@ -61,4 +61,7 @@ export const vuzixZ100: Capabilities = {
61
61
 
62
62
  // WiFi capabilities - does not support WiFi
63
63
  hasWifi: false,
64
+
65
+ // OTA capabilities - Z100 firmware updates are not driven by the ASG OTA flow
66
+ hasOta: false,
64
67
  };
@@ -11,6 +11,7 @@ export enum DeviceTypes {
11
11
  Z100 = "Vuzix Z100",
12
12
  NEX = "Mentra Display",
13
13
  FRAME = "Brilliant Frame",
14
+ NIMO = "NIMO",
14
15
  }
15
16
 
16
17
  export enum ControllerTypes {
@@ -4,6 +4,7 @@ import { evenRealitiesG1 } from "./capabilities/even-realities-g1";
4
4
  import { evenRealitiesG2 } from "./capabilities/even-realities-g2";
5
5
  import { mentraDisplay } from "./capabilities/mentra-display";
6
6
  import { mentraLive } from "./capabilities/mentra-live";
7
+ import { nimo } from "./capabilities/nimo";
7
8
  import { simulatedGlasses } from "./capabilities/simulated-glasses";
8
9
  import { vuzixZ100 } from "./capabilities/vuzix-z100";
9
10
  import { none } from "./capabilities/none";
@@ -158,7 +159,7 @@ export interface Capabilities {
158
159
  hasWifi: boolean;
159
160
 
160
161
  // OTA capability
161
- hasOta?: boolean;
162
+ hasOta: boolean;
162
163
 
163
164
  // Native dashboard capability
164
165
  // True when the device renders its own dashboard in firmware (e.g. Even
@@ -180,6 +181,7 @@ export const HARDWARE_CAPABILITIES: Record<string, Capabilities> = {
180
181
  [mentraLive.modelName]: mentraLive,
181
182
  [simulatedGlasses.modelName]: simulatedGlasses,
182
183
  [vuzixZ100.modelName]: vuzixZ100,
184
+ [nimo.modelName]: nimo,
183
185
  [DeviceTypes.MACH1]: vuzixZ100, // Mach1 uses same Vuzix Ultralite hardware as Z100
184
186
  [DeviceTypes.AR99]: {
185
187
  ...evenRealitiesG1,
@@ -207,4 +209,4 @@ export const getModelCapabilities = (deviceType: DeviceTypes): Capabilities => {
207
209
  };
208
210
 
209
211
  // export * from "./capabilities"
210
- export { simulatedGlasses, evenRealitiesG1, evenRealitiesG2, mentraLive, vuzixZ100, mentraDisplay };
212
+ export { simulatedGlasses, evenRealitiesG1, evenRealitiesG2, mentraLive, nimo, vuzixZ100, mentraDisplay };
@@ -25,6 +25,7 @@ export {
25
25
  evenRealitiesG1,
26
26
  evenRealitiesG2,
27
27
  mentraLive,
28
+ nimo,
28
29
  vuzixZ100,
29
30
  mentraDisplay,
30
31
  } from "./hardware"
@@ -11,7 +11,7 @@
11
11
  * 2. Merges columns line-by-line with pixel-precise space padding
12
12
  * 3. Returns a single pre-composed string ready for native to chunk & send
13
13
  *
14
- * @see cloud/issues/026-mobile-display-processor for design docs
14
+ * @see notes/miniapp-display-api-redesign.md for the current display design
15
15
  */
16
16
 
17
17
  import type { DisplayProfile } from "../profiles/types";