@glassly/engine 0.1.0-dev.98 → 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
@@ -0,0 +1,16 @@
1
+ import type { MirrorSnapshot } from "@glassly/miniapp";
2
+ export interface MirrorSource {
3
+ event: unknown;
4
+ canvas: {
5
+ width: number;
6
+ height: number;
7
+ } | null;
8
+ connected: boolean;
9
+ model: string | null;
10
+ battery: number;
11
+ measureChar: (char: string) => number;
12
+ now: number;
13
+ }
14
+ /** Copy and normalize host layouts at the public boundary; never leak store references. */
15
+ export declare function buildMirrorSnapshot(source: MirrorSource, revision: number): MirrorSnapshot;
16
+ //# sourceMappingURL=mirrorSnapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mirrorSnapshot.d.ts","sourceRoot":"","sources":["../../src/services/mirrorSnapshot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA+B,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAElF,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,GAAG,IAAI,CAAA;IAC9C,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;IACrC,GAAG,EAAE,MAAM,CAAA;CACZ;AAOD,2FAA2F;AAC3F,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,CAiG1F"}
@@ -0,0 +1,102 @@
1
+ const object = (v) => v !== null && typeof v === "object" && !Array.isArray(v) ? v : {};
2
+ const number = (v, fallback = 0) => (typeof v === "number" && Number.isFinite(v) ? v : fallback);
3
+ const string = (v) => (typeof v === "string" ? v : "");
4
+ /** Copy and normalize host layouts at the public boundary; never leak store references. */
5
+ export function buildMirrorSnapshot(source, revision) {
6
+ const { now, connected, model, measureChar } = source;
7
+ const event = object(source.event);
8
+ const layout = object(event.layout);
9
+ let canvas = source.canvas;
10
+ let content = { kind: "empty" };
11
+ const widths = {};
12
+ const date = new Date(now);
13
+ const pad = (n) => String(n).padStart(2, "0");
14
+ const parseText = (value) => {
15
+ const text = string(value)
16
+ .replace(/\$DATE\$/g, `${pad(date.getMonth() + 1)}/${pad(date.getDate())}`)
17
+ .replace(/\$TIME12\$/g, `${pad(date.getHours() % 12 || 12)}:${pad(date.getMinutes())}`)
18
+ .replace(/\$TIME24\$/g, `${pad(date.getHours())}:${pad(date.getMinutes())}`)
19
+ .replace(/\$GBATT\$/g, source.battery >= 0 ? `${source.battery}%` : "")
20
+ .replace(/\$CONNECTION_STATUS\$/g, connected ? "Connected" : "Disconnected");
21
+ for (const char of text)
22
+ widths[char] = measureChar(char);
23
+ return text;
24
+ };
25
+ const textElement = (id, text, x, y, w, h) => ({
26
+ id,
27
+ type: "text",
28
+ text: parseText(text),
29
+ box: { x, y, w, h },
30
+ change: "created",
31
+ });
32
+ if (!canvas)
33
+ content = { kind: "unavailable", reason: "no-display" };
34
+ else if (layout.layoutType === "unavailable")
35
+ content = { kind: "unavailable", reason: string(layout.reason) || "unknown" };
36
+ else if (layout.layoutType === "scene") {
37
+ canvas = { width: number(layout.width, canvas.width), height: number(layout.height, canvas.height) };
38
+ const elements = [];
39
+ for (const raw of Array.isArray(layout.elements) ? layout.elements : []) {
40
+ const el = object(raw);
41
+ if (typeof el.id !== "string" || typeof el.type !== "string" || !el.box)
42
+ continue;
43
+ // SceneRenderer produces validated FrameElements. Serialization strips
44
+ // references; private native compiler/hash fields stay inside the host.
45
+ const { path: _path, contentHash: _hash, ...copy } = JSON.parse(JSON.stringify(el));
46
+ if (copy.type === "text")
47
+ copy.text = parseText(copy.text);
48
+ elements.push(copy);
49
+ }
50
+ content = elements.length ? { kind: "scene", elements, epoch: number(layout.sceneEpoch) } : { kind: "empty" };
51
+ }
52
+ else if (layout.layoutType === "bitmap_view") {
53
+ content = { kind: "bitmap", data: string(layout.data) };
54
+ }
55
+ else if (layout.layoutType && layout.layoutType !== "clear_view") {
56
+ const { width: w, height: h } = canvas;
57
+ let elements = null;
58
+ switch (layout.layoutType) {
59
+ case "text_wall":
60
+ case "text_line":
61
+ elements = [textElement("text", layout.text, 0, 0, w, h)];
62
+ break;
63
+ case "text_rows":
64
+ elements = [textElement("text", Array.isArray(layout.text) ? layout.text.join("\n") : "", 0, 0, w, h)];
65
+ break;
66
+ case "reference_card":
67
+ elements = [
68
+ textElement("text", [string(layout.title), string(layout.text)].filter(Boolean).join("\n"), 0, 0, w, h),
69
+ ];
70
+ break;
71
+ case "double_text_wall":
72
+ elements = [
73
+ textElement("top", layout.topText, 0, 0, w, h / 2),
74
+ textElement("bottom", layout.bottomText, 0, h / 2, w, h / 2),
75
+ ];
76
+ break;
77
+ case "positioned_text":
78
+ elements = [
79
+ {
80
+ ...textElement("text", layout.text, number(layout.x), number(layout.y), number(layout.width, w), number(layout.height, h)),
81
+ style: { border: number(layout.borderWidth), radius: number(layout.borderRadius) },
82
+ },
83
+ ];
84
+ break;
85
+ }
86
+ content = elements
87
+ ? { kind: "scene", elements, epoch: 0 }
88
+ : { kind: "unavailable", reason: `unsupported-layout:${string(layout.layoutType)}` };
89
+ }
90
+ return {
91
+ revision,
92
+ updatedAt: now,
93
+ connected,
94
+ model,
95
+ canvas,
96
+ view: event.view === "dashboard" ? "dashboard" : canvas ? "main" : null,
97
+ appId: typeof layout.appId === "string" ? layout.appId : null,
98
+ content,
99
+ glyphWidths: widths,
100
+ };
101
+ }
102
+ //# sourceMappingURL=mirrorSnapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mirrorSnapshot.js","sourceRoot":"","sources":["../../src/services/mirrorSnapshot.ts"],"names":[],"mappings":"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","sourcesContent":["import type {MirrorContent, MirrorElement, MirrorSnapshot} from \"@glassly/miniapp\"\n\nexport interface MirrorSource {\n event: unknown\n canvas: {width: number; height: number} | null\n connected: boolean\n model: string | null\n battery: number\n measureChar: (char: string) => number\n now: number\n}\n\nconst object = (v: unknown): Record<string, unknown> =>\n v !== null && typeof v === \"object\" && !Array.isArray(v) ? (v as Record<string, unknown>) : {}\nconst number = (v: unknown, fallback = 0): number => (typeof v === \"number\" && Number.isFinite(v) ? v : fallback)\nconst string = (v: unknown): string => (typeof v === \"string\" ? v : \"\")\n\n/** Copy and normalize host layouts at the public boundary; never leak store references. */\nexport function buildMirrorSnapshot(source: MirrorSource, revision: number): MirrorSnapshot {\n const {now, connected, model, measureChar} = source\n const event = object(source.event)\n const layout = object(event.layout)\n let canvas = source.canvas\n let content: MirrorContent = {kind: \"empty\"}\n const widths: Record<string, number> = {}\n const date = new Date(now)\n const pad = (n: number) => String(n).padStart(2, \"0\")\n const parseText = (value: unknown) => {\n const text = string(value)\n .replace(/\\$DATE\\$/g, `${pad(date.getMonth() + 1)}/${pad(date.getDate())}`)\n .replace(/\\$TIME12\\$/g, `${pad(date.getHours() % 12 || 12)}:${pad(date.getMinutes())}`)\n .replace(/\\$TIME24\\$/g, `${pad(date.getHours())}:${pad(date.getMinutes())}`)\n .replace(/\\$GBATT\\$/g, source.battery >= 0 ? `${source.battery}%` : \"\")\n .replace(/\\$CONNECTION_STATUS\\$/g, connected ? \"Connected\" : \"Disconnected\")\n for (const char of text) widths[char] = measureChar(char)\n return text\n }\n const textElement = (id: string, text: unknown, x: number, y: number, w: number, h: number): MirrorElement => ({\n id,\n type: \"text\",\n text: parseText(text),\n box: {x, y, w, h},\n change: \"created\",\n })\n if (!canvas) content = {kind: \"unavailable\", reason: \"no-display\"}\n else if (layout.layoutType === \"unavailable\")\n content = {kind: \"unavailable\", reason: string(layout.reason) || \"unknown\"}\n else if (layout.layoutType === \"scene\") {\n canvas = {width: number(layout.width, canvas.width), height: number(layout.height, canvas.height)}\n const elements: MirrorElement[] = []\n for (const raw of Array.isArray(layout.elements) ? layout.elements : []) {\n const el = object(raw)\n if (typeof el.id !== \"string\" || typeof el.type !== \"string\" || !el.box) continue\n // SceneRenderer produces validated FrameElements. Serialization strips\n // references; private native compiler/hash fields stay inside the host.\n const {path: _path, contentHash: _hash, ...copy} = JSON.parse(JSON.stringify(el))\n if (copy.type === \"text\") copy.text = parseText(copy.text)\n elements.push(copy as MirrorElement)\n }\n content = elements.length ? {kind: \"scene\", elements, epoch: number(layout.sceneEpoch)} : {kind: \"empty\"}\n } else if (layout.layoutType === \"bitmap_view\") {\n content = {kind: \"bitmap\", data: string(layout.data)}\n } else if (layout.layoutType && layout.layoutType !== \"clear_view\") {\n const {width: w, height: h} = canvas\n let elements: MirrorElement[] | null = null\n switch (layout.layoutType) {\n case \"text_wall\":\n case \"text_line\":\n elements = [textElement(\"text\", layout.text, 0, 0, w, h)]\n break\n case \"text_rows\":\n elements = [textElement(\"text\", Array.isArray(layout.text) ? layout.text.join(\"\\n\") : \"\", 0, 0, w, h)]\n break\n case \"reference_card\":\n elements = [\n textElement(\"text\", [string(layout.title), string(layout.text)].filter(Boolean).join(\"\\n\"), 0, 0, w, h),\n ]\n break\n case \"double_text_wall\":\n elements = [\n textElement(\"top\", layout.topText, 0, 0, w, h / 2),\n textElement(\"bottom\", layout.bottomText, 0, h / 2, w, h / 2),\n ]\n break\n case \"positioned_text\":\n elements = [\n {\n ...textElement(\n \"text\",\n layout.text,\n number(layout.x),\n number(layout.y),\n number(layout.width, w),\n number(layout.height, h),\n ),\n style: {border: number(layout.borderWidth), radius: number(layout.borderRadius)},\n },\n ]\n break\n }\n content = elements\n ? {kind: \"scene\", elements, epoch: 0}\n : {kind: \"unavailable\", reason: `unsupported-layout:${string(layout.layoutType)}`}\n }\n return {\n revision,\n updatedAt: now,\n connected,\n model,\n canvas,\n view: event.view === \"dashboard\" ? \"dashboard\" : canvas ? \"main\" : null,\n appId: typeof layout.appId === \"string\" ? layout.appId : null,\n content,\n glyphWidths: widths,\n }\n}\n"]}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The firmware nav UI is a stock-firmware feature. Custom firmware publishes a
3
+ * scene canvas, so the navigation miniapp draws its own HUD there and reads
4
+ * session.compass directly; native nav mode would only cover that up. The
5
+ * debug knob forces it back on for comparing both UIs on hardware.
6
+ */
7
+ export declare function resolveNativeNavigation(modelSupports: boolean | undefined, customFirmware: boolean, forceOnCustomFirmware: boolean): boolean | undefined;
8
+ //# sourceMappingURL=nativeNavigationGate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nativeNavigationGate.d.ts","sourceRoot":"","sources":["../../src/services/nativeNavigationGate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,OAAO,GAAG,SAAS,EAClC,cAAc,EAAE,OAAO,EACvB,qBAAqB,EAAE,OAAO,GAC7B,OAAO,GAAG,SAAS,CAGrB"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The firmware nav UI is a stock-firmware feature. Custom firmware publishes a
3
+ * scene canvas, so the navigation miniapp draws its own HUD there and reads
4
+ * session.compass directly; native nav mode would only cover that up. The
5
+ * debug knob forces it back on for comparing both UIs on hardware.
6
+ */
7
+ export function resolveNativeNavigation(modelSupports, customFirmware, forceOnCustomFirmware) {
8
+ if (modelSupports !== true)
9
+ return modelSupports;
10
+ return !customFirmware || forceOnCustomFirmware;
11
+ }
12
+ //# sourceMappingURL=nativeNavigationGate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nativeNavigationGate.js","sourceRoot":"","sources":["../../src/services/nativeNavigationGate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CACrC,aAAkC,EAClC,cAAuB,EACvB,qBAA8B;IAE9B,IAAI,aAAa,KAAK,IAAI;QAAE,OAAO,aAAa,CAAA;IAChD,OAAO,CAAC,cAAc,IAAI,qBAAqB,CAAA;AACjD,CAAC","sourcesContent":["/**\n * The firmware nav UI is a stock-firmware feature. Custom firmware publishes a\n * scene canvas, so the navigation miniapp draws its own HUD there and reads\n * session.compass directly; native nav mode would only cover that up. The\n * debug knob forces it back on for comparing both UIs on hardware.\n */\nexport function resolveNativeNavigation(\n modelSupports: boolean | undefined,\n customFirmware: boolean,\n forceOnCustomFirmware: boolean,\n): boolean | undefined {\n if (modelSupports !== true) return modelSupports\n return !customFirmware || forceOnCustomFirmware\n}\n"]}
@@ -0,0 +1,7 @@
1
+ export interface NotificationApp {
2
+ appId: string;
3
+ displayName: string;
4
+ }
5
+ /** The catalog for the current phone platform. */
6
+ export declare function notificationAppCatalog(): NotificationApp[];
7
+ //# sourceMappingURL=notificationAppCatalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notificationAppCatalog.d.ts","sourceRoot":"","sources":["../../src/services/notificationAppCatalog.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,kDAAkD;AAClD,wBAAgB,sBAAsB,IAAI,eAAe,EAAE,CAG1D"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Seeded catalog of apps that post notifications, keyed by bundle id or
3
+ * package name. Where the phone cannot enumerate apps (iOS) the filter UI
4
+ * shows this catalog plus apps the glasses have reported, and firmware whose
5
+ * filter is an allowlist needs known ids so blocking one app does not take
6
+ * every not-yet-seen app down with it. Derived from the SDK's known-apps
7
+ * table so names live in one place.
8
+ */
9
+ import { KNOWN_APPS } from "@glassly/miniapp/known-apps";
10
+ import { Platform } from "react-native";
11
+ /** The catalog for the current phone platform. */
12
+ export function notificationAppCatalog() {
13
+ const other = Platform.OS === "ios" ? "android" : "ios";
14
+ return KNOWN_APPS.filter((app) => app.platform !== other).map((app) => ({ appId: app.id, displayName: app.name }));
15
+ }
16
+ //# sourceMappingURL=notificationAppCatalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notificationAppCatalog.js","sourceRoot":"","sources":["../../src/services/notificationAppCatalog.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAC,UAAU,EAAC,MAAM,6BAA6B,CAAA;AACtD,OAAO,EAAC,QAAQ,EAAC,MAAM,cAAc,CAAA;AAOrC,kDAAkD;AAClD,MAAM,UAAU,sBAAsB;IACpC,MAAM,KAAK,GAAG,QAAQ,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAA;IACvD,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAC,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE,WAAW,EAAE,GAAG,CAAC,IAAI,EAAC,CAAC,CAAC,CAAA;AAClH,CAAC","sourcesContent":["/**\n * Seeded catalog of apps that post notifications, keyed by bundle id or\n * package name. Where the phone cannot enumerate apps (iOS) the filter UI\n * shows this catalog plus apps the glasses have reported, and firmware whose\n * filter is an allowlist needs known ids so blocking one app does not take\n * every not-yet-seen app down with it. Derived from the SDK's known-apps\n * table so names live in one place.\n */\nimport {KNOWN_APPS} from \"@glassly/miniapp/known-apps\"\nimport {Platform} from \"react-native\"\n\nexport interface NotificationApp {\n appId: string\n displayName: string\n}\n\n/** The catalog for the current phone platform. */\nexport function notificationAppCatalog(): NotificationApp[] {\n const other = Platform.OS === \"ios\" ? \"android\" : \"ios\"\n return KNOWN_APPS.filter((app) => app.platform !== other).map((app) => ({appId: app.id, displayName: app.name}))\n}\n"]}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Notification policy, pure: what the glasses should do with phone
3
+ * notifications, from settings and the current state of the phone and the
4
+ * glasses. Two questions live here. `glassesNotificationConfig` is the
5
+ * behaviour pushed to firmware that presents notifications itself.
6
+ * `presentationOwner` names the one thing that may draw a notification for
7
+ * the wearer; every other consumer stays quiet. The adapters
8
+ * (PhoneNotificationsSync, the host) snapshot inputs and act on the answers.
9
+ */
10
+ import type { GlassesNotificationConfig } from "@glassly/bluetooth-sdk";
11
+ export interface NotificationApp {
12
+ appId: string;
13
+ displayName: string;
14
+ }
15
+ export interface NotificationConfigInput {
16
+ enabled: boolean;
17
+ popups: boolean;
18
+ popupSeconds: number;
19
+ holdDuringApps: boolean;
20
+ /** Hold popups while the wearer can see the phone. */
21
+ ignoreWhileActive: boolean;
22
+ phoneActive: boolean;
23
+ blockedApps: string[];
24
+ /** Catalog ∪ apps the glasses reported, for allowlist firmware. */
25
+ knownApps: NotificationApp[];
26
+ }
27
+ /**
28
+ * Popups fold the ignore-while-active gate in: firmware that pops
29
+ * notifications up by itself has no other way to hold them while the wearer
30
+ * is on the phone. The engine's viewer applies the same gate from its env.
31
+ */
32
+ export declare function effectivePopups(popups: boolean, ignoreWhileActive: boolean, phoneActive: boolean): boolean;
33
+ export declare function glassesNotificationConfig(input: NotificationConfigInput): GlassesNotificationConfig;
34
+ /**
35
+ * Who draws a phone notification for the wearer.
36
+ * viewer — the notifications viewer on connected Glassly CFW glasses, while it runs
37
+ * firmware — the glasses' own notification centre (hasNativeNotifications)
38
+ * host — the host app's card and speech, while its presentation surface runs
39
+ * none — nobody: notifications are off, or nothing is there to show them
40
+ * Miniapp forwarding is not presentation and is never gated by this.
41
+ */
42
+ export type PresentationOwner = "viewer" | "firmware" | "host" | "none";
43
+ export interface PresentationInput {
44
+ enabled: boolean;
45
+ /** Pages may show on the connected glasses. */
46
+ pagesEligible: boolean;
47
+ /** The viewer's app is running, so a page can actually show. */
48
+ viewerRunning: boolean;
49
+ /** The connected model presents notifications in firmware. */
50
+ nativeNotifications: boolean;
51
+ /** The Notifications miniapp is running, enabling the host fallback. */
52
+ hostActive: boolean;
53
+ }
54
+ export declare function presentationOwner(input: PresentationInput): PresentationOwner;
55
+ //# sourceMappingURL=notificationPolicy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notificationPolicy.d.ts","sourceRoot":"","sources":["../../../src/services/notifications/notificationPolicy.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,wBAAwB,CAAA;AAErE,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,OAAO,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,cAAc,EAAE,OAAO,CAAA;IACvB,sDAAsD;IACtD,iBAAiB,EAAE,OAAO,CAAA;IAC1B,WAAW,EAAE,OAAO,CAAA;IACpB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,mEAAmE;IACnE,SAAS,EAAE,eAAe,EAAE,CAAA;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,GAAG,OAAO,CAI1G;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,uBAAuB,GAAG,yBAAyB,CAgBnG;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAA;AAEvE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAA;IAChB,+CAA+C;IAC/C,aAAa,EAAE,OAAO,CAAA;IACtB,gEAAgE;IAChE,aAAa,EAAE,OAAO,CAAA;IACtB,8DAA8D;IAC9D,mBAAmB,EAAE,OAAO,CAAA;IAC5B,wEAAwE;IACxE,UAAU,EAAE,OAAO,CAAA;CACpB;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,iBAAiB,GAAG,iBAAiB,CAM7E"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Popups fold the ignore-while-active gate in: firmware that pops
3
+ * notifications up by itself has no other way to hold them while the wearer
4
+ * is on the phone. The engine's viewer applies the same gate from its env.
5
+ */
6
+ export function effectivePopups(popups, ignoreWhileActive, phoneActive) {
7
+ if (!popups)
8
+ return false;
9
+ if (!ignoreWhileActive)
10
+ return true;
11
+ return !phoneActive;
12
+ }
13
+ export function glassesNotificationConfig(input) {
14
+ const blocked = new Set(input.blockedApps);
15
+ const seconds = Number(input.popupSeconds);
16
+ // Known apps travel even while nothing is blocked so a first block enables
17
+ // the allowlist against the wearer's current list, not an empty one.
18
+ const allowedApps = input.knownApps
19
+ .filter((app) => app.appId && !blocked.has(app.appId))
20
+ .map((app) => ({ id: app.appId, name: app.displayName || app.appId }));
21
+ return {
22
+ enabled: input.enabled,
23
+ popups: effectivePopups(input.popups, input.ignoreWhileActive, input.phoneActive),
24
+ popupSeconds: Number.isFinite(seconds) && seconds > 0 ? Math.round(seconds) : 0,
25
+ holdDuringApps: input.holdDuringApps,
26
+ blockedApps: [...blocked],
27
+ allowedApps,
28
+ };
29
+ }
30
+ export function presentationOwner(input) {
31
+ if (!input.enabled)
32
+ return "none";
33
+ if (input.pagesEligible && input.viewerRunning)
34
+ return "viewer";
35
+ if (input.nativeNotifications)
36
+ return "firmware";
37
+ if (input.hostActive)
38
+ return "host";
39
+ return "none";
40
+ }
41
+ //# sourceMappingURL=notificationPolicy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notificationPolicy.js","sourceRoot":"","sources":["../../../src/services/notifications/notificationPolicy.ts"],"names":[],"mappings":"AA6BA;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,MAAe,EAAE,iBAA0B,EAAE,WAAoB;IAC/F,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAA;IACzB,IAAI,CAAC,iBAAiB;QAAE,OAAO,IAAI,CAAA;IACnC,OAAO,CAAC,WAAW,CAAA;AACrB,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,KAA8B;IACtE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;IAC1C,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;IAC1C,2EAA2E;IAC3E,qEAAqE;IACrE,MAAM,WAAW,GAAG,KAAK,CAAC,SAAS;SAChC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;SACrD,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAC,EAAE,EAAE,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,KAAK,EAAC,CAAC,CAAC,CAAA;IACtE,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,MAAM,EAAE,eAAe,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,iBAAiB,EAAE,KAAK,CAAC,WAAW,CAAC;QACjF,YAAY,EAAE,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/E,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,WAAW,EAAE,CAAC,GAAG,OAAO,CAAC;QACzB,WAAW;KACZ,CAAA;AACH,CAAC;AAwBD,MAAM,UAAU,iBAAiB,CAAC,KAAwB;IACxD,IAAI,CAAC,KAAK,CAAC,OAAO;QAAE,OAAO,MAAM,CAAA;IACjC,IAAI,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,aAAa;QAAE,OAAO,QAAQ,CAAA;IAC/D,IAAI,KAAK,CAAC,mBAAmB;QAAE,OAAO,UAAU,CAAA;IAChD,IAAI,KAAK,CAAC,UAAU;QAAE,OAAO,MAAM,CAAA;IACnC,OAAO,MAAM,CAAA;AACf,CAAC","sourcesContent":["/**\n * Notification policy, pure: what the glasses should do with phone\n * notifications, from settings and the current state of the phone and the\n * glasses. Two questions live here. `glassesNotificationConfig` is the\n * behaviour pushed to firmware that presents notifications itself.\n * `presentationOwner` names the one thing that may draw a notification for\n * the wearer; every other consumer stays quiet. The adapters\n * (PhoneNotificationsSync, the host) snapshot inputs and act on the answers.\n */\nimport type {GlassesNotificationConfig} from \"@glassly/bluetooth-sdk\"\n\nexport interface NotificationApp {\n appId: string\n displayName: string\n}\n\nexport interface NotificationConfigInput {\n enabled: boolean\n popups: boolean\n popupSeconds: number\n holdDuringApps: boolean\n /** Hold popups while the wearer can see the phone. */\n ignoreWhileActive: boolean\n phoneActive: boolean\n blockedApps: string[]\n /** Catalog ∪ apps the glasses reported, for allowlist firmware. */\n knownApps: NotificationApp[]\n}\n\n/**\n * Popups fold the ignore-while-active gate in: firmware that pops\n * notifications up by itself has no other way to hold them while the wearer\n * is on the phone. The engine's viewer applies the same gate from its env.\n */\nexport function effectivePopups(popups: boolean, ignoreWhileActive: boolean, phoneActive: boolean): boolean {\n if (!popups) return false\n if (!ignoreWhileActive) return true\n return !phoneActive\n}\n\nexport function glassesNotificationConfig(input: NotificationConfigInput): GlassesNotificationConfig {\n const blocked = new Set(input.blockedApps)\n const seconds = Number(input.popupSeconds)\n // Known apps travel even while nothing is blocked so a first block enables\n // the allowlist against the wearer's current list, not an empty one.\n const allowedApps = input.knownApps\n .filter((app) => app.appId && !blocked.has(app.appId))\n .map((app) => ({id: app.appId, name: app.displayName || app.appId}))\n return {\n enabled: input.enabled,\n popups: effectivePopups(input.popups, input.ignoreWhileActive, input.phoneActive),\n popupSeconds: Number.isFinite(seconds) && seconds > 0 ? Math.round(seconds) : 0,\n holdDuringApps: input.holdDuringApps,\n blockedApps: [...blocked],\n allowedApps,\n }\n}\n\n/**\n * Who draws a phone notification for the wearer.\n * viewer — the notifications viewer on connected Glassly CFW glasses, while it runs\n * firmware — the glasses' own notification centre (hasNativeNotifications)\n * host — the host app's card and speech, while its presentation surface runs\n * none — nobody: notifications are off, or nothing is there to show them\n * Miniapp forwarding is not presentation and is never gated by this.\n */\nexport type PresentationOwner = \"viewer\" | \"firmware\" | \"host\" | \"none\"\n\nexport interface PresentationInput {\n enabled: boolean\n /** Pages may show on the connected glasses. */\n pagesEligible: boolean\n /** The viewer's app is running, so a page can actually show. */\n viewerRunning: boolean\n /** The connected model presents notifications in firmware. */\n nativeNotifications: boolean\n /** The Notifications miniapp is running, enabling the host fallback. */\n hostActive: boolean\n}\n\nexport function presentationOwner(input: PresentationInput): PresentationOwner {\n if (!input.enabled) return \"none\"\n if (input.pagesEligible && input.viewerRunning) return \"viewer\"\n if (input.nativeNotifications) return \"firmware\"\n if (input.hostActive) return \"host\"\n return \"none\"\n}\n"]}
@@ -0,0 +1,26 @@
1
+ export type DashboardViewChangeReason = "shown" | "hidden" | "replaced" | "ineligible";
2
+ export interface OverlayPagesSink {
3
+ /** Deliver a display_view event to the app. */
4
+ send(packageName: string, event: Record<string, unknown>): void;
5
+ }
6
+ declare class OverlayPages {
7
+ private sink;
8
+ private pages;
9
+ /** Set while an app's page is torn down with the app; it hears nothing then. */
10
+ private silent;
11
+ setSink(sink: OverlayPagesSink | null): void;
12
+ /** The app whose page holds the slot, or null. */
13
+ get showingPackage(): string | null;
14
+ /** Give the app the slot (a no-op when it already shows or pages are not eligible). */
15
+ show(packageName: string): boolean;
16
+ /** Release the slot if the app holds it. */
17
+ hide(packageName: string): void;
18
+ /** The app stopped: release the slot without telling it, and forget its page. */
19
+ remove(packageName: string): void;
20
+ private pageFor;
21
+ private emit;
22
+ }
23
+ declare const overlayPages: OverlayPages;
24
+ export default overlayPages;
25
+ export { OverlayPages };
26
+ //# sourceMappingURL=OverlayPages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OverlayPages.d.ts","sourceRoot":"","sources":["../../../src/services/pages/OverlayPages.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,yBAAyB,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,GAAG,YAAY,CAAA;AAEtF,MAAM,WAAW,gBAAgB;IAC/B,+CAA+C;IAC/C,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;CAChE;AAED,cAAM,YAAY;IAChB,OAAO,CAAC,IAAI,CAAgC;IAC5C,OAAO,CAAC,KAAK,CAA0B;IACvC,gFAAgF;IAChF,OAAO,CAAC,MAAM,CAAoB;IAElC,OAAO,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,GAAG,IAAI;IAI5C,kDAAkD;IAClD,IAAI,cAAc,IAAI,MAAM,GAAG,IAAI,CAKlC;IAED,uFAAuF;IACvF,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAOlC,4CAA4C;IAC5C,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAK/B,iFAAiF;IACjF,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAYjC,OAAO,CAAC,OAAO;IAYf,OAAO,CAAC,IAAI;CAIb;AAED,QAAA,MAAM,YAAY,cAAqB,CAAA;AACvC,eAAe,YAAY,CAAA;AAC3B,OAAO,EAAC,YAAY,EAAC,CAAA"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * The overlay apps' pages (ADR-0006): one Page per app that has taken the
3
+ * slot, the only Page implementation the page host shows. The engine keeps
4
+ * the slot and the eligibility watch; a page only relays: holding the slot
5
+ * is reported to its app as a view change, and the app's frames reach the
6
+ * slot through `renderOverlay` under its package name. Whichever app asked
7
+ * last holds the slot; the previous one hears it was replaced. The runtime
8
+ * supplies the sink that delivers to apps, so this module never imports it.
9
+ */
10
+ import pageHost from "./PageHost";
11
+ import { isOverlayApp } from "./overlayApps";
12
+ import { pagesEligible } from "./pageEligibility";
13
+ class OverlayPages {
14
+ sink = null;
15
+ pages = new Map();
16
+ /** Set while an app's page is torn down with the app; it hears nothing then. */
17
+ silent = new Set();
18
+ setSink(sink) {
19
+ this.sink = sink;
20
+ }
21
+ /** The app whose page holds the slot, or null. */
22
+ get showingPackage() {
23
+ const showing = pageHost.showing;
24
+ if (!showing)
25
+ return null;
26
+ for (const [packageName, page] of this.pages)
27
+ if (page === showing)
28
+ return packageName;
29
+ return null;
30
+ }
31
+ /** Give the app the slot (a no-op when it already shows or pages are not eligible). */
32
+ show(packageName) {
33
+ if (!isOverlayApp(packageName) || !pagesEligible())
34
+ return false;
35
+ const page = this.pageFor(packageName);
36
+ pageHost.show(page);
37
+ return pageHost.showing === page;
38
+ }
39
+ /** Release the slot if the app holds it. */
40
+ hide(packageName) {
41
+ const page = this.pages.get(packageName);
42
+ if (page)
43
+ pageHost.hide(page);
44
+ }
45
+ /** The app stopped: release the slot without telling it, and forget its page. */
46
+ remove(packageName) {
47
+ const page = this.pages.get(packageName);
48
+ if (!page)
49
+ return;
50
+ this.silent.add(packageName);
51
+ try {
52
+ pageHost.hide(page);
53
+ }
54
+ finally {
55
+ this.silent.delete(packageName);
56
+ }
57
+ this.pages.delete(packageName);
58
+ }
59
+ pageFor(packageName) {
60
+ let page = this.pages.get(packageName);
61
+ if (page)
62
+ return page;
63
+ page = {
64
+ id: packageName,
65
+ onShown: () => this.emit(packageName, { kind: "change", view: "dashboard", reason: "shown" }),
66
+ onHidden: (reason) => this.emit(packageName, { kind: "change", view: "main", reason }),
67
+ };
68
+ this.pages.set(packageName, page);
69
+ return page;
70
+ }
71
+ emit(packageName, event) {
72
+ if (this.silent.has(packageName) || !isOverlayApp(packageName))
73
+ return;
74
+ this.sink?.send(packageName, event);
75
+ }
76
+ }
77
+ const overlayPages = new OverlayPages();
78
+ export default overlayPages;
79
+ export { OverlayPages };
80
+ //# sourceMappingURL=OverlayPages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OverlayPages.js","sourceRoot":"","sources":["../../../src/services/pages/OverlayPages.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The overlay apps' pages (ADR-0006): one Page per app that has taken the\n * slot, the only Page implementation the page host shows. The engine keeps\n * the slot and the eligibility watch; a page only relays: holding the slot\n * is reported to its app as a view change, and the app's frames reach the\n * slot through `renderOverlay` under its package name. Whichever app asked\n * last holds the slot; the previous one hears it was replaced. The runtime\n * supplies the sink that delivers to apps, so this module never imports it.\n */\nimport pageHost, {type Page, type PageHiddenReason} from \"./PageHost\"\nimport {isOverlayApp} from \"./overlayApps\"\nimport {pagesEligible} from \"./pageEligibility\"\n\nexport type DashboardViewChangeReason = \"shown\" | \"hidden\" | \"replaced\" | \"ineligible\"\n\nexport interface OverlayPagesSink {\n /** Deliver a display_view event to the app. */\n send(packageName: string, event: Record<string, unknown>): void\n}\n\nclass OverlayPages {\n private sink: OverlayPagesSink | null = null\n private pages = new Map<string, Page>()\n /** Set while an app's page is torn down with the app; it hears nothing then. */\n private silent = new Set<string>()\n\n setSink(sink: OverlayPagesSink | null): void {\n this.sink = sink\n }\n\n /** The app whose page holds the slot, or null. */\n get showingPackage(): string | null {\n const showing = pageHost.showing\n if (!showing) return null\n for (const [packageName, page] of this.pages) if (page === showing) return packageName\n return null\n }\n\n /** Give the app the slot (a no-op when it already shows or pages are not eligible). */\n show(packageName: string): boolean {\n if (!isOverlayApp(packageName) || !pagesEligible()) return false\n const page = this.pageFor(packageName)\n pageHost.show(page)\n return pageHost.showing === page\n }\n\n /** Release the slot if the app holds it. */\n hide(packageName: string): void {\n const page = this.pages.get(packageName)\n if (page) pageHost.hide(page)\n }\n\n /** The app stopped: release the slot without telling it, and forget its page. */\n remove(packageName: string): void {\n const page = this.pages.get(packageName)\n if (!page) return\n this.silent.add(packageName)\n try {\n pageHost.hide(page)\n } finally {\n this.silent.delete(packageName)\n }\n this.pages.delete(packageName)\n }\n\n private pageFor(packageName: string): Page {\n let page = this.pages.get(packageName)\n if (page) return page\n page = {\n id: packageName,\n onShown: () => this.emit(packageName, {kind: \"change\", view: \"dashboard\", reason: \"shown\"}),\n onHidden: (reason: PageHiddenReason) => this.emit(packageName, {kind: \"change\", view: \"main\", reason}),\n }\n this.pages.set(packageName, page)\n return page\n }\n\n private emit(packageName: string, event: Record<string, unknown>): void {\n if (this.silent.has(packageName) || !isOverlayApp(packageName)) return\n this.sink?.send(packageName, event)\n }\n}\n\nconst overlayPages = new OverlayPages()\nexport default overlayPages\nexport {OverlayPages}\n"]}
@@ -0,0 +1,32 @@
1
+ export type PageHiddenReason = "hidden" | "replaced" | "ineligible";
2
+ export interface Page {
3
+ /** Scene app id; the overlay owner while the page shows. */
4
+ readonly id: string;
5
+ /** The page holds the slot: draw the first frame. */
6
+ onShown(): void;
7
+ /** The slot was released, taken by another page, or lost with eligibility. */
8
+ onHidden(reason: PageHiddenReason): void;
9
+ }
10
+ declare class PageHost {
11
+ private showingPage;
12
+ private ops;
13
+ private draining;
14
+ private listeners;
15
+ private unsubs;
16
+ private started;
17
+ start(): void;
18
+ stop(): void;
19
+ get showing(): Page | null;
20
+ /** Give `page` the slot; no-op when it already shows or pages are not eligible. */
21
+ show(page: Page): void;
22
+ /** Release the slot if `page` holds it. */
23
+ hide(page: Page): void;
24
+ onChange(listener: (page: Page | null) => void): () => void;
25
+ private release;
26
+ private emit;
27
+ private enqueue;
28
+ }
29
+ declare const pageHost: PageHost;
30
+ export default pageHost;
31
+ export { PageHost };
32
+ //# sourceMappingURL=PageHost.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PageHost.d.ts","sourceRoot":"","sources":["../../../src/services/pages/PageHost.ts"],"names":[],"mappings":"AAeA,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,UAAU,GAAG,YAAY,CAAA;AAEnE,MAAM,WAAW,IAAI;IACnB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,qDAAqD;IACrD,OAAO,IAAI,IAAI,CAAA;IACf,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAA;CACzC;AAED,cAAM,QAAQ;IACZ,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,GAAG,CAAwB;IACnC,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,SAAS,CAAyC;IAC1D,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,OAAO,CAAQ;IAEvB,KAAK,IAAI,IAAI;IAeb,IAAI,IAAI,IAAI;IAOZ,IAAI,OAAO,IAAI,IAAI,GAAG,IAAI,CAEzB;IAED,mFAAmF;IACnF,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAYtB,2CAA2C;IAC3C,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAOtB,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,GAAG,MAAM,IAAI;IAO3D,OAAO,CAAC,OAAO;IASf,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,OAAO;CAUhB;AAED,QAAA,MAAM,QAAQ,UAAiB,CAAA;AAC/B,eAAe,QAAQ,CAAA;AACvB,OAAO,EAAC,QAAQ,EAAC,CAAA"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * The page host owns the overlay slot: the single native view above the main
3
+ * content. At most one page shows at a time; showing a page replaces whatever
4
+ * was showing, hiding releases the slot and the main content replays. Which
5
+ * app gets the wearer's gestures is the gesture claims' business, not the
6
+ * host's. Show and hide run through one queue so a page
7
+ * that hides itself from inside its own transition is hidden afterwards, never
8
+ * re-entered. Eligibility (Glassly CFW, dashboard enabled) is checked before a
9
+ * show and watched while a page is up.
10
+ */
11
+ import { useGlassesStore } from "../../stores/glasses";
12
+ import { SETTINGS, useSettingsStore } from "../../stores/settings";
13
+ import localDisplayManager from "../LocalDisplayManager";
14
+ import { pagesEligible } from "./pageEligibility";
15
+ class PageHost {
16
+ showingPage = null;
17
+ ops = [];
18
+ draining = false;
19
+ listeners = new Set();
20
+ unsubs = [];
21
+ started = false;
22
+ start() {
23
+ if (this.started)
24
+ return;
25
+ this.started = true;
26
+ const check = () => {
27
+ if (this.showingPage && !pagesEligible())
28
+ this.release("ineligible");
29
+ };
30
+ this.unsubs.push(useGlassesStore.subscribe((state) => `${state.connection.state}:${state.deviceModel}:${state.firmwareVersion}`, check), useSettingsStore.subscribe((state) => state.getSetting(SETTINGS.custom_dashboard_enabled.key), check));
31
+ }
32
+ stop() {
33
+ for (const unsub of this.unsubs)
34
+ unsub();
35
+ this.unsubs = [];
36
+ this.release("hidden");
37
+ this.started = false;
38
+ }
39
+ get showing() {
40
+ return this.showingPage;
41
+ }
42
+ /** Give `page` the slot; no-op when it already shows or pages are not eligible. */
43
+ show(page) {
44
+ this.enqueue(() => {
45
+ if (this.showingPage === page || !pagesEligible())
46
+ return;
47
+ const previous = this.showingPage;
48
+ this.showingPage = page;
49
+ localDisplayManager.setOverlayOwner(page.id);
50
+ previous?.onHidden("replaced");
51
+ page.onShown();
52
+ this.emit();
53
+ });
54
+ }
55
+ /** Release the slot if `page` holds it. */
56
+ hide(page) {
57
+ this.enqueue(() => {
58
+ if (this.showingPage !== page)
59
+ return;
60
+ this.release("hidden");
61
+ });
62
+ }
63
+ onChange(listener) {
64
+ this.listeners.add(listener);
65
+ return () => {
66
+ this.listeners.delete(listener);
67
+ };
68
+ }
69
+ release(reason) {
70
+ const page = this.showingPage;
71
+ if (!page)
72
+ return;
73
+ this.showingPage = null;
74
+ localDisplayManager.setOverlayOwner(null);
75
+ page.onHidden(reason);
76
+ this.emit();
77
+ }
78
+ emit() {
79
+ for (const listener of Array.from(this.listeners))
80
+ listener(this.showingPage);
81
+ }
82
+ enqueue(op) {
83
+ this.ops.push(op);
84
+ if (this.draining)
85
+ return;
86
+ this.draining = true;
87
+ try {
88
+ while (this.ops.length)
89
+ this.ops.shift()();
90
+ }
91
+ finally {
92
+ this.draining = false;
93
+ }
94
+ }
95
+ }
96
+ const pageHost = new PageHost();
97
+ export default pageHost;
98
+ export { PageHost };
99
+ //# sourceMappingURL=PageHost.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PageHost.js","sourceRoot":"","sources":["../../../src/services/pages/PageHost.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The page host owns the overlay slot: the single native view above the main\n * content. At most one page shows at a time; showing a page replaces whatever\n * was showing, hiding releases the slot and the main content replays. Which\n * app gets the wearer's gestures is the gesture claims' business, not the\n * host's. Show and hide run through one queue so a page\n * that hides itself from inside its own transition is hidden afterwards, never\n * re-entered. Eligibility (Glassly CFW, dashboard enabled) is checked before a\n * show and watched while a page is up.\n */\nimport {useGlassesStore} from \"../../stores/glasses\"\nimport {SETTINGS, useSettingsStore} from \"../../stores/settings\"\nimport localDisplayManager from \"../LocalDisplayManager\"\nimport {pagesEligible} from \"./pageEligibility\"\n\nexport type PageHiddenReason = \"hidden\" | \"replaced\" | \"ineligible\"\n\nexport interface Page {\n /** Scene app id; the overlay owner while the page shows. */\n readonly id: string\n /** The page holds the slot: draw the first frame. */\n onShown(): void\n /** The slot was released, taken by another page, or lost with eligibility. */\n onHidden(reason: PageHiddenReason): void\n}\n\nclass PageHost {\n private showingPage: Page | null = null\n private ops: Array<() => void> = []\n private draining = false\n private listeners = new Set<(page: Page | null) => void>()\n private unsubs: Array<() => void> = []\n private started = false\n\n start(): void {\n if (this.started) return\n this.started = true\n const check = () => {\n if (this.showingPage && !pagesEligible()) this.release(\"ineligible\")\n }\n this.unsubs.push(\n useGlassesStore.subscribe(\n (state) => `${state.connection.state}:${state.deviceModel}:${state.firmwareVersion}`,\n check,\n ),\n useSettingsStore.subscribe((state) => state.getSetting(SETTINGS.custom_dashboard_enabled.key), check),\n )\n }\n\n stop(): void {\n for (const unsub of this.unsubs) unsub()\n this.unsubs = []\n this.release(\"hidden\")\n this.started = false\n }\n\n get showing(): Page | null {\n return this.showingPage\n }\n\n /** Give `page` the slot; no-op when it already shows or pages are not eligible. */\n show(page: Page): void {\n this.enqueue(() => {\n if (this.showingPage === page || !pagesEligible()) return\n const previous = this.showingPage\n this.showingPage = page\n localDisplayManager.setOverlayOwner(page.id)\n previous?.onHidden(\"replaced\")\n page.onShown()\n this.emit()\n })\n }\n\n /** Release the slot if `page` holds it. */\n hide(page: Page): void {\n this.enqueue(() => {\n if (this.showingPage !== page) return\n this.release(\"hidden\")\n })\n }\n\n onChange(listener: (page: Page | null) => void): () => void {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n private release(reason: PageHiddenReason): void {\n const page = this.showingPage\n if (!page) return\n this.showingPage = null\n localDisplayManager.setOverlayOwner(null)\n page.onHidden(reason)\n this.emit()\n }\n\n private emit(): void {\n for (const listener of Array.from(this.listeners)) listener(this.showingPage)\n }\n\n private enqueue(op: () => void): void {\n this.ops.push(op)\n if (this.draining) return\n this.draining = true\n try {\n while (this.ops.length) (this.ops.shift() as () => void)()\n } finally {\n this.draining = false\n }\n }\n}\n\nconst pageHost = new PageHost()\nexport default pageHost\nexport {PageHost}\n"]}