@mentra/engine 0.1.0-dev.0 → 0.1.0-dev.1

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 (441) hide show
  1. package/README.md +42 -1
  2. package/build/engine.d.ts +11 -3
  3. package/build/engine.d.ts.map +1 -1
  4. package/build/engine.js +7 -2
  5. package/build/engine.js.map +1 -1
  6. package/build/facades/dev.d.ts +3 -2
  7. package/build/facades/dev.d.ts.map +1 -1
  8. package/build/facades/dev.js +18 -12
  9. package/build/facades/dev.js.map +1 -1
  10. package/build/facades/gallery.js +1 -1
  11. package/build/facades/gallery.js.map +1 -1
  12. package/build/facades/glasses.d.ts +1 -0
  13. package/build/facades/glasses.d.ts.map +1 -1
  14. package/build/facades/glasses.js +19 -4
  15. package/build/facades/glasses.js.map +1 -1
  16. package/build/facades/glassesSettings.d.ts.map +1 -1
  17. package/build/facades/glassesSettings.js +1 -0
  18. package/build/facades/glassesSettings.js.map +1 -1
  19. package/build/facades/miniapps.d.ts +4 -0
  20. package/build/facades/miniapps.d.ts.map +1 -1
  21. package/build/facades/miniapps.js +5 -0
  22. package/build/facades/miniapps.js.map +1 -1
  23. package/build/facades/ota.d.ts +11 -2
  24. package/build/facades/ota.d.ts.map +1 -1
  25. package/build/facades/ota.js +19 -4
  26. package/build/facades/ota.js.map +1 -1
  27. package/build/facades/pairing.d.ts +4 -0
  28. package/build/facades/pairing.d.ts.map +1 -1
  29. package/build/facades/pairing.js +10 -8
  30. package/build/facades/pairing.js.map +1 -1
  31. package/build/facades/permissions.d.ts +10 -0
  32. package/build/facades/permissions.d.ts.map +1 -1
  33. package/build/facades/permissions.js +10 -0
  34. package/build/facades/permissions.js.map +1 -1
  35. package/build/facades/phoneNotifications.d.ts +0 -4
  36. package/build/facades/phoneNotifications.d.ts.map +1 -1
  37. package/build/facades/phoneNotifications.js +4 -14
  38. package/build/facades/phoneNotifications.js.map +1 -1
  39. package/build/index.d.ts +6 -3
  40. package/build/index.d.ts.map +1 -1
  41. package/build/index.js +4 -2
  42. package/build/index.js.map +1 -1
  43. package/build/internal.d.ts +3 -2
  44. package/build/internal.d.ts.map +1 -1
  45. package/build/internal.js +2 -1
  46. package/build/internal.js.map +1 -1
  47. package/build/react/MentraLiveOtaFlow.d.ts +38 -0
  48. package/build/react/MentraLiveOtaFlow.d.ts.map +1 -0
  49. package/build/react/MentraLiveOtaFlow.js +528 -0
  50. package/build/react/MentraLiveOtaFlow.js.map +1 -0
  51. package/build/react/index.d.ts +2 -0
  52. package/build/react/index.d.ts.map +1 -0
  53. package/build/react/index.js +2 -0
  54. package/build/react/index.js.map +1 -0
  55. package/build/react/useEngineSnapshot.d.ts +2 -0
  56. package/build/react/useEngineSnapshot.d.ts.map +1 -0
  57. package/build/react/useEngineSnapshot.js +14 -0
  58. package/build/react/useEngineSnapshot.js.map +1 -0
  59. package/build/runtime/bootstrap.d.ts +24 -1
  60. package/build/runtime/bootstrap.d.ts.map +1 -1
  61. package/build/runtime/bootstrap.js +17 -0
  62. package/build/runtime/bootstrap.js.map +1 -1
  63. package/build/runtime/scanQrSeam.d.ts +7 -0
  64. package/build/runtime/scanQrSeam.d.ts.map +1 -0
  65. package/build/runtime/scanQrSeam.js +16 -0
  66. package/build/runtime/scanQrSeam.js.map +1 -0
  67. package/build/services/AppRegistry.d.ts +33 -57
  68. package/build/services/AppRegistry.d.ts.map +1 -1
  69. package/build/services/AppRegistry.js +193 -144
  70. package/build/services/AppRegistry.js.map +1 -1
  71. package/build/services/AudioCloudUplink.d.ts +12 -0
  72. package/build/services/AudioCloudUplink.d.ts.map +1 -1
  73. package/build/services/AudioCloudUplink.js +22 -1
  74. package/build/services/AudioCloudUplink.js.map +1 -1
  75. package/build/services/AudioPlaybackService.d.ts +41 -2
  76. package/build/services/AudioPlaybackService.d.ts.map +1 -1
  77. package/build/services/AudioPlaybackService.js +250 -33
  78. package/build/services/AudioPlaybackService.js.map +1 -1
  79. package/build/services/BlobStore.d.ts +2 -1
  80. package/build/services/BlobStore.d.ts.map +1 -1
  81. package/build/services/BlobStore.js +17 -9
  82. package/build/services/BlobStore.js.map +1 -1
  83. package/build/services/CloudAudioSubscriptionSync.d.ts.map +1 -1
  84. package/build/services/CloudAudioSubscriptionSync.js +13 -1
  85. package/build/services/CloudAudioSubscriptionSync.js.map +1 -1
  86. package/build/services/CloudClientService.d.ts +15 -0
  87. package/build/services/CloudClientService.d.ts.map +1 -1
  88. package/build/services/CloudClientService.js +93 -1
  89. package/build/services/CloudClientService.js.map +1 -1
  90. package/build/services/DeviceEventRouter.js +5 -5
  91. package/build/services/DeviceEventRouter.js.map +1 -1
  92. package/build/services/ForegroundLocationPermission.d.ts +13 -0
  93. package/build/services/ForegroundLocationPermission.d.ts.map +1 -0
  94. package/build/services/ForegroundLocationPermission.js +12 -0
  95. package/build/services/ForegroundLocationPermission.js.map +1 -0
  96. package/build/services/GlassesSettingsSync.d.ts.map +1 -1
  97. package/build/services/GlassesSettingsSync.js +9 -3
  98. package/build/services/GlassesSettingsSync.js.map +1 -1
  99. package/build/services/GlassesStatusProjection.d.ts +2 -1
  100. package/build/services/GlassesStatusProjection.d.ts.map +1 -1
  101. package/build/services/GlassesStatusProjection.js +15 -8
  102. package/build/services/GlassesStatusProjection.js.map +1 -1
  103. package/build/services/HotspotOtaTransport.d.ts +29 -0
  104. package/build/services/HotspotOtaTransport.d.ts.map +1 -0
  105. package/build/services/HotspotOtaTransport.js +146 -0
  106. package/build/services/HotspotOtaTransport.js.map +1 -0
  107. package/build/services/HotspotShutdown.d.ts +17 -0
  108. package/build/services/HotspotShutdown.d.ts.map +1 -0
  109. package/build/services/HotspotShutdown.js +29 -0
  110. package/build/services/HotspotShutdown.js.map +1 -0
  111. package/build/services/LocalDisplayManager.d.ts +15 -0
  112. package/build/services/LocalDisplayManager.d.ts.map +1 -1
  113. package/build/services/LocalDisplayManager.js +106 -20
  114. package/build/services/LocalDisplayManager.js.map +1 -1
  115. package/build/services/LocalMiniappRuntime.d.ts +74 -2
  116. package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
  117. package/build/services/LocalMiniappRuntime.js +785 -291
  118. package/build/services/LocalMiniappRuntime.js.map +1 -1
  119. package/build/services/LocalMiniappStorage.d.ts +32 -0
  120. package/build/services/LocalMiniappStorage.d.ts.map +1 -0
  121. package/build/services/LocalMiniappStorage.js +66 -0
  122. package/build/services/LocalMiniappStorage.js.map +1 -0
  123. package/build/services/LocalMiniappUserIdentity.d.ts +20 -0
  124. package/build/services/LocalMiniappUserIdentity.d.ts.map +1 -0
  125. package/build/services/LocalMiniappUserIdentity.js +43 -0
  126. package/build/services/LocalMiniappUserIdentity.js.map +1 -0
  127. package/build/services/LocalSttFallbackCoordinator.d.ts +9 -6
  128. package/build/services/LocalSttFallbackCoordinator.d.ts.map +1 -1
  129. package/build/services/LocalSttFallbackCoordinator.js +18 -12
  130. package/build/services/LocalSttFallbackCoordinator.js.map +1 -1
  131. package/build/services/MicStateCoordinator.d.ts +42 -1
  132. package/build/services/MicStateCoordinator.d.ts.map +1 -1
  133. package/build/services/MicStateCoordinator.js +141 -3
  134. package/build/services/MicStateCoordinator.js.map +1 -1
  135. package/build/services/MiniappLauncher.d.ts.map +1 -1
  136. package/build/services/MiniappLauncher.js +23 -3
  137. package/build/services/MiniappLauncher.js.map +1 -1
  138. package/build/services/MiniappLiveness.d.ts +12 -0
  139. package/build/services/MiniappLiveness.d.ts.map +1 -0
  140. package/build/services/MiniappLiveness.js +16 -0
  141. package/build/services/MiniappLiveness.js.map +1 -0
  142. package/build/services/NativeHttpResponse.d.ts +3 -0
  143. package/build/services/NativeHttpResponse.d.ts.map +1 -0
  144. package/build/services/NativeHttpResponse.js +6 -0
  145. package/build/services/NativeHttpResponse.js.map +1 -0
  146. package/build/services/OtaArtifactDownloader.d.ts +65 -0
  147. package/build/services/OtaArtifactDownloader.d.ts.map +1 -0
  148. package/build/services/OtaArtifactDownloader.js +226 -0
  149. package/build/services/OtaArtifactDownloader.js.map +1 -0
  150. package/build/services/OtaAutoChain.d.ts +34 -0
  151. package/build/services/OtaAutoChain.d.ts.map +1 -0
  152. package/build/services/OtaAutoChain.js +83 -0
  153. package/build/services/OtaAutoChain.js.map +1 -0
  154. package/build/services/OtaErrorMapping.d.ts +18 -0
  155. package/build/services/OtaErrorMapping.d.ts.map +1 -0
  156. package/build/services/OtaErrorMapping.js +63 -0
  157. package/build/services/OtaErrorMapping.js.map +1 -0
  158. package/build/services/OtaInstallCoordinator.d.ts +94 -14
  159. package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
  160. package/build/services/OtaInstallCoordinator.js +574 -130
  161. package/build/services/OtaInstallCoordinator.js.map +1 -1
  162. package/build/services/OtaService.d.ts.map +1 -1
  163. package/build/services/OtaService.js +8 -1
  164. package/build/services/OtaService.js.map +1 -1
  165. package/build/services/OtaUpdateCheckService.d.ts +38 -3
  166. package/build/services/OtaUpdateCheckService.d.ts.map +1 -1
  167. package/build/services/OtaUpdateCheckService.js +142 -22
  168. package/build/services/OtaUpdateCheckService.js.map +1 -1
  169. package/build/services/PhoneCalendarHelpers.d.ts +32 -0
  170. package/build/services/PhoneCalendarHelpers.d.ts.map +1 -0
  171. package/build/services/PhoneCalendarHelpers.js +157 -0
  172. package/build/services/PhoneCalendarHelpers.js.map +1 -0
  173. package/build/services/PhoneCalendarService.d.ts +5 -0
  174. package/build/services/PhoneCalendarService.d.ts.map +1 -0
  175. package/build/services/PhoneCalendarService.js +45 -0
  176. package/build/services/PhoneCalendarService.js.map +1 -0
  177. package/build/services/PhoneCameraFovCoordinator.d.ts +30 -0
  178. package/build/services/PhoneCameraFovCoordinator.d.ts.map +1 -0
  179. package/build/services/PhoneCameraFovCoordinator.js +194 -0
  180. package/build/services/PhoneCameraFovCoordinator.js.map +1 -0
  181. package/build/services/PhoneNotificationsSync.d.ts.map +1 -1
  182. package/build/services/PhoneNotificationsSync.js +12 -10
  183. package/build/services/PhoneNotificationsSync.js.map +1 -1
  184. package/build/services/PhonePhotoCoordinator.d.ts +26 -2
  185. package/build/services/PhonePhotoCoordinator.d.ts.map +1 -1
  186. package/build/services/PhonePhotoCoordinator.js +79 -9
  187. package/build/services/PhonePhotoCoordinator.js.map +1 -1
  188. package/build/services/PhoneStreamCoordinator.d.ts +8 -1
  189. package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
  190. package/build/services/PhoneStreamCoordinator.js +125 -13
  191. package/build/services/PhoneStreamCoordinator.js.map +1 -1
  192. package/build/services/PhoneVideoCoordinator.d.ts +2 -0
  193. package/build/services/PhoneVideoCoordinator.d.ts.map +1 -1
  194. package/build/services/PhoneVideoCoordinator.js +10 -0
  195. package/build/services/PhoneVideoCoordinator.js.map +1 -1
  196. package/build/services/SceneRenderer.d.ts.map +1 -1
  197. package/build/services/SceneRenderer.js +15 -0
  198. package/build/services/SceneRenderer.js.map +1 -1
  199. package/build/services/SentenceTtsPipeline.d.ts +31 -0
  200. package/build/services/SentenceTtsPipeline.d.ts.map +1 -0
  201. package/build/services/SentenceTtsPipeline.js +67 -0
  202. package/build/services/SentenceTtsPipeline.js.map +1 -0
  203. package/build/services/SupportProfileSync.d.ts +22 -0
  204. package/build/services/SupportProfileSync.d.ts.map +1 -0
  205. package/build/services/SupportProfileSync.js +213 -0
  206. package/build/services/SupportProfileSync.js.map +1 -0
  207. package/build/services/TranscriptionRouting.d.ts +12 -0
  208. package/build/services/TranscriptionRouting.d.ts.map +1 -0
  209. package/build/services/TranscriptionRouting.js +24 -0
  210. package/build/services/TranscriptionRouting.js.map +1 -0
  211. package/build/services/TtsTextSanitizer.d.ts +5 -0
  212. package/build/services/TtsTextSanitizer.d.ts.map +1 -0
  213. package/build/services/TtsTextSanitizer.js +61 -0
  214. package/build/services/TtsTextSanitizer.js.map +1 -0
  215. package/build/services/WifiAdbRequest.d.ts +17 -0
  216. package/build/services/WifiAdbRequest.d.ts.map +1 -0
  217. package/build/services/WifiAdbRequest.js +35 -0
  218. package/build/services/WifiAdbRequest.js.map +1 -0
  219. package/build/services/asg/asgCameraApi.d.ts +43 -0
  220. package/build/services/asg/asgCameraApi.d.ts.map +1 -1
  221. package/build/services/asg/asgCameraApi.js +509 -26
  222. package/build/services/asg/asgCameraApi.js.map +1 -1
  223. package/build/services/asg/cameraRollExportCoordinator.d.ts +60 -0
  224. package/build/services/asg/cameraRollExportCoordinator.d.ts.map +1 -0
  225. package/build/services/asg/cameraRollExportCoordinator.js +618 -0
  226. package/build/services/asg/cameraRollExportCoordinator.js.map +1 -0
  227. package/build/services/asg/cameraRollExportLedger.d.ts +44 -0
  228. package/build/services/asg/cameraRollExportLedger.d.ts.map +1 -0
  229. package/build/services/asg/cameraRollExportLedger.js +78 -0
  230. package/build/services/asg/cameraRollExportLedger.js.map +1 -0
  231. package/build/services/asg/galleryNotices.d.ts +1 -1
  232. package/build/services/asg/galleryNotices.d.ts.map +1 -1
  233. package/build/services/asg/galleryNotices.js.map +1 -1
  234. package/build/services/asg/galleryPathMigration.d.ts +3 -0
  235. package/build/services/asg/galleryPathMigration.d.ts.map +1 -0
  236. package/build/services/asg/galleryPathMigration.js +26 -0
  237. package/build/services/asg/galleryPathMigration.js.map +1 -0
  238. package/build/services/asg/gallerySettingsService.d.ts +1 -0
  239. package/build/services/asg/gallerySettingsService.d.ts.map +1 -1
  240. package/build/services/asg/gallerySettingsService.js +2 -0
  241. package/build/services/asg/gallerySettingsService.js.map +1 -1
  242. package/build/services/asg/gallerySyncService.d.ts.map +1 -1
  243. package/build/services/asg/gallerySyncService.js +162 -56
  244. package/build/services/asg/gallerySyncService.js.map +1 -1
  245. package/build/services/asg/galleryTransferLedger.d.ts +58 -0
  246. package/build/services/asg/galleryTransferLedger.d.ts.map +1 -0
  247. package/build/services/asg/galleryTransferLedger.js +225 -0
  248. package/build/services/asg/galleryTransferLedger.js.map +1 -0
  249. package/build/services/asg/localNetworkTransport.d.ts +15 -0
  250. package/build/services/asg/localNetworkTransport.d.ts.map +1 -0
  251. package/build/services/asg/localNetworkTransport.js +144 -0
  252. package/build/services/asg/localNetworkTransport.js.map +1 -0
  253. package/build/services/asg/localStorageService.d.ts +18 -0
  254. package/build/services/asg/localStorageService.d.ts.map +1 -1
  255. package/build/services/asg/localStorageService.js +168 -19
  256. package/build/services/asg/localStorageService.js.map +1 -1
  257. package/build/services/asg/mediaProcessingQueue.d.ts +10 -0
  258. package/build/services/asg/mediaProcessingQueue.d.ts.map +1 -1
  259. package/build/services/asg/mediaProcessingQueue.js +193 -62
  260. package/build/services/asg/mediaProcessingQueue.js.map +1 -1
  261. package/build/services/audioPlaybackAssets.d.ts +8 -0
  262. package/build/services/audioPlaybackAssets.d.ts.map +1 -0
  263. package/build/services/audioPlaybackAssets.js +7 -0
  264. package/build/services/audioPlaybackAssets.js.map +1 -0
  265. package/build/services/gallerySyncClock.js +1 -1
  266. package/build/services/gallerySyncClock.js.map +1 -1
  267. package/build/services/glassesClockSync.js +2 -2
  268. package/build/services/glassesClockSync.js.map +1 -1
  269. package/build/services/manifestActions.d.ts +7 -0
  270. package/build/services/manifestActions.d.ts.map +1 -0
  271. package/build/services/manifestActions.js +25 -0
  272. package/build/services/manifestActions.js.map +1 -0
  273. package/build/services/otaDisplayState.d.ts +22 -11
  274. package/build/services/otaDisplayState.d.ts.map +1 -1
  275. package/build/services/otaDisplayState.js +36 -14
  276. package/build/services/otaDisplayState.js.map +1 -1
  277. package/build/services/otaInstallPolicy.d.ts +15 -3
  278. package/build/services/otaInstallPolicy.d.ts.map +1 -1
  279. package/build/services/otaInstallPolicy.js +24 -3
  280. package/build/services/otaInstallPolicy.js.map +1 -1
  281. package/build/services/otaManifestUrl.d.ts +2 -0
  282. package/build/services/otaManifestUrl.d.ts.map +1 -0
  283. package/build/services/{asgOtaVersionUrl.js → otaManifestUrl.js} +15 -5
  284. package/build/services/otaManifestUrl.js.map +1 -0
  285. package/build/services/slimStreamStatus.d.ts +11 -0
  286. package/build/services/slimStreamStatus.d.ts.map +1 -1
  287. package/build/services/slimStreamStatus.js +14 -4
  288. package/build/services/slimStreamStatus.js.map +1 -1
  289. package/build/stores/apps.d.ts.map +1 -1
  290. package/build/stores/apps.js +11 -0
  291. package/build/stores/apps.js.map +1 -1
  292. package/build/stores/bluetoothSettingKeys.d.ts.map +1 -1
  293. package/build/stores/bluetoothSettingKeys.js +2 -0
  294. package/build/stores/bluetoothSettingKeys.js.map +1 -1
  295. package/build/stores/gallerySync.d.ts +2 -0
  296. package/build/stores/gallerySync.d.ts.map +1 -1
  297. package/build/stores/gallerySync.js +2 -0
  298. package/build/stores/gallerySync.js.map +1 -1
  299. package/build/stores/glasses.d.ts.map +1 -1
  300. package/build/stores/glasses.js +3 -0
  301. package/build/stores/glasses.js.map +1 -1
  302. package/build/stores/settings.d.ts +17 -0
  303. package/build/stores/settings.d.ts.map +1 -1
  304. package/build/stores/settings.js +157 -17
  305. package/build/stores/settings.js.map +1 -1
  306. package/build/types/applet.d.ts +2 -0
  307. package/build/types/applet.d.ts.map +1 -1
  308. package/build/types/applet.js.map +1 -1
  309. package/build/types/asg.d.ts +7 -0
  310. package/build/types/asg.d.ts.map +1 -1
  311. package/build/types/asg.js.map +1 -1
  312. package/build/types/enums.d.ts +1 -0
  313. package/build/types/enums.d.ts.map +1 -1
  314. package/build/types/enums.js +1 -0
  315. package/build/types/enums.js.map +1 -1
  316. package/build/types/hardware.d.ts +1 -0
  317. package/build/types/hardware.d.ts.map +1 -1
  318. package/build/types/hardware.js +14 -0
  319. package/build/types/hardware.js.map +1 -1
  320. package/build/utils/configuredDevHost.d.ts +6 -0
  321. package/build/utils/configuredDevHost.d.ts.map +1 -0
  322. package/build/utils/configuredDevHost.js +19 -0
  323. package/build/utils/configuredDevHost.js.map +1 -0
  324. package/build/utils/devMiniappLaunch.d.ts +19 -8
  325. package/build/utils/devMiniappLaunch.d.ts.map +1 -1
  326. package/build/utils/devMiniappLaunch.js +144 -21
  327. package/build/utils/devMiniappLaunch.js.map +1 -1
  328. package/build/utils/diagnosticContext.d.ts.map +1 -1
  329. package/build/utils/diagnosticContext.js +15 -17
  330. package/build/utils/diagnosticContext.js.map +1 -1
  331. package/build/utils/hardware/hardware.d.ts.map +1 -1
  332. package/build/utils/hardware/hardware.js +7 -3
  333. package/build/utils/hardware/hardware.js.map +1 -1
  334. package/build/utils/miniappDiagnostics.d.ts +64 -0
  335. package/build/utils/miniappDiagnostics.d.ts.map +1 -0
  336. package/build/utils/miniappDiagnostics.js +173 -0
  337. package/build/utils/miniappDiagnostics.js.map +1 -0
  338. package/build/utils/permissions/MediaLibraryPermissions.d.ts +11 -0
  339. package/build/utils/permissions/MediaLibraryPermissions.d.ts.map +1 -1
  340. package/build/utils/permissions/MediaLibraryPermissions.js +27 -4
  341. package/build/utils/permissions/MediaLibraryPermissions.js.map +1 -1
  342. package/build/utils/timers/timers.d.ts.map +1 -1
  343. package/build/utils/timers/timers.js +55 -18
  344. package/build/utils/timers/timers.js.map +1 -1
  345. package/package.json +25 -15
  346. package/src/assets/silence.wav +0 -0
  347. package/src/engine.ts +7 -2
  348. package/src/facades/dev.ts +17 -12
  349. package/src/facades/gallery.ts +1 -1
  350. package/src/facades/glasses.ts +17 -4
  351. package/src/facades/glassesSettings.ts +5 -0
  352. package/src/facades/miniapps.ts +7 -0
  353. package/src/facades/ota.ts +19 -4
  354. package/src/facades/pairing.ts +11 -7
  355. package/src/facades/permissions.ts +14 -0
  356. package/src/facades/phoneNotifications.ts +4 -13
  357. package/src/index.ts +26 -2
  358. package/src/internal.ts +3 -1
  359. package/src/react/MentraLiveOtaFlow.tsx +856 -0
  360. package/src/react/index.ts +7 -0
  361. package/src/react/useEngineSnapshot.ts +16 -0
  362. package/src/runtime/bootstrap.ts +33 -1
  363. package/src/runtime/scanQrSeam.ts +20 -0
  364. package/src/services/AppRegistry.ts +224 -149
  365. package/src/services/AudioCloudUplink.ts +23 -1
  366. package/src/services/AudioPlaybackService.ts +287 -38
  367. package/src/services/BlobStore.ts +22 -9
  368. package/src/services/CloudAudioSubscriptionSync.ts +13 -1
  369. package/src/services/CloudClientService.ts +96 -1
  370. package/src/services/DeviceEventRouter.ts +5 -5
  371. package/src/services/ForegroundLocationPermission.ts +24 -0
  372. package/src/services/GlassesSettingsSync.ts +9 -3
  373. package/src/services/GlassesStatusProjection.ts +16 -8
  374. package/src/services/HotspotOtaTransport.ts +184 -0
  375. package/src/services/HotspotShutdown.ts +41 -0
  376. package/src/services/LocalDisplayManager.ts +112 -21
  377. package/src/services/LocalMiniappRuntime.ts +967 -346
  378. package/src/services/LocalMiniappStorage.ts +82 -0
  379. package/src/services/LocalMiniappUserIdentity.ts +46 -0
  380. package/src/services/LocalSttFallbackCoordinator.ts +19 -12
  381. package/src/services/MicStateCoordinator.ts +169 -4
  382. package/src/services/MiniappLauncher.ts +30 -3
  383. package/src/services/MiniappLiveness.ts +24 -0
  384. package/src/services/NativeHttpResponse.ts +6 -0
  385. package/src/services/OtaArtifactDownloader.ts +312 -0
  386. package/src/services/OtaAutoChain.ts +106 -0
  387. package/src/services/OtaErrorMapping.ts +80 -0
  388. package/src/services/OtaInstallCoordinator.ts +645 -143
  389. package/src/services/OtaService.ts +11 -5
  390. package/src/services/OtaUpdateCheckService.ts +180 -20
  391. package/src/services/PhoneCalendarHelpers.ts +212 -0
  392. package/src/services/PhoneCalendarService.ts +65 -0
  393. package/src/services/PhoneCameraFovCoordinator.ts +210 -0
  394. package/src/services/PhoneNotificationsSync.ts +12 -10
  395. package/src/services/PhonePhotoCoordinator.ts +116 -18
  396. package/src/services/PhoneStreamCoordinator.ts +139 -25
  397. package/src/services/PhoneVideoCoordinator.ts +11 -0
  398. package/src/services/SceneRenderer.ts +16 -0
  399. package/src/services/SentenceTtsPipeline.ts +106 -0
  400. package/src/services/SupportProfileSync.ts +218 -0
  401. package/src/services/TranscriptionRouting.ts +37 -0
  402. package/src/services/TtsTextSanitizer.ts +66 -0
  403. package/src/services/WifiAdbRequest.ts +53 -0
  404. package/src/services/asg/asgCameraApi.ts +615 -33
  405. package/src/services/asg/cameraRollExportCoordinator.ts +627 -0
  406. package/src/services/asg/cameraRollExportLedger.ts +122 -0
  407. package/src/services/asg/galleryNotices.ts +1 -0
  408. package/src/services/asg/galleryPathMigration.ts +22 -0
  409. package/src/services/asg/gallerySettingsService.ts +3 -0
  410. package/src/services/asg/gallerySyncService.ts +184 -73
  411. package/src/services/asg/galleryTransferLedger.ts +312 -0
  412. package/src/services/asg/localNetworkTransport.ts +169 -0
  413. package/src/services/asg/localStorageService.ts +179 -24
  414. package/src/services/asg/mediaProcessingQueue.ts +209 -62
  415. package/src/services/audioPlaybackAssets.ts +8 -0
  416. package/src/services/gallerySyncClock.ts +1 -1
  417. package/src/services/glassesClockSync.ts +2 -2
  418. package/src/services/manifestActions.ts +30 -0
  419. package/src/services/otaDisplayState.ts +57 -16
  420. package/src/services/otaInstallPolicy.ts +29 -3
  421. package/src/services/{asgOtaVersionUrl.ts → otaManifestUrl.ts} +16 -4
  422. package/src/services/slimStreamStatus.ts +16 -5
  423. package/src/stores/apps.ts +12 -0
  424. package/src/stores/bluetoothSettingKeys.ts +2 -0
  425. package/src/stores/gallerySync.ts +4 -0
  426. package/src/stores/glasses.ts +3 -0
  427. package/src/stores/settings.ts +179 -18
  428. package/src/types/applet.ts +2 -0
  429. package/src/types/asg.ts +7 -0
  430. package/src/types/enums.ts +2 -1
  431. package/src/types/hardware.ts +17 -0
  432. package/src/utils/configuredDevHost.ts +17 -0
  433. package/src/utils/devMiniappLaunch.ts +151 -23
  434. package/src/utils/diagnosticContext.ts +17 -17
  435. package/src/utils/hardware/hardware.ts +7 -9
  436. package/src/utils/miniappDiagnostics.ts +226 -0
  437. package/src/utils/permissions/MediaLibraryPermissions.ts +35 -4
  438. package/src/utils/timers/timers.ts +57 -21
  439. package/build/services/asgOtaVersionUrl.d.ts +0 -2
  440. package/build/services/asgOtaVersionUrl.d.ts.map +0 -1
  441. package/build/services/asgOtaVersionUrl.js.map +0 -1
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Normalize manifest actions defensively for installed and dev-sideloaded
3
+ * bundles. Input and output schemas are passed through as opaque JSON Schema.
4
+ */
5
+ export function normalizeManifestActions(raw) {
6
+ if (!Array.isArray(raw))
7
+ return [];
8
+ const out = [];
9
+ for (const a of raw) {
10
+ if (a && typeof a.id === "string" && typeof a.description === "string") {
11
+ out.push({
12
+ id: a.id,
13
+ description: a.description,
14
+ ...(a.parameters && typeof a.parameters === "object" && !Array.isArray(a.parameters)
15
+ ? { parameters: a.parameters }
16
+ : {}),
17
+ ...(a.outputSchema && typeof a.outputSchema === "object" && !Array.isArray(a.outputSchema)
18
+ ? { outputSchema: a.outputSchema }
19
+ : {}),
20
+ });
21
+ }
22
+ }
23
+ return out;
24
+ }
25
+ //# sourceMappingURL=manifestActions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifestActions.js","sourceRoot":"","sources":["../../src/services/manifestActions.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CAAC,GAAY;IACnD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAA;IAClC,MAAM,GAAG,GAAqB,EAAE,CAAA;IAChC,KAAK,MAAM,CAAC,IAAI,GAKd,EAAE,CAAC;QACH,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,WAAW,KAAK,QAAQ,EAAE,CAAC;YACvE,GAAG,CAAC,IAAI,CAAC;gBACP,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,WAAW,EAAE,CAAC,CAAC,WAAW;gBAC1B,GAAG,CAAC,CAAC,CAAC,UAAU,IAAI,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;oBAClF,CAAC,CAAC,EAAC,UAAU,EAAE,CAAC,CAAC,UAAqC,EAAC;oBACvD,CAAC,CAAC,EAAE,CAAC;gBACP,GAAG,CAAC,CAAC,CAAC,YAAY,IAAI,OAAO,CAAC,CAAC,YAAY,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC;oBACxF,CAAC,CAAC,EAAC,YAAY,EAAE,CAAC,CAAC,YAAuC,EAAC;oBAC3D,CAAC,CAAC,EAAE,CAAC;aACR,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC","sourcesContent":["import type {DeclaredAction} from \"../types/applet\"\n\n/**\n * Normalize manifest actions defensively for installed and dev-sideloaded\n * bundles. Input and output schemas are passed through as opaque JSON Schema.\n */\nexport function normalizeManifestActions(raw: unknown): DeclaredAction[] {\n if (!Array.isArray(raw)) return []\n const out: DeclaredAction[] = []\n for (const a of raw as Array<{\n id?: unknown\n description?: unknown\n parameters?: unknown\n outputSchema?: unknown\n }>) {\n if (a && typeof a.id === \"string\" && typeof a.description === \"string\") {\n out.push({\n id: a.id,\n description: a.description,\n ...(a.parameters && typeof a.parameters === \"object\" && !Array.isArray(a.parameters)\n ? {parameters: a.parameters as Record<string, unknown>}\n : {}),\n ...(a.outputSchema && typeof a.outputSchema === \"object\" && !Array.isArray(a.outputSchema)\n ? {outputSchema: a.outputSchema as Record<string, unknown>}\n : {}),\n })\n }\n }\n return out\n}\n"]}
@@ -14,29 +14,40 @@ export type DisplayState = "starting" | "updating" | "complete" | "failed" | "di
14
14
  *
15
15
  * Priority-ordered rules (first match wins):
16
16
  * 1. errorMsg !== "" -> "failed"
17
- * 2. BES terminal + connected + sawReconnectEdge -> "complete"
18
- * 3. BES terminal (any connection state) -> "restarting"
17
+ * 2. BES reboot recovery complete -> "complete"
18
+ * 3. BES reboot recovery awaiting reconnect -> "restarting"
19
+ * 4. BES terminal (any connection state) -> "restarting"
19
20
  * (legacy-shaped BES "complete" counts only in install phase)
20
- * 4. apkCompletedViaBuildIncrease (legacy build-number port) -> "complete"
21
- * 5. otaStatus.status === "failed" -> "failed"
22
- * 6. otaStatus.status === "complete" (non-BES) -> "complete"
21
+ * 6. apkCompletedViaBuildIncrease (legacy build-number port) -> "complete"
22
+ * 7. otaStatus.status === "failed" -> "failed"
23
+ * 8. otaStatus.status === "complete" (non-BES) -> "complete"
23
24
  * (unless legacy-shaped download-complete or held apk settle -> in flight)
24
- * 7. !connected + legacy in-flight complete (held apk) -> "updating"
25
- * 8. !connected + APK step_complete with totalSteps > 1 -> "starting" (expected reboot)
26
- * 9. !connected + BES in flight -> "restarting" (defensive)
27
- * 10. !connected -> "disconnected"
28
- * 11. connected + in_progress | step_complete | legacy in-flight complete -> "updating"
29
- * 12. fallback -> "starting"
25
+ * 9. !connected + legacy in-flight complete (held apk) -> "updating"
26
+ * 10. !connected + APK step_complete with totalSteps > 1 -> "starting" (expected reboot)
27
+ * 11. !connected + BES in flight -> "restarting" (defensive)
28
+ * 12. !connected -> "disconnected"
29
+ * 13. connected + in_progress | step_complete | legacy in-flight complete -> "updating"
30
+ * 14. fallback -> "starting"
30
31
  */
31
32
  export declare function deriveDisplayState(args: {
32
33
  otaStatus: OtaStatus | null;
33
34
  otaProgress: OtaProgress | null;
34
35
  connected: boolean;
35
36
  errorMsg: string;
37
+ /**
38
+ * Retained for host API compatibility. A session-wide reconnect edge is not
39
+ * sufficient for BES completion because it may belong to an earlier APK step.
40
+ */
36
41
  sawReconnectEdge: boolean;
37
42
  /** Coordinator is holding a legacy apk install "complete" for the settle window (WP 8C). */
38
43
  legacyApkSettleHold?: boolean;
39
44
  /** Legacy APK completion detected by build-number increase (WP 8C). */
40
45
  apkCompletedViaBuildIncrease?: boolean;
46
+ /** Phone-observed BES disconnect/reconnect recovery, independent of stale OTA progress. */
47
+ besRestartRecovery?: "awaiting" | "complete" | null;
48
+ /** Downgrade detour: the reconnected glasses reported exactly the pinned target version. */
49
+ versionChangeConverged?: boolean;
50
+ /** True for the whole downgrade (version-change) session. */
51
+ versionChangeSession?: boolean;
41
52
  }): DisplayState;
42
53
  //# sourceMappingURL=otaDisplayState.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"otaDisplayState.d.ts","sourceRoot":"","sources":["../../src/services/otaDisplayState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,WAAW,EAAE,SAAS,EAAC,MAAM,gCAAgC,CAAA;AAI1E,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,QAAQ,GAAG,cAAc,GAAG,YAAY,CAAA;AAE1G;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAA;IAC3B,WAAW,EAAE,WAAW,GAAG,IAAI,CAAA;IAC/B,SAAS,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,gBAAgB,EAAE,OAAO,CAAA;IACzB,4FAA4F;IAC5F,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,uEAAuE;IACvE,4BAA4B,CAAC,EAAE,OAAO,CAAA;CACvC,GAAG,YAAY,CAuDf"}
1
+ {"version":3,"file":"otaDisplayState.d.ts","sourceRoot":"","sources":["../../src/services/otaDisplayState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,WAAW,EAAE,SAAS,EAAC,MAAM,gCAAgC,CAAA;AAI1E,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,QAAQ,GAAG,cAAc,GAAG,YAAY,CAAA;AAE1G;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAA;IAC3B,WAAW,EAAE,WAAW,GAAG,IAAI,CAAA;IAC/B,SAAS,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,gBAAgB,EAAE,OAAO,CAAA;IACzB,4FAA4F;IAC5F,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,uEAAuE;IACvE,4BAA4B,CAAC,EAAE,OAAO,CAAA;IACtC,2FAA2F;IAC3F,kBAAkB,CAAC,EAAE,UAAU,GAAG,UAAU,GAAG,IAAI,CAAA;IACnD,4FAA4F;IAC5F,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,6DAA6D;IAC7D,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B,GAAG,YAAY,CAqFf"}
@@ -13,27 +13,49 @@ import { isLegacyShapedOtaStatus } from "./otaInstallPolicy";
13
13
  *
14
14
  * Priority-ordered rules (first match wins):
15
15
  * 1. errorMsg !== "" -> "failed"
16
- * 2. BES terminal + connected + sawReconnectEdge -> "complete"
17
- * 3. BES terminal (any connection state) -> "restarting"
16
+ * 2. BES reboot recovery complete -> "complete"
17
+ * 3. BES reboot recovery awaiting reconnect -> "restarting"
18
+ * 4. BES terminal (any connection state) -> "restarting"
18
19
  * (legacy-shaped BES "complete" counts only in install phase)
19
- * 4. apkCompletedViaBuildIncrease (legacy build-number port) -> "complete"
20
- * 5. otaStatus.status === "failed" -> "failed"
21
- * 6. otaStatus.status === "complete" (non-BES) -> "complete"
20
+ * 6. apkCompletedViaBuildIncrease (legacy build-number port) -> "complete"
21
+ * 7. otaStatus.status === "failed" -> "failed"
22
+ * 8. otaStatus.status === "complete" (non-BES) -> "complete"
22
23
  * (unless legacy-shaped download-complete or held apk settle -> in flight)
23
- * 7. !connected + legacy in-flight complete (held apk) -> "updating"
24
- * 8. !connected + APK step_complete with totalSteps > 1 -> "starting" (expected reboot)
25
- * 9. !connected + BES in flight -> "restarting" (defensive)
26
- * 10. !connected -> "disconnected"
27
- * 11. connected + in_progress | step_complete | legacy in-flight complete -> "updating"
28
- * 12. fallback -> "starting"
24
+ * 9. !connected + legacy in-flight complete (held apk) -> "updating"
25
+ * 10. !connected + APK step_complete with totalSteps > 1 -> "starting" (expected reboot)
26
+ * 11. !connected + BES in flight -> "restarting" (defensive)
27
+ * 12. !connected -> "disconnected"
28
+ * 13. connected + in_progress | step_complete | legacy in-flight complete -> "updating"
29
+ * 14. fallback -> "starting"
29
30
  */
30
31
  export function deriveDisplayState(args) {
31
- const { otaStatus, otaProgress, connected, errorMsg, sawReconnectEdge, legacyApkSettleHold, apkCompletedViaBuildIncrease } = args;
32
+ const { otaStatus, otaProgress, connected, errorMsg, legacyApkSettleHold, apkCompletedViaBuildIncrease, besRestartRecovery, versionChangeConverged, versionChangeSession, } = args;
32
33
  if (errorMsg)
33
34
  return "failed";
34
- const besTerminal = isBesTerminal(otaStatus, otaProgress);
35
- if (besTerminal && connected && sawReconnectEdge)
35
+ // Downgrade detour completion: exact-version convergence after reconnect is the
36
+ // only completion signal (the wipe destroys ASG's ota_session, and the target is
37
+ // a LOWER build so no build-number increase fires). Outranks the stale install
38
+ // status still sitting in the store from before the handoff.
39
+ if (versionChangeConverged)
40
+ return "complete";
41
+ // A BES reboot destroys or strands the glasses-side OTA session on older
42
+ // clients. Once the phone observed that reboot, stale pre-reboot progress must
43
+ // not move the UI from restarting back to updating.
44
+ if (besRestartRecovery === "complete")
36
45
  return "complete";
46
+ if (besRestartRecovery === "awaiting")
47
+ return "restarting";
48
+ // In a version-change session, convergence (above) is the ONLY completion for the ASG
49
+ // downgrade. A bare non-firmware "complete" before convergence — the glasses refusing
50
+ // the downgrade (floor/gate) with no install, or a stale pre-handoff status — must never
51
+ // present as success. Firmware-step completions (mtk/bes) DO pass through: a combined
52
+ // downgrade+firmware manifest applies firmware first on its own pass, which must finish
53
+ // so the phone re-checks and re-offers the now-firmware-free downgrade.
54
+ const isFirmwareComplete = otaStatus?.stepType === "mtk" || otaStatus?.stepType === "bes";
55
+ if (versionChangeSession && otaStatus?.status === "complete" && !isFirmwareComplete) {
56
+ return connected ? "updating" : "disconnected";
57
+ }
58
+ const besTerminal = isBesTerminal(otaStatus, otaProgress);
37
59
  if (besTerminal)
38
60
  return "restarting";
39
61
  // Legacy build-number APK completion: the coordinator clears errorMsg when it fires,
@@ -1 +1 @@
1
- {"version":3,"file":"otaDisplayState.js","sourceRoot":"","sources":["../../src/services/otaDisplayState.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,uBAAuB,EAAC,MAAM,oBAAoB,CAAA;AAI1D;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAUlC;IACC,MAAM,EAAC,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,4BAA4B,EAAC,GACtH,IAAI,CAAA;IAEN,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAA;IAE7B,MAAM,WAAW,GAAG,aAAa,CAAC,SAAS,EAAE,WAAW,CAAC,CAAA;IACzD,IAAI,WAAW,IAAI,SAAS,IAAI,gBAAgB;QAAE,OAAO,UAAU,CAAA;IACnE,IAAI,WAAW;QAAE,OAAO,YAAY,CAAA;IAEpC,qFAAqF;IACrF,oFAAoF;IACpF,wEAAwE;IACxE,IAAI,4BAA4B;QAAE,OAAO,UAAU,CAAA;IAEnD,IAAI,SAAS,EAAE,MAAM,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAA;IAEnD,mFAAmF;IACnF,iFAAiF;IACjF,MAAM,sBAAsB,GAC1B,uBAAuB,CAAC,SAAS,CAAC;QAClC,SAAS,EAAE,MAAM,KAAK,UAAU;QAChC,CAAC,SAAS,CAAC,KAAK,KAAK,UAAU;YAC7B,CAAC,CAAC,CAAC,mBAAmB,IAAI,SAAS,CAAC,QAAQ,KAAK,KAAK,IAAI,SAAS,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAA;IAE7F,IAAI,SAAS,EAAE,MAAM,KAAK,UAAU,IAAI,CAAC,sBAAsB;QAAE,OAAO,UAAU,CAAA;IAElF,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,8EAA8E;QAC9E,4EAA4E;QAC5E,IAAI,sBAAsB,IAAI,SAAS,EAAE,KAAK,KAAK,SAAS;YAAE,OAAO,UAAU,CAAA;QAE/E,6EAA6E;QAC7E,2EAA2E;QAC3E,+CAA+C;QAC/C,MAAM,iBAAiB,GACrB,SAAS,EAAE,QAAQ,KAAK,KAAK,IAAI,CAAC,SAAS,EAAE,UAAU,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,eAAe,CAAA;QAC3G,IAAI,iBAAiB;YAAE,OAAO,UAAU,CAAA;QAExC,8EAA8E;QAC9E,+EAA+E;QAC/E,MAAM,iBAAiB,GACrB,SAAS,EAAE,QAAQ,KAAK,KAAK,IAAI,CAAC,CAAC,uBAAuB,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,KAAK,KAAK,UAAU,CAAC,CAAA;QAC1G,MAAM,WAAW,GACf,iBAAiB,IAAI,CAAC,WAAW,EAAE,aAAa,KAAK,KAAK,IAAI,WAAW,EAAE,KAAK,KAAK,SAAS,CAAC,CAAA;QACjG,IAAI,WAAW;YAAE,OAAO,YAAY,CAAA;QAEpC,OAAO,cAAc,CAAA;IACvB,CAAC;IAED,IAAI,SAAS,EAAE,MAAM,KAAK,aAAa,IAAI,SAAS,EAAE,MAAM,KAAK,eAAe,IAAI,sBAAsB,EAAE,CAAC;QAC3G,OAAO,UAAU,CAAA;IACnB,CAAC;IAED,OAAO,UAAU,CAAA;AACnB,CAAC;AAED,SAAS,aAAa,CAAC,SAA2B,EAAE,WAA+B;IACjF,IAAI,SAAS,EAAE,QAAQ,KAAK,KAAK,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,eAAe,IAAI,SAAS,CAAC,MAAM,KAAK,UAAU,CAAC,EAAE,CAAC;QAC/G,0EAA0E;QAC1E,mEAAmE;QACnE,IAAI,uBAAuB,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YACxE,OAAO,KAAK,CAAA;QACd,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IACD,IAAI,WAAW,EAAE,aAAa,KAAK,KAAK,IAAI,WAAW,CAAC,KAAK,KAAK,SAAS,IAAI,WAAW,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QACjH,OAAO,IAAI,CAAA;IACb,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC","sourcesContent":["import type {OtaProgress, OtaStatus} from \"@mentra/bluetooth-sdk/internal\"\n\nimport {isLegacyShapedOtaStatus} from \"./otaInstallPolicy\"\n\nexport type DisplayState = \"starting\" | \"updating\" | \"complete\" | \"failed\" | \"disconnected\" | \"restarting\"\n\n/**\n * Pure derivation of the OTA progress UI state from the glasses data in the\n * Zustand store plus a couple of genuinely-local inputs. See\n * OtaInstallCoordinator.ts for the state machine that consumes this (the host\n * progress screen renders its snapshot).\n *\n * Legacy shape (WP 8C): old (< 37) ASG builds send `ota_progress`, which the SDK\n * maps to ota_status with sessionId \"\" and FINISHED→\"complete\" at ANY phase. For\n * those statuses a download-phase \"complete\" only means the download finished\n * (the install is still ahead), and an apk install \"complete\" may be held by the\n * coordinator's settle window — both stay \"updating\" instead of terminal.\n *\n * Priority-ordered rules (first match wins):\n * 1. errorMsg !== \"\" -> \"failed\"\n * 2. BES terminal + connected + sawReconnectEdge -> \"complete\"\n * 3. BES terminal (any connection state) -> \"restarting\"\n * (legacy-shaped BES \"complete\" counts only in install phase)\n * 4. apkCompletedViaBuildIncrease (legacy build-number port) -> \"complete\"\n * 5. otaStatus.status === \"failed\" -> \"failed\"\n * 6. otaStatus.status === \"complete\" (non-BES) -> \"complete\"\n * (unless legacy-shaped download-complete or held apk settle -> in flight)\n * 7. !connected + legacy in-flight complete (held apk) -> \"updating\"\n * 8. !connected + APK step_complete with totalSteps > 1 -> \"starting\" (expected reboot)\n * 9. !connected + BES in flight -> \"restarting\" (defensive)\n * 10. !connected -> \"disconnected\"\n * 11. connected + in_progress | step_complete | legacy in-flight complete -> \"updating\"\n * 12. fallback -> \"starting\"\n */\nexport function deriveDisplayState(args: {\n otaStatus: OtaStatus | null\n otaProgress: OtaProgress | null\n connected: boolean\n errorMsg: string\n sawReconnectEdge: boolean\n /** Coordinator is holding a legacy apk install \"complete\" for the settle window (WP 8C). */\n legacyApkSettleHold?: boolean\n /** Legacy APK completion detected by build-number increase (WP 8C). */\n apkCompletedViaBuildIncrease?: boolean\n}): DisplayState {\n const {otaStatus, otaProgress, connected, errorMsg, sawReconnectEdge, legacyApkSettleHold, apkCompletedViaBuildIncrease} =\n args\n\n if (errorMsg) return \"failed\"\n\n const besTerminal = isBesTerminal(otaStatus, otaProgress)\n if (besTerminal && connected && sawReconnectEdge) return \"complete\"\n if (besTerminal) return \"restarting\"\n\n // Legacy build-number APK completion: the coordinator clears errorMsg when it fires,\n // and the flag outranks whatever stale legacy status is still in the store (the old\n // screen's last-write-wins completion from starting/failed/installing).\n if (apkCompletedViaBuildIncrease) return \"complete\"\n\n if (otaStatus?.status === \"failed\") return \"failed\"\n\n // Legacy-shaped \"complete\" that is still in flight: a download-phase FINISHED (the\n // install is still ahead), or an apk install FINISHED held by the settle window.\n const legacyInFlightComplete =\n isLegacyShapedOtaStatus(otaStatus) &&\n otaStatus?.status === \"complete\" &&\n (otaStatus.phase === \"download\" ||\n (!!legacyApkSettleHold && otaStatus.stepType === \"apk\" && otaStatus.phase === \"install\"))\n\n if (otaStatus?.status === \"complete\" && !legacyInFlightComplete) return \"complete\"\n\n if (!connected) {\n // The held apk install complete means the glasses are restarting into the new\n // build — the legacy screen kept showing \"installing\" through that restart.\n if (legacyInFlightComplete && otaStatus?.phase === \"install\") return \"updating\"\n\n // By here, the failed/complete rules already returned for terminal statuses.\n // For APK multi-step, \"step_complete\" means the current step ended and the\n // glasses are rebooting to start the next one.\n const apkRebootExpected =\n otaStatus?.stepType === \"apk\" && (otaStatus?.totalSteps ?? 0) > 1 && otaStatus.status === \"step_complete\"\n if (apkRebootExpected) return \"starting\"\n\n // Legacy-shaped BES download events do not mean a reboot is coming (the flash\n // has not started); the legacy screen treated that drop as a plain disconnect.\n const besStatusInFlight =\n otaStatus?.stepType === \"bes\" && !(isLegacyShapedOtaStatus(otaStatus) && otaStatus.phase === \"download\")\n const besInFlight =\n besStatusInFlight || (otaProgress?.currentUpdate === \"bes\" && otaProgress?.stage === \"install\")\n if (besInFlight) return \"restarting\"\n\n return \"disconnected\"\n }\n\n if (otaStatus?.status === \"in_progress\" || otaStatus?.status === \"step_complete\" || legacyInFlightComplete) {\n return \"updating\"\n }\n\n return \"starting\"\n}\n\nfunction isBesTerminal(otaStatus: OtaStatus | null, otaProgress: OtaProgress | null): boolean {\n if (otaStatus?.stepType === \"bes\" && (otaStatus.status === \"step_complete\" || otaStatus.status === \"complete\")) {\n // Legacy-shaped statuses map download FINISHED to \"complete\" too; only an\n // install-phase terminal means the BES flash actually ran (WP 8C).\n if (isLegacyShapedOtaStatus(otaStatus) && otaStatus.phase !== \"install\") {\n return false\n }\n return true\n }\n if (otaProgress?.currentUpdate === \"bes\" && otaProgress.stage === \"install\" && otaProgress.status === \"FINISHED\") {\n return true\n }\n return false\n}\n"]}
1
+ {"version":3,"file":"otaDisplayState.js","sourceRoot":"","sources":["../../src/services/otaDisplayState.ts"],"names":[],"mappings":"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","sourcesContent":["import type {OtaProgress, OtaStatus} from \"@mentra/bluetooth-sdk/internal\"\n\nimport {isLegacyShapedOtaStatus} from \"./otaInstallPolicy\"\n\nexport type DisplayState = \"starting\" | \"updating\" | \"complete\" | \"failed\" | \"disconnected\" | \"restarting\"\n\n/**\n * Pure derivation of the OTA progress UI state from the glasses data in the\n * Zustand store plus a couple of genuinely-local inputs. See\n * OtaInstallCoordinator.ts for the state machine that consumes this (the host\n * progress screen renders its snapshot).\n *\n * Legacy shape (WP 8C): old (< 37) ASG builds send `ota_progress`, which the SDK\n * maps to ota_status with sessionId \"\" and FINISHED→\"complete\" at ANY phase. For\n * those statuses a download-phase \"complete\" only means the download finished\n * (the install is still ahead), and an apk install \"complete\" may be held by the\n * coordinator's settle window — both stay \"updating\" instead of terminal.\n *\n * Priority-ordered rules (first match wins):\n * 1. errorMsg !== \"\" -> \"failed\"\n * 2. BES reboot recovery complete -> \"complete\"\n * 3. BES reboot recovery awaiting reconnect -> \"restarting\"\n * 4. BES terminal (any connection state) -> \"restarting\"\n * (legacy-shaped BES \"complete\" counts only in install phase)\n * 6. apkCompletedViaBuildIncrease (legacy build-number port) -> \"complete\"\n * 7. otaStatus.status === \"failed\" -> \"failed\"\n * 8. otaStatus.status === \"complete\" (non-BES) -> \"complete\"\n * (unless legacy-shaped download-complete or held apk settle -> in flight)\n * 9. !connected + legacy in-flight complete (held apk) -> \"updating\"\n * 10. !connected + APK step_complete with totalSteps > 1 -> \"starting\" (expected reboot)\n * 11. !connected + BES in flight -> \"restarting\" (defensive)\n * 12. !connected -> \"disconnected\"\n * 13. connected + in_progress | step_complete | legacy in-flight complete -> \"updating\"\n * 14. fallback -> \"starting\"\n */\nexport function deriveDisplayState(args: {\n otaStatus: OtaStatus | null\n otaProgress: OtaProgress | null\n connected: boolean\n errorMsg: string\n /**\n * Retained for host API compatibility. A session-wide reconnect edge is not\n * sufficient for BES completion because it may belong to an earlier APK step.\n */\n sawReconnectEdge: boolean\n /** Coordinator is holding a legacy apk install \"complete\" for the settle window (WP 8C). */\n legacyApkSettleHold?: boolean\n /** Legacy APK completion detected by build-number increase (WP 8C). */\n apkCompletedViaBuildIncrease?: boolean\n /** Phone-observed BES disconnect/reconnect recovery, independent of stale OTA progress. */\n besRestartRecovery?: \"awaiting\" | \"complete\" | null\n /** Downgrade detour: the reconnected glasses reported exactly the pinned target version. */\n versionChangeConverged?: boolean\n /** True for the whole downgrade (version-change) session. */\n versionChangeSession?: boolean\n}): DisplayState {\n const {\n otaStatus,\n otaProgress,\n connected,\n errorMsg,\n legacyApkSettleHold,\n apkCompletedViaBuildIncrease,\n besRestartRecovery,\n versionChangeConverged,\n versionChangeSession,\n } = args\n\n if (errorMsg) return \"failed\"\n\n // Downgrade detour completion: exact-version convergence after reconnect is the\n // only completion signal (the wipe destroys ASG's ota_session, and the target is\n // a LOWER build so no build-number increase fires). Outranks the stale install\n // status still sitting in the store from before the handoff.\n if (versionChangeConverged) return \"complete\"\n\n // A BES reboot destroys or strands the glasses-side OTA session on older\n // clients. Once the phone observed that reboot, stale pre-reboot progress must\n // not move the UI from restarting back to updating.\n if (besRestartRecovery === \"complete\") return \"complete\"\n if (besRestartRecovery === \"awaiting\") return \"restarting\"\n\n // In a version-change session, convergence (above) is the ONLY completion for the ASG\n // downgrade. A bare non-firmware \"complete\" before convergence — the glasses refusing\n // the downgrade (floor/gate) with no install, or a stale pre-handoff status — must never\n // present as success. Firmware-step completions (mtk/bes) DO pass through: a combined\n // downgrade+firmware manifest applies firmware first on its own pass, which must finish\n // so the phone re-checks and re-offers the now-firmware-free downgrade.\n const isFirmwareComplete = otaStatus?.stepType === \"mtk\" || otaStatus?.stepType === \"bes\"\n if (versionChangeSession && otaStatus?.status === \"complete\" && !isFirmwareComplete) {\n return connected ? \"updating\" : \"disconnected\"\n }\n\n const besTerminal = isBesTerminal(otaStatus, otaProgress)\n if (besTerminal) return \"restarting\"\n\n // Legacy build-number APK completion: the coordinator clears errorMsg when it fires,\n // and the flag outranks whatever stale legacy status is still in the store (the old\n // screen's last-write-wins completion from starting/failed/installing).\n if (apkCompletedViaBuildIncrease) return \"complete\"\n\n if (otaStatus?.status === \"failed\") return \"failed\"\n\n // Legacy-shaped \"complete\" that is still in flight: a download-phase FINISHED (the\n // install is still ahead), or an apk install FINISHED held by the settle window.\n const legacyInFlightComplete =\n isLegacyShapedOtaStatus(otaStatus) &&\n otaStatus?.status === \"complete\" &&\n (otaStatus.phase === \"download\" ||\n (!!legacyApkSettleHold && otaStatus.stepType === \"apk\" && otaStatus.phase === \"install\"))\n\n if (otaStatus?.status === \"complete\" && !legacyInFlightComplete) return \"complete\"\n\n if (!connected) {\n // The held apk install complete means the glasses are restarting into the new\n // build — the legacy screen kept showing \"installing\" through that restart.\n if (legacyInFlightComplete && otaStatus?.phase === \"install\") return \"updating\"\n\n // By here, the failed/complete rules already returned for terminal statuses.\n // For APK multi-step, \"step_complete\" means the current step ended and the\n // glasses are rebooting to start the next one.\n const apkRebootExpected =\n otaStatus?.stepType === \"apk\" && (otaStatus?.totalSteps ?? 0) > 1 && otaStatus.status === \"step_complete\"\n if (apkRebootExpected) return \"starting\"\n\n // Legacy-shaped BES download events do not mean a reboot is coming (the flash\n // has not started); the legacy screen treated that drop as a plain disconnect.\n const besStatusInFlight =\n otaStatus?.stepType === \"bes\" && !(isLegacyShapedOtaStatus(otaStatus) && otaStatus.phase === \"download\")\n const besInFlight = besStatusInFlight || (otaProgress?.currentUpdate === \"bes\" && otaProgress?.stage === \"install\")\n if (besInFlight) return \"restarting\"\n\n return \"disconnected\"\n }\n\n if (otaStatus?.status === \"in_progress\" || otaStatus?.status === \"step_complete\" || legacyInFlightComplete) {\n return \"updating\"\n }\n\n return \"starting\"\n}\n\nfunction isBesTerminal(otaStatus: OtaStatus | null, otaProgress: OtaProgress | null): boolean {\n if (otaStatus?.stepType === \"bes\" && (otaStatus.status === \"step_complete\" || otaStatus.status === \"complete\")) {\n // Legacy-shaped statuses map download FINISHED to \"complete\" too; only an\n // install-phase terminal means the BES flash actually ran (WP 8C).\n if (isLegacyShapedOtaStatus(otaStatus) && otaStatus.phase !== \"install\") {\n return false\n }\n return true\n }\n if (otaProgress?.currentUpdate === \"bes\" && otaProgress.stage === \"install\" && otaProgress.status === \"FINISHED\") {\n return true\n }\n return false\n}\n"]}
@@ -8,6 +8,7 @@ import type { OtaProgress, OtaStatus } from "@mentra/bluetooth-sdk/internal";
8
8
  */
9
9
  export declare const MINIMUM_OTA_STATUS_BUILD = 37;
10
10
  export declare const MAX_RETRIES = 3;
11
+ /** Wait between ended native ota_start requests; never overlaps a pending request. */
11
12
  export declare const RETRY_INTERVAL_MS = 5000;
12
13
  /** APK/BES and general install when progress events are expected */
13
14
  export declare const PROGRESS_TIMEOUT_MS = 120000;
@@ -17,8 +18,6 @@ export declare const DOWNLOAD_STUCK_TIMEOUT_MS = 70000;
17
18
  export declare const MTK_INSTALL_TIMEOUT_MS = 300000;
18
19
  /** Whole multi-step session cap */
19
20
  export declare const GLOBAL_OTA_TIMEOUT_MS: number;
20
- /** After APK reboot, ASG OTA service needs time before next ota_start */
21
- export declare const POST_APK_OTA_START_DELAY_MS = 6000;
22
21
  /** BLE keepalive during OTA */
23
22
  export declare const PING_INTERVAL_MS = 10000;
24
23
  /**
@@ -58,6 +57,7 @@ export declare const LEGACY_MTK_STALL_ZONE_MIN_PERCENT = 45;
58
57
  export declare const LEGACY_MTK_STALL_ZONE_MAX_PERCENT = 55;
59
58
  export declare const LEGACY_MTK_SIM_FLOOR_PERCENT = 51;
60
59
  export declare const LEGACY_MTK_SIM_CAP_PERCENT = 60;
60
+ export type OtaProtocolProfile = "legacy" | "unified";
61
61
  /**
62
62
  * Legacy-shaped ota_status: old (< 37) ASG builds send `ota_progress`, which the SDK
63
63
  * (Android MentraLive.kt / iOS MentraLive.swift) maps to a unified ota_status with
@@ -72,10 +72,22 @@ export declare function isLegacyShapedOtaStatus(otaStatus: OtaStatus | null): bo
72
72
  * before any event arrives only the glasses build number can tell.
73
73
  */
74
74
  export declare function isLegacyShapedOtaSession(otaStatus: OtaStatus | null, otaProgress: OtaProgress | null, buildNumber: string | null | undefined): boolean;
75
+ /**
76
+ * Select the compatibility profile once at install-screen attach. The old split
77
+ * routes made this decision from the pre-update build and kept it for the whole
78
+ * mounted flow, even when an APK step restarted into a newer ASG build. Returning
79
+ * null leaves the coordinator undecided until the first meaningful OTA event.
80
+ */
81
+ export declare function selectOtaProtocolProfile(otaStatus: OtaStatus | null, otaProgress: OtaProgress | null, buildNumber: string | null | undefined): OtaProtocolProfile | null;
75
82
  export declare const OtaProgressMessages: {
76
- readonly noAckResponse: "Unable to start update. Glasses did not respond.";
77
83
  readonly stalledOrStuck: "Update may have failed. Ensure glasses have internet access and try again.";
78
84
  readonly globalTimeout: "Update took too long. Please try again.";
79
85
  readonly sendOtaStartFailed: "Failed to communicate with glasses.";
86
+ readonly hotspotArtifactDownloadFailed: "Could not download the update to your phone. Check phone internet and try again.";
87
+ readonly hotspotArtifactVerifyFailed: "The update package could not be verified. Please try again later.";
88
+ readonly hotspotWifiPermissionDenied: "Allow nearby devices access so the phone can connect to the glasses hotspot.";
89
+ readonly hotspotStartFailed: "Could not start the glasses hotspot. Please try again.";
90
+ readonly hotspotJoinFailed: "Could not connect the phone to the glasses hotspot. Please try again.";
91
+ readonly hotspotServerFailed: "Could not make the update available to the glasses. Please try again.";
80
92
  };
81
93
  //# sourceMappingURL=otaInstallPolicy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"otaInstallPolicy.d.ts","sourceRoot":"","sources":["../../src/services/otaInstallPolicy.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,OAAO,KAAK,EAAC,WAAW,EAAE,SAAS,EAAC,MAAM,gCAAgC,CAAA;AAE1E;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,KAAK,CAAA;AAE1C,eAAO,MAAM,WAAW,IAAI,CAAA;AAC5B,eAAO,MAAM,iBAAiB,OAAO,CAAA;AACrC,oEAAoE;AACpE,eAAO,MAAM,mBAAmB,SAAU,CAAA;AAC1C,kDAAkD;AAClD,eAAO,MAAM,yBAAyB,QAAS,CAAA;AAC/C,2DAA2D;AAC3D,eAAO,MAAM,sBAAsB,SAAU,CAAA;AAC7C,mCAAmC;AACnC,eAAO,MAAM,qBAAqB,QAAiB,CAAA;AACnD,yEAAyE;AACzE,eAAO,MAAM,2BAA2B,OAAO,CAAA;AAC/C,+BAA+B;AAC/B,eAAO,MAAM,gBAAgB,QAAS,CAAA;AACtC;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,OAAO,CAAA;AAC1C,4FAA4F;AAC5F,eAAO,MAAM,uBAAuB,QAAS,CAAA;AAW7C,kFAAkF;AAClF,eAAO,MAAM,uBAAuB,QAAS,CAAA;AAC7C,eAAO,MAAM,wBAAwB,QAA8C,CAAA;AACnF,eAAO,MAAM,0BAA0B,QAAgD,CAAA;AACvF,eAAO,MAAM,gCAAgC,QAAsD,CAAA;AACnG,eAAO,MAAM,6BAA6B,QAAmD,CAAA;AAC7F,eAAO,MAAM,4BAA4B,QAAkD,CAAA;AAC3F,eAAO,MAAM,uBAAuB,QAA6C,CAAA;AACjF,eAAO,MAAM,8BAA8B,QAAoD,CAAA;AAC/F;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,QAAmC,CAAA;AAC/E;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,QAAmC,CAAA;AAC1E,eAAO,MAAM,sBAAsB,QAAmC,CAAA;AACtE,eAAO,MAAM,iCAAiC,KAAK,CAAA;AACnD,eAAO,MAAM,iCAAiC,KAAK,CAAA;AACnD,eAAO,MAAM,4BAA4B,KAAK,CAAA;AAC9C,eAAO,MAAM,0BAA0B,KAAK,CAAA;AAE5C;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,GAAG,OAAO,CAE5E;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,SAAS,GAAG,IAAI,EAC3B,WAAW,EAAE,WAAW,GAAG,IAAI,EAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACrC,OAAO,CAKT;AAED,eAAO,MAAM,mBAAmB;;;;;CAKtB,CAAA"}
1
+ {"version":3,"file":"otaInstallPolicy.d.ts","sourceRoot":"","sources":["../../src/services/otaInstallPolicy.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,OAAO,KAAK,EAAC,WAAW,EAAE,SAAS,EAAC,MAAM,gCAAgC,CAAA;AAE1E;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,KAAK,CAAA;AAE1C,eAAO,MAAM,WAAW,IAAI,CAAA;AAC5B,sFAAsF;AACtF,eAAO,MAAM,iBAAiB,OAAO,CAAA;AACrC,oEAAoE;AACpE,eAAO,MAAM,mBAAmB,SAAU,CAAA;AAC1C,kDAAkD;AAClD,eAAO,MAAM,yBAAyB,QAAS,CAAA;AAC/C,2DAA2D;AAC3D,eAAO,MAAM,sBAAsB,SAAU,CAAA;AAC7C,mCAAmC;AACnC,eAAO,MAAM,qBAAqB,QAAiB,CAAA;AACnD,+BAA+B;AAC/B,eAAO,MAAM,gBAAgB,QAAS,CAAA;AACtC;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,OAAO,CAAA;AAC1C,4FAA4F;AAC5F,eAAO,MAAM,uBAAuB,QAAS,CAAA;AAW7C,kFAAkF;AAClF,eAAO,MAAM,uBAAuB,QAAS,CAAA;AAC7C,eAAO,MAAM,wBAAwB,QAA8C,CAAA;AACnF,eAAO,MAAM,0BAA0B,QAAgD,CAAA;AACvF,eAAO,MAAM,gCAAgC,QAAsD,CAAA;AACnG,eAAO,MAAM,6BAA6B,QAAmD,CAAA;AAC7F,eAAO,MAAM,4BAA4B,QAAkD,CAAA;AAC3F,eAAO,MAAM,uBAAuB,QAA6C,CAAA;AACjF,eAAO,MAAM,8BAA8B,QAAoD,CAAA;AAC/F;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,QAAmC,CAAA;AAC/E;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,QAAmC,CAAA;AAC1E,eAAO,MAAM,sBAAsB,QAAmC,CAAA;AACtE,eAAO,MAAM,iCAAiC,KAAK,CAAA;AACnD,eAAO,MAAM,iCAAiC,KAAK,CAAA;AACnD,eAAO,MAAM,4BAA4B,KAAK,CAAA;AAC9C,eAAO,MAAM,0BAA0B,KAAK,CAAA;AAE5C,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,SAAS,CAAA;AAErD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,GAAG,OAAO,CAE5E;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,SAAS,GAAG,IAAI,EAC3B,WAAW,EAAE,WAAW,GAAG,IAAI,EAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACrC,OAAO,CAKT;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,SAAS,GAAG,IAAI,EAC3B,WAAW,EAAE,WAAW,GAAG,IAAI,EAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACrC,kBAAkB,GAAG,IAAI,CAQ3B;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;CAUtB,CAAA"}
@@ -6,6 +6,7 @@
6
6
  */
7
7
  export const MINIMUM_OTA_STATUS_BUILD = 37;
8
8
  export const MAX_RETRIES = 3;
9
+ /** Wait between ended native ota_start requests; never overlaps a pending request. */
9
10
  export const RETRY_INTERVAL_MS = 5000;
10
11
  /** APK/BES and general install when progress events are expected */
11
12
  export const PROGRESS_TIMEOUT_MS = 120_000;
@@ -15,8 +16,6 @@ export const DOWNLOAD_STUCK_TIMEOUT_MS = 70_000;
15
16
  export const MTK_INSTALL_TIMEOUT_MS = 300_000;
16
17
  /** Whole multi-step session cap */
17
18
  export const GLOBAL_OTA_TIMEOUT_MS = 20 * 60 * 1000;
18
- /** After APK reboot, ASG OTA service needs time before next ota_start */
19
- export const POST_APK_OTA_START_DELAY_MS = 6000;
20
19
  /** BLE keepalive during OTA */
21
20
  export const PING_INTERVAL_MS = 10_000;
22
21
  /**
@@ -87,10 +86,32 @@ export function isLegacyShapedOtaSession(otaStatus, otaProgress, buildNumber) {
87
86
  const build = Number.parseInt(buildNumber ?? "", 10);
88
87
  return Number.isFinite(build) && build > 0 && build < MINIMUM_OTA_STATUS_BUILD;
89
88
  }
89
+ /**
90
+ * Select the compatibility profile once at install-screen attach. The old split
91
+ * routes made this decision from the pre-update build and kept it for the whole
92
+ * mounted flow, even when an APK step restarted into a newer ASG build. Returning
93
+ * null leaves the coordinator undecided until the first meaningful OTA event.
94
+ */
95
+ export function selectOtaProtocolProfile(otaStatus, otaProgress, buildNumber) {
96
+ const build = Number.parseInt(buildNumber ?? "", 10);
97
+ if (Number.isFinite(build) && build > 0) {
98
+ return build < MINIMUM_OTA_STATUS_BUILD ? "legacy" : "unified";
99
+ }
100
+ if (otaStatus)
101
+ return isLegacyShapedOtaStatus(otaStatus) ? "legacy" : "unified";
102
+ if (otaProgress)
103
+ return "legacy";
104
+ return null;
105
+ }
90
106
  export const OtaProgressMessages = {
91
- noAckResponse: "Unable to start update. Glasses did not respond.",
92
107
  stalledOrStuck: "Update may have failed. Ensure glasses have internet access and try again.",
93
108
  globalTimeout: "Update took too long. Please try again.",
94
109
  sendOtaStartFailed: "Failed to communicate with glasses.",
110
+ hotspotArtifactDownloadFailed: "Could not download the update to your phone. Check phone internet and try again.",
111
+ hotspotArtifactVerifyFailed: "The update package could not be verified. Please try again later.",
112
+ hotspotWifiPermissionDenied: "Allow nearby devices access so the phone can connect to the glasses hotspot.",
113
+ hotspotStartFailed: "Could not start the glasses hotspot. Please try again.",
114
+ hotspotJoinFailed: "Could not connect the phone to the glasses hotspot. Please try again.",
115
+ hotspotServerFailed: "Could not make the update available to the glasses. Please try again.",
95
116
  };
96
117
  //# sourceMappingURL=otaInstallPolicy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"otaInstallPolicy.js","sourceRoot":"","sources":["../../src/services/otaInstallPolicy.ts"],"names":[],"mappings":"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","sourcesContent":["/** Shared OTA progress watchdog timings (see progress-legacy.tsx / progress.tsx). */\nimport type {OtaProgress, OtaStatus} from \"@mentra/bluetooth-sdk/internal\"\n\n/**\n * First glasses `build_number` (ASG `versionCode`) that uses `progress.tsx` with unified\n * `ota_status` session UI. Strictly lower builds use `/ota/progress-legacy` (routed from\n * `check-for-updates.tsx` before navigation), and get the LEGACY_* padded policy below\n * in the unified OtaInstallCoordinator (WP 8C). Change only here.\n */\nexport const MINIMUM_OTA_STATUS_BUILD = 37\n\nexport const MAX_RETRIES = 3\nexport const RETRY_INTERVAL_MS = 5000\n/** APK/BES and general install when progress events are expected */\nexport const PROGRESS_TIMEOUT_MS = 120_000\n/** Fail if still at 0% in starting/downloading */\nexport const DOWNLOAD_STUCK_TIMEOUT_MS = 70_000\n/** MTK system install often goes quiet for long periods */\nexport const MTK_INSTALL_TIMEOUT_MS = 300_000\n/** Whole multi-step session cap */\nexport const GLOBAL_OTA_TIMEOUT_MS = 20 * 60 * 1000\n/** After APK reboot, ASG OTA service needs time before next ota_start */\nexport const POST_APK_OTA_START_DELAY_MS = 6000\n/** BLE keepalive during OTA */\nexport const PING_INTERVAL_MS = 10_000\n/**\n * If we sent ota_query_status (e.g. on reconnect) and the glasses haven't\n * replied with an ota_status by then, fall back to ota_start. This recovers\n * from the case where the glasses process restarted between mount and\n * reconnect — the session is gone, ota_query_status returns nothing, and\n * the user would otherwise sit on the spinner forever.\n */\nexport const QUERY_REPLY_TIMEOUT_MS = 6000\n/** 15s lockout on the Continue button after a BES restart, to prevent an accidental tap. */\nexport const BES_CONTINUE_LOCKOUT_MS = 15_000\n\n// --- Legacy old-build (< MINIMUM_OTA_STATUS_BUILD) OTA policy (WP 8C) ---\n//\n// Ported verbatim from mobile/src/app/ota/progress-legacy.tsx, which padded EVERY\n// watchdog/timer by +20s for old ASG builds (\"Legacy OTA: +20s on every watchdog /\n// timer duration\"). Old builds respond slower on every path, so where the legacy\n// screen used a longer duration the coordinator applies the longer value whenever\n// the session is legacy-shaped (see isLegacyShapedOtaStatus / the coordinator's\n// session-shape check). Builds >= 37 keep the unpadded values above.\n\n/** The uniform pad progress-legacy.tsx added to every duration for old builds. */\nexport const LEGACY_EXTRA_TIMEOUT_MS = 20_000\nexport const LEGACY_RETRY_INTERVAL_MS = RETRY_INTERVAL_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_PROGRESS_TIMEOUT_MS = PROGRESS_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_DOWNLOAD_STUCK_TIMEOUT_MS = DOWNLOAD_STUCK_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_MTK_INSTALL_TIMEOUT_MS = MTK_INSTALL_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_GLOBAL_OTA_TIMEOUT_MS = GLOBAL_OTA_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_PING_INTERVAL_MS = PING_INTERVAL_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_BES_CONTINUE_LOCKOUT_MS = BES_CONTINUE_LOCKOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\n/**\n * After a legacy apk `install FINISHED` observed in-flight, the legacy screen held the\n * completed state for 12s (+20s pad) so the ASG process restart settles (and fresh\n * version_info lands) before the user can continue.\n */\nexport const LEGACY_APK_COMPLETION_SETTLE_MS = 12_000 + LEGACY_EXTRA_TIMEOUT_MS\n/**\n * Legacy MTK install stall simulation (display-only): the MTK system install typically\n * stalls around 49-50%. After LEGACY_MTK_STALL_DETECT_MS without a new event in the\n * [45, 55) zone, the legacy screen simulated +1% every LEGACY_MTK_SIM_TICK_MS starting\n * at max(stall+1, 51) and capped at 60%, purely to keep the user informed.\n */\nexport const LEGACY_MTK_STALL_DETECT_MS = 20_000 + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_MTK_SIM_TICK_MS = 15_000 + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_MTK_STALL_ZONE_MIN_PERCENT = 45\nexport const LEGACY_MTK_STALL_ZONE_MAX_PERCENT = 55\nexport const LEGACY_MTK_SIM_FLOOR_PERCENT = 51\nexport const LEGACY_MTK_SIM_CAP_PERCENT = 60\n\n/**\n * Legacy-shaped ota_status: old (< 37) ASG builds send `ota_progress`, which the SDK\n * (Android MentraLive.kt / iOS MentraLive.swift) maps to a unified ota_status with\n * sessionId \"\" and totalSteps 1, and FINISHED→\"complete\" regardless of phase. A real\n * (>= 37) session always carries a sessionId; an \"idle\" reply also has sessionId \"\" but\n * proves the glasses speak the unified protocol, so it is NOT legacy-shaped.\n */\nexport function isLegacyShapedOtaStatus(otaStatus: OtaStatus | null): boolean {\n return !!otaStatus && otaStatus.sessionId === \"\" && otaStatus.status !== \"idle\"\n}\n\n/**\n * Is the current install session legacy-shaped? Event shape wins when events exist\n * (per the WP 8C rule: key off legacy-shaped inputs, not a build flag, where possible);\n * before any event arrives only the glasses build number can tell.\n */\nexport function isLegacyShapedOtaSession(\n otaStatus: OtaStatus | null,\n otaProgress: OtaProgress | null,\n buildNumber: string | null | undefined,\n): boolean {\n if (otaStatus) return isLegacyShapedOtaStatus(otaStatus)\n if (otaProgress) return true\n const build = Number.parseInt(buildNumber ?? \"\", 10)\n return Number.isFinite(build) && build > 0 && build < MINIMUM_OTA_STATUS_BUILD\n}\n\nexport const OtaProgressMessages = {\n noAckResponse: \"Unable to start update. Glasses did not respond.\",\n stalledOrStuck: \"Update may have failed. Ensure glasses have internet access and try again.\",\n globalTimeout: \"Update took too long. Please try again.\",\n sendOtaStartFailed: \"Failed to communicate with glasses.\",\n} as const\n"]}
1
+ {"version":3,"file":"otaInstallPolicy.js","sourceRoot":"","sources":["../../src/services/otaInstallPolicy.ts"],"names":[],"mappings":"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","sourcesContent":["/** Shared OTA progress watchdog timings (see progress-legacy.tsx / progress.tsx). */\nimport type {OtaProgress, OtaStatus} from \"@mentra/bluetooth-sdk/internal\"\n\n/**\n * First glasses `build_number` (ASG `versionCode`) that uses `progress.tsx` with unified\n * `ota_status` session UI. Strictly lower builds use `/ota/progress-legacy` (routed from\n * `check-for-updates.tsx` before navigation), and get the LEGACY_* padded policy below\n * in the unified OtaInstallCoordinator (WP 8C). Change only here.\n */\nexport const MINIMUM_OTA_STATUS_BUILD = 37\n\nexport const MAX_RETRIES = 3\n/** Wait between ended native ota_start requests; never overlaps a pending request. */\nexport const RETRY_INTERVAL_MS = 5000\n/** APK/BES and general install when progress events are expected */\nexport const PROGRESS_TIMEOUT_MS = 120_000\n/** Fail if still at 0% in starting/downloading */\nexport const DOWNLOAD_STUCK_TIMEOUT_MS = 70_000\n/** MTK system install often goes quiet for long periods */\nexport const MTK_INSTALL_TIMEOUT_MS = 300_000\n/** Whole multi-step session cap */\nexport const GLOBAL_OTA_TIMEOUT_MS = 20 * 60 * 1000\n/** BLE keepalive during OTA */\nexport const PING_INTERVAL_MS = 10_000\n/**\n * If we sent ota_query_status (e.g. on reconnect) and the glasses haven't\n * replied with an ota_status by then, fall back to ota_start. This recovers\n * from the case where the glasses process restarted between mount and\n * reconnect — the session is gone, ota_query_status returns nothing, and\n * the user would otherwise sit on the spinner forever.\n */\nexport const QUERY_REPLY_TIMEOUT_MS = 6000\n/** 15s lockout on the Continue button after a BES restart, to prevent an accidental tap. */\nexport const BES_CONTINUE_LOCKOUT_MS = 15_000\n\n// --- Legacy old-build (< MINIMUM_OTA_STATUS_BUILD) OTA policy (WP 8C) ---\n//\n// Ported verbatim from mobile/src/app/ota/progress-legacy.tsx, which padded EVERY\n// watchdog/timer by +20s for old ASG builds (\"Legacy OTA: +20s on every watchdog /\n// timer duration\"). Old builds respond slower on every path, so where the legacy\n// screen used a longer duration the coordinator applies the longer value whenever\n// the session is legacy-shaped (see isLegacyShapedOtaStatus / the coordinator's\n// session-shape check). Builds >= 37 keep the unpadded values above.\n\n/** The uniform pad progress-legacy.tsx added to every duration for old builds. */\nexport const LEGACY_EXTRA_TIMEOUT_MS = 20_000\nexport const LEGACY_RETRY_INTERVAL_MS = RETRY_INTERVAL_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_PROGRESS_TIMEOUT_MS = PROGRESS_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_DOWNLOAD_STUCK_TIMEOUT_MS = DOWNLOAD_STUCK_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_MTK_INSTALL_TIMEOUT_MS = MTK_INSTALL_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_GLOBAL_OTA_TIMEOUT_MS = GLOBAL_OTA_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_PING_INTERVAL_MS = PING_INTERVAL_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_BES_CONTINUE_LOCKOUT_MS = BES_CONTINUE_LOCKOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\n/**\n * After a legacy apk `install FINISHED` observed in-flight, the legacy screen held the\n * completed state for 12s (+20s pad) so the ASG process restart settles (and fresh\n * version_info lands) before the user can continue.\n */\nexport const LEGACY_APK_COMPLETION_SETTLE_MS = 12_000 + LEGACY_EXTRA_TIMEOUT_MS\n/**\n * Legacy MTK install stall simulation (display-only): the MTK system install typically\n * stalls around 49-50%. After LEGACY_MTK_STALL_DETECT_MS without a new event in the\n * [45, 55) zone, the legacy screen simulated +1% every LEGACY_MTK_SIM_TICK_MS starting\n * at max(stall+1, 51) and capped at 60%, purely to keep the user informed.\n */\nexport const LEGACY_MTK_STALL_DETECT_MS = 20_000 + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_MTK_SIM_TICK_MS = 15_000 + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_MTK_STALL_ZONE_MIN_PERCENT = 45\nexport const LEGACY_MTK_STALL_ZONE_MAX_PERCENT = 55\nexport const LEGACY_MTK_SIM_FLOOR_PERCENT = 51\nexport const LEGACY_MTK_SIM_CAP_PERCENT = 60\n\nexport type OtaProtocolProfile = \"legacy\" | \"unified\"\n\n/**\n * Legacy-shaped ota_status: old (< 37) ASG builds send `ota_progress`, which the SDK\n * (Android MentraLive.kt / iOS MentraLive.swift) maps to a unified ota_status with\n * sessionId \"\" and totalSteps 1, and FINISHED→\"complete\" regardless of phase. A real\n * (>= 37) session always carries a sessionId; an \"idle\" reply also has sessionId \"\" but\n * proves the glasses speak the unified protocol, so it is NOT legacy-shaped.\n */\nexport function isLegacyShapedOtaStatus(otaStatus: OtaStatus | null): boolean {\n return !!otaStatus && otaStatus.sessionId === \"\" && otaStatus.status !== \"idle\"\n}\n\n/**\n * Is the current install session legacy-shaped? Event shape wins when events exist\n * (per the WP 8C rule: key off legacy-shaped inputs, not a build flag, where possible);\n * before any event arrives only the glasses build number can tell.\n */\nexport function isLegacyShapedOtaSession(\n otaStatus: OtaStatus | null,\n otaProgress: OtaProgress | null,\n buildNumber: string | null | undefined,\n): boolean {\n if (otaStatus) return isLegacyShapedOtaStatus(otaStatus)\n if (otaProgress) return true\n const build = Number.parseInt(buildNumber ?? \"\", 10)\n return Number.isFinite(build) && build > 0 && build < MINIMUM_OTA_STATUS_BUILD\n}\n\n/**\n * Select the compatibility profile once at install-screen attach. The old split\n * routes made this decision from the pre-update build and kept it for the whole\n * mounted flow, even when an APK step restarted into a newer ASG build. Returning\n * null leaves the coordinator undecided until the first meaningful OTA event.\n */\nexport function selectOtaProtocolProfile(\n otaStatus: OtaStatus | null,\n otaProgress: OtaProgress | null,\n buildNumber: string | null | undefined,\n): OtaProtocolProfile | null {\n const build = Number.parseInt(buildNumber ?? \"\", 10)\n if (Number.isFinite(build) && build > 0) {\n return build < MINIMUM_OTA_STATUS_BUILD ? \"legacy\" : \"unified\"\n }\n if (otaStatus) return isLegacyShapedOtaStatus(otaStatus) ? \"legacy\" : \"unified\"\n if (otaProgress) return \"legacy\"\n return null\n}\n\nexport const OtaProgressMessages = {\n stalledOrStuck: \"Update may have failed. Ensure glasses have internet access and try again.\",\n globalTimeout: \"Update took too long. Please try again.\",\n sendOtaStartFailed: \"Failed to communicate with glasses.\",\n hotspotArtifactDownloadFailed: \"Could not download the update to your phone. Check phone internet and try again.\",\n hotspotArtifactVerifyFailed: \"The update package could not be verified. Please try again later.\",\n hotspotWifiPermissionDenied: \"Allow nearby devices access so the phone can connect to the glasses hotspot.\",\n hotspotStartFailed: \"Could not start the glasses hotspot. Please try again.\",\n hotspotJoinFailed: \"Could not connect the phone to the glasses hotspot. Please try again.\",\n hotspotServerFailed: \"Could not make the update available to the glasses. Please try again.\",\n} as const\n"]}
@@ -0,0 +1,2 @@
1
+ export declare function resolveOtaManifestUrl(glassesUrl?: string | null, glassesBuildNumber?: string | null): string;
2
+ //# sourceMappingURL=otaManifestUrl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otaManifestUrl.d.ts","sourceRoot":"","sources":["../../src/services/otaManifestUrl.ts"],"names":[],"mappings":"AA6BA,wBAAgB,qBAAqB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAuB5G"}
@@ -1,5 +1,11 @@
1
+ import { sdkPinnedOtaManifestUrl } from "@mentra/bluetooth-sdk/internal";
1
2
  import { SETTINGS, useSettingsStore } from "../stores/settings";
2
- const OTA_VERSION_URL_PROD = "https://ota.mentraglass.com/prod_live_version.json";
3
+ // Legacy production manifest — pre-39 glasses install from this (they ignore ota_start's URL).
4
+ const OTA_VERSION_URL_LEGACY_PROD = "https://ota.mentraglass.com/prod_live_version.json";
5
+ // Modern production fleet manifest (v2). Only a last-resort fallback when the SDK-derived pin
6
+ // URL is somehow unavailable; modern glasses honor ota_start's URL, so this must be the v2
7
+ // artifact, not the legacy v1 rescue manifest.
8
+ const OTA_VERSION_URL_PROD = "https://ota.mentraglass.com/prod_live_version_v2.json";
3
9
  function isLegacyAsgOtaStartBuild(glassesBuildNumber) {
4
10
  const buildNumber = Number.parseInt(glassesBuildNumber ?? "", 10);
5
11
  // ASG builds before 39 ignore ota_start.ota_version_url, so compare against
@@ -16,12 +22,12 @@ function getOtaVersionUrlDevOverride() {
16
22
  const trimmed = typeof value === "string" ? value.trim() : "";
17
23
  return trimmed || null;
18
24
  }
19
- export function getAsgOtaVersionUrl(glassesUrl, glassesBuildNumber) {
25
+ export function resolveOtaManifestUrl(glassesUrl, glassesBuildNumber) {
20
26
  const deviceUrl = glassesUrl?.trim();
21
27
  if (isLegacyAsgOtaStartBuild(glassesBuildNumber)) {
22
28
  // Legacy glasses ignore ota_start.ota_version_url and install from their
23
29
  // compiled default, so the developer override does not apply to them either.
24
- return deviceUrl || OTA_VERSION_URL_PROD;
30
+ return deviceUrl || OTA_VERSION_URL_LEGACY_PROD;
25
31
  }
26
32
  const devOverrideUrl = getOtaVersionUrlDevOverride();
27
33
  if (devOverrideUrl) {
@@ -31,6 +37,10 @@ export function getAsgOtaVersionUrl(glassesUrl, glassesBuildNumber) {
31
37
  if (envUrl) {
32
38
  return envUrl;
33
39
  }
34
- return deviceUrl || OTA_VERSION_URL_PROD;
40
+ // The phone owns manifest selection: modern glasses are driven with the manifest pinned to
41
+ // this app's Bluetooth SDK version. Modern ASG builds report no manifest URL of their own;
42
+ // a glasses-reported URL (older modern builds advertising their baked fleet default) is only
43
+ // a last resort when the SDK version is somehow unavailable.
44
+ return sdkPinnedOtaManifestUrl() || deviceUrl || OTA_VERSION_URL_PROD;
35
45
  }
36
- //# sourceMappingURL=asgOtaVersionUrl.js.map
46
+ //# sourceMappingURL=otaManifestUrl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otaManifestUrl.js","sourceRoot":"","sources":["../../src/services/otaManifestUrl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,uBAAuB,EAAC,MAAM,gCAAgC,CAAA;AAEtE,OAAO,EAAC,QAAQ,EAAE,gBAAgB,EAAC,MAAM,oBAAoB,CAAA;AAE7D,+FAA+F;AAC/F,MAAM,2BAA2B,GAAG,oDAAoD,CAAA;AACxF,8FAA8F;AAC9F,2FAA2F;AAC3F,+CAA+C;AAC/C,MAAM,oBAAoB,GAAG,uDAAuD,CAAA;AAEpF,SAAS,wBAAwB,CAAC,kBAAkC;IAClE,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,kBAAkB,IAAI,EAAE,EAAE,EAAE,CAAC,CAAA;IACjE,4EAA4E;IAC5E,kCAAkC;IAClC,OAAO,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,WAAW,GAAG,EAAE,CAAA;AACzD,CAAC;AAED,SAAS,2BAA2B;IAClC,sEAAsE;IACtE,4DAA4D;IAC5D,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrE,OAAO,IAAI,CAAA;IACb,CAAC;IACD,MAAM,KAAK,GAAG,gBAAgB,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,eAAe,CAAC,GAAG,CAAC,CAAA;IAClF,MAAM,OAAO,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAC7D,OAAO,OAAO,IAAI,IAAI,CAAA;AACxB,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,UAA0B,EAAE,kBAAkC;IAClG,MAAM,SAAS,GAAG,UAAU,EAAE,IAAI,EAAE,CAAA;IACpC,IAAI,wBAAwB,CAAC,kBAAkB,CAAC,EAAE,CAAC;QACjD,yEAAyE;QACzE,6EAA6E;QAC7E,OAAO,SAAS,IAAI,2BAA2B,CAAA;IACjD,CAAC;IAED,MAAM,cAAc,GAAG,2BAA2B,EAAE,CAAA;IACpD,IAAI,cAAc,EAAE,CAAC;QACnB,OAAO,cAAc,CAAA;IACvB,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,+BAA+B,EAAE,IAAI,EAAE,CAAA;IAClE,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,MAAM,CAAA;IACf,CAAC;IAED,2FAA2F;IAC3F,2FAA2F;IAC3F,6FAA6F;IAC7F,6DAA6D;IAC7D,OAAO,uBAAuB,EAAE,IAAI,SAAS,IAAI,oBAAoB,CAAA;AACvE,CAAC","sourcesContent":["import {sdkPinnedOtaManifestUrl} from \"@mentra/bluetooth-sdk/internal\"\n\nimport {SETTINGS, useSettingsStore} from \"../stores/settings\"\n\n// Legacy production manifest — pre-39 glasses install from this (they ignore ota_start's URL).\nconst OTA_VERSION_URL_LEGACY_PROD = \"https://ota.mentraglass.com/prod_live_version.json\"\n// Modern production fleet manifest (v2). Only a last-resort fallback when the SDK-derived pin\n// URL is somehow unavailable; modern glasses honor ota_start's URL, so this must be the v2\n// artifact, not the legacy v1 rescue manifest.\nconst OTA_VERSION_URL_PROD = \"https://ota.mentraglass.com/prod_live_version_v2.json\"\n\nfunction isLegacyAsgOtaStartBuild(glassesBuildNumber?: string | null): boolean {\n const buildNumber = Number.parseInt(glassesBuildNumber ?? \"\", 10)\n // ASG builds before 39 ignore ota_start.ota_version_url, so compare against\n // the URL they will actually use.\n return Number.isFinite(buildNumber) && buildNumber < 39\n}\n\nfunction getOtaVersionUrlDevOverride(): string | null {\n // Super mode only: a wrong OTA manifest can brick glasses, so a saved\n // override is inert unless super mode is currently enabled.\n if (!useSettingsStore.getState().getSetting(SETTINGS.super_mode.key)) {\n return null\n }\n const value = useSettingsStore.getState().getSetting(SETTINGS.ota_version_url.key)\n const trimmed = typeof value === \"string\" ? value.trim() : \"\"\n return trimmed || null\n}\n\nexport function resolveOtaManifestUrl(glassesUrl?: string | null, glassesBuildNumber?: string | null): string {\n const deviceUrl = glassesUrl?.trim()\n if (isLegacyAsgOtaStartBuild(glassesBuildNumber)) {\n // Legacy glasses ignore ota_start.ota_version_url and install from their\n // compiled default, so the developer override does not apply to them either.\n return deviceUrl || OTA_VERSION_URL_LEGACY_PROD\n }\n\n const devOverrideUrl = getOtaVersionUrlDevOverride()\n if (devOverrideUrl) {\n return devOverrideUrl\n }\n\n const envUrl = process.env.EXPO_PUBLIC_ASG_OTA_VERSION_URL?.trim()\n if (envUrl) {\n return envUrl\n }\n\n // The phone owns manifest selection: modern glasses are driven with the manifest pinned to\n // this app's Bluetooth SDK version. Modern ASG builds report no manifest URL of their own;\n // a glasses-reported URL (older modern builds advertising their baked fleet default) is only\n // a last resort when the SDK version is somehow unavailable.\n return sdkPinnedOtaManifestUrl() || deviceUrl || OTA_VERSION_URL_PROD\n}\n"]}
@@ -1,7 +1,18 @@
1
1
  import type { StreamStatusEvent } from "@mentra/bluetooth-sdk/internal";
2
+ /**
3
+ * 1Hz encoder FPS/bitrate telemetry on `stream_status.stats`.
4
+ * Lifecycle status (started/stopped/error) is unaffected.
5
+ * Keep false in production; flip locally to debug the Mentra Call FPS ladder.
6
+ *
7
+ * Compatibility kill switch: old glasses can still emit stats. Copy onto a new object;
8
+ * never mutate the incoming event. Manual acceptance with every layer false: join
9
+ * waterfall yes; BLE stream_status.stats / STREAM_QUALITY / encoder-stats / watch-stats no.
10
+ */
11
+ export declare const ENABLE_PIPELINE_FPS_TELEMETRY = false;
2
12
  /** Fields forwarded to cloud / miniapps after the first resolvedConfig ack. */
3
13
  export declare function slimStreamStatusEvent(event: StreamStatusEvent, options?: {
4
14
  includeResolvedConfig?: boolean;
15
+ enableFpsTelemetry?: boolean;
5
16
  }): Record<string, unknown>;
6
17
  export declare function streamStatusSignature(payload: Record<string, unknown>): string;
7
18
  //# sourceMappingURL=slimStreamStatus.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"slimStreamStatus.d.ts","sourceRoot":"","sources":["../../src/services/slimStreamStatus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,gCAAgC,CAAA;AAErE,+EAA+E;AAC/E,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,iBAAiB,EACxB,OAAO,GAAE;IAAC,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAAM,GAC9C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAiBzB;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAE9E"}
1
+ {"version":3,"file":"slimStreamStatus.d.ts","sourceRoot":"","sources":["../../src/services/slimStreamStatus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,gCAAgC,CAAA;AAErE;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B,QAAQ,CAAA;AAElD,+EAA+E;AAC/E,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,iBAAiB,EACxB,OAAO,GAAE;IAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAAC,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAAM,GAC5E,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAiBzB;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAE9E"}
@@ -1,5 +1,16 @@
1
+ /**
2
+ * 1Hz encoder FPS/bitrate telemetry on `stream_status.stats`.
3
+ * Lifecycle status (started/stopped/error) is unaffected.
4
+ * Keep false in production; flip locally to debug the Mentra Call FPS ladder.
5
+ *
6
+ * Compatibility kill switch: old glasses can still emit stats. Copy onto a new object;
7
+ * never mutate the incoming event. Manual acceptance with every layer false: join
8
+ * waterfall yes; BLE stream_status.stats / STREAM_QUALITY / encoder-stats / watch-stats no.
9
+ */
10
+ export const ENABLE_PIPELINE_FPS_TELEMETRY = false;
1
11
  /** Fields forwarded to cloud / miniapps after the first resolvedConfig ack. */
2
12
  export function slimStreamStatusEvent(event, options = {}) {
13
+ const enableFpsTelemetry = options.enableFpsTelemetry ?? ENABLE_PIPELINE_FPS_TELEMETRY;
3
14
  const slim = {
4
15
  type: "stream_status",
5
16
  kind: event.kind,
@@ -13,10 +24,9 @@ export function slimStreamStatusEvent(event, options = {}) {
13
24
  if (options.includeResolvedConfig && event.resolvedConfig) {
14
25
  slim.resolvedConfig = event.resolvedConfig;
15
26
  }
16
- // Live telemetry passes straight through unlike resolvedConfig it changes
17
- // per event, and the signature dedupe upstream only suppresses identical
18
- // payloads.
19
- if (event.stats)
27
+ // Compatibility kill switch: old glasses may still emit 1Hz stats. Copy onto a
28
+ // new object; never mutate `event` other consumers may still need the original.
29
+ if (enableFpsTelemetry && event.stats)
20
30
  slim.stats = event.stats;
21
31
  return slim;
22
32
  }
@@ -1 +1 @@
1
- {"version":3,"file":"slimStreamStatus.js","sourceRoot":"","sources":["../../src/services/slimStreamStatus.ts"],"names":[],"mappings":"AAEA,+EAA+E;AAC/E,MAAM,UAAU,qBAAqB,CACnC,KAAwB,EACxB,UAA6C,EAAE;IAE/C,MAAM,IAAI,GAA4B;QACpC,IAAI,EAAE,eAAe;QACrB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,MAAM,EAAE,KAAK,CAAC,MAAM;KACrB,CAAA;IACD,IAAI,KAAK,CAAC,QAAQ;QAAE,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAA;IAClD,MAAM,EAAE,GAAG,KAAK,CAAC,SAAS,CAAA;IAC1B,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAAE,IAAI,CAAC,SAAS,GAAG,EAAE,CAAA;IACtE,IAAI,OAAO,CAAC,qBAAqB,IAAI,KAAK,CAAC,cAAc,EAAE,CAAC;QAC1D,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC,cAAc,CAAA;IAC5C,CAAC;IACD,4EAA4E;IAC5E,yEAAyE;IACzE,YAAY;IACZ,IAAI,KAAK,CAAC,KAAK;QAAE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAA;IACzC,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAgC;IACpE,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;AAChC,CAAC","sourcesContent":["import type {StreamStatusEvent} from \"@mentra/bluetooth-sdk/internal\"\r\n\r\n/** Fields forwarded to cloud / miniapps after the first resolvedConfig ack. */\r\nexport function slimStreamStatusEvent(\r\n event: StreamStatusEvent,\r\n options: {includeResolvedConfig?: boolean} = {},\r\n): Record<string, unknown> {\r\n const slim: Record<string, unknown> = {\r\n type: \"stream_status\",\r\n kind: event.kind,\r\n status: event.status,\r\n }\r\n if (event.streamId) slim.streamId = event.streamId\r\n const ts = event.timestamp\r\n if (typeof ts === \"number\" && Number.isFinite(ts)) slim.timestamp = ts\r\n if (options.includeResolvedConfig && event.resolvedConfig) {\r\n slim.resolvedConfig = event.resolvedConfig\r\n }\r\n // Live telemetry passes straight through unlike resolvedConfig it changes\r\n // per event, and the signature dedupe upstream only suppresses identical\r\n // payloads.\r\n if (event.stats) slim.stats = event.stats\r\n return slim\r\n}\r\n\r\nexport function streamStatusSignature(payload: Record<string, unknown>): string {\r\n return JSON.stringify(payload)\r\n}\r\n"]}
1
+ {"version":3,"file":"slimStreamStatus.js","sourceRoot":"","sources":["../../src/services/slimStreamStatus.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,KAAK,CAAA;AAElD,+EAA+E;AAC/E,MAAM,UAAU,qBAAqB,CACnC,KAAwB,EACxB,UAA2E,EAAE;IAE7E,MAAM,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,IAAI,6BAA6B,CAAA;IACtF,MAAM,IAAI,GAA4B;QACpC,IAAI,EAAE,eAAe;QACrB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,MAAM,EAAE,KAAK,CAAC,MAAM;KACrB,CAAA;IACD,IAAI,KAAK,CAAC,QAAQ;QAAE,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAA;IAClD,MAAM,EAAE,GAAG,KAAK,CAAC,SAAS,CAAA;IAC1B,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAAE,IAAI,CAAC,SAAS,GAAG,EAAE,CAAA;IACtE,IAAI,OAAO,CAAC,qBAAqB,IAAI,KAAK,CAAC,cAAc,EAAE,CAAC;QAC1D,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC,cAAc,CAAA;IAC5C,CAAC;IACD,+EAA+E;IAC/E,kFAAkF;IAClF,IAAI,kBAAkB,IAAI,KAAK,CAAC,KAAK;QAAE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAA;IAC/D,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAgC;IACpE,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;AAChC,CAAC","sourcesContent":["import type {StreamStatusEvent} from \"@mentra/bluetooth-sdk/internal\"\r\n\r\n/**\r\n * 1Hz encoder FPS/bitrate telemetry on `stream_status.stats`.\r\n * Lifecycle status (started/stopped/error) is unaffected.\r\n * Keep false in production; flip locally to debug the Mentra Call FPS ladder.\r\n *\r\n * Compatibility kill switch: old glasses can still emit stats. Copy onto a new object;\r\n * never mutate the incoming event. Manual acceptance with every layer false: join\r\n * waterfall yes; BLE stream_status.stats / STREAM_QUALITY / encoder-stats / watch-stats no.\r\n */\r\nexport const ENABLE_PIPELINE_FPS_TELEMETRY = false\r\n\r\n/** Fields forwarded to cloud / miniapps after the first resolvedConfig ack. */\r\nexport function slimStreamStatusEvent(\r\n event: StreamStatusEvent,\r\n options: {includeResolvedConfig?: boolean; enableFpsTelemetry?: boolean} = {},\r\n): Record<string, unknown> {\r\n const enableFpsTelemetry = options.enableFpsTelemetry ?? ENABLE_PIPELINE_FPS_TELEMETRY\r\n const slim: Record<string, unknown> = {\r\n type: \"stream_status\",\r\n kind: event.kind,\r\n status: event.status,\r\n }\r\n if (event.streamId) slim.streamId = event.streamId\r\n const ts = event.timestamp\r\n if (typeof ts === \"number\" && Number.isFinite(ts)) slim.timestamp = ts\r\n if (options.includeResolvedConfig && event.resolvedConfig) {\r\n slim.resolvedConfig = event.resolvedConfig\r\n }\r\n // Compatibility kill switch: old glasses may still emit 1Hz stats. Copy onto a\r\n // new object; never mutate `event` other consumers may still need the original.\r\n if (enableFpsTelemetry && event.stats) slim.stats = event.stats\r\n return slim\r\n}\r\n\r\nexport function streamStatusSignature(payload: Record<string, unknown>): string {\r\n return JSON.stringify(payload)\r\n}\r\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../src/stores/apps.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../src/stores/apps.ts"],"names":[],"mappings":"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"}
@@ -17,6 +17,7 @@ import { getModelCapabilities } from "../types/hardware";
17
17
  import { HardwareCompatibility } from "../utils/hardware/hardware";
18
18
  import { storage } from "../utils/storage/storage";
19
19
  import appRegistry from "../services/AppRegistry";
20
+ import localDisplayManager from "../services/LocalDisplayManager";
20
21
  import { islandNotifications } from "../services/NotificationsEmitter";
21
22
  import sttModelManager from "../services/STTModelManager";
22
23
  import { miniappLauncher } from "../services/MiniappLauncher";
@@ -433,6 +434,16 @@ miniappRunningRegistry.subscribe(() => {
433
434
  useAppStatusStore.setState({ apps: updated });
434
435
  }
435
436
  });
437
+ // The display-manager's core (foreground) slot is DERIVED state: always the
438
+ // currently-running standard app, no matter HOW it came to run — user tap
439
+ // (start()), boot restore (autostartLocalMiniapps → registry projection
440
+ // above), crash-respawn, or interop. One reconciler instead of per-path call
441
+ // sites, so no launch/stop path can forget to claim or release the slot.
442
+ // onCoreAppChange is idempotent, so firing on every store write is free.
443
+ useAppStatusStore.subscribe((state) => {
444
+ const core = state.apps.find((a) => a.running && (a.type === "standard" || !a.type));
445
+ localDisplayManager.onCoreAppChange(core?.packageName ?? null);
446
+ });
436
447
  // AppRegistry change events trigger a store refresh.
437
448
  appRegistry.subscribe(() => {
438
449
  void useAppStatusStore.getState().refresh();