@glassly/engine 0.1.0-dev.99 → 0.2.8-dev.445

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 (501) hide show
  1. package/README.md +28 -0
  2. package/build/engine.d.ts +32 -10
  3. package/build/engine.d.ts.map +1 -1
  4. package/build/engine.js +24 -16
  5. package/build/engine.js.map +1 -1
  6. package/build/facades/dev.d.ts +9 -0
  7. package/build/facades/dev.d.ts.map +1 -1
  8. package/build/facades/dev.js +9 -0
  9. package/build/facades/dev.js.map +1 -1
  10. package/build/facades/display.d.ts +10 -3
  11. package/build/facades/display.d.ts.map +1 -1
  12. package/build/facades/display.js +22 -8
  13. package/build/facades/display.js.map +1 -1
  14. package/build/facades/displayMirror.d.ts +11 -0
  15. package/build/facades/displayMirror.d.ts.map +1 -1
  16. package/build/facades/displayMirror.js +22 -0
  17. package/build/facades/displayMirror.js.map +1 -1
  18. package/build/facades/glasses.d.ts +31 -1
  19. package/build/facades/glasses.d.ts.map +1 -1
  20. package/build/facades/glasses.js +51 -0
  21. package/build/facades/glasses.js.map +1 -1
  22. package/build/facades/memory.d.ts +0 -6
  23. package/build/facades/memory.d.ts.map +1 -1
  24. package/build/facades/memory.js +1 -9
  25. package/build/facades/memory.js.map +1 -1
  26. package/build/facades/miniapps.d.ts +3 -1
  27. package/build/facades/miniapps.d.ts.map +1 -1
  28. package/build/facades/miniapps.js +3 -1
  29. package/build/facades/miniapps.js.map +1 -1
  30. package/build/facades/pairing.d.ts.map +1 -1
  31. package/build/facades/pairing.js +5 -4
  32. package/build/facades/pairing.js.map +1 -1
  33. package/build/facades/permissions.d.ts +2 -0
  34. package/build/facades/permissions.d.ts.map +1 -1
  35. package/build/facades/permissions.js +48 -0
  36. package/build/facades/permissions.js.map +1 -1
  37. package/build/facades/phoneNotifications.d.ts +20 -9
  38. package/build/facades/phoneNotifications.d.ts.map +1 -1
  39. package/build/facades/phoneNotifications.js +33 -26
  40. package/build/facades/phoneNotifications.js.map +1 -1
  41. package/build/facades/settings.d.ts.map +1 -1
  42. package/build/facades/settings.js +1 -2
  43. package/build/facades/settings.js.map +1 -1
  44. package/build/generated/releaseMetadata.js +4 -4
  45. package/build/generated/releaseMetadata.js.map +1 -1
  46. package/build/index.d.ts +6 -4
  47. package/build/index.d.ts.map +1 -1
  48. package/build/index.js +5 -4
  49. package/build/index.js.map +1 -1
  50. package/build/react/MentraLiveOtaFlow.js +2 -2
  51. package/build/react/MentraLiveOtaFlow.js.map +1 -1
  52. package/build/react/useMentraLiveOta.d.ts.map +1 -1
  53. package/build/react/useMentraLiveOta.js +8 -7
  54. package/build/react/useMentraLiveOta.js.map +1 -1
  55. package/build/runtime/config.d.ts +1 -1
  56. package/build/runtime/config.d.ts.map +1 -1
  57. package/build/runtime/config.js.map +1 -1
  58. package/build/services/AppRegistry.d.ts +4 -1
  59. package/build/services/AppRegistry.d.ts.map +1 -1
  60. package/build/services/AppRegistry.js +21 -1
  61. package/build/services/AppRegistry.js.map +1 -1
  62. package/build/services/BlobStore.d.ts +2 -2
  63. package/build/services/BlobStore.js +3 -3
  64. package/build/services/BlobStore.js.map +1 -1
  65. package/build/services/CloudClientService.d.ts +7 -3
  66. package/build/services/CloudClientService.d.ts.map +1 -1
  67. package/build/services/CloudClientService.js +34 -9
  68. package/build/services/CloudClientService.js.map +1 -1
  69. package/build/services/DevServerBridge.d.ts +1 -18
  70. package/build/services/DevServerBridge.d.ts.map +1 -1
  71. package/build/services/DevServerBridge.js +9 -8
  72. package/build/services/DevServerBridge.js.map +1 -1
  73. package/build/services/DeviceEventRouter.d.ts.map +1 -1
  74. package/build/services/DeviceEventRouter.js +58 -71
  75. package/build/services/DeviceEventRouter.js.map +1 -1
  76. package/build/services/DisplayDiagnostics.d.ts +5 -0
  77. package/build/services/DisplayDiagnostics.d.ts.map +1 -0
  78. package/build/services/DisplayDiagnostics.js +105 -0
  79. package/build/services/DisplayDiagnostics.js.map +1 -0
  80. package/build/services/DisplayProcessor.d.ts +6 -7
  81. package/build/services/DisplayProcessor.d.ts.map +1 -1
  82. package/build/services/DisplayProcessor.js +17 -45
  83. package/build/services/DisplayProcessor.js.map +1 -1
  84. package/build/services/GestureDotsService.d.ts +10 -4
  85. package/build/services/GestureDotsService.d.ts.map +1 -1
  86. package/build/services/GestureDotsService.js +70 -16
  87. package/build/services/GestureDotsService.js.map +1 -1
  88. package/build/services/GlassesKeyboardInput.d.ts +77 -0
  89. package/build/services/GlassesKeyboardInput.d.ts.map +1 -0
  90. package/build/services/GlassesKeyboardInput.js +261 -0
  91. package/build/services/GlassesKeyboardInput.js.map +1 -0
  92. package/build/services/GlassesSensorService.d.ts +47 -0
  93. package/build/services/GlassesSensorService.d.ts.map +1 -0
  94. package/build/services/GlassesSensorService.js +242 -0
  95. package/build/services/GlassesSensorService.js.map +1 -0
  96. package/build/services/GlassesTouchInput.d.ts +14 -0
  97. package/build/services/GlassesTouchInput.d.ts.map +1 -0
  98. package/build/services/GlassesTouchInput.js +107 -0
  99. package/build/services/GlassesTouchInput.js.map +1 -0
  100. package/build/services/HeadingService.d.ts +0 -6
  101. package/build/services/HeadingService.d.ts.map +1 -1
  102. package/build/services/HeadingService.js +0 -27
  103. package/build/services/HeadingService.js.map +1 -1
  104. package/build/services/HotspotShutdown.d.ts.map +1 -1
  105. package/build/services/HotspotShutdown.js +2 -1
  106. package/build/services/HotspotShutdown.js.map +1 -1
  107. package/build/services/JSCrashloopReportService.js +2 -2
  108. package/build/services/JSCrashloopReportService.js.map +1 -1
  109. package/build/services/JSRouter.d.ts +6 -4
  110. package/build/services/JSRouter.d.ts.map +1 -1
  111. package/build/services/JSRouter.js +15 -13
  112. package/build/services/JSRouter.js.map +1 -1
  113. package/build/services/LocalDisplayManager.d.ts +35 -7
  114. package/build/services/LocalDisplayManager.d.ts.map +1 -1
  115. package/build/services/LocalDisplayManager.js +105 -27
  116. package/build/services/LocalDisplayManager.js.map +1 -1
  117. package/build/services/LocalMiniappDataMigration.d.ts +1 -1
  118. package/build/services/LocalMiniappDataMigration.js +1 -1
  119. package/build/services/LocalMiniappDataMigration.js.map +1 -1
  120. package/build/services/LocalMiniappRuntime.d.ts +64 -11
  121. package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
  122. package/build/services/LocalMiniappRuntime.js +441 -35
  123. package/build/services/LocalMiniappRuntime.js.map +1 -1
  124. package/build/services/LocalSttFallbackCoordinator.d.ts +3 -0
  125. package/build/services/LocalSttFallbackCoordinator.d.ts.map +1 -1
  126. package/build/services/LocalSttFallbackCoordinator.js +27 -8
  127. package/build/services/LocalSttFallbackCoordinator.js.map +1 -1
  128. package/build/services/MemoryStore.d.ts +8 -33
  129. package/build/services/MemoryStore.d.ts.map +1 -1
  130. package/build/services/MemoryStore.js +30 -56
  131. package/build/services/MemoryStore.js.map +1 -1
  132. package/build/services/MiniappEngine.d.ts +3 -3
  133. package/build/services/MiniappEngine.js +7 -7
  134. package/build/services/MiniappEngine.js.map +1 -1
  135. package/build/services/MiniappLauncher.d.ts +8 -0
  136. package/build/services/MiniappLauncher.d.ts.map +1 -1
  137. package/build/services/MiniappLauncher.js +19 -1
  138. package/build/services/MiniappLauncher.js.map +1 -1
  139. package/build/services/MirrorService.d.ts +24 -0
  140. package/build/services/MirrorService.d.ts.map +1 -0
  141. package/build/services/MirrorService.js +132 -0
  142. package/build/services/MirrorService.js.map +1 -0
  143. package/build/services/NativeNavigationService.d.ts +2 -3
  144. package/build/services/NativeNavigationService.d.ts.map +1 -1
  145. package/build/services/NativeNavigationService.js +24 -21
  146. package/build/services/NativeNavigationService.js.map +1 -1
  147. package/build/services/NavigationHandlers.d.ts.map +1 -1
  148. package/build/services/NavigationHandlers.js +10 -5
  149. package/build/services/NavigationHandlers.js.map +1 -1
  150. package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
  151. package/build/services/OtaInstallCoordinator.js +24 -23
  152. package/build/services/OtaInstallCoordinator.js.map +1 -1
  153. package/build/services/PairedGlassesLatch.d.ts +7 -0
  154. package/build/services/PairedGlassesLatch.d.ts.map +1 -0
  155. package/build/services/PairedGlassesLatch.js +38 -0
  156. package/build/services/PairedGlassesLatch.js.map +1 -0
  157. package/build/services/PhoneActivity.d.ts +23 -0
  158. package/build/services/PhoneActivity.d.ts.map +1 -0
  159. package/build/services/PhoneActivity.js +111 -0
  160. package/build/services/PhoneActivity.js.map +1 -0
  161. package/build/services/PhoneCameraFovCoordinator.d.ts.map +1 -1
  162. package/build/services/PhoneCameraFovCoordinator.js +4 -3
  163. package/build/services/PhoneCameraFovCoordinator.js.map +1 -1
  164. package/build/services/PhoneNotificationsSync.d.ts +40 -6
  165. package/build/services/PhoneNotificationsSync.d.ts.map +1 -1
  166. package/build/services/PhoneNotificationsSync.js +160 -84
  167. package/build/services/PhoneNotificationsSync.js.map +1 -1
  168. package/build/services/PhonePhotoCoordinator.d.ts.map +1 -1
  169. package/build/services/PhonePhotoCoordinator.js +6 -5
  170. package/build/services/PhonePhotoCoordinator.js.map +1 -1
  171. package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
  172. package/build/services/PhoneStreamCoordinator.js +8 -7
  173. package/build/services/PhoneStreamCoordinator.js.map +1 -1
  174. package/build/services/STTModelManager.d.ts +3 -0
  175. package/build/services/STTModelManager.d.ts.map +1 -1
  176. package/build/services/STTModelManager.js +15 -1
  177. package/build/services/STTModelManager.js.map +1 -1
  178. package/build/services/SceneRenderer.d.ts +43 -2
  179. package/build/services/SceneRenderer.d.ts.map +1 -1
  180. package/build/services/SceneRenderer.js +123 -8
  181. package/build/services/SceneRenderer.js.map +1 -1
  182. package/build/services/StreamLifecycleController.d.ts.map +1 -1
  183. package/build/services/StreamLifecycleController.js +6 -14
  184. package/build/services/StreamLifecycleController.js.map +1 -1
  185. package/build/services/TTSModelManager.js +1 -1
  186. package/build/services/TTSModelManager.js.map +1 -1
  187. package/build/services/UIRouter.d.ts +2 -2
  188. package/build/services/UIRouter.js +5 -5
  189. package/build/services/UIRouter.js.map +1 -1
  190. package/build/services/asg/galleryPathMigration.js +1 -1
  191. package/build/services/asg/galleryPathMigration.js.map +1 -1
  192. package/build/services/asg/gallerySyncService.js +2 -2
  193. package/build/services/asg/gallerySyncService.js.map +1 -1
  194. package/build/services/asg/localStorageService.d.ts.map +1 -1
  195. package/build/services/asg/localStorageService.js +3 -3
  196. package/build/services/asg/localStorageService.js.map +1 -1
  197. package/build/services/debug/DashboardOpenTrace.d.ts +32 -0
  198. package/build/services/debug/DashboardOpenTrace.d.ts.map +1 -0
  199. package/build/services/debug/DashboardOpenTrace.js +128 -0
  200. package/build/services/debug/DashboardOpenTrace.js.map +1 -0
  201. package/build/services/debug/dashboardOpenTimeline.d.ts +77 -0
  202. package/build/services/debug/dashboardOpenTimeline.d.ts.map +1 -0
  203. package/build/services/debug/dashboardOpenTimeline.js +195 -0
  204. package/build/services/debug/dashboardOpenTimeline.js.map +1 -0
  205. package/build/services/effectiveCapabilities.d.ts.map +1 -1
  206. package/build/services/effectiveCapabilities.js +25 -13
  207. package/build/services/effectiveCapabilities.js.map +1 -1
  208. package/build/services/gestureClaims.d.ts +34 -15
  209. package/build/services/gestureClaims.d.ts.map +1 -1
  210. package/build/services/gestureClaims.js +42 -21
  211. package/build/services/gestureClaims.js.map +1 -1
  212. package/build/services/manifestFields.d.ts +9 -0
  213. package/build/services/manifestFields.d.ts.map +1 -0
  214. package/build/services/manifestFields.js +26 -0
  215. package/build/services/manifestFields.js.map +1 -0
  216. package/build/services/memoryStoreInstance.d.ts +0 -10
  217. package/build/services/memoryStoreInstance.d.ts.map +1 -1
  218. package/build/services/memoryStoreInstance.js +2 -31
  219. package/build/services/memoryStoreInstance.js.map +1 -1
  220. package/build/services/mirrorSnapshot.d.ts +16 -0
  221. package/build/services/mirrorSnapshot.d.ts.map +1 -0
  222. package/build/services/mirrorSnapshot.js +102 -0
  223. package/build/services/mirrorSnapshot.js.map +1 -0
  224. package/build/services/nativeNavigationGate.d.ts +8 -0
  225. package/build/services/nativeNavigationGate.d.ts.map +1 -0
  226. package/build/services/nativeNavigationGate.js +12 -0
  227. package/build/services/nativeNavigationGate.js.map +1 -0
  228. package/build/services/notificationAppCatalog.d.ts +7 -0
  229. package/build/services/notificationAppCatalog.d.ts.map +1 -0
  230. package/build/services/notificationAppCatalog.js +16 -0
  231. package/build/services/notificationAppCatalog.js.map +1 -0
  232. package/build/services/notifications/notificationPolicy.d.ts +55 -0
  233. package/build/services/notifications/notificationPolicy.d.ts.map +1 -0
  234. package/build/services/notifications/notificationPolicy.js +41 -0
  235. package/build/services/notifications/notificationPolicy.js.map +1 -0
  236. package/build/services/pages/OverlayPages.d.ts +26 -0
  237. package/build/services/pages/OverlayPages.d.ts.map +1 -0
  238. package/build/services/pages/OverlayPages.js +80 -0
  239. package/build/services/pages/OverlayPages.js.map +1 -0
  240. package/build/services/pages/PageHost.d.ts +32 -0
  241. package/build/services/pages/PageHost.d.ts.map +1 -0
  242. package/build/services/pages/PageHost.js +99 -0
  243. package/build/services/pages/PageHost.js.map +1 -0
  244. package/build/services/pages/overlayApps.d.ts +25 -0
  245. package/build/services/pages/overlayApps.d.ts.map +1 -0
  246. package/build/services/pages/overlayApps.js +66 -0
  247. package/build/services/pages/overlayApps.js.map +1 -0
  248. package/build/services/pages/pageEligibility.d.ts +9 -0
  249. package/build/services/pages/pageEligibility.d.ts.map +1 -0
  250. package/build/services/pages/pageEligibility.js +27 -0
  251. package/build/services/pages/pageEligibility.js.map +1 -0
  252. package/build/services/settingsBridge.d.ts +58 -0
  253. package/build/services/settingsBridge.d.ts.map +1 -0
  254. package/build/services/settingsBridge.js +90 -0
  255. package/build/services/settingsBridge.js.map +1 -0
  256. package/build/services/speakerProfileStoreInstance.js +1 -1
  257. package/build/services/speakerProfileStoreInstance.js.map +1 -1
  258. package/build/services/uiShim.d.ts +1 -1
  259. package/build/services/uiShim.js +4 -4
  260. package/build/services/uiShim.js.map +1 -1
  261. package/build/stores/appVisibility.d.ts +28 -0
  262. package/build/stores/appVisibility.d.ts.map +1 -1
  263. package/build/stores/appVisibility.js +34 -0
  264. package/build/stores/appVisibility.js.map +1 -1
  265. package/build/stores/apps.d.ts +13 -0
  266. package/build/stores/apps.d.ts.map +1 -1
  267. package/build/stores/apps.js +66 -12
  268. package/build/stores/apps.js.map +1 -1
  269. package/build/stores/bluetoothSettingKeys.js +1 -1
  270. package/build/stores/bluetoothSettingKeys.js.map +1 -1
  271. package/build/stores/display.d.ts +3 -3
  272. package/build/stores/display.d.ts.map +1 -1
  273. package/build/stores/display.js +16 -4
  274. package/build/stores/display.js.map +1 -1
  275. package/build/stores/glasses.d.ts.map +1 -1
  276. package/build/stores/glasses.js +14 -1
  277. package/build/stores/glasses.js.map +1 -1
  278. package/build/stores/settings.d.ts +1 -0
  279. package/build/stores/settings.d.ts.map +1 -1
  280. package/build/stores/settings.js +170 -44
  281. package/build/stores/settings.js.map +1 -1
  282. package/build/types/applet.d.ts +14 -1
  283. package/build/types/applet.d.ts.map +1 -1
  284. package/build/types/applet.js.map +1 -1
  285. package/build/types/capabilities/even-realities-g2.d.ts.map +1 -1
  286. package/build/types/capabilities/even-realities-g2.js +5 -0
  287. package/build/types/capabilities/even-realities-g2.js.map +1 -1
  288. package/build/types/capabilities/simulated-glasses.d.ts +1 -1
  289. package/build/types/capabilities/simulated-glasses.d.ts.map +1 -1
  290. package/build/types/capabilities/simulated-glasses.js +7 -4
  291. package/build/types/capabilities/simulated-glasses.js.map +1 -1
  292. package/build/types/hardware.d.ts +20 -1
  293. package/build/types/hardware.d.ts.map +1 -1
  294. package/build/types/hardware.js +2 -0
  295. package/build/types/hardware.js.map +1 -1
  296. package/build/types/index.d.ts +1 -0
  297. package/build/types/index.d.ts.map +1 -1
  298. package/build/types/index.js +1 -0
  299. package/build/types/index.js.map +1 -1
  300. package/build/utils/debouncedPatch.d.ts +3 -1
  301. package/build/utils/debouncedPatch.d.ts.map +1 -1
  302. package/build/utils/debouncedPatch.js +6 -3
  303. package/build/utils/debouncedPatch.js.map +1 -1
  304. package/build/utils/devMiniappLaunch.d.ts.map +1 -1
  305. package/build/utils/devMiniappLaunch.js +4 -3
  306. package/build/utils/devMiniappLaunch.js.map +1 -1
  307. package/build/utils/display/measurer/TextMeasurer.d.ts +2 -159
  308. package/build/utils/display/measurer/TextMeasurer.d.ts.map +1 -1
  309. package/build/utils/display/measurer/TextMeasurer.js +2 -272
  310. package/build/utils/display/measurer/TextMeasurer.js.map +1 -1
  311. package/build/utils/display/measurer/script-detection.d.ts +1 -52
  312. package/build/utils/display/measurer/script-detection.d.ts.map +1 -1
  313. package/build/utils/display/measurer/script-detection.js +2 -183
  314. package/build/utils/display/measurer/script-detection.js.map +1 -1
  315. package/build/utils/display/pixelArt.d.ts +3 -0
  316. package/build/utils/display/pixelArt.d.ts.map +1 -0
  317. package/build/utils/display/pixelArt.js +3 -0
  318. package/build/utils/display/pixelArt.js.map +1 -0
  319. package/build/utils/display/profiles/g1.d.ts +1 -32
  320. package/build/utils/display/profiles/g1.d.ts.map +1 -1
  321. package/build/utils/display/profiles/g1.js +2 -212
  322. package/build/utils/display/profiles/g1.js.map +1 -1
  323. package/build/utils/display/profiles/g2.d.ts +1 -12
  324. package/build/utils/display/profiles/g2.d.ts.map +1 -1
  325. package/build/utils/display/profiles/g2.js +2 -33
  326. package/build/utils/display/profiles/g2.js.map +1 -1
  327. package/build/utils/display/profiles/nex.d.ts +1 -9
  328. package/build/utils/display/profiles/nex.d.ts.map +1 -1
  329. package/build/utils/display/profiles/nex.js +2 -149
  330. package/build/utils/display/profiles/nex.js.map +1 -1
  331. package/build/utils/display/profiles/types.d.ts +1 -102
  332. package/build/utils/display/profiles/types.d.ts.map +1 -1
  333. package/build/utils/display/profiles/types.js.map +1 -1
  334. package/build/utils/display/profiles/z100.d.ts +1 -32
  335. package/build/utils/display/profiles/z100.d.ts.map +1 -1
  336. package/build/utils/display/profiles/z100.js +2 -181
  337. package/build/utils/display/profiles/z100.js.map +1 -1
  338. package/build/utils/display/scene/degrade.d.ts.map +1 -1
  339. package/build/utils/display/scene/degrade.js +4 -1
  340. package/build/utils/display/scene/degrade.js.map +1 -1
  341. package/build/utils/display/scene/differ.d.ts +13 -1
  342. package/build/utils/display/scene/differ.d.ts.map +1 -1
  343. package/build/utils/display/scene/differ.js +22 -0
  344. package/build/utils/display/scene/differ.js.map +1 -1
  345. package/build/utils/display/scene/index.d.ts +1 -1
  346. package/build/utils/display/scene/index.d.ts.map +1 -1
  347. package/build/utils/display/scene/index.js.map +1 -1
  348. package/build/utils/display/scene/process.d.ts.map +1 -1
  349. package/build/utils/display/scene/process.js +183 -11
  350. package/build/utils/display/scene/process.js.map +1 -1
  351. package/build/utils/display/scene/store.d.ts +1 -1
  352. package/build/utils/display/scene/store.d.ts.map +1 -1
  353. package/build/utils/display/scene/store.js +0 -0
  354. package/build/utils/display/scene/store.js.map +1 -1
  355. package/build/utils/display/scene/svgPath.d.ts +9 -0
  356. package/build/utils/display/scene/svgPath.d.ts.map +1 -0
  357. package/build/utils/display/scene/svgPath.js +167 -0
  358. package/build/utils/display/scene/svgPath.js.map +1 -0
  359. package/build/utils/display/scene/types.d.ts +2 -142
  360. package/build/utils/display/scene/types.d.ts.map +1 -1
  361. package/build/utils/display/scene/types.js +0 -0
  362. package/build/utils/display/scene/types.js.map +1 -1
  363. package/build/utils/display/wrapper/TextWrapper.d.ts +1 -101
  364. package/build/utils/display/wrapper/TextWrapper.d.ts.map +1 -1
  365. package/build/utils/display/wrapper/TextWrapper.js +2 -470
  366. package/build/utils/display/wrapper/TextWrapper.js.map +1 -1
  367. package/build/utils/display/wrapper/types.d.ts +2 -74
  368. package/build/utils/display/wrapper/types.d.ts.map +1 -1
  369. package/build/utils/display/wrapper/types.js +2 -10
  370. package/build/utils/display/wrapper/types.js.map +1 -1
  371. package/build/utils/hardware/hardware.js +1 -1
  372. package/build/utils/hardware/hardware.js.map +1 -1
  373. package/build/utils/timers/timers.d.ts.map +1 -1
  374. package/build/utils/timers/timers.js +26 -4
  375. package/build/utils/timers/timers.js.map +1 -1
  376. package/package.json +8 -8
  377. package/src/engine.ts +24 -15
  378. package/src/facades/dev.ts +10 -0
  379. package/src/facades/display.ts +21 -8
  380. package/src/facades/displayMirror.ts +29 -0
  381. package/src/facades/glasses.ts +61 -1
  382. package/src/facades/memory.ts +1 -12
  383. package/src/facades/miniapps.ts +4 -1
  384. package/src/facades/pairing.ts +8 -6
  385. package/src/facades/permissions.ts +46 -0
  386. package/src/facades/phoneNotifications.ts +45 -26
  387. package/src/facades/settings.ts +1 -2
  388. package/src/generated/releaseMetadata.ts +4 -4
  389. package/src/index.ts +6 -9
  390. package/src/react/MentraLiveOtaFlow.tsx +2 -2
  391. package/src/react/useMentraLiveOta.ts +14 -8
  392. package/src/runtime/config.ts +1 -1
  393. package/src/services/AppRegistry.ts +43 -7
  394. package/src/services/BlobStore.ts +3 -3
  395. package/src/services/CloudClientService.ts +37 -10
  396. package/src/services/DevServerBridge.ts +12 -10
  397. package/src/services/DeviceEventRouter.ts +73 -74
  398. package/src/services/DisplayDiagnostics.ts +107 -0
  399. package/src/services/DisplayProcessor.ts +20 -55
  400. package/src/services/GestureDotsService.ts +77 -16
  401. package/src/services/GlassesKeyboardInput.ts +306 -0
  402. package/src/services/GlassesSensorService.ts +233 -0
  403. package/src/services/GlassesTouchInput.ts +128 -0
  404. package/src/services/HeadingService.ts +0 -24
  405. package/src/services/HotspotShutdown.ts +3 -1
  406. package/src/services/JSCrashloopReportService.ts +2 -2
  407. package/src/services/JSRouter.ts +29 -14
  408. package/src/services/LocalDisplayManager.ts +112 -26
  409. package/src/services/LocalMiniappDataMigration.ts +1 -1
  410. package/src/services/LocalMiniappRuntime.ts +500 -43
  411. package/src/services/LocalSttFallbackCoordinator.ts +28 -7
  412. package/src/services/MemoryStore.ts +32 -80
  413. package/src/services/MiniappEngine.ts +7 -7
  414. package/src/services/MiniappLauncher.ts +25 -1
  415. package/src/services/MirrorService.ts +139 -0
  416. package/src/services/NativeNavigationService.ts +29 -25
  417. package/src/services/NavigationHandlers.ts +10 -5
  418. package/src/services/OtaInstallCoordinator.ts +36 -34
  419. package/src/services/PairedGlassesLatch.ts +39 -0
  420. package/src/services/PhoneActivity.ts +116 -0
  421. package/src/services/PhoneCameraFovCoordinator.ts +6 -4
  422. package/src/services/PhoneNotificationsSync.ts +185 -103
  423. package/src/services/PhonePhotoCoordinator.ts +9 -10
  424. package/src/services/PhoneStreamCoordinator.ts +13 -11
  425. package/src/services/STTModelManager.ts +15 -1
  426. package/src/services/SceneRenderer.ts +148 -10
  427. package/src/services/StreamLifecycleController.ts +9 -7
  428. package/src/services/TTSModelManager.ts +1 -1
  429. package/src/services/UIRouter.ts +5 -5
  430. package/src/services/asg/galleryPathMigration.ts +1 -1
  431. package/src/services/asg/gallerySyncService.ts +2 -2
  432. package/src/services/asg/localStorageService.ts +3 -3
  433. package/src/services/debug/DashboardOpenTrace.ts +153 -0
  434. package/src/services/debug/dashboardOpenTimeline.ts +237 -0
  435. package/src/services/effectiveCapabilities.ts +32 -13
  436. package/src/services/gestureClaims.ts +72 -23
  437. package/src/services/manifestFields.ts +23 -0
  438. package/src/services/memoryStoreInstance.ts +2 -34
  439. package/src/services/mirrorSnapshot.ts +116 -0
  440. package/src/services/nativeNavigationGate.ts +14 -0
  441. package/src/services/notificationAppCatalog.ts +21 -0
  442. package/src/services/notifications/notificationPolicy.ts +87 -0
  443. package/src/services/pages/OverlayPages.ts +86 -0
  444. package/src/services/pages/PageHost.ts +116 -0
  445. package/src/services/pages/overlayApps.ts +72 -0
  446. package/src/services/pages/pageEligibility.ts +30 -0
  447. package/src/services/settingsBridge.ts +111 -0
  448. package/src/services/speakerProfileStoreInstance.ts +1 -1
  449. package/src/services/uiShim.ts +4 -4
  450. package/src/stores/appVisibility.ts +45 -0
  451. package/src/stores/apps.ts +110 -32
  452. package/src/stores/bluetoothSettingKeys.ts +1 -1
  453. package/src/stores/display.ts +18 -7
  454. package/src/stores/glasses.ts +15 -1
  455. package/src/stores/settings.ts +175 -51
  456. package/src/types/applet.ts +14 -1
  457. package/src/types/capabilities/even-realities-g2.ts +6 -0
  458. package/src/types/capabilities/simulated-glasses.ts +8 -4
  459. package/src/types/hardware.ts +34 -1
  460. package/src/types/index.ts +1 -0
  461. package/src/utils/debouncedPatch.ts +8 -4
  462. package/src/utils/devMiniappLaunch.ts +5 -3
  463. package/src/utils/display/measurer/TextMeasurer.ts +3 -346
  464. package/src/utils/display/measurer/script-detection.ts +10 -218
  465. package/src/utils/display/pixelArt.ts +3 -0
  466. package/src/utils/display/profiles/g1.ts +2 -236
  467. package/src/utils/display/profiles/g2.ts +2 -39
  468. package/src/utils/display/profiles/nex.ts +2 -166
  469. package/src/utils/display/profiles/types.ts +9 -132
  470. package/src/utils/display/profiles/z100.ts +2 -198
  471. package/src/utils/display/scene/degrade.ts +4 -1
  472. package/src/utils/display/scene/differ.ts +25 -1
  473. package/src/utils/display/scene/index.ts +5 -0
  474. package/src/utils/display/scene/process.ts +196 -13
  475. package/src/utils/display/scene/store.ts +0 -0
  476. package/src/utils/display/scene/svgPath.ts +163 -0
  477. package/src/utils/display/scene/types.ts +0 -0
  478. package/src/utils/display/wrapper/TextWrapper.ts +2 -546
  479. package/src/utils/display/wrapper/types.ts +3 -102
  480. package/src/utils/hardware/hardware.ts +1 -1
  481. package/src/utils/timers/timers.ts +32 -4
  482. package/build/services/CustomDashboardModel.d.ts +0 -48
  483. package/build/services/CustomDashboardModel.d.ts.map +0 -1
  484. package/build/services/CustomDashboardModel.js +0 -73
  485. package/build/services/CustomDashboardModel.js.map +0 -1
  486. package/build/services/CustomDashboardService.d.ts +0 -63
  487. package/build/services/CustomDashboardService.d.ts.map +0 -1
  488. package/build/services/CustomDashboardService.js +0 -576
  489. package/build/services/CustomDashboardService.js.map +0 -1
  490. package/build/services/DashboardCoordinator.d.ts +0 -26
  491. package/build/services/DashboardCoordinator.d.ts.map +0 -1
  492. package/build/services/DashboardCoordinator.js +0 -125
  493. package/build/services/DashboardCoordinator.js.map +0 -1
  494. package/build/services/iosNotificationAppCatalog.d.ts +0 -13
  495. package/build/services/iosNotificationAppCatalog.d.ts.map +0 -1
  496. package/build/services/iosNotificationAppCatalog.js +0 -28
  497. package/build/services/iosNotificationAppCatalog.js.map +0 -1
  498. package/src/services/CustomDashboardModel.ts +0 -83
  499. package/src/services/CustomDashboardService.ts +0 -598
  500. package/src/services/DashboardCoordinator.ts +0 -121
  501. package/src/services/iosNotificationAppCatalog.ts +0 -39
@@ -58,7 +58,7 @@ export class HardwareCompatibility {
58
58
  case HardwareType.DISPLAY:
59
59
  return capabilities.hasDisplay;
60
60
  case HardwareType.MICROPHONE:
61
- // GlasslyOS always provides an audio-input path. When the connected
61
+ // Glassly always provides an audio-input path. When the connected
62
62
  // glasses do not have an onboard microphone, the engine falls back to
63
63
  // the phone microphone. Keep `capabilities.hasMicrophone` reserved for
64
64
  // physical-device/source selection; app compatibility is about whether
@@ -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 simulatedGlasses,\n} 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 // GlasslyOS 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"]}
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 simulatedGlasses,\n} 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 // Glassly 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"]}
@@ -1 +1 @@
1
- {"version":3,"file":"timers.d.ts","sourceRoot":"","sources":["../../../src/utils/timers/timers.ts"],"names":[],"mappings":"AAwHA,qBAAa,OAAO;IAClB,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAO/D,MAAM,CAAC,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAO9C,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAO9D,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;CAM7C;AAED,wBAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,CAU/G;AAED,wBAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,CAY/G"}
1
+ {"version":3,"file":"timers.d.ts","sourceRoot":"","sources":["../../../src/utils/timers/timers.ts"],"names":[],"mappings":"AAoJA,qBAAa,OAAO;IAClB,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAO/D,MAAM,CAAC,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAO9C,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAO9D,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;CAM7C;AAED,wBAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,CAU/G;AAED,wBAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,CAY/G"}
@@ -21,7 +21,29 @@
21
21
  // https://github.com/tconns/react-native-nitro-bg-timer/issues/2. iOS
22
22
  // suspends the whole process in background anyway, so background timing
23
23
  // there is handled by native per-device queues, not JS timers.
24
- import { Alert, Platform } from "react-native";
24
+ //
25
+ // react-native is loaded lazily, not imported. Every engine service runs its
26
+ // timers through this module, and the engine's bun test suites load those
27
+ // services in a plain JS runtime that cannot parse react-native's Flow
28
+ // source. A static import would force every such suite to mock this module;
29
+ // with the lazy load, a runtime without react-native simply gets the JS
30
+ // timers, which is the correct answer there anyway.
31
+ let reactNative;
32
+ function getReactNative() {
33
+ if (reactNative !== undefined) {
34
+ return reactNative;
35
+ }
36
+ try {
37
+ reactNative = require("react-native");
38
+ }
39
+ catch {
40
+ reactNative = null;
41
+ }
42
+ return reactNative;
43
+ }
44
+ function isDev() {
45
+ return typeof __DEV__ !== "undefined" && __DEV__;
46
+ }
25
47
  let nitroTimer;
26
48
  let nitroDisabled = false;
27
49
  let failedLoud = false;
@@ -42,12 +64,12 @@ function failUnavailable(reason) {
42
64
  "Backgrounded behavior IS BROKEN until you rebuild the Android app: run `bun android`. " +
43
65
  "Engine timers and local miniapps (captions, wake words) freeze whenever the app is not foregrounded.";
44
66
  console.error(message);
45
- if (__DEV__) {
67
+ if (isDev()) {
46
68
  // A stale dev client may ALSO show the library's own require-time red box
47
69
  // (bridgeless LogBox surfaces it even though we catch below) — this alert
48
70
  // is the actionable one: it names the fix.
49
71
  try {
50
- Alert.alert("Background timers unavailable", message);
72
+ getReactNative()?.Alert?.alert("Background timers unavailable", message);
51
73
  }
52
74
  catch {
53
75
  /* Alert not available (tests / headless) — the console.error stands. */
@@ -55,7 +77,7 @@ function failUnavailable(reason) {
55
77
  }
56
78
  }
57
79
  function getNitroTimer() {
58
- if (nitroDisabled || Platform.OS !== "android") {
80
+ if (nitroDisabled || getReactNative()?.Platform.OS !== "android") {
59
81
  return null;
60
82
  }
61
83
  if (nitroTimer !== undefined) {
@@ -1 +1 @@
1
- {"version":3,"file":"timers.js","sourceRoot":"","sources":["../../../src/utils/timers/timers.ts"],"names":[],"mappings":"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","sourcesContent":["// BgTimer — background-safe timers for the engine.\n//\n// Everything timing-critical in the engine runs through this class: the\n// miniapp liveness watchdog, display durationMs expiries, boot windows,\n// auth-token refresh. On Android, React Native PAUSES plain JS timers while\n// the app is backgrounded, so those features only keep working in the\n// background when the native implementation (react-native-nitro-bg-timer)\n// is active.\n//\n// Who actually gets native timers:\n// - Android, dev AND release: always attempted — dev must match production\n// background behavior. There is no opt-in/opt-out env var. If the native\n// module is unavailable (a dev client whose binary predates it, or a\n// broken release binary), the failure is LOUD: a console.error with the\n// remediation, plus a blocking dev alert. The JS-timer fallback still\n// engages so foreground behavior keeps working, but backgrounded\n// behavior is broken until the native rebuild — the error says exactly\n// that. (A silent dev fallback previously cost a full debugging day of\n// phantom \"zombie miniapp\" bugs; see OS-1790.)\n// - iOS: never, dev or prod — the package is disabled pending\n// https://github.com/tconns/react-native-nitro-bg-timer/issues/2. iOS\n// suspends the whole process in background anyway, so background timing\n// there is handled by native per-device queues, not JS timers.\n\nimport {Alert, Platform} from \"react-native\"\n\ntype NitroTimerApi = {\n setInterval: (callback: () => void, delay: number) => number\n clearInterval: (intervalId: number) => void\n setTimeout: (callback: () => void, delay: number) => number\n clearTimeout: (timeoutId: number) => void\n}\n\nlet nitroTimer: NitroTimerApi | null | undefined\nlet nitroDisabled = false\nlet failedLoud = false\n\n/**\n * The native background timer is unavailable — say so ONCE, loudly, with the\n * remediation. The JS-timer fallback keeps foreground behavior working, but\n * everything timing-driven freezes while the app is backgrounded, which\n * presents as phantom miniapp bugs (frozen captions, missed wake words,\n * watchdog kills on resume). A quiet warning here has already cost a full\n * debugging day; never downgrade this to console.warn.\n */\nfunction failUnavailable(reason: string) {\n if (failedLoud) {\n return\n }\n failedLoud = true\n const message =\n `BgTimer: native background timer unavailable (${reason}). ` +\n \"Backgrounded behavior IS BROKEN until you rebuild the Android app: run `bun android`. \" +\n \"Engine timers and local miniapps (captions, wake words) freeze whenever the app is not foregrounded.\"\n console.error(message)\n if (__DEV__) {\n // A stale dev client may ALSO show the library's own require-time red box\n // (bridgeless LogBox surfaces it even though we catch below) — this alert\n // is the actionable one: it names the fix.\n try {\n Alert.alert(\"Background timers unavailable\", message)\n } catch {\n /* Alert not available (tests / headless) — the console.error stands. */\n }\n }\n}\n\nfunction getNitroTimer(): NitroTimerApi | null {\n if (nitroDisabled || Platform.OS !== \"android\") {\n return null\n }\n\n if (nitroTimer !== undefined) {\n return nitroTimer\n }\n\n try {\n const {isRuntimeAlive} = require(\"react-native-nitro-modules\") as {isRuntimeAlive?: () => boolean}\n if (typeof isRuntimeAlive === \"function\" && !isRuntimeAlive()) {\n nitroTimer = null\n failUnavailable(\"nitro runtime is not alive\")\n return nitroTimer\n }\n\n const {BackgroundTimer} = require(\"react-native-nitro-bg-timer\") as {BackgroundTimer?: NitroTimerApi}\n nitroTimer =\n BackgroundTimer &&\n typeof BackgroundTimer.setTimeout === \"function\" &&\n typeof BackgroundTimer.setInterval === \"function\" &&\n typeof BackgroundTimer.clearTimeout === \"function\" &&\n typeof BackgroundTimer.clearInterval === \"function\"\n ? BackgroundTimer\n : null\n } catch {\n nitroTimer = null\n nitroDisabled = true\n }\n\n if (!nitroTimer) {\n failUnavailable(\"react-native-nitro-bg-timer failed to load\")\n }\n return nitroTimer\n}\n\nfunction withNitro<T>(run: (api: NitroTimerApi) => T, fallback: () => T): T {\n const api = getNitroTimer()\n if (!api) {\n return fallback()\n }\n try {\n return run(api)\n } catch (error) {\n nitroDisabled = true\n nitroTimer = null\n failedLoud = false // a mid-session failure is new information — re-announce\n failUnavailable(`nitro timer call threw: ${String(error)}`)\n return fallback()\n }\n}\n\nexport class BgTimer {\n static setInterval(callback: () => void, delay: number): number {\n return withNitro(\n (api) => api.setInterval(callback, delay),\n () => setInterval(callback, delay) as unknown as number,\n )\n }\n\n static clearInterval(intervalId: number): void {\n withNitro(\n (api) => api.clearInterval(intervalId),\n () => clearInterval(intervalId),\n )\n }\n\n static setTimeout(callback: () => void, delay: number): number {\n return withNitro(\n (api) => api.setTimeout(callback, delay),\n () => setTimeout(callback, delay) as unknown as number,\n )\n }\n\n static clearTimeout(timeoutId: number): void {\n withNitro(\n (api) => api.clearTimeout(timeoutId),\n () => clearTimeout(timeoutId),\n )\n }\n}\n\nexport function throttle<T extends (...args: any[]) => any>(fn: T, ms: number): (...args: Parameters<T>) => void {\n let lastCalled = 0\n\n return (...args: Parameters<T>) => {\n const now = Date.now()\n if (now - lastCalled >= ms) {\n lastCalled = now\n fn(...args)\n }\n }\n}\n\nexport function debounce<T extends (...args: any[]) => any>(fn: T, ms: number): (...args: Parameters<T>) => void {\n let timeoutId: number | null = null\n\n return (...args: Parameters<T>) => {\n if (timeoutId) {\n BgTimer.clearTimeout(timeoutId)\n }\n timeoutId = BgTimer.setTimeout(() => {\n fn(...args)\n timeoutId = null\n }, ms)\n }\n}\n"]}
1
+ {"version":3,"file":"timers.js","sourceRoot":"","sources":["../../../src/utils/timers/timers.ts"],"names":[],"mappings":"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","sourcesContent":["// BgTimer — background-safe timers for the engine.\n//\n// Everything timing-critical in the engine runs through this class: the\n// miniapp liveness watchdog, display durationMs expiries, boot windows,\n// auth-token refresh. On Android, React Native PAUSES plain JS timers while\n// the app is backgrounded, so those features only keep working in the\n// background when the native implementation (react-native-nitro-bg-timer)\n// is active.\n//\n// Who actually gets native timers:\n// - Android, dev AND release: always attempted — dev must match production\n// background behavior. There is no opt-in/opt-out env var. If the native\n// module is unavailable (a dev client whose binary predates it, or a\n// broken release binary), the failure is LOUD: a console.error with the\n// remediation, plus a blocking dev alert. The JS-timer fallback still\n// engages so foreground behavior keeps working, but backgrounded\n// behavior is broken until the native rebuild — the error says exactly\n// that. (A silent dev fallback previously cost a full debugging day of\n// phantom \"zombie miniapp\" bugs; see OS-1790.)\n// - iOS: never, dev or prod — the package is disabled pending\n// https://github.com/tconns/react-native-nitro-bg-timer/issues/2. iOS\n// suspends the whole process in background anyway, so background timing\n// there is handled by native per-device queues, not JS timers.\n//\n// react-native is loaded lazily, not imported. Every engine service runs its\n// timers through this module, and the engine's bun test suites load those\n// services in a plain JS runtime that cannot parse react-native's Flow\n// source. A static import would force every such suite to mock this module;\n// with the lazy load, a runtime without react-native simply gets the JS\n// timers, which is the correct answer there anyway.\n\ntype ReactNativeSubset = {\n Platform: {OS: string}\n Alert?: {alert: (title: string, message?: string) => void}\n}\n\nlet reactNative: ReactNativeSubset | null | undefined\n\nfunction getReactNative(): ReactNativeSubset | null {\n if (reactNative !== undefined) {\n return reactNative\n }\n try {\n reactNative = require(\"react-native\") as ReactNativeSubset\n } catch {\n reactNative = null\n }\n return reactNative\n}\n\nfunction isDev(): boolean {\n return typeof __DEV__ !== \"undefined\" && __DEV__\n}\n\ntype NitroTimerApi = {\n setInterval: (callback: () => void, delay: number) => number\n clearInterval: (intervalId: number) => void\n setTimeout: (callback: () => void, delay: number) => number\n clearTimeout: (timeoutId: number) => void\n}\n\nlet nitroTimer: NitroTimerApi | null | undefined\nlet nitroDisabled = false\nlet failedLoud = false\n\n/**\n * The native background timer is unavailable — say so ONCE, loudly, with the\n * remediation. The JS-timer fallback keeps foreground behavior working, but\n * everything timing-driven freezes while the app is backgrounded, which\n * presents as phantom miniapp bugs (frozen captions, missed wake words,\n * watchdog kills on resume). A quiet warning here has already cost a full\n * debugging day; never downgrade this to console.warn.\n */\nfunction failUnavailable(reason: string) {\n if (failedLoud) {\n return\n }\n failedLoud = true\n const message =\n `BgTimer: native background timer unavailable (${reason}). ` +\n \"Backgrounded behavior IS BROKEN until you rebuild the Android app: run `bun android`. \" +\n \"Engine timers and local miniapps (captions, wake words) freeze whenever the app is not foregrounded.\"\n console.error(message)\n if (isDev()) {\n // A stale dev client may ALSO show the library's own require-time red box\n // (bridgeless LogBox surfaces it even though we catch below) — this alert\n // is the actionable one: it names the fix.\n try {\n getReactNative()?.Alert?.alert(\"Background timers unavailable\", message)\n } catch {\n /* Alert not available (tests / headless) — the console.error stands. */\n }\n }\n}\n\nfunction getNitroTimer(): NitroTimerApi | null {\n if (nitroDisabled || getReactNative()?.Platform.OS !== \"android\") {\n return null\n }\n\n if (nitroTimer !== undefined) {\n return nitroTimer\n }\n\n try {\n const {isRuntimeAlive} = require(\"react-native-nitro-modules\") as {isRuntimeAlive?: () => boolean}\n if (typeof isRuntimeAlive === \"function\" && !isRuntimeAlive()) {\n nitroTimer = null\n failUnavailable(\"nitro runtime is not alive\")\n return nitroTimer\n }\n\n const {BackgroundTimer} = require(\"react-native-nitro-bg-timer\") as {BackgroundTimer?: NitroTimerApi}\n nitroTimer =\n BackgroundTimer &&\n typeof BackgroundTimer.setTimeout === \"function\" &&\n typeof BackgroundTimer.setInterval === \"function\" &&\n typeof BackgroundTimer.clearTimeout === \"function\" &&\n typeof BackgroundTimer.clearInterval === \"function\"\n ? BackgroundTimer\n : null\n } catch {\n nitroTimer = null\n nitroDisabled = true\n }\n\n if (!nitroTimer) {\n failUnavailable(\"react-native-nitro-bg-timer failed to load\")\n }\n return nitroTimer\n}\n\nfunction withNitro<T>(run: (api: NitroTimerApi) => T, fallback: () => T): T {\n const api = getNitroTimer()\n if (!api) {\n return fallback()\n }\n try {\n return run(api)\n } catch (error) {\n nitroDisabled = true\n nitroTimer = null\n failedLoud = false // a mid-session failure is new information — re-announce\n failUnavailable(`nitro timer call threw: ${String(error)}`)\n return fallback()\n }\n}\n\nexport class BgTimer {\n static setInterval(callback: () => void, delay: number): number {\n return withNitro(\n (api) => api.setInterval(callback, delay),\n () => setInterval(callback, delay) as unknown as number,\n )\n }\n\n static clearInterval(intervalId: number): void {\n withNitro(\n (api) => api.clearInterval(intervalId),\n () => clearInterval(intervalId),\n )\n }\n\n static setTimeout(callback: () => void, delay: number): number {\n return withNitro(\n (api) => api.setTimeout(callback, delay),\n () => setTimeout(callback, delay) as unknown as number,\n )\n }\n\n static clearTimeout(timeoutId: number): void {\n withNitro(\n (api) => api.clearTimeout(timeoutId),\n () => clearTimeout(timeoutId),\n )\n }\n}\n\nexport function throttle<T extends (...args: any[]) => any>(fn: T, ms: number): (...args: Parameters<T>) => void {\n let lastCalled = 0\n\n return (...args: Parameters<T>) => {\n const now = Date.now()\n if (now - lastCalled >= ms) {\n lastCalled = now\n fn(...args)\n }\n }\n}\n\nexport function debounce<T extends (...args: any[]) => any>(fn: T, ms: number): (...args: Parameters<T>) => void {\n let timeoutId: number | null = null\n\n return (...args: Parameters<T>) => {\n if (timeoutId) {\n BgTimer.clearTimeout(timeoutId)\n }\n timeoutId = BgTimer.setTimeout(() => {\n fn(...args)\n timeoutId = null\n }, ms)\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glassly/engine",
3
- "version": "0.1.0-dev.99",
3
+ "version": "0.2.8-dev.445",
4
4
  "description": "Glassly Engine — miniapp registry, WebView bridge, and miniapp store",
5
5
  "main": "build/index.js",
6
6
  "react-native": "src/index.ts",
@@ -97,23 +97,23 @@
97
97
  "registry": "https://registry.npmjs.org/"
98
98
  },
99
99
  "dependencies": {
100
- "@glassly/bluetooth-sdk": "0.1.0-dev.99",
101
- "@glassly/cloud-client": "0.1.0-dev.99",
102
- "@glassly/cloud-protocol": "0.1.0-dev.99",
103
- "@glassly/crust": "0.1.0-dev.99",
104
- "@glassly/miniapp": "0.1.0-dev.99",
100
+ "@glassly/bluetooth-sdk": "0.2.8-dev.445",
101
+ "@glassly/cloud-client": "0.2.8-dev.445",
102
+ "@glassly/cloud-protocol": "0.2.8-dev.445",
103
+ "@glassly/crust": "0.2.8-dev.445",
104
+ "@glassly/miniapp": "0.2.8-dev.445",
105
105
  "buffer": "^6.0.3",
106
106
  "events": "^3.3.0",
107
107
  "react-native-marked": "8.1.1",
108
108
  "semver": "^7.7.4",
109
109
  "typesafe-ts": "^1.7.1",
110
- "@glassly/llm-providers": "0.1.0-dev.99"
110
+ "@glassly/llm-providers": "0.2.8-dev.445"
111
111
  },
112
112
  "devDependencies": {
113
113
  "@glassly/llm-providers": "workspace:*",
114
114
  "@types/semver": "^7.7.1",
115
115
  "expo-module-scripts": "^56.0.3",
116
- "expo-modules-core": "57.0.7",
116
+ "expo-modules-core": "^57.0.7",
117
117
  "react-native-nitro-modules": "^0.31.10",
118
118
  "typescript": "~5.9.2"
119
119
  },
package/src/engine.ts CHANGED
@@ -5,12 +5,13 @@
5
5
  * name stays `engine` in code; the public API surface is `engine`.)
6
6
  *
7
7
  * It grows one facade at a time. The migration-era flat store/service exports
8
- * remain in a private GlasslyOS host package; they shrink as screens move onto
8
+ * remain in a private Glassly host package; they shrink as screens move onto
9
9
  * `engine.*`.
10
10
  */
11
11
  import {configure, start as bootstrapStart, stop as bootstrapStop, updateUiSeams} from "./runtime/bootstrap"
12
12
  import {cloudClientService} from "./services/CloudClientService"
13
13
  import {hydrateDeviceStore, demoteOrphanedDefaultWearable} from "./services/DeviceStoreHydration"
14
+ import {startPairedGlassesLatch, stopPairedGlassesLatch} from "./services/PairedGlassesLatch"
14
15
  import {startGlassesSettingsSync, stopGlassesSettingsSync} from "./services/GlassesSettingsSync"
15
16
  import {startGlassesStatusProjection, stopGlassesStatusProjection} from "./services/GlassesStatusProjection"
16
17
  import {startOtaService, stopOtaService} from "./services/OtaService"
@@ -18,6 +19,7 @@ import {startAudioCloudUplink, stopAudioCloudUplink} from "./services/AudioCloud
18
19
  import sonioxDirectService from "./services/soniox/SonioxDirectService"
19
20
  import {startSupportProfileSync, stopSupportProfileSync} from "./services/SupportProfileSync"
20
21
  import {startDeviceEventRouter, stopDeviceEventRouter} from "./services/DeviceEventRouter"
22
+ import {startPhoneActivityTracking, stopPhoneActivityTracking} from "./services/PhoneActivity"
21
23
  import {startPhoneNotificationsSync, stopPhoneNotificationsSync} from "./services/PhoneNotificationsSync"
22
24
  import {startSpeakerIdSync, stopSpeakerIdSync} from "./services/SpeakerIdSync"
23
25
  import {startCaptionsTesterReportService, stopCaptionsTesterReportService} from "./services/CaptionsTesterReportService"
@@ -45,8 +47,7 @@ import {memory} from "./facades/memory"
45
47
  import {speakers} from "./facades/speakers"
46
48
  import {providerKeys} from "./facades/providerKeys"
47
49
  import {logBuffer} from "./utils/devLogging"
48
- import customDashboardService from "./services/CustomDashboardService"
49
- import dashboardCoordinator from "./services/DashboardCoordinator"
50
+ import pageHost from "./services/pages/PageHost"
50
51
  import gestureDotsService from "./services/GestureDotsService"
51
52
 
52
53
  export const engine = {
@@ -69,8 +70,12 @@ export const engine = {
69
70
  // of the runtime reads). Established first so the stores are live before the
70
71
  // syncs below react to them.
71
72
  startGlassesStatusProjection((changed) => localMiniappRuntime.forwardEvent("glasses_connection_state", changed))
72
- customDashboardService.start()
73
- dashboardCoordinator.start()
73
+ // Lock + foreground state, read by the dashboard's notification gate and
74
+ // the G2 notification ctrl below; up before either consumer.
75
+ startPhoneActivityTracking()
76
+ // The overlay slot's owner: the designated dashboard miniapp's page shows
77
+ // through it (ADR-0006), so it is up before the miniapp runtime.
78
+ pageHost.start()
74
79
  gestureDotsService.start()
75
80
  // Route the rest of the inbound device events (wifi/hotspot/gallery -> stores+bus,
76
81
  // photo/stream -> coordinators, button/touch/accel/head -> miniapps, save_setting ->
@@ -95,6 +100,8 @@ export const engine = {
95
100
  } catch (error) {
96
101
  console.warn("engine.start: device-store hydration failed:", error instanceof Error ? error.message : error)
97
102
  }
103
+ // After the settings load so an already-paired phone latches on this start.
104
+ startPairedGlassesLatch()
98
105
  // Project the glasses' OTA events into the store for the engine.ota read surface.
99
106
  startOtaService()
100
107
  // Forward glasses mic_lc3 frames to the v2 cloud session so cloud transcription
@@ -103,14 +110,15 @@ export const engine = {
103
110
  // Phone -> Soniox direct transcription (user-supplied API key). Started
104
111
  // after device-store hydration so the persisted key is already loaded.
105
112
  sonioxDirectService.start()
106
- try {
107
- await cloudClientService.syncCoreTokenToBluetooth()
108
- } catch (error) {
113
+ // Not awaited: the exchange behind it is a Core round trip with no client
114
+ // deadline, and start() must resolve offline. The glasses get the token
115
+ // when it lands; identity resolution joins the same single-flight exchange.
116
+ void cloudClientService.syncCoreTokenToBluetooth().catch((error) => {
109
117
  console.warn(
110
118
  "engine.start: initial Cloud V2 core token sync failed:",
111
119
  error instanceof Error ? error.message : error,
112
120
  )
113
- }
121
+ })
114
122
  startSupportProfileSync()
115
123
  // Push device-setting changes to the glasses for ANY host, so
116
124
  // engine.glasses.settings.set() reaches the device (not just the Glassly app).
@@ -124,11 +132,11 @@ export const engine = {
124
132
  // Android internal/e2e: laptop captions tester can broadcast a failure intent;
125
133
  // engine owns turning that into a Cloud V2 report.
126
134
  startCaptionsTesterReportService()
127
- // GlasslyJS crashloop-disabled is runtime state; engine owns filing the
135
+ // JSRuntime crashloop-disabled is runtime state; engine owns filing the
128
136
  // automatic report while hosts only render alert/telemetry side effects.
129
137
  startJSCrashloopReportService()
130
- // Bring up the local-miniapp engine so a bare OEM can run GlasslyJS miniapps:
131
- // the LocalMiniappRuntime (registry + WebView bridge), the GlasslyJS router
138
+ // Bring up the local-miniapp engine so a bare OEM can run JSRuntime miniapps:
139
+ // the LocalMiniappRuntime (registry + WebView bridge), the JSRuntime router
132
140
  // (crust-bound spawn/dispatch pump + launcher wiring), the DisplayProcessor
133
141
  // (layout arbitration over the engine stores), and the gallery-sync service.
134
142
  // All idempotent — when the Glassly app's host bootstrap also calls these, the
@@ -151,19 +159,20 @@ export const engine = {
151
159
  }
152
160
  }
153
161
  await safely("glasses settings sync", stopGlassesSettingsSync)
162
+ await safely("paired glasses latch", stopPairedGlassesLatch)
154
163
  await safely("glasses status projection", stopGlassesStatusProjection)
155
164
  await safely("device event router", stopDeviceEventRouter)
156
- await safely("dashboard coordinator", () => dashboardCoordinator.stop())
157
- await safely("custom dashboard service", () => customDashboardService.stop())
165
+ await safely("page host", () => pageHost.stop())
158
166
  await safely("gesture dots service", () => gestureDotsService.stop())
159
167
  await safely("ota service", stopOtaService)
160
168
  await safely("audio cloud uplink", stopAudioCloudUplink)
161
169
  await safely("soniox direct service", () => sonioxDirectService.stop())
162
170
  await safely("support profile sync", stopSupportProfileSync)
163
171
  await safely("phone notifications sync", stopPhoneNotificationsSync)
172
+ await safely("phone activity tracking", stopPhoneActivityTracking)
164
173
  await safely("speaker id sync", stopSpeakerIdSync)
165
174
  await safely("captions tester report service", stopCaptionsTesterReportService)
166
- await safely("glasslyjs crashloop report service", stopJSCrashloopReportService)
175
+ await safely("js crashloop report service", stopJSCrashloopReportService)
167
176
  await safely("miniapp engine", stopMiniappEngine)
168
177
  await safely("local miniapp runtime", () => localMiniappRuntime.cleanup())
169
178
  await safely("display processor", () => displayProcessor.detachFromRuntime())
@@ -20,6 +20,8 @@ import {getConfigValues} from "../runtime/bootstrap"
20
20
  import {decideDevLaunchRoute} from "../utils/devMiniappLaunch"
21
21
  import {deriveDevPackageId, registerDevApp, DEV_APP_PACKAGE_NAME, type DevAppRecord} from "../services/AppRegistry"
22
22
  import {useAppStatusStore} from "../stores/apps"
23
+ import {sendGesture} from "../services/GlassesTouchInput"
24
+ import dashboardOpenTrace, {type DashboardOpenReport} from "../services/debug/DashboardOpenTrace"
23
25
 
24
26
  type CloudUrlOverrides = {core?: string; runtime?: string}
25
27
 
@@ -90,6 +92,8 @@ function projectRuntimeStatus() {
90
92
  export type DevRuntimeStatusSnapshot = ReturnType<typeof projectRuntimeStatus>
91
93
 
92
94
  export const dev = {
95
+ /** Inject a glasses gesture through the normal dashboard/miniapp input policy. */
96
+ sendGesture,
93
97
  /** The cloud-v2 core/runtime URL overrides. */
94
98
  cloudUrls: (): {core?: string; runtime?: string} => {
95
99
  const s = useSettingsStore.getState()
@@ -210,4 +214,10 @@ export const dev = {
210
214
  unsubscribers.forEach((unsubscribe) => unsubscribe())
211
215
  }
212
216
  },
217
+
218
+ /**
219
+ * Each finished dashboard open while the debug_dashboard_open_timing setting
220
+ * is on: a ready-made title/body plus the stage timings. Returns an unsubscribe.
221
+ */
222
+ onDashboardOpenTrace: (cb: (report: DashboardOpenReport) => void): (() => void) => dashboardOpenTrace.onReport(cb),
213
223
  }
@@ -5,20 +5,33 @@
5
5
  * the engine DisplayProcessor / layout system, not these).
6
6
  */
7
7
  import BluetoothSdk from "@glassly/bluetooth-sdk"
8
- import dashboardCoordinator from "../services/DashboardCoordinator"
8
+ import {sendGesture} from "../services/GlassesTouchInput"
9
+ import localMiniappRuntime from "../services/LocalMiniappRuntime"
10
+ import {useDisplayStore} from "../stores/display"
9
11
  import {displayMirror} from "./displayMirror"
10
12
 
11
13
  export const display = {
12
14
  /** Mirrored-view read-model (current/onMirror). */
13
15
  mirror: displayMirror,
14
- /** Phone-composed dashboard controls (simulated head-up, dev tools). */
16
+ /**
17
+ * Dashboard controls for the simulator and dev tools. The dashboard is a
18
+ * miniapp's (ADR-0006): these replay the wearer's own inputs, so they do
19
+ * whatever the running apps make of them.
20
+ */
15
21
  dashboard: {
16
- isOpen: (): boolean => dashboardCoordinator.isOpen,
17
- /** Open/close as if the head was raised/lowered (respects contextual_dashboard). */
18
- setHeadUp: (up: boolean): void => dashboardCoordinator.setHeadUp(up),
19
- /** Force open/close, ignoring contextual_dashboard (simulator button). */
20
- open: (): void => dashboardCoordinator.open(),
21
- close: (): void => dashboardCoordinator.close(),
22
+ /** An overlay app holds the slot. */
23
+ isOpen: (): boolean => useDisplayStore.getState().overlayOwner !== null,
24
+ /** As if the head was raised/lowered (the dashboard app applies contextual_dashboard). */
25
+ setHeadUp: (up: boolean): void =>
26
+ localMiniappRuntime.forwardEvent("head_up", {position: up ? "up" : "down", timestamp: Date.now()}),
27
+ /** A double tap on the empty screen: the dashboard app opens (simulator button). */
28
+ open: (): void => {
29
+ if (!display.dashboard.isOpen()) sendGesture("double_tap")
30
+ },
31
+ /** A double tap on the showing page: it closes. */
32
+ close: (): void => {
33
+ if (display.dashboard.isOpen()) sendGesture("double_tap")
34
+ },
22
35
  },
23
36
  /** Write raw text to the glasses display at (x, y) with a font size. */
24
37
  text: (...args: Parameters<typeof BluetoothSdk.displayText>) => BluetoothSdk.displayText(...args),
@@ -7,10 +7,20 @@
7
7
  * The raw store is also exposed as `engine.displayStore` (the Glassly-app
8
8
  * escape hatch).
9
9
  */
10
+ import displayProcessor from "../services/DisplayProcessor"
11
+ import {getEffectiveCapabilities} from "../services/effectiveCapabilities"
10
12
  import {useDisplayStore} from "../stores/display"
13
+ import {useGlassesStore} from "../stores/glasses"
14
+ import {SETTINGS, useSettingsStore} from "../stores/settings"
15
+ import {DeviceTypes} from "../types"
11
16
 
12
17
  export type DisplayMirrorEvent = Record<string, unknown> & {view?: string; layout?: any}
13
18
 
19
+ export interface DisplayMirrorCanvas {
20
+ width: number
21
+ height: number
22
+ }
23
+
14
24
  export const displayMirror = {
15
25
  /** The display event currently on the glasses (snapshot). */
16
26
  current(): DisplayMirrorEvent {
@@ -22,4 +32,23 @@ export const displayMirror = {
22
32
  onMirror(cb: (event: DisplayMirrorEvent) => void): () => void {
23
33
  return useDisplayStore.subscribe((s) => s.currentEvent, cb)
24
34
  },
35
+
36
+ /**
37
+ * Drawable canvas of the selected glasses, in device px — the space scene
38
+ * frames and positioned layouts are laid out in (same source SceneRenderer
39
+ * sends CONNECT_ACK from). Falls back to the text profile's line width.
40
+ * `previewModel` previews a model that is not selected yet (pairing prep).
41
+ */
42
+ canvas(previewModel?: string): DisplayMirrorCanvas {
43
+ const model =
44
+ previewModel ??
45
+ (useSettingsStore.getState().getSetting(SETTINGS.default_wearable.key) as string | undefined) ??
46
+ (useGlassesStore.getState().deviceModel as string | undefined)
47
+ const display = getEffectiveCapabilities((model ?? DeviceTypes.NONE) as DeviceTypes)?.display
48
+ const profile = displayProcessor.getProfile()
49
+ return {
50
+ width: display?.width ?? display?.resolution?.width ?? profile.displayWidthPx,
51
+ height: display?.height ?? display?.resolution?.height ?? profile.displayHeightPx ?? profile.displayWidthPx / 2,
52
+ }
53
+ },
25
54
  }
@@ -11,7 +11,14 @@
11
11
  // surface, not the public entry. Relative path (the alias doesn't resolve in engine's
12
12
  // standalone build); jest moduleNameMapper + tsconfig both resolve it.
13
13
  import BluetoothSdk from "@glassly/bluetooth-sdk/internal"
14
- import type {ButtonPressEvent, ConnectOptions, Device, TouchEvent} from "@glassly/bluetooth-sdk"
14
+ import type {
15
+ ButtonPressEvent,
16
+ ConnectOptions,
17
+ Device,
18
+ KeyboardAdvertEvent,
19
+ KeyboardPairingEvent,
20
+ TouchEvent,
21
+ } from "@glassly/bluetooth-sdk"
15
22
  import {useGlassesStore} from "../stores/glasses"
16
23
  import {useSettingsStore, SETTINGS} from "../stores/settings"
17
24
  import {hasDefaultDevice} from "../services/DeviceStoreHydration"
@@ -50,6 +57,20 @@ function projectControllerStatus() {
50
57
  }
51
58
  }
52
59
 
60
+ function projectKeyboardStatus() {
61
+ const s = useGlassesStore.getState()
62
+ return {
63
+ /** Connected glasses run a firmware that can host a keyboard (G2 Glassly CFW 39+). */
64
+ available: s.keyboardBridge === true,
65
+ connected: s.keyboardConnected === true,
66
+ name: s.keyboardName ?? "",
67
+ /** A keyboard is remembered and reconnects automatically. */
68
+ saved: s.keyboardSaved === true,
69
+ state: s.keyboardState ?? "idle",
70
+ error: s.keyboardError ?? "",
71
+ }
72
+ }
73
+
53
74
  function projectInfo() {
54
75
  const s = useGlassesStore.getState()
55
76
  return {
@@ -77,6 +98,7 @@ function projectInfo() {
77
98
 
78
99
  export type GlassesStatusSnapshot = ReturnType<typeof projectStatus>
79
100
  export type ControllerStatusSnapshot = ReturnType<typeof projectControllerStatus>
101
+ export type KeyboardStatusSnapshot = ReturnType<typeof projectKeyboardStatus>
80
102
  export type GlassesInfoSnapshot = ReturnType<typeof projectInfo>
81
103
 
82
104
  export const glasses = {
@@ -189,6 +211,44 @@ export const glasses = {
189
211
  return () => sub.remove()
190
212
  },
191
213
 
214
+ // --- BLE keyboard bridged through G2 Glassly CFW (revision 39+) ---
215
+ keyboard: {
216
+ /** Five-second scan; distinct advertisers, HID ones flagged. Also streams via onAdvert. */
217
+ scan: (): Promise<KeyboardAdvertEvent[]> => BluetoothSdk.g2KeyboardScan(),
218
+ /** Connect, pair and subscribe; the keyboard is remembered and auto-reconnected. */
219
+ connect: async (device: {address: string; addressType: number; name: string}): Promise<void> => {
220
+ await BluetoothSdk.g2KeyboardConnect(device.address, device.addressType, device.name)
221
+ useSettingsStore.getState().setSetting(SETTINGS.keyboard_name.key, device.name)
222
+ },
223
+ reconnect: (): Promise<void> => BluetoothSdk.g2KeyboardReconnect(),
224
+ disconnect: (): Promise<void> => BluetoothSdk.g2KeyboardDisconnect(),
225
+ forget: async (): Promise<void> => {
226
+ await BluetoothSdk.g2KeyboardForget()
227
+ useSettingsStore.getState().setSetting(SETTINGS.keyboard_name.key, "")
228
+ },
229
+ passkey: (pin: number): Promise<void> => BluetoothSdk.g2KeyboardPasskey(pin),
230
+ compare: (accept: boolean): Promise<void> => BluetoothSdk.g2KeyboardCompare(accept),
231
+ status: (): KeyboardStatusSnapshot => projectKeyboardStatus(),
232
+ onStatus: (cb: (status: KeyboardStatusSnapshot) => void): (() => void) => {
233
+ let last = JSON.stringify(projectKeyboardStatus())
234
+ return useGlassesStore.subscribe(() => {
235
+ const snap = projectKeyboardStatus()
236
+ const key = JSON.stringify(snap)
237
+ if (key === last) return
238
+ last = key
239
+ cb(snap)
240
+ })
241
+ },
242
+ onAdvert: (cb: (advert: KeyboardAdvertEvent) => void): (() => void) => {
243
+ const sub = BluetoothSdk.addListener("keyboard_advert", cb)
244
+ return () => sub.remove()
245
+ },
246
+ onPairing: (cb: (prompt: KeyboardPairingEvent) => void): (() => void) => {
247
+ const sub = BluetoothSdk.addListener("keyboard_pairing", cb)
248
+ return () => sub.remove()
249
+ },
250
+ },
251
+
192
252
  // --- ring controller (optional input device) ---
193
253
  controller: {
194
254
  connectDefault: (): Promise<void> => BluetoothSdk.connectDefaultController(),
@@ -7,8 +7,7 @@
7
7
  import type {MemoryEntry, MemorySession} from "@glassly/miniapp"
8
8
 
9
9
  import type {MemoryStats} from "../services/MemoryStore"
10
- import {EXTENDED_RETENTION, STANDARD_RETENTION} from "../services/MemoryStore"
11
- import {isMemoryRetentionExtended, memoryStore, setMemoryRetentionExtended} from "../services/memoryStoreInstance"
10
+ import {memoryStore} from "../services/memoryStoreInstance"
12
11
 
13
12
  export const memory = {
14
13
  /** All note entries, newest first. */
@@ -33,14 +32,4 @@ export const memory = {
33
32
  clearAll: (): Promise<void> => memoryStore.clear(),
34
33
  /** Subscribe to store mutations (from miniapps or Settings). */
35
34
  onChanged: (listener: () => void): (() => void) => memoryStore.onChanged(listener),
36
- /** Whether the extended (Plus/Pro) retention window is active. */
37
- retentionExtended: (): boolean => isMemoryRetentionExtended(),
38
- /** Retention window in days for the given (or current) tier, for UI copy. */
39
- retentionDays: (extended?: boolean): number =>
40
- Math.round(
41
- ((extended ?? isMemoryRetentionExtended()) ? EXTENDED_RETENTION : STANDARD_RETENTION).maxAgeMs /
42
- (24 * 60 * 60 * 1000),
43
- ),
44
- /** Flip retention on subscription change. Host app (RevenueCat sync) only. */
45
- setRetentionExtended: (extended: boolean): void => setMemoryRetentionExtended(extended),
46
35
  }
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * The miniapp WebView is a HOST component (engine ships the bridge, not the view) —
7
7
  * the bridge primitives (`buildMiniappGlobalsScript`, `buildUiShim`, the
8
- * GlasslyJS router) are exported from `@glassly/engine` directly; the host mounts a
8
+ * JSRuntime router) are exported from `@glassly/engine` directly; the host mounts a
9
9
  * `<WebView>` wired to them. This facade is the lifecycle half.
10
10
  */
11
11
  import {useAppStatusStore} from "../stores/apps"
@@ -59,4 +59,7 @@ export const miniapps = {
59
59
  /** Hide/show a miniapp on the home surfaces. */
60
60
  setHiddenStatus: (...args: Parameters<AppsState["setHiddenStatus"]>) =>
61
61
  useAppStatusStore.getState().setHiddenStatus(...args),
62
+ /** Mark a miniapp persistent (starts at launch, stops only from the switcher pill), persisted for the next boot. */
63
+ setPersistent: (...args: Parameters<AppsState["setPersistent"]>) =>
64
+ useAppStatusStore.getState().setPersistent(...args),
62
65
  }
@@ -31,6 +31,8 @@ import {pushAllBluetoothSettings} from "../services/GlassesSettingsSync"
31
31
  import {ControllerTypes} from "../types"
32
32
  import {submitAutomaticReport} from "./reports"
33
33
 
34
+ import {BgTimer} from "../utils/timers"
35
+
34
36
  export type {IdentitySnapshot} from "../services/PairingIdentity"
35
37
 
36
38
  export interface PairingReadyWaitOptions {
@@ -110,13 +112,13 @@ async function waitForTargetReady(options: PairingReadyWaitOptions, timeoutMs: n
110
112
  }
111
113
 
112
114
  let settled = false
113
- let timeout: ReturnType<typeof setTimeout> | null = null
115
+ let timeout: number | null = null
114
116
  let unsubscribe: (() => void) | null = null
115
117
  let onAbort: (() => void) | null = null
116
118
  const finish = (ready: boolean) => {
117
119
  if (settled) return
118
120
  settled = true
119
- if (timeout) clearTimeout(timeout)
121
+ if (timeout) BgTimer.clearTimeout(timeout)
120
122
  if (unsubscribe) unsubscribe()
121
123
  if (onAbort && options.signal) options.signal.removeEventListener("abort", onAbort)
122
124
  resolve(ready)
@@ -129,7 +131,7 @@ async function waitForTargetReady(options: PairingReadyWaitOptions, timeoutMs: n
129
131
  onAbort = () => finish(false)
130
132
  options.signal.addEventListener("abort", onAbort)
131
133
  }
132
- timeout = setTimeout(() => finish(projectTargetReady(options)), timeoutMs)
134
+ timeout = BgTimer.setTimeout(() => finish(projectTargetReady(options)), timeoutMs)
133
135
  })
134
136
  }
135
137
 
@@ -218,14 +220,14 @@ async function waitForBluetoothClassic(
218
220
  }
219
221
 
220
222
  let settled = false
221
- let timeout: ReturnType<typeof setTimeout> | null = null
223
+ let timeout: number | null = null
222
224
  let unsubscribe: (() => void) | null = null
223
225
  let onAbort: (() => void) | null = null
224
226
 
225
227
  const finish = (value: boolean) => {
226
228
  if (settled) return
227
229
  settled = true
228
- if (timeout) clearTimeout(timeout)
230
+ if (timeout) BgTimer.clearTimeout(timeout)
229
231
  if (unsubscribe) unsubscribe()
230
232
  if (onAbort && options.signal) options.signal.removeEventListener("abort", onAbort)
231
233
  resolve(value)
@@ -243,7 +245,7 @@ async function waitForBluetoothClassic(
243
245
  },
244
246
  )
245
247
 
246
- timeout = setTimeout(() => {
248
+ timeout = BgTimer.setTimeout(() => {
247
249
  finish(useGlassesStore.getState().bluetoothClassicConnected)
248
250
  }, timeoutMs)
249
251
  })