@mentra/engine 0.1.0-beta.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 (355) 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.map +1 -1
  7. package/build/facades/dev.js +9 -5
  8. package/build/facades/dev.js.map +1 -1
  9. package/build/facades/gallery.js +1 -1
  10. package/build/facades/gallery.js.map +1 -1
  11. package/build/facades/glasses.d.ts +1 -0
  12. package/build/facades/glasses.d.ts.map +1 -1
  13. package/build/facades/glasses.js +19 -4
  14. package/build/facades/glasses.js.map +1 -1
  15. package/build/facades/glassesSettings.d.ts.map +1 -1
  16. package/build/facades/glassesSettings.js +1 -0
  17. package/build/facades/glassesSettings.js.map +1 -1
  18. package/build/facades/miniapps.d.ts +4 -0
  19. package/build/facades/miniapps.d.ts.map +1 -1
  20. package/build/facades/miniapps.js +5 -0
  21. package/build/facades/miniapps.js.map +1 -1
  22. package/build/facades/ota.d.ts +11 -2
  23. package/build/facades/ota.d.ts.map +1 -1
  24. package/build/facades/ota.js +19 -4
  25. package/build/facades/ota.js.map +1 -1
  26. package/build/facades/pairing.d.ts +4 -0
  27. package/build/facades/pairing.d.ts.map +1 -1
  28. package/build/facades/pairing.js +10 -8
  29. package/build/facades/pairing.js.map +1 -1
  30. package/build/facades/phoneNotifications.d.ts +0 -4
  31. package/build/facades/phoneNotifications.d.ts.map +1 -1
  32. package/build/facades/phoneNotifications.js +4 -14
  33. package/build/facades/phoneNotifications.js.map +1 -1
  34. package/build/index.d.ts +6 -3
  35. package/build/index.d.ts.map +1 -1
  36. package/build/index.js +4 -2
  37. package/build/index.js.map +1 -1
  38. package/build/internal.d.ts +2 -2
  39. package/build/internal.d.ts.map +1 -1
  40. package/build/internal.js +1 -1
  41. package/build/internal.js.map +1 -1
  42. package/build/react/MentraLiveOtaFlow.d.ts +38 -0
  43. package/build/react/MentraLiveOtaFlow.d.ts.map +1 -0
  44. package/build/react/MentraLiveOtaFlow.js +528 -0
  45. package/build/react/MentraLiveOtaFlow.js.map +1 -0
  46. package/build/react/index.d.ts +2 -0
  47. package/build/react/index.d.ts.map +1 -0
  48. package/build/react/index.js +2 -0
  49. package/build/react/index.js.map +1 -0
  50. package/build/react/useEngineSnapshot.d.ts +2 -0
  51. package/build/react/useEngineSnapshot.d.ts.map +1 -0
  52. package/build/react/useEngineSnapshot.js +14 -0
  53. package/build/react/useEngineSnapshot.js.map +1 -0
  54. package/build/runtime/bootstrap.d.ts +24 -1
  55. package/build/runtime/bootstrap.d.ts.map +1 -1
  56. package/build/runtime/bootstrap.js +17 -0
  57. package/build/runtime/bootstrap.js.map +1 -1
  58. package/build/runtime/scanQrSeam.d.ts +7 -0
  59. package/build/runtime/scanQrSeam.d.ts.map +1 -0
  60. package/build/runtime/scanQrSeam.js +16 -0
  61. package/build/runtime/scanQrSeam.js.map +1 -0
  62. package/build/services/AppRegistry.d.ts +18 -8
  63. package/build/services/AppRegistry.d.ts.map +1 -1
  64. package/build/services/AppRegistry.js +44 -45
  65. package/build/services/AppRegistry.js.map +1 -1
  66. package/build/services/AudioCloudUplink.d.ts +9 -3
  67. package/build/services/AudioCloudUplink.d.ts.map +1 -1
  68. package/build/services/AudioCloudUplink.js +9 -3
  69. package/build/services/AudioCloudUplink.js.map +1 -1
  70. package/build/services/AudioPlaybackService.d.ts +9 -1
  71. package/build/services/AudioPlaybackService.d.ts.map +1 -1
  72. package/build/services/AudioPlaybackService.js +77 -32
  73. package/build/services/AudioPlaybackService.js.map +1 -1
  74. package/build/services/BlobStore.d.ts +2 -1
  75. package/build/services/BlobStore.d.ts.map +1 -1
  76. package/build/services/BlobStore.js +17 -9
  77. package/build/services/BlobStore.js.map +1 -1
  78. package/build/services/CloudAudioSubscriptionSync.d.ts.map +1 -1
  79. package/build/services/CloudAudioSubscriptionSync.js +13 -1
  80. package/build/services/CloudAudioSubscriptionSync.js.map +1 -1
  81. package/build/services/CloudClientService.d.ts +15 -0
  82. package/build/services/CloudClientService.d.ts.map +1 -1
  83. package/build/services/CloudClientService.js +75 -0
  84. package/build/services/CloudClientService.js.map +1 -1
  85. package/build/services/ForegroundLocationPermission.d.ts +13 -0
  86. package/build/services/ForegroundLocationPermission.d.ts.map +1 -0
  87. package/build/services/ForegroundLocationPermission.js +12 -0
  88. package/build/services/ForegroundLocationPermission.js.map +1 -0
  89. package/build/services/GlassesSettingsSync.d.ts.map +1 -1
  90. package/build/services/GlassesSettingsSync.js +9 -3
  91. package/build/services/GlassesSettingsSync.js.map +1 -1
  92. package/build/services/GlassesStatusProjection.d.ts +2 -1
  93. package/build/services/GlassesStatusProjection.d.ts.map +1 -1
  94. package/build/services/GlassesStatusProjection.js +15 -8
  95. package/build/services/GlassesStatusProjection.js.map +1 -1
  96. package/build/services/HotspotOtaTransport.d.ts +29 -0
  97. package/build/services/HotspotOtaTransport.d.ts.map +1 -0
  98. package/build/services/HotspotOtaTransport.js +146 -0
  99. package/build/services/HotspotOtaTransport.js.map +1 -0
  100. package/build/services/HotspotShutdown.d.ts +17 -0
  101. package/build/services/HotspotShutdown.d.ts.map +1 -0
  102. package/build/services/HotspotShutdown.js +29 -0
  103. package/build/services/HotspotShutdown.js.map +1 -0
  104. package/build/services/LocalDisplayManager.d.ts +15 -0
  105. package/build/services/LocalDisplayManager.d.ts.map +1 -1
  106. package/build/services/LocalDisplayManager.js +106 -20
  107. package/build/services/LocalDisplayManager.js.map +1 -1
  108. package/build/services/LocalMiniappRuntime.d.ts +67 -1
  109. package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
  110. package/build/services/LocalMiniappRuntime.js +486 -126
  111. package/build/services/LocalMiniappRuntime.js.map +1 -1
  112. package/build/services/LocalMiniappStorage.d.ts +32 -0
  113. package/build/services/LocalMiniappStorage.d.ts.map +1 -0
  114. package/build/services/LocalMiniappStorage.js +66 -0
  115. package/build/services/LocalMiniappStorage.js.map +1 -0
  116. package/build/services/LocalMiniappUserIdentity.d.ts +20 -0
  117. package/build/services/LocalMiniappUserIdentity.d.ts.map +1 -0
  118. package/build/services/LocalMiniappUserIdentity.js +43 -0
  119. package/build/services/LocalMiniappUserIdentity.js.map +1 -0
  120. package/build/services/MicStateCoordinator.d.ts +42 -1
  121. package/build/services/MicStateCoordinator.d.ts.map +1 -1
  122. package/build/services/MicStateCoordinator.js +141 -3
  123. package/build/services/MicStateCoordinator.js.map +1 -1
  124. package/build/services/MiniappLauncher.d.ts.map +1 -1
  125. package/build/services/MiniappLauncher.js +23 -3
  126. package/build/services/MiniappLauncher.js.map +1 -1
  127. package/build/services/MiniappLiveness.d.ts +12 -0
  128. package/build/services/MiniappLiveness.d.ts.map +1 -0
  129. package/build/services/MiniappLiveness.js +16 -0
  130. package/build/services/MiniappLiveness.js.map +1 -0
  131. package/build/services/OtaArtifactDownloader.d.ts +65 -0
  132. package/build/services/OtaArtifactDownloader.d.ts.map +1 -0
  133. package/build/services/OtaArtifactDownloader.js +226 -0
  134. package/build/services/OtaArtifactDownloader.js.map +1 -0
  135. package/build/services/OtaAutoChain.d.ts +34 -0
  136. package/build/services/OtaAutoChain.d.ts.map +1 -0
  137. package/build/services/OtaAutoChain.js +83 -0
  138. package/build/services/OtaAutoChain.js.map +1 -0
  139. package/build/services/OtaErrorMapping.d.ts +18 -0
  140. package/build/services/OtaErrorMapping.d.ts.map +1 -0
  141. package/build/services/OtaErrorMapping.js +63 -0
  142. package/build/services/OtaErrorMapping.js.map +1 -0
  143. package/build/services/OtaInstallCoordinator.d.ts +94 -14
  144. package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
  145. package/build/services/OtaInstallCoordinator.js +574 -130
  146. package/build/services/OtaInstallCoordinator.js.map +1 -1
  147. package/build/services/OtaService.d.ts.map +1 -1
  148. package/build/services/OtaService.js +8 -1
  149. package/build/services/OtaService.js.map +1 -1
  150. package/build/services/OtaUpdateCheckService.d.ts +38 -3
  151. package/build/services/OtaUpdateCheckService.d.ts.map +1 -1
  152. package/build/services/OtaUpdateCheckService.js +142 -22
  153. package/build/services/OtaUpdateCheckService.js.map +1 -1
  154. package/build/services/PhoneCalendarService.d.ts.map +1 -1
  155. package/build/services/PhoneCalendarService.js +22 -1
  156. package/build/services/PhoneCalendarService.js.map +1 -1
  157. package/build/services/PhoneCameraFovCoordinator.d.ts +2 -0
  158. package/build/services/PhoneCameraFovCoordinator.d.ts.map +1 -1
  159. package/build/services/PhoneCameraFovCoordinator.js +14 -0
  160. package/build/services/PhoneCameraFovCoordinator.js.map +1 -1
  161. package/build/services/PhoneNotificationsSync.d.ts.map +1 -1
  162. package/build/services/PhoneNotificationsSync.js +12 -10
  163. package/build/services/PhoneNotificationsSync.js.map +1 -1
  164. package/build/services/PhonePhotoCoordinator.d.ts +10 -3
  165. package/build/services/PhonePhotoCoordinator.d.ts.map +1 -1
  166. package/build/services/PhonePhotoCoordinator.js +21 -3
  167. package/build/services/PhonePhotoCoordinator.js.map +1 -1
  168. package/build/services/PhoneStreamCoordinator.d.ts +8 -1
  169. package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
  170. package/build/services/PhoneStreamCoordinator.js +125 -13
  171. package/build/services/PhoneStreamCoordinator.js.map +1 -1
  172. package/build/services/PhoneVideoCoordinator.d.ts +2 -0
  173. package/build/services/PhoneVideoCoordinator.d.ts.map +1 -1
  174. package/build/services/PhoneVideoCoordinator.js +10 -0
  175. package/build/services/PhoneVideoCoordinator.js.map +1 -1
  176. package/build/services/SceneRenderer.d.ts.map +1 -1
  177. package/build/services/SceneRenderer.js +15 -0
  178. package/build/services/SceneRenderer.js.map +1 -1
  179. package/build/services/SupportProfileSync.d.ts +22 -0
  180. package/build/services/SupportProfileSync.d.ts.map +1 -0
  181. package/build/services/SupportProfileSync.js +213 -0
  182. package/build/services/SupportProfileSync.js.map +1 -0
  183. package/build/services/TtsTextSanitizer.d.ts +5 -0
  184. package/build/services/TtsTextSanitizer.d.ts.map +1 -0
  185. package/build/services/TtsTextSanitizer.js +61 -0
  186. package/build/services/TtsTextSanitizer.js.map +1 -0
  187. package/build/services/WifiAdbRequest.d.ts +17 -0
  188. package/build/services/WifiAdbRequest.d.ts.map +1 -0
  189. package/build/services/WifiAdbRequest.js +35 -0
  190. package/build/services/WifiAdbRequest.js.map +1 -0
  191. package/build/services/asg/asgCameraApi.d.ts +3 -0
  192. package/build/services/asg/asgCameraApi.d.ts.map +1 -1
  193. package/build/services/asg/asgCameraApi.js +72 -2
  194. package/build/services/asg/asgCameraApi.js.map +1 -1
  195. package/build/services/asg/gallerySyncService.d.ts.map +1 -1
  196. package/build/services/asg/gallerySyncService.js +26 -14
  197. package/build/services/asg/gallerySyncService.js.map +1 -1
  198. package/build/services/asg/localNetworkTransport.d.ts +2 -2
  199. package/build/services/asg/localNetworkTransport.d.ts.map +1 -1
  200. package/build/services/asg/localNetworkTransport.js +6 -6
  201. package/build/services/asg/localNetworkTransport.js.map +1 -1
  202. package/build/services/audioPlaybackAssets.d.ts +8 -0
  203. package/build/services/audioPlaybackAssets.d.ts.map +1 -0
  204. package/build/services/audioPlaybackAssets.js +7 -0
  205. package/build/services/audioPlaybackAssets.js.map +1 -0
  206. package/build/services/glassesClockSync.js +2 -2
  207. package/build/services/glassesClockSync.js.map +1 -1
  208. package/build/services/manifestActions.d.ts +7 -0
  209. package/build/services/manifestActions.d.ts.map +1 -0
  210. package/build/services/manifestActions.js +25 -0
  211. package/build/services/manifestActions.js.map +1 -0
  212. package/build/services/otaDisplayState.d.ts +22 -11
  213. package/build/services/otaDisplayState.d.ts.map +1 -1
  214. package/build/services/otaDisplayState.js +36 -14
  215. package/build/services/otaDisplayState.js.map +1 -1
  216. package/build/services/otaInstallPolicy.d.ts +15 -3
  217. package/build/services/otaInstallPolicy.d.ts.map +1 -1
  218. package/build/services/otaInstallPolicy.js +24 -3
  219. package/build/services/otaInstallPolicy.js.map +1 -1
  220. package/build/services/otaManifestUrl.d.ts +2 -0
  221. package/build/services/otaManifestUrl.d.ts.map +1 -0
  222. package/build/services/{asgOtaVersionUrl.js → otaManifestUrl.js} +15 -5
  223. package/build/services/otaManifestUrl.js.map +1 -0
  224. package/build/services/slimStreamStatus.d.ts +11 -0
  225. package/build/services/slimStreamStatus.d.ts.map +1 -1
  226. package/build/services/slimStreamStatus.js +14 -4
  227. package/build/services/slimStreamStatus.js.map +1 -1
  228. package/build/stores/apps.d.ts.map +1 -1
  229. package/build/stores/apps.js +11 -0
  230. package/build/stores/apps.js.map +1 -1
  231. package/build/stores/bluetoothSettingKeys.d.ts.map +1 -1
  232. package/build/stores/bluetoothSettingKeys.js +2 -0
  233. package/build/stores/bluetoothSettingKeys.js.map +1 -1
  234. package/build/stores/gallerySync.d.ts +2 -0
  235. package/build/stores/gallerySync.d.ts.map +1 -1
  236. package/build/stores/gallerySync.js +2 -0
  237. package/build/stores/gallerySync.js.map +1 -1
  238. package/build/stores/glasses.d.ts.map +1 -1
  239. package/build/stores/glasses.js +3 -0
  240. package/build/stores/glasses.js.map +1 -1
  241. package/build/stores/settings.d.ts +17 -0
  242. package/build/stores/settings.d.ts.map +1 -1
  243. package/build/stores/settings.js +152 -19
  244. package/build/stores/settings.js.map +1 -1
  245. package/build/types/applet.d.ts +2 -0
  246. package/build/types/applet.d.ts.map +1 -1
  247. package/build/types/applet.js.map +1 -1
  248. package/build/types/enums.d.ts +1 -0
  249. package/build/types/enums.d.ts.map +1 -1
  250. package/build/types/enums.js +1 -0
  251. package/build/types/enums.js.map +1 -1
  252. package/build/types/hardware.d.ts +1 -0
  253. package/build/types/hardware.d.ts.map +1 -1
  254. package/build/types/hardware.js +14 -0
  255. package/build/types/hardware.js.map +1 -1
  256. package/build/utils/configuredDevHost.d.ts +6 -0
  257. package/build/utils/configuredDevHost.d.ts.map +1 -0
  258. package/build/utils/configuredDevHost.js +19 -0
  259. package/build/utils/configuredDevHost.js.map +1 -0
  260. package/build/utils/devMiniappLaunch.d.ts +19 -8
  261. package/build/utils/devMiniappLaunch.d.ts.map +1 -1
  262. package/build/utils/devMiniappLaunch.js +144 -21
  263. package/build/utils/devMiniappLaunch.js.map +1 -1
  264. package/build/utils/diagnosticContext.d.ts.map +1 -1
  265. package/build/utils/diagnosticContext.js +15 -17
  266. package/build/utils/diagnosticContext.js.map +1 -1
  267. package/build/utils/hardware/hardware.d.ts.map +1 -1
  268. package/build/utils/hardware/hardware.js +7 -3
  269. package/build/utils/hardware/hardware.js.map +1 -1
  270. package/build/utils/miniappDiagnostics.d.ts +64 -0
  271. package/build/utils/miniappDiagnostics.d.ts.map +1 -0
  272. package/build/utils/miniappDiagnostics.js +173 -0
  273. package/build/utils/miniappDiagnostics.js.map +1 -0
  274. package/build/utils/timers/timers.d.ts.map +1 -1
  275. package/build/utils/timers/timers.js +55 -18
  276. package/build/utils/timers/timers.js.map +1 -1
  277. package/package.json +27 -18
  278. package/src/assets/silence.wav +0 -0
  279. package/src/engine.ts +7 -2
  280. package/src/facades/dev.ts +9 -5
  281. package/src/facades/gallery.ts +1 -1
  282. package/src/facades/glasses.ts +17 -4
  283. package/src/facades/glassesSettings.ts +5 -0
  284. package/src/facades/miniapps.ts +7 -0
  285. package/src/facades/ota.ts +19 -4
  286. package/src/facades/pairing.ts +11 -7
  287. package/src/facades/phoneNotifications.ts +4 -13
  288. package/src/index.ts +26 -2
  289. package/src/internal.ts +2 -1
  290. package/src/react/MentraLiveOtaFlow.tsx +856 -0
  291. package/src/react/index.ts +7 -0
  292. package/src/react/useEngineSnapshot.ts +16 -0
  293. package/src/runtime/bootstrap.ts +33 -1
  294. package/src/runtime/scanQrSeam.ts +20 -0
  295. package/src/services/AppRegistry.ts +72 -48
  296. package/src/services/AudioCloudUplink.ts +9 -3
  297. package/src/services/AudioPlaybackService.ts +94 -34
  298. package/src/services/BlobStore.ts +22 -9
  299. package/src/services/CloudAudioSubscriptionSync.ts +13 -1
  300. package/src/services/CloudClientService.ts +74 -0
  301. package/src/services/ForegroundLocationPermission.ts +24 -0
  302. package/src/services/GlassesSettingsSync.ts +9 -3
  303. package/src/services/GlassesStatusProjection.ts +16 -8
  304. package/src/services/HotspotOtaTransport.ts +184 -0
  305. package/src/services/HotspotShutdown.ts +41 -0
  306. package/src/services/LocalDisplayManager.ts +112 -21
  307. package/src/services/LocalMiniappRuntime.ts +576 -130
  308. package/src/services/LocalMiniappStorage.ts +82 -0
  309. package/src/services/LocalMiniappUserIdentity.ts +46 -0
  310. package/src/services/MicStateCoordinator.ts +169 -4
  311. package/src/services/MiniappLauncher.ts +30 -3
  312. package/src/services/MiniappLiveness.ts +24 -0
  313. package/src/services/OtaArtifactDownloader.ts +312 -0
  314. package/src/services/OtaAutoChain.ts +106 -0
  315. package/src/services/OtaErrorMapping.ts +80 -0
  316. package/src/services/OtaInstallCoordinator.ts +645 -143
  317. package/src/services/OtaService.ts +11 -5
  318. package/src/services/OtaUpdateCheckService.ts +180 -20
  319. package/src/services/PhoneCalendarService.ts +27 -4
  320. package/src/services/PhoneCameraFovCoordinator.ts +15 -0
  321. package/src/services/PhoneNotificationsSync.ts +12 -10
  322. package/src/services/PhonePhotoCoordinator.ts +33 -7
  323. package/src/services/PhoneStreamCoordinator.ts +139 -25
  324. package/src/services/PhoneVideoCoordinator.ts +11 -0
  325. package/src/services/SceneRenderer.ts +16 -0
  326. package/src/services/SupportProfileSync.ts +218 -0
  327. package/src/services/TtsTextSanitizer.ts +66 -0
  328. package/src/services/WifiAdbRequest.ts +53 -0
  329. package/src/services/asg/asgCameraApi.ts +99 -8
  330. package/src/services/asg/gallerySyncService.ts +28 -19
  331. package/src/services/asg/localNetworkTransport.ts +7 -11
  332. package/src/services/audioPlaybackAssets.ts +8 -0
  333. package/src/services/glassesClockSync.ts +2 -2
  334. package/src/services/manifestActions.ts +30 -0
  335. package/src/services/otaDisplayState.ts +57 -16
  336. package/src/services/otaInstallPolicy.ts +29 -3
  337. package/src/services/{asgOtaVersionUrl.ts → otaManifestUrl.ts} +16 -4
  338. package/src/services/slimStreamStatus.ts +16 -5
  339. package/src/stores/apps.ts +12 -0
  340. package/src/stores/bluetoothSettingKeys.ts +2 -0
  341. package/src/stores/gallerySync.ts +4 -0
  342. package/src/stores/glasses.ts +3 -0
  343. package/src/stores/settings.ts +174 -21
  344. package/src/types/applet.ts +2 -0
  345. package/src/types/enums.ts +2 -1
  346. package/src/types/hardware.ts +17 -0
  347. package/src/utils/configuredDevHost.ts +17 -0
  348. package/src/utils/devMiniappLaunch.ts +151 -23
  349. package/src/utils/diagnosticContext.ts +17 -17
  350. package/src/utils/hardware/hardware.ts +7 -9
  351. package/src/utils/miniappDiagnostics.ts +226 -0
  352. package/src/utils/timers/timers.ts +57 -21
  353. package/build/services/asgOtaVersionUrl.d.ts +0 -2
  354. package/build/services/asgOtaVersionUrl.d.ts.map +0 -1
  355. package/build/services/asgOtaVersionUrl.js.map +0 -1
@@ -12,21 +12,28 @@
12
12
  * get it in the same round trip — no second fetch.
13
13
  *
14
14
  * Pre-flighting at the call site keeps /applet/local a pure mount route.
15
+ *
16
+ * When the laptop's Wi-Fi IP changes, the URL stored from the last QR scan
17
+ * goes stale. We then retry alternate hosts (Metro / EXPO_PUBLIC_LOCAL_MINIAPP_HOST,
18
+ * plus an mDNS name captured at scan time) and persist the working URL so
19
+ * the next launch doesn't need a re-scan.
15
20
  */
21
+ import { configuredDevHost } from "./configuredDevHost";
16
22
  import { storage } from "./storage/storage";
17
23
  const REACHABILITY_TIMEOUT_MS = 1500;
18
- /**
19
- * GET <devUrl>/miniapp.json with a hard timeout. Returns the parsed
20
- * manifest on success ("live") or null ("offline").
21
- *
22
- * Side effect: on success, writes <packageName>_dev_last_reachable so
23
- * the dev-offline screen can show "Last reached: N min ago" the next
24
- * time the user lands there.
25
- *
26
- * The fetch doubles as the reachability probe AND the manifest source —
27
- * one request per launch attempt instead of two.
28
- */
29
- export async function decideDevLaunchRoute(packageName, devUrl) {
24
+ // A single dropped DNS lookup or momentary Wi-Fi blip (AP roam, DHCP renewal,
25
+ // phone hopping to cellular for a beat) looks identical to a dead dev server —
26
+ // both throw out of fetch(). Retrying once absorbs that transient case instead
27
+ // of bouncing straight to the offline screen. We do NOT retry a real HTTP
28
+ // response (res.ok === false): that's the server telling us something
29
+ // definitive, not a network-layer hiccup.
30
+ const REACHABILITY_MAX_ATTEMPTS = 2;
31
+ const REACHABILITY_RETRY_DELAY_MS = 400;
32
+ function delay(ms) {
33
+ return new Promise((resolve) => setTimeout(resolve, ms));
34
+ }
35
+ /** Single GET <devUrl>/miniapp.json attempt with a hard timeout. */
36
+ async function fetchManifestOnce(devUrl) {
30
37
  const controller = new AbortController();
31
38
  const timer = setTimeout(() => controller.abort(), REACHABILITY_TIMEOUT_MS);
32
39
  try {
@@ -35,18 +42,134 @@ export async function decideDevLaunchRoute(packageName, devUrl) {
35
42
  signal: controller.signal,
36
43
  });
37
44
  if (!res.ok)
38
- return { decision: "offline", manifest: null };
39
- const manifest = (await res.json());
40
- if (packageName) {
41
- storage.save(`${packageName}_dev_last_reachable`, Date.now());
42
- }
43
- return { decision: "live", manifest };
44
- }
45
- catch {
46
- return { decision: "offline", manifest: null };
45
+ return null;
46
+ return (await res.json());
47
47
  }
48
48
  finally {
49
49
  clearTimeout(timer);
50
50
  }
51
51
  }
52
+ function rewriteHost(devUrl, host) {
53
+ const trimmed = host.trim();
54
+ if (!trimmed)
55
+ return null;
56
+ try {
57
+ const url = new URL(devUrl);
58
+ if (url.hostname === trimmed)
59
+ return null;
60
+ url.hostname = trimmed;
61
+ return url.toString().replace(/\/$/, "");
62
+ }
63
+ catch {
64
+ return null;
65
+ }
66
+ }
67
+ /**
68
+ * Point an http(s) icon at the host that actually answered. Cached dev icons are
69
+ * local `file://` paths and third-party icons live on unrelated hosts, so only
70
+ * icons still served by the stale dev host are rewritten.
71
+ */
72
+ function rewriteIconHost(iconUrl, staleDevUrl, resolvedDevUrl) {
73
+ try {
74
+ const icon = new URL(iconUrl);
75
+ if (icon.protocol !== "http:" && icon.protocol !== "https:")
76
+ return null;
77
+ const stale = new URL(staleDevUrl);
78
+ const resolved = new URL(resolvedDevUrl);
79
+ // Compare host (hostname+port) so an icon on the same hostname but a
80
+ // different service port is left alone.
81
+ if (icon.host !== stale.host)
82
+ return null;
83
+ icon.host = resolved.host;
84
+ return icon.toString();
85
+ }
86
+ catch {
87
+ return null;
88
+ }
89
+ }
90
+ function collectAlternateHosts(packageName, extra) {
91
+ const hosts = [];
92
+ const push = (h) => {
93
+ const v = h?.trim();
94
+ if (v && !hosts.includes(v))
95
+ hosts.push(v);
96
+ };
97
+ push(configuredDevHost());
98
+ if (packageName) {
99
+ const mdns = storage.load(`${packageName}_dev_mdns`);
100
+ if (mdns.is_ok())
101
+ push(mdns.value);
102
+ }
103
+ for (const h of extra ?? [])
104
+ push(h);
105
+ return hosts;
106
+ }
107
+ async function probeUrl(devUrl) {
108
+ for (let attempt = 1; attempt <= REACHABILITY_MAX_ATTEMPTS; attempt++) {
109
+ try {
110
+ const manifest = await fetchManifestOnce(devUrl);
111
+ // Definitive HTTP failure — do not retry this URL further.
112
+ if (!manifest)
113
+ return null;
114
+ return manifest;
115
+ }
116
+ catch {
117
+ if (attempt < REACHABILITY_MAX_ATTEMPTS) {
118
+ await delay(REACHABILITY_RETRY_DELAY_MS);
119
+ continue;
120
+ }
121
+ return "network-error";
122
+ }
123
+ }
124
+ return "network-error";
125
+ }
126
+ /**
127
+ * GET <devUrl>/miniapp.json with a hard timeout, retrying once on a
128
+ * network-layer failure (DNS/connection/abort) before trying alternate
129
+ * hosts (Metro laptop IP, mDNS name from the QR). Returns the parsed
130
+ * manifest on success ("live") or null ("offline").
131
+ *
132
+ * Side effects on success:
133
+ * - writes <packageName>_dev_last_reachable
134
+ * - if an alternate host worked, rewrites <packageName>_dev_url so the
135
+ * next launch skips the stale IP
136
+ */
137
+ export async function decideDevLaunchRoute(packageName, devUrl, options) {
138
+ const candidates = [devUrl];
139
+ for (const host of collectAlternateHosts(packageName, options?.alternateHosts)) {
140
+ const rewritten = rewriteHost(devUrl, host);
141
+ if (rewritten && !candidates.includes(rewritten))
142
+ candidates.push(rewritten);
143
+ }
144
+ for (const candidate of candidates) {
145
+ const result = await probeUrl(candidate);
146
+ if (result === "network-error" || result === null)
147
+ continue;
148
+ if (packageName) {
149
+ storage.save(`${packageName}_dev_last_reachable`, Date.now());
150
+ if (candidate !== devUrl) {
151
+ storage.save(`${packageName}_dev_url`, candidate);
152
+ // Keep _dev_meta.devUrl in sync when present so home-tile reads match.
153
+ const metaRes = storage.load(`${packageName}_dev_meta`);
154
+ if (metaRes.is_ok()) {
155
+ try {
156
+ const meta = JSON.parse(metaRes.value);
157
+ meta.devUrl = candidate;
158
+ if (typeof meta.iconUrl === "string") {
159
+ const rewritten = rewriteIconHost(meta.iconUrl, devUrl, candidate);
160
+ if (rewritten)
161
+ meta.iconUrl = rewritten;
162
+ }
163
+ storage.save(`${packageName}_dev_meta`, JSON.stringify(meta));
164
+ }
165
+ catch {
166
+ /* ignore malformed meta */
167
+ }
168
+ }
169
+ }
170
+ }
171
+ return { decision: "live", manifest: result, resolvedUrl: candidate };
172
+ }
173
+ return { decision: "offline", manifest: null };
174
+ }
52
175
  //# sourceMappingURL=devMiniappLaunch.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"devMiniappLaunch.js","sourceRoot":"","sources":["../../src/utils/devMiniappLaunch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAC,OAAO,EAAC,MAAM,mBAAmB,CAAA;AAEzC,MAAM,uBAAuB,GAAG,IAAI,CAAA;AAgBpC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,WAAmB,EACnB,MAAc;IAEd,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;IACxC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,uBAAuB,CAAC,CAAA;IAC3E,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,eAAe,EAAE;YACnE,MAAM,EAAE,KAAK;YACb,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAA;QACF,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,EAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAC,CAAA;QACzD,MAAM,QAAQ,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAgB,CAAA;QAClD,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO,CAAC,IAAI,CAAC,GAAG,WAAW,qBAAqB,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;QAC/D,CAAC;QACD,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAC,CAAA;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAC,CAAA;IAC9C,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAA;IACrB,CAAC;AACH,CAAC","sourcesContent":["/**\n * decideDevLaunchRoute — pre-flight reachability + manifest fetch for dev\n * miniapp launches.\n *\n * Every entry point that wants to launch a dev miniapp (home tile, QR\n * scan, URL screen, dev-offline \"Try again\" button) calls this BEFORE\n * navigating, so:\n *\n * 1. We land on the right destination in a single transition\n * (live mount vs offline takeover) — no flash through /applet/local.\n * 2. Callers that need the manifest (permission gate, name/icon read)\n * get it in the same round trip — no second fetch.\n *\n * Pre-flighting at the call site keeps /applet/local a pure mount route.\n */\n\nimport {storage} from \"./storage/storage\"\n\nconst REACHABILITY_TIMEOUT_MS = 1500\n\nexport type DevManifest = {\n packageName?: string\n name?: string\n /** First-found of `icon` / `iconUrl` / `logoUrl` (relative or absolute). */\n icon?: string\n permissions?: unknown\n hardwareRequirements?: unknown\n [key: string]: unknown\n}\n\nexport type DevLaunchResult =\n | {decision: \"live\"; manifest: DevManifest}\n | {decision: \"offline\"; manifest: null}\n\n/**\n * GET <devUrl>/miniapp.json with a hard timeout. Returns the parsed\n * manifest on success (\"live\") or null (\"offline\").\n *\n * Side effect: on success, writes <packageName>_dev_last_reachable so\n * the dev-offline screen can show \"Last reached: N min ago\" the next\n * time the user lands there.\n *\n * The fetch doubles as the reachability probe AND the manifest source —\n * one request per launch attempt instead of two.\n */\nexport async function decideDevLaunchRoute(\n packageName: string,\n devUrl: string,\n): Promise<DevLaunchResult> {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), REACHABILITY_TIMEOUT_MS)\n try {\n const res = await fetch(`${devUrl.replace(/\\/$/, \"\")}/miniapp.json`, {\n method: \"GET\",\n signal: controller.signal,\n })\n if (!res.ok) return {decision: \"offline\", manifest: null}\n const manifest = (await res.json()) as DevManifest\n if (packageName) {\n storage.save(`${packageName}_dev_last_reachable`, Date.now())\n }\n return {decision: \"live\", manifest}\n } catch {\n return {decision: \"offline\", manifest: null}\n } finally {\n clearTimeout(timer)\n }\n}\n"]}
1
+ {"version":3,"file":"devMiniappLaunch.js","sourceRoot":"","sources":["../../src/utils/devMiniappLaunch.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * decideDevLaunchRoute — pre-flight reachability + manifest fetch for dev\n * miniapp launches.\n *\n * Every entry point that wants to launch a dev miniapp (home tile, QR\n * scan, URL screen, dev-offline \"Try again\" button) calls this BEFORE\n * navigating, so:\n *\n * 1. We land on the right destination in a single transition\n * (live mount vs offline takeover) — no flash through /applet/local.\n * 2. Callers that need the manifest (permission gate, name/icon read)\n * get it in the same round trip — no second fetch.\n *\n * Pre-flighting at the call site keeps /applet/local a pure mount route.\n *\n * When the laptop's Wi-Fi IP changes, the URL stored from the last QR scan\n * goes stale. We then retry alternate hosts (Metro / EXPO_PUBLIC_LOCAL_MINIAPP_HOST,\n * plus an mDNS name captured at scan time) and persist the working URL so\n * the next launch doesn't need a re-scan.\n */\n\nimport {configuredDevHost} from \"./configuredDevHost\"\nimport {storage} from \"./storage/storage\"\n\nconst REACHABILITY_TIMEOUT_MS = 1500\n\n// A single dropped DNS lookup or momentary Wi-Fi blip (AP roam, DHCP renewal,\n// phone hopping to cellular for a beat) looks identical to a dead dev server —\n// both throw out of fetch(). Retrying once absorbs that transient case instead\n// of bouncing straight to the offline screen. We do NOT retry a real HTTP\n// response (res.ok === false): that's the server telling us something\n// definitive, not a network-layer hiccup.\nconst REACHABILITY_MAX_ATTEMPTS = 2\nconst REACHABILITY_RETRY_DELAY_MS = 400\n\nexport type DevManifest = {\n packageName?: string\n name?: string\n /** First-found of `icon` / `iconUrl` / `logoUrl` (relative or absolute). */\n icon?: string\n permissions?: unknown\n hardwareRequirements?: unknown\n [key: string]: unknown\n}\n\nexport type DevLaunchResult =\n | {decision: \"live\"; manifest: DevManifest; resolvedUrl: string}\n | {decision: \"offline\"; manifest: null; resolvedUrl?: undefined}\n\nexport type DecideDevLaunchOptions = {\n /** Extra hostnames / IPs to try if `devUrl` is unreachable (no scheme/port). */\n alternateHosts?: string[]\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\n/** Single GET <devUrl>/miniapp.json attempt with a hard timeout. */\nasync function fetchManifestOnce(devUrl: string): Promise<DevManifest | null> {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), REACHABILITY_TIMEOUT_MS)\n try {\n const res = await fetch(`${devUrl.replace(/\\/$/, \"\")}/miniapp.json`, {\n method: \"GET\",\n signal: controller.signal,\n })\n if (!res.ok) return null\n return (await res.json()) as DevManifest\n } finally {\n clearTimeout(timer)\n }\n}\n\nfunction rewriteHost(devUrl: string, host: string): string | null {\n const trimmed = host.trim()\n if (!trimmed) return null\n try {\n const url = new URL(devUrl)\n if (url.hostname === trimmed) return null\n url.hostname = trimmed\n return url.toString().replace(/\\/$/, \"\")\n } catch {\n return null\n }\n}\n\n/**\n * Point an http(s) icon at the host that actually answered. Cached dev icons are\n * local `file://` paths and third-party icons live on unrelated hosts, so only\n * icons still served by the stale dev host are rewritten.\n */\nfunction rewriteIconHost(iconUrl: string, staleDevUrl: string, resolvedDevUrl: string): string | null {\n try {\n const icon = new URL(iconUrl)\n if (icon.protocol !== \"http:\" && icon.protocol !== \"https:\") return null\n const stale = new URL(staleDevUrl)\n const resolved = new URL(resolvedDevUrl)\n // Compare host (hostname+port) so an icon on the same hostname but a\n // different service port is left alone.\n if (icon.host !== stale.host) return null\n icon.host = resolved.host\n return icon.toString()\n } catch {\n return null\n }\n}\n\nfunction collectAlternateHosts(packageName: string, extra?: string[]): string[] {\n const hosts: string[] = []\n const push = (h: string | undefined | null) => {\n const v = h?.trim()\n if (v && !hosts.includes(v)) hosts.push(v)\n }\n\n push(configuredDevHost())\n\n if (packageName) {\n const mdns = storage.load<string>(`${packageName}_dev_mdns`)\n if (mdns.is_ok()) push(mdns.value)\n }\n\n for (const h of extra ?? []) push(h)\n return hosts\n}\n\nasync function probeUrl(devUrl: string): Promise<DevManifest | null | \"network-error\"> {\n for (let attempt = 1; attempt <= REACHABILITY_MAX_ATTEMPTS; attempt++) {\n try {\n const manifest = await fetchManifestOnce(devUrl)\n // Definitive HTTP failure — do not retry this URL further.\n if (!manifest) return null\n return manifest\n } catch {\n if (attempt < REACHABILITY_MAX_ATTEMPTS) {\n await delay(REACHABILITY_RETRY_DELAY_MS)\n continue\n }\n return \"network-error\"\n }\n }\n return \"network-error\"\n}\n\n/**\n * GET <devUrl>/miniapp.json with a hard timeout, retrying once on a\n * network-layer failure (DNS/connection/abort) before trying alternate\n * hosts (Metro laptop IP, mDNS name from the QR). Returns the parsed\n * manifest on success (\"live\") or null (\"offline\").\n *\n * Side effects on success:\n * - writes <packageName>_dev_last_reachable\n * - if an alternate host worked, rewrites <packageName>_dev_url so the\n * next launch skips the stale IP\n */\nexport async function decideDevLaunchRoute(\n packageName: string,\n devUrl: string,\n options?: DecideDevLaunchOptions,\n): Promise<DevLaunchResult> {\n const candidates: string[] = [devUrl]\n for (const host of collectAlternateHosts(packageName, options?.alternateHosts)) {\n const rewritten = rewriteHost(devUrl, host)\n if (rewritten && !candidates.includes(rewritten)) candidates.push(rewritten)\n }\n\n for (const candidate of candidates) {\n const result = await probeUrl(candidate)\n if (result === \"network-error\" || result === null) continue\n\n if (packageName) {\n storage.save(`${packageName}_dev_last_reachable`, Date.now())\n if (candidate !== devUrl) {\n storage.save(`${packageName}_dev_url`, candidate)\n // Keep _dev_meta.devUrl in sync when present so home-tile reads match.\n const metaRes = storage.load<string>(`${packageName}_dev_meta`)\n if (metaRes.is_ok()) {\n try {\n const meta = JSON.parse(metaRes.value) as {devUrl?: string; iconUrl?: string}\n meta.devUrl = candidate\n if (typeof meta.iconUrl === \"string\") {\n const rewritten = rewriteIconHost(meta.iconUrl, devUrl, candidate)\n if (rewritten) meta.iconUrl = rewritten\n }\n storage.save(`${packageName}_dev_meta`, JSON.stringify(meta))\n } catch {\n /* ignore malformed meta */\n }\n }\n }\n }\n return {decision: \"live\", manifest: result, resolvedUrl: candidate}\n }\n\n return {decision: \"offline\", manifest: null}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"diagnosticContext.d.ts","sourceRoot":"","sources":["../../src/utils/diagnosticContext.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,sBAAsB,CAAA;AAyBvD,wBAAsB,wBAAwB,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CA6HrG"}
1
+ {"version":3,"file":"diagnosticContext.d.ts","sourceRoot":"","sources":["../../src/utils/diagnosticContext.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,sBAAsB,CAAA;AA4BvD,wBAAsB,wBAAwB,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CA0HrG"}
@@ -2,11 +2,14 @@ import NetInfo from "@react-native-community/netinfo";
2
2
  import Constants from "expo-constants";
3
3
  import * as Location from "expo-location";
4
4
  import { Platform } from "react-native";
5
- import { useAppStatusStore } from "../stores/apps";
5
+ import appRegistry from "../services/AppRegistry";
6
+ import localMiniappRuntime from "../services/LocalMiniappRuntime";
7
+ import { getLastOpenTime, useAppStatusStore } from "../stores/apps";
6
8
  import { useConnectionStore } from "../stores/connection";
7
9
  import { useCoreStore } from "../stores/core";
8
10
  import { useGlassesStore } from "../stores/glasses";
9
11
  import { SETTINGS, useSettingsStore } from "../stores/settings";
12
+ import { buildMiniappDiagnosticContext } from "./miniappDiagnostics";
10
13
  const SENSITIVE_SETTINGS_KEYS = ["core_token", "auth_token", "auth_email"];
11
14
  const SENSITIVE_GLASSES_KEYS = ["hotspotPassword"];
12
15
  /**
@@ -72,17 +75,15 @@ export async function collectDiagnosticContext(extra) {
72
75
  }
73
76
  const offlineMode = await useSettingsStore.getState().getSetting(SETTINGS.offline_mode.key);
74
77
  const defaultWearable = await useSettingsStore.getState().getSetting(SETTINGS.default_wearable.key);
75
- const apps = appletState.apps.map((app) => ({
76
- packageName: app.packageName,
77
- name: app.name,
78
- running: app.running,
79
- loading: app.loading,
80
- healthy: app.healthy,
81
- hidden: app.hidden,
82
- type: app.type,
83
- offline: app.offline,
84
- local: app.local,
85
- }));
78
+ const miniappRuntime = localMiniappRuntime.getDiagnosticSnapshot();
79
+ const miniapps = buildMiniappDiagnosticContext({
80
+ apps: appletState.apps,
81
+ foregroundedPackage: appletState.foregroundedPackage,
82
+ runtime: miniappRuntime,
83
+ getLastOpenedAtMs: (app) => getLastOpenTime(app.packageName),
84
+ getManifest: (app) => app.local && app.version ? appRegistry.getMiniappManifest(app.packageName, app.version) : undefined,
85
+ getReleaseIdentity: (app) => app.local && app.version ? appRegistry.getReleaseIdentity(app.packageName, app.version) : undefined,
86
+ });
86
87
  return {
87
88
  app: {
88
89
  appVersion: process.env.EXPO_PUBLIC_MENTRAOS_VERSION || "version",
@@ -102,12 +103,9 @@ export async function collectDiagnosticContext(extra) {
102
103
  runtime: {
103
104
  core: coreState,
104
105
  connection: connectionState,
106
+ miniapps: miniappRuntime,
105
107
  },
106
- apps: {
107
- apps,
108
- installed: apps.map((app) => app.packageName),
109
- running: apps.filter((app) => app.running).map((app) => app.packageName),
110
- },
108
+ apps: miniapps,
111
109
  settings: {
112
110
  ...filteredSettings,
113
111
  offlineMode: !!offlineMode,
@@ -1 +1 @@
1
- {"version":3,"file":"diagnosticContext.js","sourceRoot":"","sources":["../../src/utils/diagnosticContext.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,iCAAiC,CAAA;AACrD,OAAO,SAAS,MAAM,gBAAgB,CAAA;AACtC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,EAAC,QAAQ,EAAC,MAAM,cAAc,CAAA;AAGrC,OAAO,EAAC,iBAAiB,EAAC,MAAM,gBAAgB,CAAA;AAChD,OAAO,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAC,eAAe,EAAC,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAC,QAAQ,EAAE,gBAAgB,EAAC,MAAM,oBAAoB,CAAA;AAE7D,MAAM,uBAAuB,GAAG,CAAC,YAAY,EAAE,YAAY,EAAE,YAAY,CAAU,CAAA;AACnF,MAAM,sBAAsB,GAAG,CAAC,iBAAiB,CAAU,CAAA;AAE3D;;;;GAIG;AACH,SAAS,uBAAuB,CAAC,OAAgC;IAC/D,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAA;IAC/B,IAAI,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,UAAU,IAAI,OAAO,EAAE,CAAC;QACpE,MAAM,EAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,EAAC,GAAG,OAAkC,CAAA;QACzE,OAAO,EAAC,GAAG,OAAO,EAAE,OAAO,EAAE,EAAC,GAAG,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAC,EAAC,CAAA;IACjE,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,KAA8B;IAC3E,MAAM,WAAW,GAAG,iBAAiB,CAAC,QAAQ,EAAE,CAAA;IAChD,MAAM,aAAa,GAAG,gBAAgB,CAAC,QAAQ,EAAE,CAAA;IACjD,MAAM,EAAC,WAAW,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,SAAS,EAAC,GAAG,YAAY,CAAC,QAAQ,EAAE,CAAA;IACjG,MAAM,EACJ,SAAS,EAAE,oBAAoB,EAC/B,MAAM,EAAE,iBAAiB,EACzB,QAAQ,EAAE,mBAAmB,EAC7B,0BAA0B,EAAE,2BAA2B,EACvD,sBAAsB,EAAE,uBAAuB,EAC/C,KAAK,EAAE,gBAAgB,EACvB,GAAG,eAAe,EACnB,GAAG,kBAAkB,CAAC,QAAQ,EAAE,CAAA;IACjC,MAAM,EACJ,cAAc,EAAE,eAAe,EAC/B,cAAc,EAAE,eAAe,EAC/B,WAAW,EAAE,YAAY,EACzB,cAAc,EAAE,eAAe,EAC/B,qBAAqB,EAAE,sBAAsB,EAC7C,cAAc,EAAE,eAAe,EAC/B,gBAAgB,EAAE,iBAAiB,EACnC,wBAAwB,EAAE,yBAAyB,EACnD,aAAa,EAAE,cAAc,EAC7B,KAAK,EAAE,aAAa,EACpB,GAAG,YAAY,EAChB,GAAG,eAAe,CAAC,QAAQ,EAAE,CAAA;IAE9B,MAAM,eAAe,GAAG,uBAAuB,CAC7C,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,MAAM,CACjC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,sBAAsB,CAAC,QAAQ,CAAC,GAA8C,CAAC,CAC5F,CACF,CACF,CAAA;IACD,MAAM,gBAAgB,GAAG,MAAM,CAAC,WAAW,CACzC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,MAAM,CACjD,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,uBAAuB,CAAC,QAAQ,CAAC,GAA+C,CAAC,CAC9F,CACF,CAAA;IAED,IAAI,WAAW,GAA4B,EAAC,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAC,CAAA;IAC5G,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE,CAAA;QACtC,WAAW,GAAG;YACZ,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,WAAW,EAAE,QAAQ,CAAC,WAAW,IAAI,KAAK;YAC1C,mBAAmB,EAAE,QAAQ,CAAC,mBAAmB,IAAI,KAAK;SAC3D,CAAA;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,gDAAgD,EAAE,KAAK,CAAC,CAAA;IACtE,CAAC;IAED,IAAI,YAAiD,CAAA;IACrD,IAAI,CAAC;QACH,MAAM,EAAC,MAAM,EAAC,GAAG,MAAM,QAAQ,CAAC,6BAA6B,EAAE,CAAA;QAC/D,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,yBAAyB,EAAE,CAAA;YAC3D,IAAI,QAAQ,EAAE,CAAC;gBACb,YAAY,GAAG;oBACb,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;oBACrD,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;iBACxD,CAAA;gBACD,IAAI,CAAC;oBACH,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,QAAQ,CAAC,mBAAmB,CAAC;wBACjD,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ;wBAClC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS;qBACrC,CAAC,CAAA;oBACF,IAAI,KAAK,EAAE,CAAC;wBACV,YAAY,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;oBAC3F,CAAC;gBACH,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,GAAG,CAAC,+CAA+C,EAAE,KAAK,CAAC,CAAA;gBACrE,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,4CAA4C,EAAE,KAAK,CAAC,CAAA;IAClE,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,gBAAgB,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,CAAA;IAC3F,MAAM,eAAe,GAAG,MAAM,gBAAgB,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAA;IACnG,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC1C,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,KAAK,EAAE,GAAG,CAAC,KAAK;KACjB,CAAC,CAAC,CAAA;IAEH,OAAO;QACL,GAAG,EAAE;YACH,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,4BAA4B,IAAI,SAAS;YACjE,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,QAAQ;YAC7D,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,QAAQ;YAC7D,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,MAAM;YACvD,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,MAAM;SACxD;QACD,KAAK,EAAE;YACL,UAAU,EAAE,SAAS,CAAC,UAAU,IAAI,YAAY;YAChD,SAAS,EAAE,GAAG,QAAQ,CAAC,EAAE,IAAI,QAAQ,CAAC,OAAO,EAAE;YAC/C,QAAQ,EAAE,QAAQ,CAAC,EAAE;YACrB,OAAO,EAAE,WAAW;YACpB,QAAQ,EAAE,YAAY;SACvB;QACD,OAAO,EAAE,eAAe;QACxB,OAAO,EAAE;YACP,IAAI,EAAE,SAAS;YACf,UAAU,EAAE,eAAe;SAC5B;QACD,IAAI,EAAE;YACJ,IAAI;YACJ,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC;YAC7C,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC;SACzE;QACD,QAAQ,EAAE;YACR,GAAG,gBAAgB;YACnB,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,eAAe;SAChB;QACD,GAAG,KAAK;KACT,CAAA;AACH,CAAC","sourcesContent":["import NetInfo from \"@react-native-community/netinfo\"\nimport Constants from \"expo-constants\"\nimport * as Location from \"expo-location\"\nimport {Platform} from \"react-native\"\nimport type {ReportContext} from \"@mentra/cloud-client\"\n\nimport {useAppStatusStore} from \"../stores/apps\"\nimport {useConnectionStore} from \"../stores/connection\"\nimport {useCoreStore} from \"../stores/core\"\nimport {useGlassesStore} from \"../stores/glasses\"\nimport {SETTINGS, useSettingsStore} from \"../stores/settings\"\n\nconst SENSITIVE_SETTINGS_KEYS = [\"core_token\", \"auth_token\", \"auth_email\"] as const\nconst SENSITIVE_GLASSES_KEYS = [\"hotspotPassword\"] as const\n\n/**\n * The glasses store keeps hotspot credentials NESTED (`hotspot: {state, ssid,\n * password, localIp}`), not just on the legacy top-level `hotspotPassword` key —\n * strip the password before the state is attached to a report.\n */\nfunction redactNestedCredentials(glasses: Record<string, unknown>): Record<string, unknown> {\n const hotspot = glasses.hotspot\n if (hotspot && typeof hotspot === \"object\" && \"password\" in hotspot) {\n const {password: _password, ...rest} = hotspot as Record<string, unknown>\n return {...glasses, hotspot: {...rest, password: \"[REDACTED]\"}}\n }\n return glasses\n}\n\nexport async function collectDiagnosticContext(extra?: Partial<ReportContext>): Promise<ReportContext> {\n const appletState = useAppStatusStore.getState()\n const settingsState = useSettingsStore.getState()\n const {setCoreInfo: _setCoreInfo, reset: _resetBluetooth, ...coreState} = useCoreStore.getState()\n const {\n setStatus: _setConnectionStatus,\n setUrl: _setConnectionUrl,\n setError: _setConnectionError,\n incrementReconnectAttempts: _incrementReconnectAttempts,\n resetReconnectAttempts: _resetReconnectAttempts,\n reset: _resetConnection,\n ...connectionState\n } = useConnectionStore.getState()\n const {\n setGlassesInfo: _setGlassesInfo,\n setBatteryInfo: _setBatteryInfo,\n setWifiInfo: _setWifiInfo,\n setHotspotInfo: _setHotspotInfo,\n setOtaUpdateAvailable: _setOtaUpdateAvailable,\n setOtaProgress: _setOtaProgress,\n setOtaInProgress: _setOtaInProgress,\n setMtkUpdatedThisSession: _setMtkUpdatedThisSession,\n clearOtaState: _clearOtaState,\n reset: _resetGlasses,\n ...glassesState\n } = useGlassesStore.getState()\n\n const filteredGlasses = redactNestedCredentials(\n Object.fromEntries(\n Object.entries(glassesState).filter(\n ([key]) => !SENSITIVE_GLASSES_KEYS.includes(key as (typeof SENSITIVE_GLASSES_KEYS)[number]),\n ),\n ),\n )\n const filteredSettings = Object.fromEntries(\n Object.entries(settingsState.settings || {}).filter(\n ([key]) => !SENSITIVE_SETTINGS_KEYS.includes(key as (typeof SENSITIVE_SETTINGS_KEYS)[number]),\n ),\n )\n\n let networkInfo: Record<string, unknown> = {type: \"unknown\", isConnected: false, isInternetReachable: false}\n try {\n const netState = await NetInfo.fetch()\n networkInfo = {\n type: netState.type,\n isConnected: netState.isConnected ?? false,\n isInternetReachable: netState.isInternetReachable ?? false,\n }\n } catch (error) {\n console.log(\"diagnosticContext: failed to get network info:\", error)\n }\n\n let locationInfo: Record<string, unknown> | undefined\n try {\n const {status} = await Location.getForegroundPermissionsAsync()\n if (status === \"granted\") {\n const location = await Location.getLastKnownPositionAsync()\n if (location) {\n locationInfo = {\n latitude: Number(location.coords.latitude.toFixed(4)),\n longitude: Number(location.coords.longitude.toFixed(4)),\n }\n try {\n const [place] = await Location.reverseGeocodeAsync({\n latitude: location.coords.latitude,\n longitude: location.coords.longitude,\n })\n if (place) {\n locationInfo.place = [place.city, place.region, place.country].filter(Boolean).join(\", \")\n }\n } catch (error) {\n console.log(\"diagnosticContext: failed to reverse geocode:\", error)\n }\n }\n }\n } catch (error) {\n console.log(\"diagnosticContext: failed to get location:\", error)\n }\n\n const offlineMode = await useSettingsStore.getState().getSetting(SETTINGS.offline_mode.key)\n const defaultWearable = await useSettingsStore.getState().getSetting(SETTINGS.default_wearable.key)\n const apps = appletState.apps.map((app) => ({\n packageName: app.packageName,\n name: app.name,\n running: app.running,\n loading: app.loading,\n healthy: app.healthy,\n hidden: app.hidden,\n type: app.type,\n offline: app.offline,\n local: app.local,\n }))\n\n return {\n app: {\n appVersion: process.env.EXPO_PUBLIC_MENTRAOS_VERSION || \"version\",\n buildCommit: process.env.EXPO_PUBLIC_BUILD_COMMIT || \"commit\",\n buildBranch: process.env.EXPO_PUBLIC_BUILD_BRANCH || \"branch\",\n buildTime: process.env.EXPO_PUBLIC_BUILD_TIME || \"time\",\n buildUser: process.env.EXPO_PUBLIC_BUILD_USER || \"user\",\n },\n phone: {\n deviceName: Constants.deviceName || \"deviceName\",\n osVersion: `${Platform.OS} ${Platform.Version}`,\n platform: Platform.OS,\n network: networkInfo,\n location: locationInfo,\n },\n glasses: filteredGlasses,\n runtime: {\n core: coreState,\n connection: connectionState,\n },\n apps: {\n apps,\n installed: apps.map((app) => app.packageName),\n running: apps.filter((app) => app.running).map((app) => app.packageName),\n },\n settings: {\n ...filteredSettings,\n offlineMode: !!offlineMode,\n defaultWearable,\n },\n ...extra,\n }\n}\n"]}
1
+ {"version":3,"file":"diagnosticContext.js","sourceRoot":"","sources":["../../src/utils/diagnosticContext.ts"],"names":[],"mappings":"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","sourcesContent":["import NetInfo from \"@react-native-community/netinfo\"\nimport Constants from \"expo-constants\"\nimport * as Location from \"expo-location\"\nimport {Platform} from \"react-native\"\nimport type {ReportContext} from \"@mentra/cloud-client\"\n\nimport appRegistry from \"../services/AppRegistry\"\nimport localMiniappRuntime from \"../services/LocalMiniappRuntime\"\nimport {getLastOpenTime, useAppStatusStore} from \"../stores/apps\"\nimport {useConnectionStore} from \"../stores/connection\"\nimport {useCoreStore} from \"../stores/core\"\nimport {useGlassesStore} from \"../stores/glasses\"\nimport {SETTINGS, useSettingsStore} from \"../stores/settings\"\nimport {buildMiniappDiagnosticContext} from \"./miniappDiagnostics\"\n\nconst SENSITIVE_SETTINGS_KEYS = [\"core_token\", \"auth_token\", \"auth_email\"] as const\nconst SENSITIVE_GLASSES_KEYS = [\"hotspotPassword\"] as const\n\n/**\n * The glasses store keeps hotspot credentials NESTED (`hotspot: {state, ssid,\n * password, localIp}`), not just on the legacy top-level `hotspotPassword` key —\n * strip the password before the state is attached to a report.\n */\nfunction redactNestedCredentials(glasses: Record<string, unknown>): Record<string, unknown> {\n const hotspot = glasses.hotspot\n if (hotspot && typeof hotspot === \"object\" && \"password\" in hotspot) {\n const {password: _password, ...rest} = hotspot as Record<string, unknown>\n return {...glasses, hotspot: {...rest, password: \"[REDACTED]\"}}\n }\n return glasses\n}\n\nexport async function collectDiagnosticContext(extra?: Partial<ReportContext>): Promise<ReportContext> {\n const appletState = useAppStatusStore.getState()\n const settingsState = useSettingsStore.getState()\n const {setCoreInfo: _setCoreInfo, reset: _resetBluetooth, ...coreState} = useCoreStore.getState()\n const {\n setStatus: _setConnectionStatus,\n setUrl: _setConnectionUrl,\n setError: _setConnectionError,\n incrementReconnectAttempts: _incrementReconnectAttempts,\n resetReconnectAttempts: _resetReconnectAttempts,\n reset: _resetConnection,\n ...connectionState\n } = useConnectionStore.getState()\n const {\n setGlassesInfo: _setGlassesInfo,\n setBatteryInfo: _setBatteryInfo,\n setWifiInfo: _setWifiInfo,\n setHotspotInfo: _setHotspotInfo,\n setOtaUpdateAvailable: _setOtaUpdateAvailable,\n setOtaProgress: _setOtaProgress,\n setOtaInProgress: _setOtaInProgress,\n setMtkUpdatedThisSession: _setMtkUpdatedThisSession,\n clearOtaState: _clearOtaState,\n reset: _resetGlasses,\n ...glassesState\n } = useGlassesStore.getState()\n\n const filteredGlasses = redactNestedCredentials(\n Object.fromEntries(\n Object.entries(glassesState).filter(\n ([key]) => !SENSITIVE_GLASSES_KEYS.includes(key as (typeof SENSITIVE_GLASSES_KEYS)[number]),\n ),\n ),\n )\n const filteredSettings = Object.fromEntries(\n Object.entries(settingsState.settings || {}).filter(\n ([key]) => !SENSITIVE_SETTINGS_KEYS.includes(key as (typeof SENSITIVE_SETTINGS_KEYS)[number]),\n ),\n )\n\n let networkInfo: Record<string, unknown> = {type: \"unknown\", isConnected: false, isInternetReachable: false}\n try {\n const netState = await NetInfo.fetch()\n networkInfo = {\n type: netState.type,\n isConnected: netState.isConnected ?? false,\n isInternetReachable: netState.isInternetReachable ?? false,\n }\n } catch (error) {\n console.log(\"diagnosticContext: failed to get network info:\", error)\n }\n\n let locationInfo: Record<string, unknown> | undefined\n try {\n const {status} = await Location.getForegroundPermissionsAsync()\n if (status === \"granted\") {\n const location = await Location.getLastKnownPositionAsync()\n if (location) {\n locationInfo = {\n latitude: Number(location.coords.latitude.toFixed(4)),\n longitude: Number(location.coords.longitude.toFixed(4)),\n }\n try {\n const [place] = await Location.reverseGeocodeAsync({\n latitude: location.coords.latitude,\n longitude: location.coords.longitude,\n })\n if (place) {\n locationInfo.place = [place.city, place.region, place.country].filter(Boolean).join(\", \")\n }\n } catch (error) {\n console.log(\"diagnosticContext: failed to reverse geocode:\", error)\n }\n }\n }\n } catch (error) {\n console.log(\"diagnosticContext: failed to get location:\", error)\n }\n\n const offlineMode = await useSettingsStore.getState().getSetting(SETTINGS.offline_mode.key)\n const defaultWearable = await useSettingsStore.getState().getSetting(SETTINGS.default_wearable.key)\n const miniappRuntime = localMiniappRuntime.getDiagnosticSnapshot()\n const miniapps = buildMiniappDiagnosticContext({\n apps: appletState.apps,\n foregroundedPackage: appletState.foregroundedPackage,\n runtime: miniappRuntime,\n getLastOpenedAtMs: (app) => getLastOpenTime(app.packageName),\n getManifest: (app) =>\n app.local && app.version ? appRegistry.getMiniappManifest(app.packageName, app.version) : undefined,\n getReleaseIdentity: (app) =>\n app.local && app.version ? appRegistry.getReleaseIdentity(app.packageName, app.version) : undefined,\n })\n\n return {\n app: {\n appVersion: process.env.EXPO_PUBLIC_MENTRAOS_VERSION || \"version\",\n buildCommit: process.env.EXPO_PUBLIC_BUILD_COMMIT || \"commit\",\n buildBranch: process.env.EXPO_PUBLIC_BUILD_BRANCH || \"branch\",\n buildTime: process.env.EXPO_PUBLIC_BUILD_TIME || \"time\",\n buildUser: process.env.EXPO_PUBLIC_BUILD_USER || \"user\",\n },\n phone: {\n deviceName: Constants.deviceName || \"deviceName\",\n osVersion: `${Platform.OS} ${Platform.Version}`,\n platform: Platform.OS,\n network: networkInfo,\n location: locationInfo,\n },\n glasses: filteredGlasses,\n runtime: {\n core: coreState,\n connection: connectionState,\n miniapps: miniappRuntime,\n },\n apps: miniapps,\n settings: {\n ...filteredSettings,\n offlineMode: !!offlineMode,\n defaultWearable,\n },\n ...extra,\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"hardware.d.ts","sourceRoot":"","sources":["../../../src/utils/hardware/hardware.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,mBAAmB,EAIpB,MAAM,aAAa,CAAA;AAGpB;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,OAAO,CAAA;IACrB,eAAe,EAAE,mBAAmB,EAAE,CAAA;IACtC,eAAe,EAAE,mBAAmB,EAAE,CAAA;IACtC,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED;;GAEG;AACH,qBAAa,qBAAqB;IAChC;;;;;OAKG;IACH,MAAM,CAAC,kBAAkB,CACvB,oBAAoB,EAAE,mBAAmB,EAAE,EAC3C,YAAY,EAAE,YAAY,GAAG,IAAI,GAChC,mBAAmB;IAkCtB;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAuCrC;;;;OAIG;IACH,MAAM,CAAC,uBAAuB,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM;IAkBnE;;;;OAIG;IACH,MAAM,CAAC,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,EAAE;CA0BlE"}
1
+ {"version":3,"file":"hardware.d.ts","sourceRoot":"","sources":["../../../src/utils/hardware/hardware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAe,mBAAmB,EAA2D,MAAM,aAAa,CAAA;AAEpI;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,OAAO,CAAA;IACrB,eAAe,EAAE,mBAAmB,EAAE,CAAA;IACtC,eAAe,EAAE,mBAAmB,EAAE,CAAA;IACtC,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED;;GAEG;AACH,qBAAa,qBAAqB;IAChC;;;;;OAKG;IACH,MAAM,CAAC,kBAAkB,CACvB,oBAAoB,EAAE,mBAAmB,EAAE,EAC3C,YAAY,EAAE,YAAY,GAAG,IAAI,GAChC,mBAAmB;IAkCtB;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,sBAAsB;IA4CrC;;;;OAIG;IACH,MAAM,CAAC,uBAAuB,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM;IAkBnE;;;;OAIG;IACH,MAAM,CAAC,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,EAAE;CA0BlE"}
@@ -1,5 +1,4 @@
1
- import { HardwareType, HardwareRequirementLevel, DeviceTypes, } from "../../types";
2
- import { simulatedGlasses } from "../../types";
1
+ import { DeviceTypes, HardwareRequirementLevel, HardwareType, simulatedGlasses } from "../../types";
3
2
  /**
4
3
  * Service for checking hardware compatibility between apps and glasses
5
4
  */
@@ -59,7 +58,12 @@ export class HardwareCompatibility {
59
58
  case HardwareType.DISPLAY:
60
59
  return capabilities.hasDisplay;
61
60
  case HardwareType.MICROPHONE:
62
- return capabilities.hasMicrophone;
61
+ // MentraOS always provides an audio-input path. When the connected
62
+ // glasses do not have an onboard microphone, the engine falls back to
63
+ // the phone microphone. Keep `capabilities.hasMicrophone` reserved for
64
+ // physical-device/source selection; app compatibility is about whether
65
+ // the requested input is available to the miniapp.
66
+ return true;
63
67
  case HardwareType.SPEAKER:
64
68
  return capabilities.hasSpeaker;
65
69
  case HardwareType.IMU:
@@ -1 +1 @@
1
- {"version":3,"file":"hardware.js","sourceRoot":"","sources":["../../../src/utils/hardware/hardware.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Capabilities,\n HardwareRequirement,\n HardwareType,\n HardwareRequirementLevel,\n DeviceTypes,\n} from \"../../types\"\nimport {simulatedGlasses} from \"../../types\"\n\n/**\n * Result of a hardware compatibility check\n */\nexport interface CompatibilityResult {\n isCompatible: boolean\n missingRequired: HardwareRequirement[]\n missingOptional: HardwareRequirement[]\n warnings: string[]\n}\n\n/**\n * Service for checking hardware compatibility between apps and glasses\n */\nexport class HardwareCompatibility {\n /**\n * Check if app is compatible with given device capabilities\n * @param app The app to check\n * @param capabilities The device capabilities (null if no device connected)\n * @returns Detailed compatibility result\n */\n static checkCompatibility(\n hardwareRequirements: HardwareRequirement[],\n capabilities: Capabilities | null,\n ): CompatibilityResult {\n const result: CompatibilityResult = {\n isCompatible: true,\n missingRequired: [],\n missingOptional: [],\n warnings: [],\n }\n\n // If no hardware requirements specified, app is compatible with any hardware\n if (hardwareRequirements.length === 0) {\n return result\n }\n\n // If no capabilities available assume simulated glasses:\n if (!capabilities) {\n capabilities = simulatedGlasses\n }\n\n // Check each hardware requirement\n for (const requirement of hardwareRequirements) {\n const hasHardware = this.checkHardwareAvailable(requirement.type, capabilities!)\n if (!hasHardware) {\n if (requirement.level === HardwareRequirementLevel.REQUIRED) {\n result.missingRequired.push(requirement)\n result.isCompatible = false\n } else {\n result.missingOptional.push(requirement)\n }\n }\n }\n\n return result\n }\n\n /**\n * Check if specific hardware is available in capabilities\n * @param hardwareType The type of hardware to check\n * @param capabilities The device capabilities\n * @returns true if hardware is available\n */\n private static checkHardwareAvailable(hardwareType: HardwareType, capabilities: Capabilities): boolean {\n if (hardwareType === HardwareType.EXIST) {\n if (capabilities.modelName === DeviceTypes.NONE) {\n return false\n }\n return true\n }\n\n switch (hardwareType) {\n case HardwareType.CAMERA:\n return capabilities.hasCamera\n\n case HardwareType.DISPLAY:\n return capabilities.hasDisplay\n\n case HardwareType.MICROPHONE:\n return capabilities.hasMicrophone\n\n case HardwareType.SPEAKER:\n return capabilities.hasSpeaker\n\n case HardwareType.IMU:\n return capabilities.hasIMU\n\n case HardwareType.BUTTON:\n return capabilities.hasButton\n\n case HardwareType.LIGHT:\n return capabilities.hasLight\n\n case HardwareType.WIFI:\n return capabilities.hasWifi\n\n default:\n // Unknown hardware type - assume not available\n return false\n }\n }\n\n /**\n * Get human-readable compatibility message\n * @param result The compatibility check result\n * @returns User-friendly message about compatibility\n */\n static getCompatibilityMessage(result: CompatibilityResult): string {\n if (result.isCompatible) {\n if (result.missingOptional.length > 0) {\n const optionalHardware = result.missingOptional.map((req) => req.type.toLowerCase()).join(\", \")\n return `This app works with your glasses but has optional features that require: ${optionalHardware}`\n }\n return \"This app is fully compatible with your glasses\"\n }\n\n const requiredHardware = result.missingRequired.map((req) => req.type.toLowerCase()).join(\", \")\n\n if (result.missingRequired.length === 1) {\n return `This app requires a ${requiredHardware} which is not available on your connected glasses`\n } else {\n return `This app requires the following hardware which is not available on your connected glasses: ${requiredHardware}`\n }\n }\n\n /**\n * Get detailed compatibility messages including descriptions\n * @param result The compatibility check result\n * @returns Array of detailed messages\n */\n static getDetailedMessages(result: CompatibilityResult): string[] {\n const messages: string[] = []\n\n // Add warnings first\n messages.push(...result.warnings)\n\n // Add missing required hardware\n for (const req of result.missingRequired) {\n let message = `❌ Missing required ${req.type.toLowerCase()}`\n if (req.description) {\n message += `: ${req.description}`\n }\n messages.push(message)\n }\n\n // Add missing optional hardware\n for (const req of result.missingOptional) {\n let message = `⚠️ Missing optional ${req.type.toLowerCase()}`\n if (req.description) {\n message += `: ${req.description}`\n }\n messages.push(message)\n }\n\n return messages\n }\n}\n"]}
1
+ {"version":3,"file":"hardware.js","sourceRoot":"","sources":["../../../src/utils/hardware/hardware.ts"],"names":[],"mappings":"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","sourcesContent":["import {Capabilities, DeviceTypes, HardwareRequirement, HardwareRequirementLevel, HardwareType, simulatedGlasses} from \"../../types\"\n\n/**\n * Result of a hardware compatibility check\n */\nexport interface CompatibilityResult {\n isCompatible: boolean\n missingRequired: HardwareRequirement[]\n missingOptional: HardwareRequirement[]\n warnings: string[]\n}\n\n/**\n * Service for checking hardware compatibility between apps and glasses\n */\nexport class HardwareCompatibility {\n /**\n * Check if app is compatible with given device capabilities\n * @param app The app to check\n * @param capabilities The device capabilities (null if no device connected)\n * @returns Detailed compatibility result\n */\n static checkCompatibility(\n hardwareRequirements: HardwareRequirement[],\n capabilities: Capabilities | null,\n ): CompatibilityResult {\n const result: CompatibilityResult = {\n isCompatible: true,\n missingRequired: [],\n missingOptional: [],\n warnings: [],\n }\n\n // If no hardware requirements specified, app is compatible with any hardware\n if (hardwareRequirements.length === 0) {\n return result\n }\n\n // If no capabilities available assume simulated glasses:\n if (!capabilities) {\n capabilities = simulatedGlasses\n }\n\n // Check each hardware requirement\n for (const requirement of hardwareRequirements) {\n const hasHardware = this.checkHardwareAvailable(requirement.type, capabilities!)\n if (!hasHardware) {\n if (requirement.level === HardwareRequirementLevel.REQUIRED) {\n result.missingRequired.push(requirement)\n result.isCompatible = false\n } else {\n result.missingOptional.push(requirement)\n }\n }\n }\n\n return result\n }\n\n /**\n * Check if specific hardware is available in capabilities\n * @param hardwareType The type of hardware to check\n * @param capabilities The device capabilities\n * @returns true if hardware is available\n */\n private static checkHardwareAvailable(hardwareType: HardwareType, capabilities: Capabilities): boolean {\n if (hardwareType === HardwareType.EXIST) {\n if (capabilities.modelName === DeviceTypes.NONE) {\n return false\n }\n return true\n }\n\n switch (hardwareType) {\n case HardwareType.CAMERA:\n return capabilities.hasCamera\n\n case HardwareType.DISPLAY:\n return capabilities.hasDisplay\n\n case HardwareType.MICROPHONE:\n // MentraOS always provides an audio-input path. When the connected\n // glasses do not have an onboard microphone, the engine falls back to\n // the phone microphone. Keep `capabilities.hasMicrophone` reserved for\n // physical-device/source selection; app compatibility is about whether\n // the requested input is available to the miniapp.\n return true\n\n case HardwareType.SPEAKER:\n return capabilities.hasSpeaker\n\n case HardwareType.IMU:\n return capabilities.hasIMU\n\n case HardwareType.BUTTON:\n return capabilities.hasButton\n\n case HardwareType.LIGHT:\n return capabilities.hasLight\n\n case HardwareType.WIFI:\n return capabilities.hasWifi\n\n default:\n // Unknown hardware type - assume not available\n return false\n }\n }\n\n /**\n * Get human-readable compatibility message\n * @param result The compatibility check result\n * @returns User-friendly message about compatibility\n */\n static getCompatibilityMessage(result: CompatibilityResult): string {\n if (result.isCompatible) {\n if (result.missingOptional.length > 0) {\n const optionalHardware = result.missingOptional.map((req) => req.type.toLowerCase()).join(\", \")\n return `This app works with your glasses but has optional features that require: ${optionalHardware}`\n }\n return \"This app is fully compatible with your glasses\"\n }\n\n const requiredHardware = result.missingRequired.map((req) => req.type.toLowerCase()).join(\", \")\n\n if (result.missingRequired.length === 1) {\n return `This app requires a ${requiredHardware} which is not available on your connected glasses`\n } else {\n return `This app requires the following hardware which is not available on your connected glasses: ${requiredHardware}`\n }\n }\n\n /**\n * Get detailed compatibility messages including descriptions\n * @param result The compatibility check result\n * @returns Array of detailed messages\n */\n static getDetailedMessages(result: CompatibilityResult): string[] {\n const messages: string[] = []\n\n // Add warnings first\n messages.push(...result.warnings)\n\n // Add missing required hardware\n for (const req of result.missingRequired) {\n let message = `❌ Missing required ${req.type.toLowerCase()}`\n if (req.description) {\n message += `: ${req.description}`\n }\n messages.push(message)\n }\n\n // Add missing optional hardware\n for (const req of result.missingOptional) {\n let message = `⚠️ Missing optional ${req.type.toLowerCase()}`\n if (req.description) {\n message += `: ${req.description}`\n }\n messages.push(message)\n }\n\n return messages\n }\n}\n"]}
@@ -0,0 +1,64 @@
1
+ import type { ClientApp } from "../types/applet";
2
+ export interface MiniappManifestSnapshot {
3
+ packageName: string;
4
+ name?: string;
5
+ version?: string;
6
+ sdkVersion?: string;
7
+ minHostVersion?: string;
8
+ type?: string;
9
+ entry?: {
10
+ background?: string;
11
+ ui?: string;
12
+ };
13
+ permissions: Array<{
14
+ type: string;
15
+ required?: boolean;
16
+ }>;
17
+ hardwareRequirements: Array<{
18
+ type: string;
19
+ level: string;
20
+ }>;
21
+ actionIds: string[];
22
+ }
23
+ export interface MiniappRuntimeAppSnapshot {
24
+ packageName: string;
25
+ handshakeComplete: boolean;
26
+ subscriptions: string[];
27
+ lastMessageAgeMs: number;
28
+ requestedLocationRate: string | null;
29
+ hasActiveSpeakerStream: boolean;
30
+ manifest?: MiniappManifestSnapshot;
31
+ }
32
+ export interface MiniappRuntimeDiagnosticSnapshot {
33
+ connectedApps: MiniappRuntimeAppSnapshot[];
34
+ subscriptionsByStream: Record<string, string[]>;
35
+ resources: {
36
+ display: Record<string, unknown>;
37
+ camera: Record<string, unknown>;
38
+ video: Record<string, unknown>;
39
+ stream: Record<string, unknown>;
40
+ cameraFov: Record<string, unknown>;
41
+ };
42
+ }
43
+ type ManifestFallback = {
44
+ packageName: string;
45
+ name?: string;
46
+ version?: string;
47
+ type?: string;
48
+ };
49
+ /**
50
+ * Keep the routing/build fields from miniapp.json while excluding arbitrary
51
+ * free-form manifest content from reports. Descriptions, URLs, and unknown
52
+ * extension fields are intentionally omitted.
53
+ */
54
+ export declare function buildMiniappManifestSnapshot(raw: unknown, fallback: ManifestFallback): MiniappManifestSnapshot;
55
+ export declare function buildMiniappDiagnosticContext(input: {
56
+ apps: ClientApp[];
57
+ foregroundedPackage: string | null;
58
+ runtime: MiniappRuntimeDiagnosticSnapshot;
59
+ getLastOpenedAtMs: (app: ClientApp) => number;
60
+ getManifest: (app: ClientApp) => unknown;
61
+ getReleaseIdentity: (app: ClientApp) => unknown;
62
+ }): Record<string, unknown>;
63
+ export {};
64
+ //# sourceMappingURL=miniappDiagnostics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"miniappDiagnostics.d.ts","sourceRoot":"","sources":["../../src/utils/miniappDiagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAA;AAM9C,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE;QACN,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,EAAE,CAAC,EAAE,MAAM,CAAA;KACZ,CAAA;IACD,WAAW,EAAE,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAC,CAAC,CAAA;IACtD,oBAAoB,EAAE,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CAAC,CAAA;IAC1D,SAAS,EAAE,MAAM,EAAE,CAAA;CACpB;AAED,MAAM,WAAW,yBAAyB;IACxC,WAAW,EAAE,MAAM,CAAA;IACnB,iBAAiB,EAAE,OAAO,CAAA;IAC1B,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,gBAAgB,EAAE,MAAM,CAAA;IACxB,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAA;IACpC,sBAAsB,EAAE,OAAO,CAAA;IAC/B,QAAQ,CAAC,EAAE,uBAAuB,CAAA;CACnC;AAED,MAAM,WAAW,gCAAgC;IAC/C,aAAa,EAAE,yBAAyB,EAAE,CAAA;IAC1C,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;IAC/C,SAAS,EAAE;QACT,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAChC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC/B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC/B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KACnC,CAAA;CACF;AAED,KAAK,gBAAgB,GAAG;IACtB,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAsDD;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,gBAAgB,GAAG,uBAAuB,CAsB9G;AAoBD,wBAAgB,6BAA6B,CAAC,KAAK,EAAE;IACnD,IAAI,EAAE,SAAS,EAAE,CAAA;IACjB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,OAAO,EAAE,gCAAgC,CAAA;IACzC,iBAAiB,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,MAAM,CAAA;IAC7C,WAAW,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,OAAO,CAAA;IACxC,kBAAkB,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,OAAO,CAAA;CAChD,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAoE1B"}