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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (503) hide show
  1. package/README.md +55 -18
  2. package/build/bluetooth-sdk/debug.d.ts +2 -0
  3. package/build/bluetooth-sdk/debug.d.ts.map +1 -0
  4. package/build/bluetooth-sdk/debug.js +2 -0
  5. package/build/bluetooth-sdk/debug.js.map +1 -0
  6. package/build/bluetooth-sdk/index.d.ts +3 -0
  7. package/build/bluetooth-sdk/index.d.ts.map +1 -0
  8. package/build/bluetooth-sdk/index.js +3 -0
  9. package/build/bluetooth-sdk/index.js.map +1 -0
  10. package/build/bluetooth-sdk/photo-receiver.d.ts +3 -0
  11. package/build/bluetooth-sdk/photo-receiver.d.ts.map +1 -0
  12. package/build/bluetooth-sdk/photo-receiver.js +3 -0
  13. package/build/bluetooth-sdk/photo-receiver.js.map +1 -0
  14. package/build/bluetooth-sdk/react.d.ts +2 -0
  15. package/build/bluetooth-sdk/react.d.ts.map +1 -0
  16. package/build/bluetooth-sdk/react.js +2 -0
  17. package/build/bluetooth-sdk/react.js.map +1 -0
  18. package/build/bluetooth-sdk/types.d.ts +2 -0
  19. package/build/bluetooth-sdk/types.d.ts.map +1 -0
  20. package/build/bluetooth-sdk/types.js +2 -0
  21. package/build/bluetooth-sdk/types.js.map +1 -0
  22. package/build/engine.d.ts +24 -16
  23. package/build/engine.d.ts.map +1 -1
  24. package/build/engine.js +9 -4
  25. package/build/engine.js.map +1 -1
  26. package/build/facades/dev.d.ts +3 -2
  27. package/build/facades/dev.d.ts.map +1 -1
  28. package/build/facades/dev.js +18 -12
  29. package/build/facades/dev.js.map +1 -1
  30. package/build/facades/display.d.ts +1 -1
  31. package/build/facades/display.d.ts.map +1 -1
  32. package/build/facades/display.js +1 -1
  33. package/build/facades/display.js.map +1 -1
  34. package/build/facades/gallery.js +1 -1
  35. package/build/facades/gallery.js.map +1 -1
  36. package/build/facades/glasses.d.ts +4 -13
  37. package/build/facades/glasses.d.ts.map +1 -1
  38. package/build/facades/glasses.js +21 -6
  39. package/build/facades/glasses.js.map +1 -1
  40. package/build/facades/glassesSettings.d.ts.map +1 -1
  41. package/build/facades/glassesSettings.js +1 -0
  42. package/build/facades/glassesSettings.js.map +1 -1
  43. package/build/facades/miniapps.d.ts +4 -0
  44. package/build/facades/miniapps.d.ts.map +1 -1
  45. package/build/facades/miniapps.js +5 -0
  46. package/build/facades/miniapps.js.map +1 -1
  47. package/build/facades/ota.d.ts +14 -16
  48. package/build/facades/ota.d.ts.map +1 -1
  49. package/build/facades/ota.js +22 -7
  50. package/build/facades/ota.js.map +1 -1
  51. package/build/facades/pairing.d.ts +8 -5
  52. package/build/facades/pairing.d.ts.map +1 -1
  53. package/build/facades/pairing.js +12 -10
  54. package/build/facades/pairing.js.map +1 -1
  55. package/build/facades/permissions.d.ts +10 -0
  56. package/build/facades/permissions.d.ts.map +1 -1
  57. package/build/facades/permissions.js +10 -0
  58. package/build/facades/permissions.js.map +1 -1
  59. package/build/facades/phoneNotifications.d.ts +0 -4
  60. package/build/facades/phoneNotifications.d.ts.map +1 -1
  61. package/build/facades/phoneNotifications.js +4 -14
  62. package/build/facades/phoneNotifications.js.map +1 -1
  63. package/build/facades/speech.d.ts +7 -6
  64. package/build/facades/speech.d.ts.map +1 -1
  65. package/build/facades/speech.js +1 -1
  66. package/build/facades/speech.js.map +1 -1
  67. package/build/generated/releaseMetadata.d.ts +12 -0
  68. package/build/generated/releaseMetadata.d.ts.map +1 -0
  69. package/build/generated/releaseMetadata.js +10 -0
  70. package/build/generated/releaseMetadata.js.map +1 -0
  71. package/build/index.d.ts +10 -8
  72. package/build/index.d.ts.map +1 -1
  73. package/build/index.js +6 -5
  74. package/build/index.js.map +1 -1
  75. package/build/react/MentraLiveOtaFlow.d.ts +38 -0
  76. package/build/react/MentraLiveOtaFlow.d.ts.map +1 -0
  77. package/build/react/MentraLiveOtaFlow.js +528 -0
  78. package/build/react/MentraLiveOtaFlow.js.map +1 -0
  79. package/build/react/index.d.ts +2 -0
  80. package/build/react/index.d.ts.map +1 -0
  81. package/build/react/index.js +2 -0
  82. package/build/react/index.js.map +1 -0
  83. package/build/react/useEngineSnapshot.d.ts +2 -0
  84. package/build/react/useEngineSnapshot.d.ts.map +1 -0
  85. package/build/react/useEngineSnapshot.js +14 -0
  86. package/build/react/useEngineSnapshot.js.map +1 -0
  87. package/build/runtime/bootstrap.d.ts +24 -1
  88. package/build/runtime/bootstrap.d.ts.map +1 -1
  89. package/build/runtime/bootstrap.js +17 -0
  90. package/build/runtime/bootstrap.js.map +1 -1
  91. package/build/runtime/scanQrSeam.d.ts +7 -0
  92. package/build/runtime/scanQrSeam.d.ts.map +1 -0
  93. package/build/runtime/scanQrSeam.js +16 -0
  94. package/build/runtime/scanQrSeam.js.map +1 -0
  95. package/build/services/AppRegistry.d.ts +41 -57
  96. package/build/services/AppRegistry.d.ts.map +1 -1
  97. package/build/services/AppRegistry.js +208 -144
  98. package/build/services/AppRegistry.js.map +1 -1
  99. package/build/services/AudioCloudUplink.d.ts +12 -0
  100. package/build/services/AudioCloudUplink.d.ts.map +1 -1
  101. package/build/services/AudioCloudUplink.js +22 -1
  102. package/build/services/AudioCloudUplink.js.map +1 -1
  103. package/build/services/AudioPlaybackService.d.ts +41 -2
  104. package/build/services/AudioPlaybackService.d.ts.map +1 -1
  105. package/build/services/AudioPlaybackService.js +250 -33
  106. package/build/services/AudioPlaybackService.js.map +1 -1
  107. package/build/services/BlobStore.d.ts +2 -1
  108. package/build/services/BlobStore.d.ts.map +1 -1
  109. package/build/services/BlobStore.js +17 -9
  110. package/build/services/BlobStore.js.map +1 -1
  111. package/build/services/CloudAudioSubscriptionSync.d.ts.map +1 -1
  112. package/build/services/CloudAudioSubscriptionSync.js +13 -1
  113. package/build/services/CloudAudioSubscriptionSync.js.map +1 -1
  114. package/build/services/CloudClientService.d.ts +15 -0
  115. package/build/services/CloudClientService.d.ts.map +1 -1
  116. package/build/services/CloudClientService.js +93 -1
  117. package/build/services/CloudClientService.js.map +1 -1
  118. package/build/services/DeviceEventRouter.js +5 -5
  119. package/build/services/DeviceEventRouter.js.map +1 -1
  120. package/build/services/ForegroundLocationPermission.d.ts +13 -0
  121. package/build/services/ForegroundLocationPermission.d.ts.map +1 -0
  122. package/build/services/ForegroundLocationPermission.js +12 -0
  123. package/build/services/ForegroundLocationPermission.js.map +1 -0
  124. package/build/services/GlassesSettingsSync.d.ts.map +1 -1
  125. package/build/services/GlassesSettingsSync.js +9 -3
  126. package/build/services/GlassesSettingsSync.js.map +1 -1
  127. package/build/services/GlassesStatusProjection.d.ts +2 -1
  128. package/build/services/GlassesStatusProjection.d.ts.map +1 -1
  129. package/build/services/GlassesStatusProjection.js +15 -8
  130. package/build/services/GlassesStatusProjection.js.map +1 -1
  131. package/build/services/HotspotOtaTransport.d.ts +29 -0
  132. package/build/services/HotspotOtaTransport.d.ts.map +1 -0
  133. package/build/services/HotspotOtaTransport.js +146 -0
  134. package/build/services/HotspotOtaTransport.js.map +1 -0
  135. package/build/services/HotspotShutdown.d.ts +17 -0
  136. package/build/services/HotspotShutdown.d.ts.map +1 -0
  137. package/build/services/HotspotShutdown.js +29 -0
  138. package/build/services/HotspotShutdown.js.map +1 -0
  139. package/build/services/LocalDisplayManager.d.ts +15 -0
  140. package/build/services/LocalDisplayManager.d.ts.map +1 -1
  141. package/build/services/LocalDisplayManager.js +106 -20
  142. package/build/services/LocalDisplayManager.js.map +1 -1
  143. package/build/services/LocalMiniappRuntime.d.ts +74 -2
  144. package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
  145. package/build/services/LocalMiniappRuntime.js +785 -291
  146. package/build/services/LocalMiniappRuntime.js.map +1 -1
  147. package/build/services/LocalMiniappStorage.d.ts +32 -0
  148. package/build/services/LocalMiniappStorage.d.ts.map +1 -0
  149. package/build/services/LocalMiniappStorage.js +66 -0
  150. package/build/services/LocalMiniappStorage.js.map +1 -0
  151. package/build/services/LocalMiniappUserIdentity.d.ts +20 -0
  152. package/build/services/LocalMiniappUserIdentity.d.ts.map +1 -0
  153. package/build/services/LocalMiniappUserIdentity.js +43 -0
  154. package/build/services/LocalMiniappUserIdentity.js.map +1 -0
  155. package/build/services/LocalSttFallbackCoordinator.d.ts +9 -6
  156. package/build/services/LocalSttFallbackCoordinator.d.ts.map +1 -1
  157. package/build/services/LocalSttFallbackCoordinator.js +18 -12
  158. package/build/services/LocalSttFallbackCoordinator.js.map +1 -1
  159. package/build/services/MicStateCoordinator.d.ts +42 -1
  160. package/build/services/MicStateCoordinator.d.ts.map +1 -1
  161. package/build/services/MicStateCoordinator.js +141 -3
  162. package/build/services/MicStateCoordinator.js.map +1 -1
  163. package/build/services/MiniappLauncher.d.ts.map +1 -1
  164. package/build/services/MiniappLauncher.js +23 -3
  165. package/build/services/MiniappLauncher.js.map +1 -1
  166. package/build/services/MiniappLiveness.d.ts +12 -0
  167. package/build/services/MiniappLiveness.d.ts.map +1 -0
  168. package/build/services/MiniappLiveness.js +16 -0
  169. package/build/services/MiniappLiveness.js.map +1 -0
  170. package/build/services/NativeHttpResponse.d.ts +3 -0
  171. package/build/services/NativeHttpResponse.d.ts.map +1 -0
  172. package/build/services/NativeHttpResponse.js +6 -0
  173. package/build/services/NativeHttpResponse.js.map +1 -0
  174. package/build/services/OtaArtifactDownloader.d.ts +65 -0
  175. package/build/services/OtaArtifactDownloader.d.ts.map +1 -0
  176. package/build/services/OtaArtifactDownloader.js +226 -0
  177. package/build/services/OtaArtifactDownloader.js.map +1 -0
  178. package/build/services/OtaAutoChain.d.ts +34 -0
  179. package/build/services/OtaAutoChain.d.ts.map +1 -0
  180. package/build/services/OtaAutoChain.js +83 -0
  181. package/build/services/OtaAutoChain.js.map +1 -0
  182. package/build/services/OtaErrorMapping.d.ts +18 -0
  183. package/build/services/OtaErrorMapping.d.ts.map +1 -0
  184. package/build/services/OtaErrorMapping.js +63 -0
  185. package/build/services/OtaErrorMapping.js.map +1 -0
  186. package/build/services/OtaInstallCoordinator.d.ts +95 -15
  187. package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
  188. package/build/services/OtaInstallCoordinator.js +577 -130
  189. package/build/services/OtaInstallCoordinator.js.map +1 -1
  190. package/build/services/OtaService.d.ts.map +1 -1
  191. package/build/services/OtaService.js +8 -1
  192. package/build/services/OtaService.js.map +1 -1
  193. package/build/services/OtaUpdateCheckService.d.ts +39 -4
  194. package/build/services/OtaUpdateCheckService.d.ts.map +1 -1
  195. package/build/services/OtaUpdateCheckService.js +138 -22
  196. package/build/services/OtaUpdateCheckService.js.map +1 -1
  197. package/build/services/PhoneCalendarHelpers.d.ts +32 -0
  198. package/build/services/PhoneCalendarHelpers.d.ts.map +1 -0
  199. package/build/services/PhoneCalendarHelpers.js +157 -0
  200. package/build/services/PhoneCalendarHelpers.js.map +1 -0
  201. package/build/services/PhoneCalendarService.d.ts +5 -0
  202. package/build/services/PhoneCalendarService.d.ts.map +1 -0
  203. package/build/services/PhoneCalendarService.js +45 -0
  204. package/build/services/PhoneCalendarService.js.map +1 -0
  205. package/build/services/PhoneCameraFovCoordinator.d.ts +30 -0
  206. package/build/services/PhoneCameraFovCoordinator.d.ts.map +1 -0
  207. package/build/services/PhoneCameraFovCoordinator.js +194 -0
  208. package/build/services/PhoneCameraFovCoordinator.js.map +1 -0
  209. package/build/services/PhoneNotificationsSync.d.ts.map +1 -1
  210. package/build/services/PhoneNotificationsSync.js +12 -10
  211. package/build/services/PhoneNotificationsSync.js.map +1 -1
  212. package/build/services/PhonePhotoCoordinator.d.ts +26 -2
  213. package/build/services/PhonePhotoCoordinator.d.ts.map +1 -1
  214. package/build/services/PhonePhotoCoordinator.js +79 -9
  215. package/build/services/PhonePhotoCoordinator.js.map +1 -1
  216. package/build/services/PhoneStreamCoordinator.d.ts +8 -1
  217. package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
  218. package/build/services/PhoneStreamCoordinator.js +125 -13
  219. package/build/services/PhoneStreamCoordinator.js.map +1 -1
  220. package/build/services/PhoneVideoCoordinator.d.ts +2 -0
  221. package/build/services/PhoneVideoCoordinator.d.ts.map +1 -1
  222. package/build/services/PhoneVideoCoordinator.js +10 -0
  223. package/build/services/PhoneVideoCoordinator.js.map +1 -1
  224. package/build/services/SceneRenderer.d.ts.map +1 -1
  225. package/build/services/SceneRenderer.js +15 -0
  226. package/build/services/SceneRenderer.js.map +1 -1
  227. package/build/services/SentenceTtsPipeline.d.ts +31 -0
  228. package/build/services/SentenceTtsPipeline.d.ts.map +1 -0
  229. package/build/services/SentenceTtsPipeline.js +67 -0
  230. package/build/services/SentenceTtsPipeline.js.map +1 -0
  231. package/build/services/SupportProfileSync.d.ts +22 -0
  232. package/build/services/SupportProfileSync.d.ts.map +1 -0
  233. package/build/services/SupportProfileSync.js +213 -0
  234. package/build/services/SupportProfileSync.js.map +1 -0
  235. package/build/services/TranscriptionRouting.d.ts +12 -0
  236. package/build/services/TranscriptionRouting.d.ts.map +1 -0
  237. package/build/services/TranscriptionRouting.js +24 -0
  238. package/build/services/TranscriptionRouting.js.map +1 -0
  239. package/build/services/TtsTextSanitizer.d.ts +5 -0
  240. package/build/services/TtsTextSanitizer.d.ts.map +1 -0
  241. package/build/services/TtsTextSanitizer.js +61 -0
  242. package/build/services/TtsTextSanitizer.js.map +1 -0
  243. package/build/services/WifiAdbRequest.d.ts +17 -0
  244. package/build/services/WifiAdbRequest.d.ts.map +1 -0
  245. package/build/services/WifiAdbRequest.js +35 -0
  246. package/build/services/WifiAdbRequest.js.map +1 -0
  247. package/build/services/asg/asgCameraApi.d.ts +43 -0
  248. package/build/services/asg/asgCameraApi.d.ts.map +1 -1
  249. package/build/services/asg/asgCameraApi.js +509 -26
  250. package/build/services/asg/asgCameraApi.js.map +1 -1
  251. package/build/services/asg/cameraRollExportCoordinator.d.ts +60 -0
  252. package/build/services/asg/cameraRollExportCoordinator.d.ts.map +1 -0
  253. package/build/services/asg/cameraRollExportCoordinator.js +618 -0
  254. package/build/services/asg/cameraRollExportCoordinator.js.map +1 -0
  255. package/build/services/asg/cameraRollExportLedger.d.ts +44 -0
  256. package/build/services/asg/cameraRollExportLedger.d.ts.map +1 -0
  257. package/build/services/asg/cameraRollExportLedger.js +78 -0
  258. package/build/services/asg/cameraRollExportLedger.js.map +1 -0
  259. package/build/services/asg/galleryNotices.d.ts +1 -1
  260. package/build/services/asg/galleryNotices.d.ts.map +1 -1
  261. package/build/services/asg/galleryNotices.js.map +1 -1
  262. package/build/services/asg/galleryPathMigration.d.ts +3 -0
  263. package/build/services/asg/galleryPathMigration.d.ts.map +1 -0
  264. package/build/services/asg/galleryPathMigration.js +26 -0
  265. package/build/services/asg/galleryPathMigration.js.map +1 -0
  266. package/build/services/asg/gallerySettingsService.d.ts +1 -0
  267. package/build/services/asg/gallerySettingsService.d.ts.map +1 -1
  268. package/build/services/asg/gallerySettingsService.js +2 -0
  269. package/build/services/asg/gallerySettingsService.js.map +1 -1
  270. package/build/services/asg/gallerySyncService.d.ts.map +1 -1
  271. package/build/services/asg/gallerySyncService.js +162 -56
  272. package/build/services/asg/gallerySyncService.js.map +1 -1
  273. package/build/services/asg/galleryTransferLedger.d.ts +58 -0
  274. package/build/services/asg/galleryTransferLedger.d.ts.map +1 -0
  275. package/build/services/asg/galleryTransferLedger.js +225 -0
  276. package/build/services/asg/galleryTransferLedger.js.map +1 -0
  277. package/build/services/asg/localNetworkTransport.d.ts +15 -0
  278. package/build/services/asg/localNetworkTransport.d.ts.map +1 -0
  279. package/build/services/asg/localNetworkTransport.js +144 -0
  280. package/build/services/asg/localNetworkTransport.js.map +1 -0
  281. package/build/services/asg/localStorageService.d.ts +18 -0
  282. package/build/services/asg/localStorageService.d.ts.map +1 -1
  283. package/build/services/asg/localStorageService.js +168 -19
  284. package/build/services/asg/localStorageService.js.map +1 -1
  285. package/build/services/asg/mediaProcessingQueue.d.ts +10 -0
  286. package/build/services/asg/mediaProcessingQueue.d.ts.map +1 -1
  287. package/build/services/asg/mediaProcessingQueue.js +193 -62
  288. package/build/services/asg/mediaProcessingQueue.js.map +1 -1
  289. package/build/services/audioPlaybackAssets.d.ts +8 -0
  290. package/build/services/audioPlaybackAssets.d.ts.map +1 -0
  291. package/build/services/audioPlaybackAssets.js +7 -0
  292. package/build/services/audioPlaybackAssets.js.map +1 -0
  293. package/build/services/gallerySyncClock.js +1 -1
  294. package/build/services/gallerySyncClock.js.map +1 -1
  295. package/build/services/glassesClockSync.d.ts.map +1 -1
  296. package/build/services/glassesClockSync.js +6 -2
  297. package/build/services/glassesClockSync.js.map +1 -1
  298. package/build/services/manifestActions.d.ts +7 -0
  299. package/build/services/manifestActions.d.ts.map +1 -0
  300. package/build/services/manifestActions.js +25 -0
  301. package/build/services/manifestActions.js.map +1 -0
  302. package/build/services/otaDisplayState.d.ts +23 -12
  303. package/build/services/otaDisplayState.d.ts.map +1 -1
  304. package/build/services/otaDisplayState.js +36 -14
  305. package/build/services/otaDisplayState.js.map +1 -1
  306. package/build/services/otaInstallPolicy.d.ts +16 -4
  307. package/build/services/otaInstallPolicy.d.ts.map +1 -1
  308. package/build/services/otaInstallPolicy.js +24 -3
  309. package/build/services/otaInstallPolicy.js.map +1 -1
  310. package/build/services/otaLegacyMapping.d.ts +1 -1
  311. package/build/services/otaLegacyMapping.d.ts.map +1 -1
  312. package/build/services/otaLegacyMapping.js.map +1 -1
  313. package/build/services/otaManifestPolicy.d.ts +14 -0
  314. package/build/services/otaManifestPolicy.d.ts.map +1 -0
  315. package/build/services/otaManifestPolicy.js +19 -0
  316. package/build/services/otaManifestPolicy.js.map +1 -0
  317. package/build/services/otaManifestUrl.d.ts +3 -0
  318. package/build/services/otaManifestUrl.d.ts.map +1 -0
  319. package/build/services/otaManifestUrl.js +38 -0
  320. package/build/services/otaManifestUrl.js.map +1 -0
  321. package/build/services/slimStreamStatus.d.ts +11 -0
  322. package/build/services/slimStreamStatus.d.ts.map +1 -1
  323. package/build/services/slimStreamStatus.js +14 -4
  324. package/build/services/slimStreamStatus.js.map +1 -1
  325. package/build/stores/apps.d.ts.map +1 -1
  326. package/build/stores/apps.js +11 -0
  327. package/build/stores/apps.js.map +1 -1
  328. package/build/stores/bluetoothSettingKeys.d.ts.map +1 -1
  329. package/build/stores/bluetoothSettingKeys.js +2 -0
  330. package/build/stores/bluetoothSettingKeys.js.map +1 -1
  331. package/build/stores/gallerySync.d.ts +2 -0
  332. package/build/stores/gallerySync.d.ts.map +1 -1
  333. package/build/stores/gallerySync.js +2 -0
  334. package/build/stores/gallerySync.js.map +1 -1
  335. package/build/stores/glasses.d.ts.map +1 -1
  336. package/build/stores/glasses.js +3 -0
  337. package/build/stores/glasses.js.map +1 -1
  338. package/build/stores/settings.d.ts +17 -0
  339. package/build/stores/settings.d.ts.map +1 -1
  340. package/build/stores/settings.js +157 -17
  341. package/build/stores/settings.js.map +1 -1
  342. package/build/types/applet.d.ts +2 -0
  343. package/build/types/applet.d.ts.map +1 -1
  344. package/build/types/applet.js.map +1 -1
  345. package/build/types/asg.d.ts +7 -0
  346. package/build/types/asg.d.ts.map +1 -1
  347. package/build/types/asg.js.map +1 -1
  348. package/build/types/enums.d.ts +2 -25
  349. package/build/types/enums.d.ts.map +1 -1
  350. package/build/types/enums.js +2 -27
  351. package/build/types/enums.js.map +1 -1
  352. package/build/types/hardware.d.ts +4 -13
  353. package/build/types/hardware.d.ts.map +1 -1
  354. package/build/types/hardware.js +15 -3
  355. package/build/types/hardware.js.map +1 -1
  356. package/build/types/index.d.ts +2 -6
  357. package/build/types/index.d.ts.map +1 -1
  358. package/build/types/index.js +2 -6
  359. package/build/types/index.js.map +1 -1
  360. package/build/utils/configuredDevHost.d.ts +6 -0
  361. package/build/utils/configuredDevHost.d.ts.map +1 -0
  362. package/build/utils/configuredDevHost.js +19 -0
  363. package/build/utils/configuredDevHost.js.map +1 -0
  364. package/build/utils/devMiniappLaunch.d.ts +19 -8
  365. package/build/utils/devMiniappLaunch.d.ts.map +1 -1
  366. package/build/utils/devMiniappLaunch.js +144 -21
  367. package/build/utils/devMiniappLaunch.js.map +1 -1
  368. package/build/utils/diagnosticContext.d.ts.map +1 -1
  369. package/build/utils/diagnosticContext.js +15 -17
  370. package/build/utils/diagnosticContext.js.map +1 -1
  371. package/build/utils/hardware/hardware.d.ts.map +1 -1
  372. package/build/utils/hardware/hardware.js +7 -3
  373. package/build/utils/hardware/hardware.js.map +1 -1
  374. package/build/utils/miniappDiagnostics.d.ts +64 -0
  375. package/build/utils/miniappDiagnostics.d.ts.map +1 -0
  376. package/build/utils/miniappDiagnostics.js +173 -0
  377. package/build/utils/miniappDiagnostics.js.map +1 -0
  378. package/build/utils/permissions/MediaLibraryPermissions.d.ts +11 -0
  379. package/build/utils/permissions/MediaLibraryPermissions.d.ts.map +1 -1
  380. package/build/utils/permissions/MediaLibraryPermissions.js +27 -4
  381. package/build/utils/permissions/MediaLibraryPermissions.js.map +1 -1
  382. package/build/utils/timers/timers.d.ts.map +1 -1
  383. package/build/utils/timers/timers.js +55 -18
  384. package/build/utils/timers/timers.js.map +1 -1
  385. package/package.json +59 -31
  386. package/src/assets/silence.wav +0 -0
  387. package/src/bluetooth-sdk/debug.ts +1 -0
  388. package/src/bluetooth-sdk/index.ts +2 -0
  389. package/src/bluetooth-sdk/photo-receiver.ts +2 -0
  390. package/src/bluetooth-sdk/react.ts +1 -0
  391. package/src/bluetooth-sdk/types.ts +1 -0
  392. package/src/engine.ts +9 -4
  393. package/src/facades/dev.ts +17 -12
  394. package/src/facades/display.ts +1 -1
  395. package/src/facades/gallery.ts +1 -1
  396. package/src/facades/glasses.ts +20 -7
  397. package/src/facades/glassesSettings.ts +5 -0
  398. package/src/facades/miniapps.ts +7 -0
  399. package/src/facades/ota.ts +23 -8
  400. package/src/facades/pairing.ts +15 -11
  401. package/src/facades/permissions.ts +14 -0
  402. package/src/facades/phoneNotifications.ts +4 -13
  403. package/src/facades/speech.ts +21 -7
  404. package/src/generated/releaseMetadata.ts +20 -0
  405. package/src/index.ts +39 -13
  406. package/src/react/MentraLiveOtaFlow.tsx +856 -0
  407. package/src/react/index.ts +7 -0
  408. package/src/react/useEngineSnapshot.ts +16 -0
  409. package/src/runtime/bootstrap.ts +33 -1
  410. package/src/runtime/scanQrSeam.ts +20 -0
  411. package/src/services/AppRegistry.ts +240 -149
  412. package/src/services/AudioCloudUplink.ts +23 -1
  413. package/src/services/AudioPlaybackService.ts +287 -38
  414. package/src/services/BlobStore.ts +22 -9
  415. package/src/services/CloudAudioSubscriptionSync.ts +13 -1
  416. package/src/services/CloudClientService.ts +96 -1
  417. package/src/services/DeviceEventRouter.ts +5 -5
  418. package/src/services/ForegroundLocationPermission.ts +24 -0
  419. package/src/services/GlassesSettingsSync.ts +9 -3
  420. package/src/services/GlassesStatusProjection.ts +16 -8
  421. package/src/services/HotspotOtaTransport.ts +184 -0
  422. package/src/services/HotspotShutdown.ts +41 -0
  423. package/src/services/LocalDisplayManager.ts +112 -21
  424. package/src/services/LocalMiniappRuntime.ts +967 -346
  425. package/src/services/LocalMiniappStorage.ts +82 -0
  426. package/src/services/LocalMiniappUserIdentity.ts +46 -0
  427. package/src/services/LocalSttFallbackCoordinator.ts +19 -12
  428. package/src/services/MicStateCoordinator.ts +169 -4
  429. package/src/services/MiniappLauncher.ts +30 -3
  430. package/src/services/MiniappLiveness.ts +24 -0
  431. package/src/services/NativeHttpResponse.ts +6 -0
  432. package/src/services/OtaArtifactDownloader.ts +312 -0
  433. package/src/services/OtaAutoChain.ts +106 -0
  434. package/src/services/OtaErrorMapping.ts +80 -0
  435. package/src/services/OtaInstallCoordinator.ts +649 -144
  436. package/src/services/OtaService.ts +11 -5
  437. package/src/services/OtaUpdateCheckService.ts +181 -21
  438. package/src/services/PhoneCalendarHelpers.ts +212 -0
  439. package/src/services/PhoneCalendarService.ts +65 -0
  440. package/src/services/PhoneCameraFovCoordinator.ts +210 -0
  441. package/src/services/PhoneNotificationsSync.ts +12 -10
  442. package/src/services/PhonePhotoCoordinator.ts +116 -18
  443. package/src/services/PhoneStreamCoordinator.ts +139 -25
  444. package/src/services/PhoneVideoCoordinator.ts +11 -0
  445. package/src/services/SceneRenderer.ts +16 -0
  446. package/src/services/SentenceTtsPipeline.ts +106 -0
  447. package/src/services/SupportProfileSync.ts +218 -0
  448. package/src/services/TranscriptionRouting.ts +37 -0
  449. package/src/services/TtsTextSanitizer.ts +66 -0
  450. package/src/services/WifiAdbRequest.ts +53 -0
  451. package/src/services/asg/asgCameraApi.ts +615 -33
  452. package/src/services/asg/cameraRollExportCoordinator.ts +627 -0
  453. package/src/services/asg/cameraRollExportLedger.ts +122 -0
  454. package/src/services/asg/galleryNotices.ts +1 -0
  455. package/src/services/asg/galleryPathMigration.ts +22 -0
  456. package/src/services/asg/gallerySettingsService.ts +3 -0
  457. package/src/services/asg/gallerySyncService.ts +184 -73
  458. package/src/services/asg/galleryTransferLedger.ts +312 -0
  459. package/src/services/asg/localNetworkTransport.ts +169 -0
  460. package/src/services/asg/localStorageService.ts +179 -24
  461. package/src/services/asg/mediaProcessingQueue.ts +209 -62
  462. package/src/services/audioPlaybackAssets.ts +8 -0
  463. package/src/services/gallerySyncClock.ts +1 -1
  464. package/src/services/glassesClockSync.ts +6 -2
  465. package/src/services/manifestActions.ts +30 -0
  466. package/src/services/otaDisplayState.ts +58 -17
  467. package/src/services/otaInstallPolicy.ts +30 -4
  468. package/src/services/otaLegacyMapping.ts +1 -1
  469. package/src/services/otaManifestPolicy.ts +42 -0
  470. package/src/services/otaManifestUrl.ts +44 -0
  471. package/src/services/slimStreamStatus.ts +16 -5
  472. package/src/stores/apps.ts +12 -0
  473. package/src/stores/bluetoothSettingKeys.ts +2 -0
  474. package/src/stores/gallerySync.ts +4 -0
  475. package/src/stores/glasses.ts +3 -0
  476. package/src/stores/settings.ts +179 -18
  477. package/src/types/applet.ts +2 -0
  478. package/src/types/asg.ts +7 -0
  479. package/src/types/enums.ts +3 -28
  480. package/src/types/hardware.ts +20 -13
  481. package/src/types/index.ts +2 -6
  482. package/src/utils/configuredDevHost.ts +17 -0
  483. package/src/utils/devMiniappLaunch.ts +151 -23
  484. package/src/utils/diagnosticContext.ts +17 -17
  485. package/src/utils/hardware/hardware.ts +7 -9
  486. package/src/utils/miniappDiagnostics.ts +226 -0
  487. package/src/utils/permissions/MediaLibraryPermissions.ts +35 -4
  488. package/src/utils/timers/timers.ts +57 -21
  489. package/build/devtools.d.ts +0 -11
  490. package/build/devtools.d.ts.map +0 -1
  491. package/build/devtools.js +0 -13
  492. package/build/devtools.js.map +0 -1
  493. package/build/internal.d.ts +0 -66
  494. package/build/internal.d.ts.map +0 -1
  495. package/build/internal.js +0 -89
  496. package/build/internal.js.map +0 -1
  497. package/build/services/asgOtaVersionUrl.d.ts +0 -2
  498. package/build/services/asgOtaVersionUrl.d.ts.map +0 -1
  499. package/build/services/asgOtaVersionUrl.js +0 -36
  500. package/build/services/asgOtaVersionUrl.js.map +0 -1
  501. package/src/devtools.ts +0 -13
  502. package/src/internal.ts +0 -158
  503. package/src/services/asgOtaVersionUrl.ts +0 -41
@@ -14,7 +14,8 @@ import {INVALID_DOWNLOADED_MEDIA, validateDownloadedMediaFile} from "./galleryMe
14
14
  import {reportInvalidGalleryMedia} from "./GalleryMediaIntegrityReportService"
15
15
  import {useGallerySyncStore} from "../../stores/gallerySync"
16
16
  import {BgTimer} from "../../utils/timers"
17
- import {MediaLibraryPermissions} from "../../utils/permissions/MediaLibraryPermissions"
17
+ import {galleryTransferLedger, GalleryTransferEntry} from "./galleryTransferLedger"
18
+ import {cameraRollExportCoordinator} from "./cameraRollExportCoordinator"
18
19
 
19
20
  const TAG = "[MediaProcessingQueue]"
20
21
 
@@ -48,6 +49,8 @@ export interface ProcessingItem {
48
49
  thumbnailPath?: string
49
50
  /** File names to delete from glasses after processing completes */
50
51
  deleteFromGlasses?: string[]
52
+ /** Negotiated gallery protocol; absent entries are inferred from the transfer ledger. */
53
+ protocolVersion?: number
51
54
  }
52
55
 
53
56
  class MediaProcessingQueue {
@@ -93,7 +96,7 @@ class MediaProcessingQueue {
93
96
  }
94
97
 
95
98
  /** Returns a promise that resolves when the queue is fully drained, or rejects on timeout. */
96
- waitUntilDrained(timeoutMs: number = 600000): Promise<void> {
99
+ waitUntilDrained(timeoutMs: number = 4 * 60 * 60 * 1000): Promise<void> {
97
100
  if (!this.hasPending) return Promise.resolve()
98
101
  return new Promise((resolve, reject) => {
99
102
  const deadline = Date.now() + timeoutMs
@@ -112,6 +115,71 @@ class MediaProcessingQueue {
112
115
  })
113
116
  }
114
117
 
118
+ /** Retry durable export/ack work after an app restart without downloading media again. */
119
+ async retryPending(): Promise<{retried: number; failed: number}> {
120
+ let retried = 0
121
+ let failed = 0
122
+ for (let entry of galleryTransferLedger.pendingRecovery()) {
123
+ try {
124
+ if (entry.state === "RESTORE_PENDING") {
125
+ await asgCameraApi.restoreCapture(entry.captureId)
126
+ galleryTransferLedger.transition(entry.captureId, "DISCOVERED", {lastError: undefined})
127
+ retried++
128
+ continue
129
+ }
130
+ if (!entry.finalPath || !(await RNFS.exists(entry.finalPath))) {
131
+ throw new Error(`Recovery file is missing for ${entry.captureId}`)
132
+ }
133
+ // Rebuild a missing app index before any source acknowledgement, even when camera-roll
134
+ // saving is disabled or an export receipt was already committed before restart.
135
+ const downloadedFile = await this.recoverDownloadedFile(entry)
136
+ if (entry.state === "EXPORT_PENDING" || entry.state === "INDEXED") {
137
+ const shouldAutoSave = await cameraRollExportCoordinator.isAutoSaveEnabled()
138
+ entry = galleryTransferLedger.update(entry.captureId, {shouldAutoSave, lastError: undefined})
139
+ if (shouldAutoSave) {
140
+ if (entry.state !== "EXPORT_PENDING") {
141
+ entry = galleryTransferLedger.transition(entry.captureId, "EXPORT_PENDING")
142
+ }
143
+ const receipt = await cameraRollExportCoordinator.exportForSource(downloadedFile, entry.captureId)
144
+ entry = receipt
145
+ ? galleryTransferLedger.transition(entry.captureId, "EXPORTED", {assetReceipt: receipt})
146
+ : galleryTransferLedger.transition(entry.captureId, "INDEXED", {
147
+ shouldAutoSave: false,
148
+ lastError: undefined,
149
+ })
150
+ } else if (entry.state === "EXPORT_PENDING") {
151
+ entry = galleryTransferLedger.transition(entry.captureId, "INDEXED", {
152
+ shouldAutoSave: false,
153
+ lastError: undefined,
154
+ })
155
+ }
156
+ }
157
+ entry = galleryTransferLedger.transition(entry.captureId, "ACK_PENDING")
158
+ await this.acknowledgeEntry(entry)
159
+ galleryTransferLedger.transition(entry.captureId, "TRASHED", {lastError: undefined})
160
+ retried++
161
+ } catch (error) {
162
+ galleryTransferLedger.recordFailure(entry.captureId, error)
163
+ failed++
164
+ console.warn(`${TAG} Recovery remains pending for ${entry.captureId}:`, error)
165
+ }
166
+ }
167
+ return {retried, failed}
168
+ }
169
+
170
+ private async acknowledgeEntry(entry: GalleryTransferEntry): Promise<void> {
171
+ if (entry.protocolVersion >= 3) {
172
+ await asgCameraApi.acknowledgeCapture(entry.captureId, entry.ackId)
173
+ return
174
+ }
175
+ const result = await asgCameraApi.deleteFilesFromServer(
176
+ entry.deleteFromGlasses.length > 0 ? entry.deleteFromGlasses : [entry.captureId],
177
+ )
178
+ if (result.failed.length > 0 || result.deleted.length === 0) {
179
+ throw new Error(`Glasses did not acknowledge ${entry.captureId}`)
180
+ }
181
+ }
182
+
115
183
  /** Process items one at a time. */
116
184
  private async processLoop(): Promise<void> {
117
185
  if (this.isRunning) return
@@ -126,6 +194,10 @@ class MediaProcessingQueue {
126
194
  } catch (error) {
127
195
  console.error(`${TAG} Error processing ${item.id}:`, error)
128
196
  processFailed = true
197
+ const store = useGallerySyncStore.getState()
198
+ if (!store.failedFiles.includes(item.id)) {
199
+ store.onFileFailed(item.id, error instanceof Error ? error.message : String(error))
200
+ }
129
201
  }
130
202
 
131
203
  // Exit if generation changed (reset was called during processing)
@@ -136,9 +208,8 @@ class MediaProcessingQueue {
136
208
  // Success: increment processedFiles and remove from processingFiles set.
137
209
  store.onFileProcessed(item.id)
138
210
  } else {
139
- // Failure: processItem already called onFileFailed. Calling onFileProcessed
140
- // here would double-count the item (counted as both failed AND processed).
141
- // Still clear the processingFiles entry so the UI doesn't show it as in-progress.
211
+ // Failure is counted exactly once above. Still clear the processingFiles entry so the UI
212
+ // does not show it as in-progress.
142
213
  const current = store.processingFiles
143
214
  if (current.has(item.id)) {
144
215
  const newSet = new Set(current)
@@ -158,6 +229,23 @@ class MediaProcessingQueue {
158
229
  private async processItem(item: ProcessingItem): Promise<void> {
159
230
  const startTime = Date.now()
160
231
  let filePathToSave = item.primaryPath
232
+ let ledgerEntry = galleryTransferLedger.get(item.id)
233
+ if (!ledgerEntry) {
234
+ ledgerEntry = galleryTransferLedger.ensureCapture(
235
+ {
236
+ capture_id: item.id,
237
+ type: item.type,
238
+ timestamp: item.timestamp || Date.now(),
239
+ total_size: item.totalSize,
240
+ files: (item.deleteFromGlasses?.length ? item.deleteFromGlasses : [item.id]).map((name, index) => ({
241
+ name,
242
+ size: index === 0 ? item.totalSize : 0,
243
+ role: index === 0 ? "primary" : "sidecar",
244
+ })),
245
+ },
246
+ item.protocolVersion || 2,
247
+ )
248
+ }
161
249
 
162
250
  // 1. HDR merge (photos with brackets only)
163
251
  if (item.shouldProcess && item.type === "photo" && item.bracketPaths && item.bracketPaths.length >= 3) {
@@ -231,9 +319,8 @@ class MediaProcessingQueue {
231
319
  mediaKind: item.type,
232
320
  })
233
321
  } catch (validationError: any) {
234
- const reason =
235
- validationError?.message?.includes(INVALID_DOWNLOADED_MEDIA) ?
236
- validationError.message
322
+ const reason = validationError?.message?.includes(INVALID_DOWNLOADED_MEDIA)
323
+ ? validationError.message
237
324
  : `${INVALID_DOWNLOADED_MEDIA}: ${item.id}`
238
325
  console.error(`${TAG} Validation failed for ${item.id}: ${reason}`)
239
326
  reportInvalidGalleryMedia({
@@ -248,41 +335,23 @@ class MediaProcessingQueue {
248
335
  })
249
336
  const store = useGallerySyncStore.getState()
250
337
  store.onFileFailed(item.id, reason)
251
- await RNFS.unlink(filePathToSave).catch(() => {})
252
- for (const intermediate of [
253
- item.primaryPath + ".hdr.jpg",
254
- item.primaryPath + ".processed.jpg",
255
- item.primaryPath + ".stabilized.mp4",
256
- ]) {
257
- if (intermediate !== filePathToSave) {
258
- await RNFS.unlink(intermediate).catch(() => {})
259
- }
260
- }
338
+ galleryTransferLedger.recordFailure(item.id, validationError)
261
339
  throw new Error(reason)
262
340
  }
263
341
 
264
- // 6. Save to camera roll
265
- if (item.shouldAutoSave) {
266
- const success = await MediaLibraryPermissions.saveToLibrary(filePathToSave, item.timestamp)
267
- if (success) {
268
- console.log(`${TAG} ✅ Saved to camera roll: ${item.id}`)
269
- } else {
270
- console.warn(`${TAG} ❌ Failed to save to camera roll: ${item.id}`)
271
- // D1: Surface camera roll save failures to the UI
272
- const store = useGallerySyncStore.getState()
273
- store.onFileFailed(item.id, "camera roll save failed")
274
- }
275
- }
276
-
277
- // 7. Save metadata
342
+ // 6. Commit the app-local index before any export or source acknowledgement. Use the final
343
+ // on-disk output metadata for camera-roll identity: processing can change byte size, while
344
+ // recovery reconstructs this row from the same file and the transfer ledger timestamp.
278
345
  const isVideo = item.type === "video"
346
+ const finalFileStat = await RNFS.stat(filePathToSave)
347
+ const finalFileSize = Number(finalFileStat.size)
279
348
  const downloadedFile = localStorageService.convertToDownloadedFile(
280
349
  {
281
350
  name: item.id,
282
351
  url: "",
283
352
  download: "",
284
- size: item.totalSize,
285
- modified: item.timestamp || Date.now(),
353
+ size: finalFileSize,
354
+ modified: ledgerEntry.timestamp,
286
355
  is_video: isVideo,
287
356
  thumbnail_data: item.thumbnailData,
288
357
  duration: item.duration,
@@ -293,15 +362,52 @@ class MediaProcessingQueue {
293
362
  localThumbnailPath,
294
363
  item.glassesModel,
295
364
  )
365
+ downloadedFile.capture_id = item.id
366
+ const shouldAutoSave = await cameraRollExportCoordinator.isAutoSaveEnabled()
296
367
  try {
297
368
  await localStorageService.saveDownloadedFile(downloadedFile)
369
+ ledgerEntry = galleryTransferLedger.transition(item.id, "INDEXED", {
370
+ finalPath: filePathToSave,
371
+ thumbnailPath: localThumbnailPath,
372
+ shouldAutoSave,
373
+ })
374
+ await cameraRollExportCoordinator.recordIndexed(
375
+ downloadedFile,
376
+ shouldAutoSave,
377
+ shouldAutoSave ? "SOURCE_BARRIER" : "HISTORICAL_BACKFILL",
378
+ item.id,
379
+ )
298
380
  } catch (metadataError) {
299
- // D2: Clean up orphaned file if metadata save fails, then re-throw
300
- console.error(`${TAG} Metadata save failed for ${item.id}, cleaning up file:`, metadataError)
301
- await RNFS.unlink(filePathToSave).catch(() => {})
381
+ console.error(`${TAG} Metadata save failed for ${item.id}; retaining local and glasses copies:`, metadataError)
382
+ galleryTransferLedger.recordFailure(item.id, metadataError)
302
383
  throw metadataError
303
384
  }
304
385
 
386
+ // 7. While enabled, export is a durable, receipted step whose failures block ack. Turning
387
+ // auto-save off safely falls back to the already-verified app-local copy and later backfill.
388
+ if (shouldAutoSave) {
389
+ galleryTransferLedger.transition(item.id, "EXPORT_PENDING")
390
+ let receipt
391
+ try {
392
+ receipt = await cameraRollExportCoordinator.exportForSource(downloadedFile, item.id)
393
+ } catch (error) {
394
+ galleryTransferLedger.recordFailure(item.id, error)
395
+ throw error
396
+ }
397
+ if (receipt) {
398
+ ledgerEntry = galleryTransferLedger.transition(item.id, "EXPORTED", {
399
+ assetReceipt: receipt,
400
+ })
401
+ console.log(`${TAG} ✅ Saved to camera roll with receipt: ${item.id}`)
402
+ } else {
403
+ ledgerEntry = galleryTransferLedger.transition(item.id, "INDEXED", {
404
+ shouldAutoSave: false,
405
+ lastError: undefined,
406
+ })
407
+ console.log(`${TAG} Automatic camera-roll saving was disabled; keeping app-local copy: ${item.id}`)
408
+ }
409
+ }
410
+
305
411
  // S4: Clean up intermediate processing files
306
412
  const intermediates = [
307
413
  item.primaryPath + ".hdr.jpg",
@@ -326,8 +432,8 @@ class MediaProcessingQueue {
326
432
  name: item.id,
327
433
  url: localFileUrl,
328
434
  download: localFileUrl,
329
- size: item.totalSize,
330
- modified: item.timestamp || Date.now(),
435
+ size: finalFileSize,
436
+ modified: ledgerEntry.timestamp,
331
437
  is_video: isVideo,
332
438
  filePath: filePathToSave,
333
439
  mime_type: isVideo ? "video/mp4" : "image/jpeg",
@@ -336,35 +442,76 @@ class MediaProcessingQueue {
336
442
  duration: item.duration,
337
443
  })
338
444
 
339
- // 9. Delete from glasses now that processing is complete but only if the
340
- // local file actually exists and has data. If the download was truncated or
341
- // processing failed silently, we must not destroy the only good copy.
342
- if (item.deleteFromGlasses && item.deleteFromGlasses.length > 0) {
445
+ // 9. Acknowledge only after VERIFIED -> INDEXED -> (EXPORTED). The server turns this into
446
+ // recoverable trash; failures remain ACK_PENDING and are retried without re-downloading.
447
+ const localFileExists = await RNFS.exists(filePathToSave)
448
+ const localStat = localFileExists ? await RNFS.stat(filePathToSave) : null
449
+ if (!localStat || localStat.size <= 0) {
450
+ const error = new Error(`Cannot acknowledge ${item.id}: committed local file is missing or empty`)
451
+ galleryTransferLedger.recordFailure(item.id, error)
452
+ throw error
453
+ }
454
+ ledgerEntry = galleryTransferLedger.transition(item.id, "ACK_PENDING")
455
+ try {
456
+ await this.acknowledgeEntry(ledgerEntry)
457
+ galleryTransferLedger.transition(item.id, "TRASHED", {lastError: undefined})
458
+ } catch (ackError) {
459
+ galleryTransferLedger.recordFailure(item.id, ackError)
460
+ throw ackError
461
+ }
462
+
463
+ const elapsed = Date.now() - startTime
464
+ console.log(`${TAG} ✅ Finished ${item.id} in ${elapsed}ms`)
465
+ }
466
+
467
+ /** Rebuild a missing app-local index row from the durable transfer ledger. */
468
+ private async recoverDownloadedFile(entry: GalleryTransferEntry) {
469
+ if (!entry.finalPath) throw new Error(`Recovery file is missing for ${entry.captureId}`)
470
+
471
+ // The transfer ledger is the durable source of truth for a committed generation. A local
472
+ // index row can survive an interrupted replacement and still point at an older/missing path,
473
+ // or contain the pre-processing size. Only reuse it when its path and identity still match the
474
+ // ledger's committed file; otherwise rebuild the row before export or source acknowledgement.
475
+ const finalPath = entry.finalPath.replace(/^file:\/\//, "")
476
+ const indexed = await localStorageService.getDownloadedFile(entry.captureId)
477
+ if (indexed) {
343
478
  try {
344
- const localFileExists = await RNFS.exists(filePathToSave)
345
- if (!localFileExists) {
346
- console.error(`${TAG} Skipping glasses deletion for ${item.id}: local file missing at ${filePathToSave}`)
347
- } else {
348
- const localStat = await RNFS.stat(filePathToSave)
349
- if (localStat.size === 0) {
350
- console.error(`${TAG} Skipping glasses deletion for ${item.id}: local file is 0 bytes`)
351
- } else if (item.totalSize > 0 && localStat.size < item.totalSize * 0.5) {
352
- // If local file is less than 50% of expected size, something went wrong
353
- console.error(
354
- `${TAG} Skipping glasses deletion for ${item.id}: local file ${localStat.size} bytes is much smaller than expected ${item.totalSize} bytes`,
355
- )
356
- } else {
357
- await asgCameraApi.deleteFilesFromServer(item.deleteFromGlasses)
358
- console.log(`${TAG} 🗑️ Deleted ${item.deleteFromGlasses.join(", ")} from glasses`)
479
+ const indexedPath = indexed.filePath?.replace(/^file:\/\//, "")
480
+ if (indexedPath === finalPath && (await RNFS.exists(indexedPath))) {
481
+ const indexedStat = await RNFS.stat(indexedPath)
482
+ const indexedSize = Number(indexedStat.size)
483
+ if (indexedSize > 0 && indexed.size === indexedSize && indexed.modified === entry.timestamp) {
484
+ return indexed
359
485
  }
360
486
  }
361
- } catch (deleteError) {
362
- console.warn(`${TAG} Delete from glasses failed for ${item.id} (non-fatal):`, deleteError)
487
+ } catch (error) {
488
+ console.warn(`${TAG} Ignoring stale local index for ${entry.captureId}:`, error)
363
489
  }
364
490
  }
365
491
 
366
- const elapsed = Date.now() - startTime
367
- console.log(`${TAG} Finished ${item.id} in ${elapsed}ms`)
492
+ const stat = await RNFS.stat(finalPath)
493
+ const finalSize = Number(stat.size)
494
+ if (!Number.isFinite(finalSize) || finalSize <= 0) {
495
+ throw new Error(`Recovery file is missing or empty for ${entry.captureId}`)
496
+ }
497
+ const recovered = localStorageService.convertToDownloadedFile(
498
+ {
499
+ name: entry.captureId,
500
+ url: "",
501
+ download: "",
502
+ size: finalSize,
503
+ modified: entry.timestamp,
504
+ mime_type: entry.captureType === "video" ? "video/mp4" : "image/jpeg",
505
+ is_video: entry.captureType === "video",
506
+ filePath: finalPath,
507
+ },
508
+ finalPath,
509
+ entry.thumbnailPath,
510
+ )
511
+ recovered.capture_id = entry.captureId
512
+ recovered.assetReceipt = entry.assetReceipt
513
+ await localStorageService.saveDownloadedFile(recovered)
514
+ return recovered
368
515
  }
369
516
  }
370
517
 
@@ -0,0 +1,8 @@
1
+ import type {AudioSource} from "expo-audio"
2
+
3
+ /**
4
+ * A tiny bundled source used to detach completed or interrupted audio without
5
+ * destroying the reusable native player. If a media control later sends Play,
6
+ * only this silence can be resumed instead of the previous miniapp audio.
7
+ */
8
+ export const SILENT_AUDIO_SOURCE: AudioSource = require("../assets/silence.wav")
@@ -32,7 +32,7 @@ export function isSyncManifestEmpty(syncData: {
32
32
  captures?: unknown[]
33
33
  changed_files?: unknown[]
34
34
  }): boolean {
35
- if (syncData.api_version === 2 && syncData.captures && syncData.captures.length > 0) {
35
+ if ((syncData.api_version || 0) >= 2 && syncData.captures && syncData.captures.length > 0) {
36
36
  return false
37
37
  }
38
38
  return !syncData.changed_files || syncData.changed_files.length === 0
@@ -6,7 +6,7 @@ import BluetoothSdk from "@mentra/bluetooth-sdk/internal"
6
6
  import {BgTimer} from "../utils/timers"
7
7
  import {useGlassesStore} from "../stores/glasses"
8
8
 
9
- import {getAsgOtaVersionUrl} from "./asgOtaVersionUrl"
9
+ import {resolveOtaManifestUrl} from "./otaManifestUrl"
10
10
  import {detectClockSkew} from "./gallerySyncClock"
11
11
 
12
12
  export const CLOCK_SETTLE_MS = 500
@@ -86,7 +86,11 @@ export async function handleOtaClockSkewFromGlasses(
86
86
 
87
87
  lastOtaClockFixAt = Date.now()
88
88
  const {buildNumber, otaVersionUrl} = useGlassesStore.getState()
89
- const manifestUrl = getAsgOtaVersionUrl(otaVersionUrl, buildNumber)
89
+ const manifestUrl = resolveOtaManifestUrl(otaVersionUrl, buildNumber)
90
+ if (!manifestUrl) {
91
+ console.warn("[GlassesClockSync] OTA restart skipped because this build has no manifest pin")
92
+ return false
93
+ }
90
94
  console.log("[GlassesClockSync] ⏰ Restarting OTA with ota_start after clock fix")
91
95
  await BluetoothSdk.startOtaUpdate(manifestUrl)
92
96
  return true
@@ -0,0 +1,30 @@
1
+ import type {DeclaredAction} from "../types/applet"
2
+
3
+ /**
4
+ * Normalize manifest actions defensively for installed and dev-sideloaded
5
+ * bundles. Input and output schemas are passed through as opaque JSON Schema.
6
+ */
7
+ export function normalizeManifestActions(raw: unknown): DeclaredAction[] {
8
+ if (!Array.isArray(raw)) return []
9
+ const out: DeclaredAction[] = []
10
+ for (const a of raw as Array<{
11
+ id?: unknown
12
+ description?: unknown
13
+ parameters?: unknown
14
+ outputSchema?: unknown
15
+ }>) {
16
+ if (a && typeof a.id === "string" && typeof a.description === "string") {
17
+ out.push({
18
+ id: a.id,
19
+ description: a.description,
20
+ ...(a.parameters && typeof a.parameters === "object" && !Array.isArray(a.parameters)
21
+ ? {parameters: a.parameters as Record<string, unknown>}
22
+ : {}),
23
+ ...(a.outputSchema && typeof a.outputSchema === "object" && !Array.isArray(a.outputSchema)
24
+ ? {outputSchema: a.outputSchema as Record<string, unknown>}
25
+ : {}),
26
+ })
27
+ }
28
+ }
29
+ return out
30
+ }
@@ -1,4 +1,4 @@
1
- import type {OtaProgress, OtaStatus} from "@mentra/bluetooth-sdk/internal"
1
+ import type {OtaProgress, OtaStatus} from "@mentra/bluetooth-sdk"
2
2
 
3
3
  import {isLegacyShapedOtaStatus} from "./otaInstallPolicy"
4
4
 
@@ -18,38 +18,80 @@ export type DisplayState = "starting" | "updating" | "complete" | "failed" | "di
18
18
  *
19
19
  * Priority-ordered rules (first match wins):
20
20
  * 1. errorMsg !== "" -> "failed"
21
- * 2. BES terminal + connected + sawReconnectEdge -> "complete"
22
- * 3. BES terminal (any connection state) -> "restarting"
21
+ * 2. BES reboot recovery complete -> "complete"
22
+ * 3. BES reboot recovery awaiting reconnect -> "restarting"
23
+ * 4. BES terminal (any connection state) -> "restarting"
23
24
  * (legacy-shaped BES "complete" counts only in install phase)
24
- * 4. apkCompletedViaBuildIncrease (legacy build-number port) -> "complete"
25
- * 5. otaStatus.status === "failed" -> "failed"
26
- * 6. otaStatus.status === "complete" (non-BES) -> "complete"
25
+ * 6. apkCompletedViaBuildIncrease (legacy build-number port) -> "complete"
26
+ * 7. otaStatus.status === "failed" -> "failed"
27
+ * 8. otaStatus.status === "complete" (non-BES) -> "complete"
27
28
  * (unless legacy-shaped download-complete or held apk settle -> in flight)
28
- * 7. !connected + legacy in-flight complete (held apk) -> "updating"
29
- * 8. !connected + APK step_complete with totalSteps > 1 -> "starting" (expected reboot)
30
- * 9. !connected + BES in flight -> "restarting" (defensive)
31
- * 10. !connected -> "disconnected"
32
- * 11. connected + in_progress | step_complete | legacy in-flight complete -> "updating"
33
- * 12. fallback -> "starting"
29
+ * 9. !connected + legacy in-flight complete (held apk) -> "updating"
30
+ * 10. !connected + APK step_complete with totalSteps > 1 -> "starting" (expected reboot)
31
+ * 11. !connected + BES in flight -> "restarting" (defensive)
32
+ * 12. !connected -> "disconnected"
33
+ * 13. connected + in_progress | step_complete | legacy in-flight complete -> "updating"
34
+ * 14. fallback -> "starting"
34
35
  */
35
36
  export function deriveDisplayState(args: {
36
37
  otaStatus: OtaStatus | null
37
38
  otaProgress: OtaProgress | null
38
39
  connected: boolean
39
40
  errorMsg: string
41
+ /**
42
+ * Retained for host API compatibility. A session-wide reconnect edge is not
43
+ * sufficient for BES completion because it may belong to an earlier APK step.
44
+ */
40
45
  sawReconnectEdge: boolean
41
46
  /** Coordinator is holding a legacy apk install "complete" for the settle window (WP 8C). */
42
47
  legacyApkSettleHold?: boolean
43
48
  /** Legacy APK completion detected by build-number increase (WP 8C). */
44
49
  apkCompletedViaBuildIncrease?: boolean
50
+ /** Phone-observed BES disconnect/reconnect recovery, independent of stale OTA progress. */
51
+ besRestartRecovery?: "awaiting" | "complete" | null
52
+ /** Downgrade detour: the reconnected glasses reported exactly the pinned target version. */
53
+ versionChangeConverged?: boolean
54
+ /** True for the whole downgrade (version-change) session. */
55
+ versionChangeSession?: boolean
45
56
  }): DisplayState {
46
- const {otaStatus, otaProgress, connected, errorMsg, sawReconnectEdge, legacyApkSettleHold, apkCompletedViaBuildIncrease} =
47
- args
57
+ const {
58
+ otaStatus,
59
+ otaProgress,
60
+ connected,
61
+ errorMsg,
62
+ legacyApkSettleHold,
63
+ apkCompletedViaBuildIncrease,
64
+ besRestartRecovery,
65
+ versionChangeConverged,
66
+ versionChangeSession,
67
+ } = args
48
68
 
49
69
  if (errorMsg) return "failed"
50
70
 
71
+ // Downgrade detour completion: exact-version convergence after reconnect is the
72
+ // only completion signal (the wipe destroys ASG's ota_session, and the target is
73
+ // a LOWER build so no build-number increase fires). Outranks the stale install
74
+ // status still sitting in the store from before the handoff.
75
+ if (versionChangeConverged) return "complete"
76
+
77
+ // A BES reboot destroys or strands the glasses-side OTA session on older
78
+ // clients. Once the phone observed that reboot, stale pre-reboot progress must
79
+ // not move the UI from restarting back to updating.
80
+ if (besRestartRecovery === "complete") return "complete"
81
+ if (besRestartRecovery === "awaiting") return "restarting"
82
+
83
+ // In a version-change session, convergence (above) is the ONLY completion for the ASG
84
+ // downgrade. A bare non-firmware "complete" before convergence — the glasses refusing
85
+ // the downgrade (floor/gate) with no install, or a stale pre-handoff status — must never
86
+ // present as success. Firmware-step completions (mtk/bes) DO pass through: a combined
87
+ // downgrade+firmware manifest applies firmware first on its own pass, which must finish
88
+ // so the phone re-checks and re-offers the now-firmware-free downgrade.
89
+ const isFirmwareComplete = otaStatus?.stepType === "mtk" || otaStatus?.stepType === "bes"
90
+ if (versionChangeSession && otaStatus?.status === "complete" && !isFirmwareComplete) {
91
+ return connected ? "updating" : "disconnected"
92
+ }
93
+
51
94
  const besTerminal = isBesTerminal(otaStatus, otaProgress)
52
- if (besTerminal && connected && sawReconnectEdge) return "complete"
53
95
  if (besTerminal) return "restarting"
54
96
 
55
97
  // Legacy build-number APK completion: the coordinator clears errorMsg when it fires,
@@ -85,8 +127,7 @@ export function deriveDisplayState(args: {
85
127
  // has not started); the legacy screen treated that drop as a plain disconnect.
86
128
  const besStatusInFlight =
87
129
  otaStatus?.stepType === "bes" && !(isLegacyShapedOtaStatus(otaStatus) && otaStatus.phase === "download")
88
- const besInFlight =
89
- besStatusInFlight || (otaProgress?.currentUpdate === "bes" && otaProgress?.stage === "install")
130
+ const besInFlight = besStatusInFlight || (otaProgress?.currentUpdate === "bes" && otaProgress?.stage === "install")
90
131
  if (besInFlight) return "restarting"
91
132
 
92
133
  return "disconnected"
@@ -1,5 +1,5 @@
1
1
  /** Shared OTA progress watchdog timings (see progress-legacy.tsx / progress.tsx). */
2
- import type {OtaProgress, OtaStatus} from "@mentra/bluetooth-sdk/internal"
2
+ import type {OtaProgress, OtaStatus} from "@mentra/bluetooth-sdk"
3
3
 
4
4
  /**
5
5
  * First glasses `build_number` (ASG `versionCode`) that uses `progress.tsx` with unified
@@ -10,6 +10,7 @@ import type {OtaProgress, OtaStatus} from "@mentra/bluetooth-sdk/internal"
10
10
  export const MINIMUM_OTA_STATUS_BUILD = 37
11
11
 
12
12
  export const MAX_RETRIES = 3
13
+ /** Wait between ended native ota_start requests; never overlaps a pending request. */
13
14
  export const RETRY_INTERVAL_MS = 5000
14
15
  /** APK/BES and general install when progress events are expected */
15
16
  export const PROGRESS_TIMEOUT_MS = 120_000
@@ -19,8 +20,6 @@ export const DOWNLOAD_STUCK_TIMEOUT_MS = 70_000
19
20
  export const MTK_INSTALL_TIMEOUT_MS = 300_000
20
21
  /** Whole multi-step session cap */
21
22
  export const GLOBAL_OTA_TIMEOUT_MS = 20 * 60 * 1000
22
- /** After APK reboot, ASG OTA service needs time before next ota_start */
23
- export const POST_APK_OTA_START_DELAY_MS = 6000
24
23
  /** BLE keepalive during OTA */
25
24
  export const PING_INTERVAL_MS = 10_000
26
25
  /**
@@ -71,6 +70,8 @@ export const LEGACY_MTK_STALL_ZONE_MAX_PERCENT = 55
71
70
  export const LEGACY_MTK_SIM_FLOOR_PERCENT = 51
72
71
  export const LEGACY_MTK_SIM_CAP_PERCENT = 60
73
72
 
73
+ export type OtaProtocolProfile = "legacy" | "unified"
74
+
74
75
  /**
75
76
  * Legacy-shaped ota_status: old (< 37) ASG builds send `ota_progress`, which the SDK
76
77
  * (Android MentraLive.kt / iOS MentraLive.swift) maps to a unified ota_status with
@@ -98,9 +99,34 @@ export function isLegacyShapedOtaSession(
98
99
  return Number.isFinite(build) && build > 0 && build < MINIMUM_OTA_STATUS_BUILD
99
100
  }
100
101
 
102
+ /**
103
+ * Select the compatibility profile once at install-screen attach. The old split
104
+ * routes made this decision from the pre-update build and kept it for the whole
105
+ * mounted flow, even when an APK step restarted into a newer ASG build. Returning
106
+ * null leaves the coordinator undecided until the first meaningful OTA event.
107
+ */
108
+ export function selectOtaProtocolProfile(
109
+ otaStatus: OtaStatus | null,
110
+ otaProgress: OtaProgress | null,
111
+ buildNumber: string | null | undefined,
112
+ ): OtaProtocolProfile | null {
113
+ const build = Number.parseInt(buildNumber ?? "", 10)
114
+ if (Number.isFinite(build) && build > 0) {
115
+ return build < MINIMUM_OTA_STATUS_BUILD ? "legacy" : "unified"
116
+ }
117
+ if (otaStatus) return isLegacyShapedOtaStatus(otaStatus) ? "legacy" : "unified"
118
+ if (otaProgress) return "legacy"
119
+ return null
120
+ }
121
+
101
122
  export const OtaProgressMessages = {
102
- noAckResponse: "Unable to start update. Glasses did not respond.",
103
123
  stalledOrStuck: "Update may have failed. Ensure glasses have internet access and try again.",
104
124
  globalTimeout: "Update took too long. Please try again.",
105
125
  sendOtaStartFailed: "Failed to communicate with glasses.",
126
+ hotspotArtifactDownloadFailed: "Could not download the update to your phone. Check phone internet and try again.",
127
+ hotspotArtifactVerifyFailed: "The update package could not be verified. Please try again later.",
128
+ hotspotWifiPermissionDenied: "Allow nearby devices access so the phone can connect to the glasses hotspot.",
129
+ hotspotStartFailed: "Could not start the glasses hotspot. Please try again.",
130
+ hotspotJoinFailed: "Could not connect the phone to the glasses hotspot. Please try again.",
131
+ hotspotServerFailed: "Could not make the update available to the glasses. Please try again.",
106
132
  } as const
@@ -1,4 +1,4 @@
1
- import type {OtaProgress, OtaProgressStatus, OtaStatus} from "@mentra/bluetooth-sdk/internal"
1
+ import type {OtaProgress, OtaProgressStatus, OtaStatus} from "@mentra/bluetooth-sdk"
2
2
 
3
3
  /** Normalized ota_status fields (snake_case) after bridging Core/expo (snake or camel). */
4
4
  export type NormalizedOtaStatusEvent = {