@mentra/engine 0.1.0-dev.0 → 3.1.0-dev.10

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 (503) hide show
  1. package/README.md +55 -18
  2. package/build/bluetooth-sdk/debug.d.ts +2 -0
  3. package/build/bluetooth-sdk/debug.d.ts.map +1 -0
  4. package/build/bluetooth-sdk/debug.js +2 -0
  5. package/build/bluetooth-sdk/debug.js.map +1 -0
  6. package/build/bluetooth-sdk/index.d.ts +3 -0
  7. package/build/bluetooth-sdk/index.d.ts.map +1 -0
  8. package/build/bluetooth-sdk/index.js +3 -0
  9. package/build/bluetooth-sdk/index.js.map +1 -0
  10. package/build/bluetooth-sdk/photo-receiver.d.ts +3 -0
  11. package/build/bluetooth-sdk/photo-receiver.d.ts.map +1 -0
  12. package/build/bluetooth-sdk/photo-receiver.js +3 -0
  13. package/build/bluetooth-sdk/photo-receiver.js.map +1 -0
  14. package/build/bluetooth-sdk/react.d.ts +2 -0
  15. package/build/bluetooth-sdk/react.d.ts.map +1 -0
  16. package/build/bluetooth-sdk/react.js +2 -0
  17. package/build/bluetooth-sdk/react.js.map +1 -0
  18. package/build/bluetooth-sdk/types.d.ts +2 -0
  19. package/build/bluetooth-sdk/types.d.ts.map +1 -0
  20. package/build/bluetooth-sdk/types.js +2 -0
  21. package/build/bluetooth-sdk/types.js.map +1 -0
  22. package/build/engine.d.ts +24 -16
  23. package/build/engine.d.ts.map +1 -1
  24. package/build/engine.js +9 -4
  25. package/build/engine.js.map +1 -1
  26. package/build/facades/dev.d.ts +3 -2
  27. package/build/facades/dev.d.ts.map +1 -1
  28. package/build/facades/dev.js +18 -12
  29. package/build/facades/dev.js.map +1 -1
  30. package/build/facades/display.d.ts +1 -1
  31. package/build/facades/display.d.ts.map +1 -1
  32. package/build/facades/display.js +1 -1
  33. package/build/facades/display.js.map +1 -1
  34. package/build/facades/gallery.js +1 -1
  35. package/build/facades/gallery.js.map +1 -1
  36. package/build/facades/glasses.d.ts +4 -13
  37. package/build/facades/glasses.d.ts.map +1 -1
  38. package/build/facades/glasses.js +21 -6
  39. package/build/facades/glasses.js.map +1 -1
  40. package/build/facades/glassesSettings.d.ts.map +1 -1
  41. package/build/facades/glassesSettings.js +1 -0
  42. package/build/facades/glassesSettings.js.map +1 -1
  43. package/build/facades/miniapps.d.ts +4 -0
  44. package/build/facades/miniapps.d.ts.map +1 -1
  45. package/build/facades/miniapps.js +5 -0
  46. package/build/facades/miniapps.js.map +1 -1
  47. package/build/facades/ota.d.ts +14 -16
  48. package/build/facades/ota.d.ts.map +1 -1
  49. package/build/facades/ota.js +22 -7
  50. package/build/facades/ota.js.map +1 -1
  51. package/build/facades/pairing.d.ts +8 -5
  52. package/build/facades/pairing.d.ts.map +1 -1
  53. package/build/facades/pairing.js +12 -10
  54. package/build/facades/pairing.js.map +1 -1
  55. package/build/facades/permissions.d.ts +10 -0
  56. package/build/facades/permissions.d.ts.map +1 -1
  57. package/build/facades/permissions.js +10 -0
  58. package/build/facades/permissions.js.map +1 -1
  59. package/build/facades/phoneNotifications.d.ts +0 -4
  60. package/build/facades/phoneNotifications.d.ts.map +1 -1
  61. package/build/facades/phoneNotifications.js +4 -14
  62. package/build/facades/phoneNotifications.js.map +1 -1
  63. package/build/facades/speech.d.ts +7 -6
  64. package/build/facades/speech.d.ts.map +1 -1
  65. package/build/facades/speech.js +1 -1
  66. package/build/facades/speech.js.map +1 -1
  67. package/build/generated/releaseMetadata.d.ts +12 -0
  68. package/build/generated/releaseMetadata.d.ts.map +1 -0
  69. package/build/generated/releaseMetadata.js +10 -0
  70. package/build/generated/releaseMetadata.js.map +1 -0
  71. package/build/index.d.ts +10 -8
  72. package/build/index.d.ts.map +1 -1
  73. package/build/index.js +6 -5
  74. package/build/index.js.map +1 -1
  75. package/build/react/MentraLiveOtaFlow.d.ts +38 -0
  76. package/build/react/MentraLiveOtaFlow.d.ts.map +1 -0
  77. package/build/react/MentraLiveOtaFlow.js +528 -0
  78. package/build/react/MentraLiveOtaFlow.js.map +1 -0
  79. package/build/react/index.d.ts +2 -0
  80. package/build/react/index.d.ts.map +1 -0
  81. package/build/react/index.js +2 -0
  82. package/build/react/index.js.map +1 -0
  83. package/build/react/useEngineSnapshot.d.ts +2 -0
  84. package/build/react/useEngineSnapshot.d.ts.map +1 -0
  85. package/build/react/useEngineSnapshot.js +14 -0
  86. package/build/react/useEngineSnapshot.js.map +1 -0
  87. package/build/runtime/bootstrap.d.ts +24 -1
  88. package/build/runtime/bootstrap.d.ts.map +1 -1
  89. package/build/runtime/bootstrap.js +17 -0
  90. package/build/runtime/bootstrap.js.map +1 -1
  91. package/build/runtime/scanQrSeam.d.ts +7 -0
  92. package/build/runtime/scanQrSeam.d.ts.map +1 -0
  93. package/build/runtime/scanQrSeam.js +16 -0
  94. package/build/runtime/scanQrSeam.js.map +1 -0
  95. package/build/services/AppRegistry.d.ts +41 -57
  96. package/build/services/AppRegistry.d.ts.map +1 -1
  97. package/build/services/AppRegistry.js +208 -144
  98. package/build/services/AppRegistry.js.map +1 -1
  99. package/build/services/AudioCloudUplink.d.ts +12 -0
  100. package/build/services/AudioCloudUplink.d.ts.map +1 -1
  101. package/build/services/AudioCloudUplink.js +22 -1
  102. package/build/services/AudioCloudUplink.js.map +1 -1
  103. package/build/services/AudioPlaybackService.d.ts +41 -2
  104. package/build/services/AudioPlaybackService.d.ts.map +1 -1
  105. package/build/services/AudioPlaybackService.js +250 -33
  106. package/build/services/AudioPlaybackService.js.map +1 -1
  107. package/build/services/BlobStore.d.ts +2 -1
  108. package/build/services/BlobStore.d.ts.map +1 -1
  109. package/build/services/BlobStore.js +17 -9
  110. package/build/services/BlobStore.js.map +1 -1
  111. package/build/services/CloudAudioSubscriptionSync.d.ts.map +1 -1
  112. package/build/services/CloudAudioSubscriptionSync.js +13 -1
  113. package/build/services/CloudAudioSubscriptionSync.js.map +1 -1
  114. package/build/services/CloudClientService.d.ts +15 -0
  115. package/build/services/CloudClientService.d.ts.map +1 -1
  116. package/build/services/CloudClientService.js +93 -1
  117. package/build/services/CloudClientService.js.map +1 -1
  118. package/build/services/DeviceEventRouter.js +5 -5
  119. package/build/services/DeviceEventRouter.js.map +1 -1
  120. package/build/services/ForegroundLocationPermission.d.ts +13 -0
  121. package/build/services/ForegroundLocationPermission.d.ts.map +1 -0
  122. package/build/services/ForegroundLocationPermission.js +12 -0
  123. package/build/services/ForegroundLocationPermission.js.map +1 -0
  124. package/build/services/GlassesSettingsSync.d.ts.map +1 -1
  125. package/build/services/GlassesSettingsSync.js +9 -3
  126. package/build/services/GlassesSettingsSync.js.map +1 -1
  127. package/build/services/GlassesStatusProjection.d.ts +2 -1
  128. package/build/services/GlassesStatusProjection.d.ts.map +1 -1
  129. package/build/services/GlassesStatusProjection.js +15 -8
  130. package/build/services/GlassesStatusProjection.js.map +1 -1
  131. package/build/services/HotspotOtaTransport.d.ts +29 -0
  132. package/build/services/HotspotOtaTransport.d.ts.map +1 -0
  133. package/build/services/HotspotOtaTransport.js +146 -0
  134. package/build/services/HotspotOtaTransport.js.map +1 -0
  135. package/build/services/HotspotShutdown.d.ts +17 -0
  136. package/build/services/HotspotShutdown.d.ts.map +1 -0
  137. package/build/services/HotspotShutdown.js +29 -0
  138. package/build/services/HotspotShutdown.js.map +1 -0
  139. package/build/services/LocalDisplayManager.d.ts +15 -0
  140. package/build/services/LocalDisplayManager.d.ts.map +1 -1
  141. package/build/services/LocalDisplayManager.js +106 -20
  142. package/build/services/LocalDisplayManager.js.map +1 -1
  143. package/build/services/LocalMiniappRuntime.d.ts +74 -2
  144. package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
  145. package/build/services/LocalMiniappRuntime.js +785 -291
  146. package/build/services/LocalMiniappRuntime.js.map +1 -1
  147. package/build/services/LocalMiniappStorage.d.ts +32 -0
  148. package/build/services/LocalMiniappStorage.d.ts.map +1 -0
  149. package/build/services/LocalMiniappStorage.js +66 -0
  150. package/build/services/LocalMiniappStorage.js.map +1 -0
  151. package/build/services/LocalMiniappUserIdentity.d.ts +20 -0
  152. package/build/services/LocalMiniappUserIdentity.d.ts.map +1 -0
  153. package/build/services/LocalMiniappUserIdentity.js +43 -0
  154. package/build/services/LocalMiniappUserIdentity.js.map +1 -0
  155. package/build/services/LocalSttFallbackCoordinator.d.ts +9 -6
  156. package/build/services/LocalSttFallbackCoordinator.d.ts.map +1 -1
  157. package/build/services/LocalSttFallbackCoordinator.js +18 -12
  158. package/build/services/LocalSttFallbackCoordinator.js.map +1 -1
  159. package/build/services/MicStateCoordinator.d.ts +42 -1
  160. package/build/services/MicStateCoordinator.d.ts.map +1 -1
  161. package/build/services/MicStateCoordinator.js +141 -3
  162. package/build/services/MicStateCoordinator.js.map +1 -1
  163. package/build/services/MiniappLauncher.d.ts.map +1 -1
  164. package/build/services/MiniappLauncher.js +23 -3
  165. package/build/services/MiniappLauncher.js.map +1 -1
  166. package/build/services/MiniappLiveness.d.ts +12 -0
  167. package/build/services/MiniappLiveness.d.ts.map +1 -0
  168. package/build/services/MiniappLiveness.js +16 -0
  169. package/build/services/MiniappLiveness.js.map +1 -0
  170. package/build/services/NativeHttpResponse.d.ts +3 -0
  171. package/build/services/NativeHttpResponse.d.ts.map +1 -0
  172. package/build/services/NativeHttpResponse.js +6 -0
  173. package/build/services/NativeHttpResponse.js.map +1 -0
  174. package/build/services/OtaArtifactDownloader.d.ts +65 -0
  175. package/build/services/OtaArtifactDownloader.d.ts.map +1 -0
  176. package/build/services/OtaArtifactDownloader.js +226 -0
  177. package/build/services/OtaArtifactDownloader.js.map +1 -0
  178. package/build/services/OtaAutoChain.d.ts +34 -0
  179. package/build/services/OtaAutoChain.d.ts.map +1 -0
  180. package/build/services/OtaAutoChain.js +83 -0
  181. package/build/services/OtaAutoChain.js.map +1 -0
  182. package/build/services/OtaErrorMapping.d.ts +18 -0
  183. package/build/services/OtaErrorMapping.d.ts.map +1 -0
  184. package/build/services/OtaErrorMapping.js +63 -0
  185. package/build/services/OtaErrorMapping.js.map +1 -0
  186. package/build/services/OtaInstallCoordinator.d.ts +95 -15
  187. package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
  188. package/build/services/OtaInstallCoordinator.js +577 -130
  189. package/build/services/OtaInstallCoordinator.js.map +1 -1
  190. package/build/services/OtaService.d.ts.map +1 -1
  191. package/build/services/OtaService.js +8 -1
  192. package/build/services/OtaService.js.map +1 -1
  193. package/build/services/OtaUpdateCheckService.d.ts +39 -4
  194. package/build/services/OtaUpdateCheckService.d.ts.map +1 -1
  195. package/build/services/OtaUpdateCheckService.js +138 -22
  196. package/build/services/OtaUpdateCheckService.js.map +1 -1
  197. package/build/services/PhoneCalendarHelpers.d.ts +32 -0
  198. package/build/services/PhoneCalendarHelpers.d.ts.map +1 -0
  199. package/build/services/PhoneCalendarHelpers.js +157 -0
  200. package/build/services/PhoneCalendarHelpers.js.map +1 -0
  201. package/build/services/PhoneCalendarService.d.ts +5 -0
  202. package/build/services/PhoneCalendarService.d.ts.map +1 -0
  203. package/build/services/PhoneCalendarService.js +45 -0
  204. package/build/services/PhoneCalendarService.js.map +1 -0
  205. package/build/services/PhoneCameraFovCoordinator.d.ts +30 -0
  206. package/build/services/PhoneCameraFovCoordinator.d.ts.map +1 -0
  207. package/build/services/PhoneCameraFovCoordinator.js +194 -0
  208. package/build/services/PhoneCameraFovCoordinator.js.map +1 -0
  209. package/build/services/PhoneNotificationsSync.d.ts.map +1 -1
  210. package/build/services/PhoneNotificationsSync.js +12 -10
  211. package/build/services/PhoneNotificationsSync.js.map +1 -1
  212. package/build/services/PhonePhotoCoordinator.d.ts +26 -2
  213. package/build/services/PhonePhotoCoordinator.d.ts.map +1 -1
  214. package/build/services/PhonePhotoCoordinator.js +79 -9
  215. package/build/services/PhonePhotoCoordinator.js.map +1 -1
  216. package/build/services/PhoneStreamCoordinator.d.ts +8 -1
  217. package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
  218. package/build/services/PhoneStreamCoordinator.js +125 -13
  219. package/build/services/PhoneStreamCoordinator.js.map +1 -1
  220. package/build/services/PhoneVideoCoordinator.d.ts +2 -0
  221. package/build/services/PhoneVideoCoordinator.d.ts.map +1 -1
  222. package/build/services/PhoneVideoCoordinator.js +10 -0
  223. package/build/services/PhoneVideoCoordinator.js.map +1 -1
  224. package/build/services/SceneRenderer.d.ts.map +1 -1
  225. package/build/services/SceneRenderer.js +15 -0
  226. package/build/services/SceneRenderer.js.map +1 -1
  227. package/build/services/SentenceTtsPipeline.d.ts +31 -0
  228. package/build/services/SentenceTtsPipeline.d.ts.map +1 -0
  229. package/build/services/SentenceTtsPipeline.js +67 -0
  230. package/build/services/SentenceTtsPipeline.js.map +1 -0
  231. package/build/services/SupportProfileSync.d.ts +22 -0
  232. package/build/services/SupportProfileSync.d.ts.map +1 -0
  233. package/build/services/SupportProfileSync.js +213 -0
  234. package/build/services/SupportProfileSync.js.map +1 -0
  235. package/build/services/TranscriptionRouting.d.ts +12 -0
  236. package/build/services/TranscriptionRouting.d.ts.map +1 -0
  237. package/build/services/TranscriptionRouting.js +24 -0
  238. package/build/services/TranscriptionRouting.js.map +1 -0
  239. package/build/services/TtsTextSanitizer.d.ts +5 -0
  240. package/build/services/TtsTextSanitizer.d.ts.map +1 -0
  241. package/build/services/TtsTextSanitizer.js +61 -0
  242. package/build/services/TtsTextSanitizer.js.map +1 -0
  243. package/build/services/WifiAdbRequest.d.ts +17 -0
  244. package/build/services/WifiAdbRequest.d.ts.map +1 -0
  245. package/build/services/WifiAdbRequest.js +35 -0
  246. package/build/services/WifiAdbRequest.js.map +1 -0
  247. package/build/services/asg/asgCameraApi.d.ts +43 -0
  248. package/build/services/asg/asgCameraApi.d.ts.map +1 -1
  249. package/build/services/asg/asgCameraApi.js +509 -26
  250. package/build/services/asg/asgCameraApi.js.map +1 -1
  251. package/build/services/asg/cameraRollExportCoordinator.d.ts +60 -0
  252. package/build/services/asg/cameraRollExportCoordinator.d.ts.map +1 -0
  253. package/build/services/asg/cameraRollExportCoordinator.js +618 -0
  254. package/build/services/asg/cameraRollExportCoordinator.js.map +1 -0
  255. package/build/services/asg/cameraRollExportLedger.d.ts +44 -0
  256. package/build/services/asg/cameraRollExportLedger.d.ts.map +1 -0
  257. package/build/services/asg/cameraRollExportLedger.js +78 -0
  258. package/build/services/asg/cameraRollExportLedger.js.map +1 -0
  259. package/build/services/asg/galleryNotices.d.ts +1 -1
  260. package/build/services/asg/galleryNotices.d.ts.map +1 -1
  261. package/build/services/asg/galleryNotices.js.map +1 -1
  262. package/build/services/asg/galleryPathMigration.d.ts +3 -0
  263. package/build/services/asg/galleryPathMigration.d.ts.map +1 -0
  264. package/build/services/asg/galleryPathMigration.js +26 -0
  265. package/build/services/asg/galleryPathMigration.js.map +1 -0
  266. package/build/services/asg/gallerySettingsService.d.ts +1 -0
  267. package/build/services/asg/gallerySettingsService.d.ts.map +1 -1
  268. package/build/services/asg/gallerySettingsService.js +2 -0
  269. package/build/services/asg/gallerySettingsService.js.map +1 -1
  270. package/build/services/asg/gallerySyncService.d.ts.map +1 -1
  271. package/build/services/asg/gallerySyncService.js +162 -56
  272. package/build/services/asg/gallerySyncService.js.map +1 -1
  273. package/build/services/asg/galleryTransferLedger.d.ts +58 -0
  274. package/build/services/asg/galleryTransferLedger.d.ts.map +1 -0
  275. package/build/services/asg/galleryTransferLedger.js +225 -0
  276. package/build/services/asg/galleryTransferLedger.js.map +1 -0
  277. package/build/services/asg/localNetworkTransport.d.ts +15 -0
  278. package/build/services/asg/localNetworkTransport.d.ts.map +1 -0
  279. package/build/services/asg/localNetworkTransport.js +144 -0
  280. package/build/services/asg/localNetworkTransport.js.map +1 -0
  281. package/build/services/asg/localStorageService.d.ts +18 -0
  282. package/build/services/asg/localStorageService.d.ts.map +1 -1
  283. package/build/services/asg/localStorageService.js +168 -19
  284. package/build/services/asg/localStorageService.js.map +1 -1
  285. package/build/services/asg/mediaProcessingQueue.d.ts +10 -0
  286. package/build/services/asg/mediaProcessingQueue.d.ts.map +1 -1
  287. package/build/services/asg/mediaProcessingQueue.js +193 -62
  288. package/build/services/asg/mediaProcessingQueue.js.map +1 -1
  289. package/build/services/audioPlaybackAssets.d.ts +8 -0
  290. package/build/services/audioPlaybackAssets.d.ts.map +1 -0
  291. package/build/services/audioPlaybackAssets.js +7 -0
  292. package/build/services/audioPlaybackAssets.js.map +1 -0
  293. package/build/services/gallerySyncClock.js +1 -1
  294. package/build/services/gallerySyncClock.js.map +1 -1
  295. package/build/services/glassesClockSync.d.ts.map +1 -1
  296. package/build/services/glassesClockSync.js +6 -2
  297. package/build/services/glassesClockSync.js.map +1 -1
  298. package/build/services/manifestActions.d.ts +7 -0
  299. package/build/services/manifestActions.d.ts.map +1 -0
  300. package/build/services/manifestActions.js +25 -0
  301. package/build/services/manifestActions.js.map +1 -0
  302. package/build/services/otaDisplayState.d.ts +23 -12
  303. package/build/services/otaDisplayState.d.ts.map +1 -1
  304. package/build/services/otaDisplayState.js +36 -14
  305. package/build/services/otaDisplayState.js.map +1 -1
  306. package/build/services/otaInstallPolicy.d.ts +16 -4
  307. package/build/services/otaInstallPolicy.d.ts.map +1 -1
  308. package/build/services/otaInstallPolicy.js +24 -3
  309. package/build/services/otaInstallPolicy.js.map +1 -1
  310. package/build/services/otaLegacyMapping.d.ts +1 -1
  311. package/build/services/otaLegacyMapping.d.ts.map +1 -1
  312. package/build/services/otaLegacyMapping.js.map +1 -1
  313. package/build/services/otaManifestPolicy.d.ts +14 -0
  314. package/build/services/otaManifestPolicy.d.ts.map +1 -0
  315. package/build/services/otaManifestPolicy.js +19 -0
  316. package/build/services/otaManifestPolicy.js.map +1 -0
  317. package/build/services/otaManifestUrl.d.ts +3 -0
  318. package/build/services/otaManifestUrl.d.ts.map +1 -0
  319. package/build/services/otaManifestUrl.js +38 -0
  320. package/build/services/otaManifestUrl.js.map +1 -0
  321. package/build/services/slimStreamStatus.d.ts +11 -0
  322. package/build/services/slimStreamStatus.d.ts.map +1 -1
  323. package/build/services/slimStreamStatus.js +14 -4
  324. package/build/services/slimStreamStatus.js.map +1 -1
  325. package/build/stores/apps.d.ts.map +1 -1
  326. package/build/stores/apps.js +11 -0
  327. package/build/stores/apps.js.map +1 -1
  328. package/build/stores/bluetoothSettingKeys.d.ts.map +1 -1
  329. package/build/stores/bluetoothSettingKeys.js +2 -0
  330. package/build/stores/bluetoothSettingKeys.js.map +1 -1
  331. package/build/stores/gallerySync.d.ts +2 -0
  332. package/build/stores/gallerySync.d.ts.map +1 -1
  333. package/build/stores/gallerySync.js +2 -0
  334. package/build/stores/gallerySync.js.map +1 -1
  335. package/build/stores/glasses.d.ts.map +1 -1
  336. package/build/stores/glasses.js +3 -0
  337. package/build/stores/glasses.js.map +1 -1
  338. package/build/stores/settings.d.ts +17 -0
  339. package/build/stores/settings.d.ts.map +1 -1
  340. package/build/stores/settings.js +157 -17
  341. package/build/stores/settings.js.map +1 -1
  342. package/build/types/applet.d.ts +2 -0
  343. package/build/types/applet.d.ts.map +1 -1
  344. package/build/types/applet.js.map +1 -1
  345. package/build/types/asg.d.ts +7 -0
  346. package/build/types/asg.d.ts.map +1 -1
  347. package/build/types/asg.js.map +1 -1
  348. package/build/types/enums.d.ts +2 -25
  349. package/build/types/enums.d.ts.map +1 -1
  350. package/build/types/enums.js +2 -27
  351. package/build/types/enums.js.map +1 -1
  352. package/build/types/hardware.d.ts +4 -13
  353. package/build/types/hardware.d.ts.map +1 -1
  354. package/build/types/hardware.js +15 -3
  355. package/build/types/hardware.js.map +1 -1
  356. package/build/types/index.d.ts +2 -6
  357. package/build/types/index.d.ts.map +1 -1
  358. package/build/types/index.js +2 -6
  359. package/build/types/index.js.map +1 -1
  360. package/build/utils/configuredDevHost.d.ts +6 -0
  361. package/build/utils/configuredDevHost.d.ts.map +1 -0
  362. package/build/utils/configuredDevHost.js +19 -0
  363. package/build/utils/configuredDevHost.js.map +1 -0
  364. package/build/utils/devMiniappLaunch.d.ts +19 -8
  365. package/build/utils/devMiniappLaunch.d.ts.map +1 -1
  366. package/build/utils/devMiniappLaunch.js +144 -21
  367. package/build/utils/devMiniappLaunch.js.map +1 -1
  368. package/build/utils/diagnosticContext.d.ts.map +1 -1
  369. package/build/utils/diagnosticContext.js +15 -17
  370. package/build/utils/diagnosticContext.js.map +1 -1
  371. package/build/utils/hardware/hardware.d.ts.map +1 -1
  372. package/build/utils/hardware/hardware.js +7 -3
  373. package/build/utils/hardware/hardware.js.map +1 -1
  374. package/build/utils/miniappDiagnostics.d.ts +64 -0
  375. package/build/utils/miniappDiagnostics.d.ts.map +1 -0
  376. package/build/utils/miniappDiagnostics.js +173 -0
  377. package/build/utils/miniappDiagnostics.js.map +1 -0
  378. package/build/utils/permissions/MediaLibraryPermissions.d.ts +11 -0
  379. package/build/utils/permissions/MediaLibraryPermissions.d.ts.map +1 -1
  380. package/build/utils/permissions/MediaLibraryPermissions.js +27 -4
  381. package/build/utils/permissions/MediaLibraryPermissions.js.map +1 -1
  382. package/build/utils/timers/timers.d.ts.map +1 -1
  383. package/build/utils/timers/timers.js +55 -18
  384. package/build/utils/timers/timers.js.map +1 -1
  385. package/package.json +59 -31
  386. package/src/assets/silence.wav +0 -0
  387. package/src/bluetooth-sdk/debug.ts +1 -0
  388. package/src/bluetooth-sdk/index.ts +2 -0
  389. package/src/bluetooth-sdk/photo-receiver.ts +2 -0
  390. package/src/bluetooth-sdk/react.ts +1 -0
  391. package/src/bluetooth-sdk/types.ts +1 -0
  392. package/src/engine.ts +9 -4
  393. package/src/facades/dev.ts +17 -12
  394. package/src/facades/display.ts +1 -1
  395. package/src/facades/gallery.ts +1 -1
  396. package/src/facades/glasses.ts +20 -7
  397. package/src/facades/glassesSettings.ts +5 -0
  398. package/src/facades/miniapps.ts +7 -0
  399. package/src/facades/ota.ts +23 -8
  400. package/src/facades/pairing.ts +15 -11
  401. package/src/facades/permissions.ts +14 -0
  402. package/src/facades/phoneNotifications.ts +4 -13
  403. package/src/facades/speech.ts +21 -7
  404. package/src/generated/releaseMetadata.ts +20 -0
  405. package/src/index.ts +39 -13
  406. package/src/react/MentraLiveOtaFlow.tsx +856 -0
  407. package/src/react/index.ts +7 -0
  408. package/src/react/useEngineSnapshot.ts +16 -0
  409. package/src/runtime/bootstrap.ts +33 -1
  410. package/src/runtime/scanQrSeam.ts +20 -0
  411. package/src/services/AppRegistry.ts +240 -149
  412. package/src/services/AudioCloudUplink.ts +23 -1
  413. package/src/services/AudioPlaybackService.ts +287 -38
  414. package/src/services/BlobStore.ts +22 -9
  415. package/src/services/CloudAudioSubscriptionSync.ts +13 -1
  416. package/src/services/CloudClientService.ts +96 -1
  417. package/src/services/DeviceEventRouter.ts +5 -5
  418. package/src/services/ForegroundLocationPermission.ts +24 -0
  419. package/src/services/GlassesSettingsSync.ts +9 -3
  420. package/src/services/GlassesStatusProjection.ts +16 -8
  421. package/src/services/HotspotOtaTransport.ts +184 -0
  422. package/src/services/HotspotShutdown.ts +41 -0
  423. package/src/services/LocalDisplayManager.ts +112 -21
  424. package/src/services/LocalMiniappRuntime.ts +967 -346
  425. package/src/services/LocalMiniappStorage.ts +82 -0
  426. package/src/services/LocalMiniappUserIdentity.ts +46 -0
  427. package/src/services/LocalSttFallbackCoordinator.ts +19 -12
  428. package/src/services/MicStateCoordinator.ts +169 -4
  429. package/src/services/MiniappLauncher.ts +30 -3
  430. package/src/services/MiniappLiveness.ts +24 -0
  431. package/src/services/NativeHttpResponse.ts +6 -0
  432. package/src/services/OtaArtifactDownloader.ts +312 -0
  433. package/src/services/OtaAutoChain.ts +106 -0
  434. package/src/services/OtaErrorMapping.ts +80 -0
  435. package/src/services/OtaInstallCoordinator.ts +649 -144
  436. package/src/services/OtaService.ts +11 -5
  437. package/src/services/OtaUpdateCheckService.ts +181 -21
  438. package/src/services/PhoneCalendarHelpers.ts +212 -0
  439. package/src/services/PhoneCalendarService.ts +65 -0
  440. package/src/services/PhoneCameraFovCoordinator.ts +210 -0
  441. package/src/services/PhoneNotificationsSync.ts +12 -10
  442. package/src/services/PhonePhotoCoordinator.ts +116 -18
  443. package/src/services/PhoneStreamCoordinator.ts +139 -25
  444. package/src/services/PhoneVideoCoordinator.ts +11 -0
  445. package/src/services/SceneRenderer.ts +16 -0
  446. package/src/services/SentenceTtsPipeline.ts +106 -0
  447. package/src/services/SupportProfileSync.ts +218 -0
  448. package/src/services/TranscriptionRouting.ts +37 -0
  449. package/src/services/TtsTextSanitizer.ts +66 -0
  450. package/src/services/WifiAdbRequest.ts +53 -0
  451. package/src/services/asg/asgCameraApi.ts +615 -33
  452. package/src/services/asg/cameraRollExportCoordinator.ts +627 -0
  453. package/src/services/asg/cameraRollExportLedger.ts +122 -0
  454. package/src/services/asg/galleryNotices.ts +1 -0
  455. package/src/services/asg/galleryPathMigration.ts +22 -0
  456. package/src/services/asg/gallerySettingsService.ts +3 -0
  457. package/src/services/asg/gallerySyncService.ts +184 -73
  458. package/src/services/asg/galleryTransferLedger.ts +312 -0
  459. package/src/services/asg/localNetworkTransport.ts +169 -0
  460. package/src/services/asg/localStorageService.ts +179 -24
  461. package/src/services/asg/mediaProcessingQueue.ts +209 -62
  462. package/src/services/audioPlaybackAssets.ts +8 -0
  463. package/src/services/gallerySyncClock.ts +1 -1
  464. package/src/services/glassesClockSync.ts +6 -2
  465. package/src/services/manifestActions.ts +30 -0
  466. package/src/services/otaDisplayState.ts +58 -17
  467. package/src/services/otaInstallPolicy.ts +30 -4
  468. package/src/services/otaLegacyMapping.ts +1 -1
  469. package/src/services/otaManifestPolicy.ts +42 -0
  470. package/src/services/otaManifestUrl.ts +44 -0
  471. package/src/services/slimStreamStatus.ts +16 -5
  472. package/src/stores/apps.ts +12 -0
  473. package/src/stores/bluetoothSettingKeys.ts +2 -0
  474. package/src/stores/gallerySync.ts +4 -0
  475. package/src/stores/glasses.ts +3 -0
  476. package/src/stores/settings.ts +179 -18
  477. package/src/types/applet.ts +2 -0
  478. package/src/types/asg.ts +7 -0
  479. package/src/types/enums.ts +3 -28
  480. package/src/types/hardware.ts +20 -13
  481. package/src/types/index.ts +2 -6
  482. package/src/utils/configuredDevHost.ts +17 -0
  483. package/src/utils/devMiniappLaunch.ts +151 -23
  484. package/src/utils/diagnosticContext.ts +17 -17
  485. package/src/utils/hardware/hardware.ts +7 -9
  486. package/src/utils/miniappDiagnostics.ts +226 -0
  487. package/src/utils/permissions/MediaLibraryPermissions.ts +35 -4
  488. package/src/utils/timers/timers.ts +57 -21
  489. package/build/devtools.d.ts +0 -11
  490. package/build/devtools.d.ts.map +0 -1
  491. package/build/devtools.js +0 -13
  492. package/build/devtools.js.map +0 -1
  493. package/build/internal.d.ts +0 -66
  494. package/build/internal.d.ts.map +0 -1
  495. package/build/internal.js +0 -89
  496. package/build/internal.js.map +0 -1
  497. package/build/services/asgOtaVersionUrl.d.ts +0 -2
  498. package/build/services/asgOtaVersionUrl.d.ts.map +0 -1
  499. package/build/services/asgOtaVersionUrl.js +0 -36
  500. package/build/services/asgOtaVersionUrl.js.map +0 -1
  501. package/src/devtools.ts +0 -13
  502. package/src/internal.ts +0 -158
  503. package/src/services/asgOtaVersionUrl.ts +0 -41
@@ -13,21 +13,26 @@
13
13
  * The local-miniapp path drives the cloud's transcription/translation through
14
14
  * this service.
15
15
  */
16
- import {CloudClient, setNativeUdp, setSecureStorage} from "@mentra/cloud-client/react-native"
16
+ import {CloudClient, setNativeHttp, setNativeUdp, setSecureStorage} from "@mentra/cloud-client/react-native"
17
17
  import type {PreinstalledMiniappRegistry, RuntimeSnapshot} from "@mentra/cloud-client/react-native"
18
18
  import type {SubjectTokenType} from "@mentra/cloud-client"
19
+ import {Platform} from "react-native"
19
20
  import type {AudioSubscription, TranscriptionData, TranslationData} from "@mentra/cloud-protocol"
20
21
 
21
22
  import BluetoothSdk from "@mentra/bluetooth-sdk/internal"
23
+ import CrustModule from "@mentra/crust"
22
24
  import {getAuth, getConfigValues} from "../runtime/bootstrap"
23
25
  import {useSettingsStore, SETTINGS} from "../stores/settings"
24
26
  import {type CloudClientStatusSnapshot, type MiniappAuthToken} from "../runtime/config"
25
27
  import {createCloudUdpSocket} from "../utils/cloudClient/RnUdpAdapter"
26
28
  import {cloudSecureStore} from "../utils/cloudClient/cloudSecureStore"
29
+ import {storage as mmkvStorage} from "../utils/storage"
27
30
  import {useCloudClientStatusStore} from "../stores/cloudClientStatus"
28
31
  import {islandNotifications} from "./NotificationsEmitter"
29
32
  import {BgTimer} from "../utils/timers"
30
33
  import {logCloudV2TranscriptMetric} from "./CloudTranscriptE2EMetrics"
34
+ import {LocalMiniappUserIdentity} from "./LocalMiniappUserIdentity"
35
+ import {nativeHttpResponseBody} from "./NativeHttpResponse"
31
36
 
32
37
  const LOG_TAG = "cloudClient"
33
38
  type CloudCore = NonNullable<CloudClient["core"]>
@@ -37,6 +42,7 @@ type CloudCore = NonNullable<CloudClient["core"]>
37
42
  // been continuously NOT connected for this long. A quick reconnect cancels it; brief
38
43
  // flaps that recover don't fire. Raised as engine.notifications(connection_failed_persistent).
39
44
  const CLOUD_PERSISTENT_FAILURE_MS = 60_000
45
+ const LOCAL_MINIAPP_USER_ID_KEY = "mentra.localMiniapp.userId"
40
46
 
41
47
  /** Cancel the pending persistent-failure alarm + re-arm for the next outage. */
42
48
  function clearPersistentFailureAlarm(): void {
@@ -72,6 +78,21 @@ let localDevRuntimeToken: {runtimeUrl: string; token: string; expiresAtMs: numbe
72
78
  let lc3FrameSizeUnsubscribe: (() => void) | null = null
73
79
  let coreTokenSyncPromise: Promise<string> | null = null
74
80
 
81
+ const localMiniappUserIdentity = new LocalMiniappUserIdentity({
82
+ get(): string | null {
83
+ const result = mmkvStorage.load<string>(LOCAL_MINIAPP_USER_ID_KEY)
84
+ return result.is_ok() ? result.value : null
85
+ },
86
+ set(userId: string): void {
87
+ const result = mmkvStorage.save(LOCAL_MINIAPP_USER_ID_KEY, userId)
88
+ if (result.is_error()) throw result.error
89
+ },
90
+ remove(): void {
91
+ const result = mmkvStorage.remove(LOCAL_MINIAPP_USER_ID_KEY)
92
+ if (result.is_error()) throw result.error
93
+ },
94
+ })
95
+
75
96
  const transcriptListeners = new Set<(d: TranscriptionData) => void>()
76
97
  const translationListeners = new Set<(d: TranslationData) => void>()
77
98
  const statusListeners = new Set<(snapshot: CloudClientStatusSnapshot) => void>()
@@ -111,6 +132,7 @@ async function syncCoreAccessTokenToBluetoothInternal(): Promise<string> {
111
132
  if (c !== client) {
112
133
  throw new Error("cloud client changed while syncing core token")
113
134
  }
135
+ localMiniappUserIdentity.remember(c.auth.identity.mentraUserId)
114
136
  const result = await useSettingsStore.getState().setSetting(SETTINGS.core_token.key, token, false)
115
137
  if (result.is_error()) {
116
138
  throw result.error
@@ -261,6 +283,13 @@ function ensureAuthWatch(): void {
261
283
  let reconnectPending = false
262
284
  try {
263
285
  const sub = auth.onStateChange((event, session) => {
286
+ if (event === "SIGNED_OUT") {
287
+ localMiniappUserIdentity.forget()
288
+ return
289
+ }
290
+ // A new sign-in may belong to a different account. Force the next
291
+ // storage request to resolve and persist that account's Core identity.
292
+ if (event === "SIGNED_IN") localMiniappUserIdentity.forget()
264
293
  if (!session?.token) return
265
294
  if (connected || reconnectPending) return
266
295
 
@@ -322,6 +351,24 @@ function ensureTransports(): void {
322
351
  transportsReady = true
323
352
  setNativeUdp(() => createCloudUdpSocket())
324
353
  setSecureStorage(cloudSecureStore)
354
+ if (Platform.OS !== "android") return
355
+ setNativeHttp(async (input, init) => {
356
+ if (typeof input !== "string" || (init?.body != null && typeof init.body !== "string")) {
357
+ return globalThis.fetch(input, init)
358
+ }
359
+ const headers = Object.fromEntries(new Headers(init?.headers).entries())
360
+ const result = await CrustModule.nativeHttpRequest(
361
+ init?.method ?? "GET",
362
+ input,
363
+ headers,
364
+ (init?.body as string | undefined) ?? null,
365
+ )
366
+ return new Response(nativeHttpResponseBody(result.status, result.body), {
367
+ status: result.status,
368
+ statusText: result.statusText,
369
+ headers: result.headers,
370
+ })
371
+ })
325
372
  }
326
373
 
327
374
  function clearRuntimeEventSubscriptions(): void {
@@ -375,6 +422,12 @@ function construct(): void {
375
422
  // LC3 at 16 kHz with the frame size the encoder emits.
376
423
  audio: {codec: "lc3", sampleRate: 16000, frameSizeBytes: frameSizeBytes()},
377
424
  auth,
425
+ timers: {
426
+ setTimeout: (callback, delayMs) => BgTimer.setTimeout(callback, delayMs),
427
+ clearTimeout: (handle) => BgTimer.clearTimeout(handle as number),
428
+ setInterval: (callback, intervalMs) => BgTimer.setInterval(callback, intervalMs),
429
+ clearInterval: (handle) => BgTimer.clearInterval(handle as number),
430
+ },
378
431
  logger: cloudLogger,
379
432
  })
380
433
 
@@ -399,6 +452,7 @@ function construct(): void {
399
452
  if (c !== client) return
400
453
  connected = true
401
454
  console.log(`${LOG_TAG}: runtime connected`)
455
+ console.log(`${LOG_TAG}: debug: ws-session-debug connected`)
402
456
  // Cloud is up — cancel any pending persistent-failure alarm and re-arm for the
403
457
  // next outage.
404
458
  clearPersistentFailureAlarm()
@@ -415,6 +469,9 @@ function construct(): void {
415
469
  if (c !== client) return
416
470
  connected = false
417
471
  console.log(`${LOG_TAG}: runtime disconnected (${info.reason})`)
472
+ console.log(
473
+ `${LOG_TAG}: debug: ws-session-debug disconnected reason=${info.reason} willStayDown=${/superseded by newer session/i.test(info.reason)}`,
474
+ )
418
475
  // Arm the persistent-failure alarm once; if we're still down when it fires, raise
419
476
  // the notification. A reconnect within the window cancels it (onConnected above).
420
477
  if (!persistentFailureTimer && !persistentFailureNotified) {
@@ -497,6 +554,34 @@ export const cloudClientService = {
497
554
  return c.core.miniapps.getRegistry()
498
555
  },
499
556
 
557
+ /**
558
+ * Resolve the stable Core-owned Mentra user id.
559
+ *
560
+ * Storage must use this identity rather than the short-lived Core access
561
+ * token. A previously verified id is restored from MMKV so local miniapps
562
+ * remain available after an offline process restart. On first sign-in,
563
+ * callers join the auth module's single-flight exchange/refresh instead of
564
+ * falling back to an anonymous namespace.
565
+ */
566
+ async resolveMentraUserId(): Promise<string> {
567
+ return localMiniappUserIdentity.resolve(async () => {
568
+ if (!client) this.init()
569
+ const c = client
570
+ if (!c) throw new Error("cloud client not initialized")
571
+
572
+ await c.auth.getCoreToken()
573
+ if (c !== client) throw new Error("cloud client changed while resolving user identity")
574
+ return c.auth.identity.mentraUserId
575
+ })
576
+ },
577
+
578
+ /** Read the stable Mentra user id after async identity resolution. */
579
+ getMentraUserId(): string {
580
+ const userId = localMiniappUserIdentity.get()
581
+ if (!userId) throw new Error("Mentra user identity is unavailable")
582
+ return userId
583
+ },
584
+
500
585
  async getMiniappAuthToken(
501
586
  packageName: string,
502
587
  opts?: {minTtlMs?: number; devAttestation?: string},
@@ -528,6 +613,11 @@ export const cloudClientService = {
528
613
  clearPersistentFailureAlarm()
529
614
  const wasConnected = connected
530
615
  client = null
616
+ // stop() is part of the logout lifecycle and runs before the host emits
617
+ // SIGNED_OUT. Remove the persisted namespace owner here so a later account
618
+ // can never inherit it. A force-stop/process kill does not call stop(), so
619
+ // the cached id still survives the offline cold-start case.
620
+ localMiniappUserIdentity.forget()
531
621
  localDevRuntimeToken = null
532
622
  connected = false
533
623
  resetRuntimeStatus()
@@ -660,6 +750,11 @@ export const cloudClientService = {
660
750
  return getCoreClient().reports.complete(...args)
661
751
  },
662
752
  },
753
+ supportProfile: {
754
+ update(...args: Parameters<CloudCore["supportProfile"]["update"]>) {
755
+ return getCoreClient().supportProfile.update(...args)
756
+ },
757
+ },
663
758
  },
664
759
 
665
760
  hasAudioSubscriptions(): boolean {
@@ -201,17 +201,17 @@ export function startDeviceEventRouter(): void {
201
201
  localMiniappRuntime.forwardEvent("head_up", {position: event.up ? "up" : "down", timestamp: Date.now()})
202
202
  }),
203
203
  )
204
- // On-device STT transcripts → local miniapps, but ONLY when local STT fallback is the
205
- // active engine (cloud STT is down). When the cloud WS is up, cloud transcripts reach
206
- // miniapps independently via the same forwardEvent, so gating on isActive() avoids
207
- // double-delivery. forwardEvent is subscriber-gated — a no-op when no miniapp listens.
204
+ // On-device STT transcripts → local miniapps only while the local engine is
205
+ // active (cloud fallback or an explicit forceLocal subscription). The runtime
206
+ // filters mixed local/cloud delivery per miniapp to avoid double-delivery.
207
+ // forwardEvent is subscriber-gated — a no-op when no miniapp listens.
208
208
  // (Was MantleManager.handle_local_transcription; its offline-captions display branch
209
209
  // went away with the pseudo captions renderer.)
210
210
  subs.push(
211
211
  BluetoothSdk.addListener("local_transcription", (event) => {
212
212
  if (!localSttFallbackCoordinator.isActive()) return
213
213
  const lang = event.transcribeLanguage ?? localSttFallbackCoordinator.getActiveLanguage() ?? "en-US"
214
- localMiniappRuntime.forwardEvent(`transcription:${lang}`, event)
214
+ localMiniappRuntime.forwardEvent(`transcription:${lang}`, event, "local")
215
215
  }),
216
216
  )
217
217
 
@@ -0,0 +1,24 @@
1
+ export interface ForegroundLocationPermissionResponse {
2
+ status: string
3
+ }
4
+
5
+ export interface ForegroundLocationPermissionClient {
6
+ getForegroundPermissionsAsync(): Promise<ForegroundLocationPermissionResponse>
7
+ requestForegroundPermissionsAsync(): Promise<ForegroundLocationPermissionResponse>
8
+ }
9
+
10
+ /**
11
+ * Resolve foreground location permission without invoking an Activity-bound
12
+ * Android permission request while the app is backgrounded.
13
+ */
14
+ export async function resolveForegroundLocationPermission(
15
+ client: ForegroundLocationPermissionClient,
16
+ getAppState: () => string,
17
+ ): Promise<ForegroundLocationPermissionResponse> {
18
+ const current = await client.getForegroundPermissionsAsync()
19
+ if (current.status === "granted" || getAppState() !== "active") {
20
+ return current
21
+ }
22
+
23
+ return client.requestForegroundPermissionsAsync()
24
+ }
@@ -19,6 +19,7 @@ import {useSettingsStore, PAIRING_IDENTITY_KEYS} from "../stores/settings"
19
19
  import {useGlassesStore} from "../stores/glasses"
20
20
  import {createDebouncedPatchFlusher} from "../utils/debouncedPatch"
21
21
  import {isGlassesConnected} from "./GlassesReadiness"
22
+ import micStateCoordinator from "./MicStateCoordinator"
22
23
 
23
24
  /**
24
25
  * Change-pushes are debounced (300ms) and merged so a burst of setSetting
@@ -28,7 +29,10 @@ import {isGlassesConnected} from "./GlassesReadiness"
28
29
  const flushBluetoothSettingsPatch = createDebouncedPatchFlusher<Record<string, unknown>>((patch) => {
29
30
  // Settings can change while the glasses are disconnected — a native
30
31
  // rejection must not surface as an unhandled promise rejection.
31
- void Promise.resolve(BluetoothSdk.updateBluetoothSettings(patch)).catch((error) => {
32
+ // Apply mic overrides at flush time, not enqueue time: raw PCM can stop
33
+ // during the debounce window and a captured VAD=false would then be stale.
34
+ const runtimePatch = micStateCoordinator.applyRuntimeOverrides(patch)
35
+ void Promise.resolve(BluetoothSdk.updateBluetoothSettings(runtimePatch)).catch((error) => {
32
36
  console.warn("GlassesSettingsSync: updateBluetoothSettings failed:", error)
33
37
  })
34
38
  }, 300)
@@ -79,7 +83,8 @@ export async function pushAllBluetoothSettings(): Promise<void> {
79
83
  // Returns the native write promise so callers can await the seed before the
80
84
  // connect handshake replays settings to the glasses (otherwise the handshake
81
85
  // can race ahead and replay stale native settings).
82
- await BluetoothSdk.updateBluetoothSettings(useSettingsStore.getState().getBluetoothSettings())
86
+ const settings = useSettingsStore.getState().getBluetoothSettings()
87
+ await BluetoothSdk.updateBluetoothSettings(micStateCoordinator.applyRuntimeOverrides(settings))
83
88
  }
84
89
 
85
90
  /**
@@ -91,7 +96,8 @@ export async function pushAllBluetoothSettings(): Promise<void> {
91
96
  * with pre-promotion empties (wiping the pairing it had just made).
92
97
  */
93
98
  export async function pushDeviceSettingsOnConnect(): Promise<void> {
94
- await BluetoothSdk.updateBluetoothSettings(stripPairingIdentity(useSettingsStore.getState().getBluetoothSettings()))
99
+ const settings = stripPairingIdentity(useSettingsStore.getState().getBluetoothSettings())
100
+ await BluetoothSdk.updateBluetoothSettings(micStateCoordinator.applyRuntimeOverrides(settings))
95
101
  }
96
102
 
97
103
  export function startGlassesSettingsSync(): void {
@@ -12,21 +12,24 @@
12
12
  * Started by `engine.start()`. Idempotent.
13
13
  */
14
14
  import BluetoothSdk from "@mentra/bluetooth-sdk/internal"
15
+ import type {GlassesStatus} from "@mentra/bluetooth-sdk/internal"
15
16
  import {useCoreStore} from "../stores/core"
16
17
  import {useGlassesStore} from "../stores/glasses"
17
- import localMiniappRuntime from "./LocalMiniappRuntime"
18
18
 
19
19
  let unsubs: Array<() => void> = []
20
20
  let projectionRunId = 0
21
+ let glassesStatusForwarder: ((status: Partial<GlassesStatus>) => void) | null = null
22
+ let hydrationPromise: Promise<void> | null = null
21
23
 
22
- export function startGlassesStatusProjection(): void {
23
- if (unsubs.length) return
24
+ export function startGlassesStatusProjection(forwarder?: (status: Partial<GlassesStatus>) => void): Promise<void> {
25
+ if (forwarder) glassesStatusForwarder = forwarder
26
+ if (unsubs.length) return hydrationPromise ?? Promise.resolve()
24
27
 
25
28
  const runId = ++projectionRunId
26
29
  let bluetoothEventSeen = false
27
30
  let glassesEventSeen = false
28
31
 
29
- void BluetoothSdk.getBluetoothStatus()
32
+ const bluetoothHydration = BluetoothSdk.getBluetoothStatus()
30
33
  .then((status) => {
31
34
  if (runId !== projectionRunId || bluetoothEventSeen) return
32
35
  useCoreStore.getState().setCoreInfo(status)
@@ -35,7 +38,7 @@ export function startGlassesStatusProjection(): void {
35
38
  console.warn("GlassesStatusProjection: getBluetoothStatus failed", error)
36
39
  })
37
40
 
38
- void BluetoothSdk.getGlassesStatus()
41
+ const glassesHydration = BluetoothSdk.getGlassesStatus()
39
42
  .then((status) => {
40
43
  if (runId !== projectionRunId || glassesEventSeen) return
41
44
  useGlassesStore.getState().setGlassesInfo(status)
@@ -52,22 +55,27 @@ export function startGlassesStatusProjection(): void {
52
55
  }),
53
56
  )
54
57
 
55
- // Glasses status -> glasses store (+ forward to local miniapps; clear any stale
56
- // OTA-available flag on disconnect).
58
+ // Glasses status -> glasses store (+ optional full-runtime forwarding to local
59
+ // miniapps; clear any stale OTA-available flag on disconnect).
57
60
  unsubs.push(
58
61
  BluetoothSdk.onGlassesStatus((changed) => {
59
62
  glassesEventSeen = true
60
63
  useGlassesStore.getState().setGlassesInfo(changed)
61
- localMiniappRuntime.forwardEvent("glasses_connection_state", changed)
64
+ glassesStatusForwarder?.(changed)
62
65
  if (changed.connection?.state === "disconnected") {
63
66
  useGlassesStore.getState().setOtaUpdateAvailable(null)
64
67
  }
65
68
  }),
66
69
  )
70
+
71
+ hydrationPromise = Promise.allSettled([bluetoothHydration, glassesHydration]).then(() => undefined)
72
+ return hydrationPromise
67
73
  }
68
74
 
69
75
  export function stopGlassesStatusProjection(): void {
70
76
  projectionRunId++
71
77
  unsubs.forEach((unsub) => unsub())
72
78
  unsubs = []
79
+ glassesStatusForwarder = null
80
+ hydrationPromise = null
73
81
  }
@@ -0,0 +1,184 @@
1
+ import BluetoothSdk, {isEnabledHotspotStatus, MentraOtaServer} from "@mentra/bluetooth-sdk/internal"
2
+ // One coordinator selects the native Android or iOS staging implementation at runtime.
3
+ // eslint-disable-next-line react-native/split-platform-components
4
+ import {PermissionsAndroid, Platform} from "react-native"
5
+ import type {OtaCheckCurrentGlassesResult} from "./OtaUpdateCheckService"
6
+ import {
7
+ cleanupArtifacts,
8
+ OtaArtifactError,
9
+ planArtifacts,
10
+ prepareArtifacts,
11
+ rewriteManifestForLocalServer,
12
+ type OtaArtifactDownloadProgress,
13
+ type PreparedOtaArtifact,
14
+ } from "./OtaArtifactDownloader"
15
+ import {disableHotspotWithRetry} from "./HotspotShutdown"
16
+ import {localNetworkTransport} from "./asg/localNetworkTransport"
17
+
18
+ export type HotspotOtaPhase = "idle" | "downloading" | "starting_hotspot" | "joining_hotspot" | "serving"
19
+
20
+ export type HotspotOtaProgress = {
21
+ phase: HotspotOtaPhase
22
+ artifact?: OtaArtifactDownloadProgress
23
+ }
24
+
25
+ export type HotspotOtaErrorCode =
26
+ | "hotspot_wifi_permission_denied"
27
+ | "hotspot_start_failed"
28
+ | "hotspot_join_failed"
29
+ | "hotspot_server_failed"
30
+
31
+ export class HotspotOtaTransportError extends Error {
32
+ constructor(
33
+ public readonly code: HotspotOtaErrorCode,
34
+ message: string,
35
+ ) {
36
+ super(message)
37
+ this.name = "HotspotOtaTransportError"
38
+ }
39
+ }
40
+
41
+ /** Owns the single phone-side endpoint and network lease for one hotspot OTA attempt. */
42
+ class HotspotOtaTransport {
43
+ private active = false
44
+ private prepared: PreparedOtaArtifact[] = []
45
+ private hotspotRequested = false
46
+ private localNetworkConnected = false
47
+ private serverStarted = false
48
+ private teardownPromise: Promise<void> | null = null
49
+
50
+ async prepare(
51
+ checkResult: OtaCheckCurrentGlassesResult,
52
+ onProgress?: (progress: HotspotOtaProgress) => void,
53
+ ): Promise<string> {
54
+ if (this.teardownPromise) await this.teardownPromise
55
+ if (this.active) {
56
+ throw new Error("A hotspot OTA transport is already active")
57
+ }
58
+ if (!checkResult.manifestBody) {
59
+ throw new Error("The selected OTA check has no manifest body")
60
+ }
61
+
62
+ let phase: HotspotOtaPhase = "downloading"
63
+ try {
64
+ await this.ensureAndroidWifiPermission()
65
+ onProgress?.({phase: "downloading"})
66
+ this.prepared = await prepareArtifacts(
67
+ planArtifacts(checkResult),
68
+ (artifact) => onProgress?.({phase: "downloading", artifact}),
69
+ Platform.OS === "ios" ? this.downloadIosArtifact : undefined,
70
+ )
71
+
72
+ phase = "starting_hotspot"
73
+ onProgress?.({phase: "starting_hotspot"})
74
+ this.hotspotRequested = true
75
+ const hotspot = await BluetoothSdk.setHotspotState(true)
76
+ if (!isEnabledHotspotStatus(hotspot)) {
77
+ throw new HotspotOtaTransportError("hotspot_start_failed", "Mentra Live did not return hotspot credentials")
78
+ }
79
+ phase = "joining_hotspot"
80
+ onProgress?.({phase: "joining_hotspot"})
81
+ const scopedAddress = await localNetworkTransport.connect(hotspot.ssid, hotspot.password)
82
+ this.localNetworkConnected = true
83
+ let localAddress = scopedAddress
84
+ if (Platform.OS === "ios") {
85
+ try {
86
+ localAddress = await MentraOtaServer.waitForWifiAddress(hotspot.localIp, 15_000)
87
+ } catch (error) {
88
+ throw new HotspotOtaTransportError(
89
+ "hotspot_join_failed",
90
+ error instanceof Error ? error.message : String(error),
91
+ )
92
+ }
93
+ }
94
+ const artifactPaths = Object.fromEntries(this.prepared.map((artifact) => [artifact.sha256, artifact.filePath]))
95
+ // Start exactly one native listener to learn its selected port, then atomically replace
96
+ // the placeholder with the immutable rewritten manifest before ota_start is sent.
97
+ const server = await MentraOtaServer.startOtaServer("{}", artifactPaths, localAddress)
98
+ this.serverStarted = true
99
+ const manifest = rewriteManifestForLocalServer(checkResult.manifestBody, this.prepared, server.baseUrl)
100
+ const published = await MentraOtaServer.startOtaServer(manifest, artifactPaths, server.host)
101
+ if (published.manifestUrl !== server.manifestUrl) {
102
+ throw new Error("Local OTA server endpoint changed while publishing the manifest")
103
+ }
104
+ this.active = true
105
+ onProgress?.({phase: "serving"})
106
+ return published.manifestUrl
107
+ } catch (error) {
108
+ const joined = this.localNetworkConnected
109
+ await this.teardown()
110
+ if (error instanceof OtaArtifactError || error instanceof HotspotOtaTransportError) {
111
+ throw error
112
+ }
113
+ const message = error instanceof Error ? error.message : String(error)
114
+ if (phase === "starting_hotspot") {
115
+ throw new HotspotOtaTransportError("hotspot_start_failed", message)
116
+ }
117
+ if (phase === "joining_hotspot" && !joined) {
118
+ throw new HotspotOtaTransportError("hotspot_join_failed", message)
119
+ }
120
+ throw new HotspotOtaTransportError("hotspot_server_failed", message)
121
+ }
122
+ }
123
+
124
+ /** Android 13+ requires the nearby-WiFi runtime grant before WifiNetworkSpecifier is usable. */
125
+ private async ensureAndroidWifiPermission(): Promise<void> {
126
+ if (Platform.OS !== "android") return
127
+
128
+ const permission = PermissionsAndroid.PERMISSIONS.NEARBY_WIFI_DEVICES
129
+ if (await PermissionsAndroid.check(permission)) return
130
+ const result = await PermissionsAndroid.request(permission)
131
+ if (result !== PermissionsAndroid.RESULTS.GRANTED) {
132
+ throw new HotspotOtaTransportError(
133
+ "hotspot_wifi_permission_denied",
134
+ "Nearby devices permission is required to connect to the glasses hotspot",
135
+ )
136
+ }
137
+ }
138
+
139
+ private downloadIosArtifact = async (
140
+ entry: {url: string},
141
+ destination: string,
142
+ onProgress?: (bytesWritten: number, contentLength: number) => void,
143
+ ): Promise<{statusCode: number}> => {
144
+ const subscription = MentraOtaServer.addListener("artifactDownloadProgress", (event) => {
145
+ if (event.destination === destination) onProgress?.(event.bytesWritten, event.contentLength)
146
+ })
147
+ try {
148
+ return await MentraOtaServer.downloadArtifact(entry.url, destination)
149
+ } finally {
150
+ subscription.remove()
151
+ }
152
+ }
153
+
154
+ async teardown(): Promise<void> {
155
+ if (this.teardownPromise) return this.teardownPromise
156
+ this.teardownPromise = (async () => {
157
+ if (this.hotspotRequested) {
158
+ const hotspotStopped = await disableHotspotWithRetry(() => BluetoothSdk.setHotspotState(false), {
159
+ // A completed APK step has just replaced ASG. Let the new command path
160
+ // settle before asking it to tear down the SystemUI-owned access point.
161
+ initialDelayMs: this.serverStarted ? 750 : 0,
162
+ })
163
+ if (!hotspotStopped) {
164
+ console.warn("[OTA_PROGRESS] glasses hotspot shutdown was not confirmed after bounded retries")
165
+ }
166
+ }
167
+ if (this.serverStarted) await MentraOtaServer.stopOtaServer().catch(() => {})
168
+ if (this.localNetworkConnected) await localNetworkTransport.disconnect().catch(() => {})
169
+ await cleanupArtifacts().catch(() => {})
170
+ this.prepared = []
171
+ this.active = false
172
+ this.serverStarted = false
173
+ this.localNetworkConnected = false
174
+ this.hotspotRequested = false
175
+ })()
176
+ try {
177
+ await this.teardownPromise
178
+ } finally {
179
+ this.teardownPromise = null
180
+ }
181
+ }
182
+ }
183
+
184
+ export const hotspotOtaTransport = new HotspotOtaTransport()
@@ -0,0 +1,41 @@
1
+ type HotspotState = {state: "disabled" | "enabled"}
2
+
3
+ type HotspotShutdownOptions = {
4
+ attempts?: number
5
+ initialDelayMs?: number
6
+ retryDelayMs?: number
7
+ sleep?: (delayMs: number) => Promise<void>
8
+ }
9
+
10
+ const sleep = (delayMs: number) => new Promise<void>((resolve) => setTimeout(resolve, delayMs))
11
+
12
+ /**
13
+ * Disable a glasses hotspot with a bounded retry. ASG APK replacement keeps the
14
+ * BLE link alive through BES, but the first command after the new ASG process
15
+ * appears can still land while its command path is settling.
16
+ */
17
+ export async function disableHotspotWithRetry(
18
+ requestDisabled: () => Promise<HotspotState>,
19
+ options: HotspotShutdownOptions = {},
20
+ ): Promise<boolean> {
21
+ const attempts = Math.max(1, options.attempts ?? 2)
22
+ const initialDelayMs = Math.max(0, options.initialDelayMs ?? 0)
23
+ const retryDelayMs = Math.max(0, options.retryDelayMs ?? 500)
24
+ const wait = options.sleep ?? sleep
25
+
26
+ if (initialDelayMs > 0) await wait(initialDelayMs)
27
+
28
+ for (let attempt = 1; attempt <= attempts; attempt += 1) {
29
+ try {
30
+ const status = await requestDisabled()
31
+ if (status.state === "disabled") return true
32
+ } catch {
33
+ // A lost command is indistinguishable from a response timeout here. Retry
34
+ // while the phone still owns the hotspot network and local server.
35
+ }
36
+
37
+ if (attempt < attempts && retryDelayMs > 0) await wait(retryDelayMs)
38
+ }
39
+
40
+ return false
41
+ }