@glassly/engine 0.1.0-dev.99 → 0.2.9-beta.448
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.
- package/README.md +28 -0
- package/build/engine.d.ts +32 -10
- package/build/engine.d.ts.map +1 -1
- package/build/engine.js +24 -16
- package/build/engine.js.map +1 -1
- package/build/facades/dev.d.ts +9 -0
- package/build/facades/dev.d.ts.map +1 -1
- package/build/facades/dev.js +9 -0
- package/build/facades/dev.js.map +1 -1
- package/build/facades/display.d.ts +10 -3
- package/build/facades/display.d.ts.map +1 -1
- package/build/facades/display.js +22 -8
- package/build/facades/display.js.map +1 -1
- package/build/facades/displayMirror.d.ts +11 -0
- package/build/facades/displayMirror.d.ts.map +1 -1
- package/build/facades/displayMirror.js +22 -0
- package/build/facades/displayMirror.js.map +1 -1
- package/build/facades/glasses.d.ts +31 -1
- package/build/facades/glasses.d.ts.map +1 -1
- package/build/facades/glasses.js +51 -0
- package/build/facades/glasses.js.map +1 -1
- package/build/facades/memory.d.ts +0 -6
- package/build/facades/memory.d.ts.map +1 -1
- package/build/facades/memory.js +1 -9
- package/build/facades/memory.js.map +1 -1
- package/build/facades/miniapps.d.ts +3 -1
- package/build/facades/miniapps.d.ts.map +1 -1
- package/build/facades/miniapps.js +3 -1
- package/build/facades/miniapps.js.map +1 -1
- package/build/facades/pairing.d.ts.map +1 -1
- package/build/facades/pairing.js +5 -4
- package/build/facades/pairing.js.map +1 -1
- package/build/facades/permissions.d.ts +2 -0
- package/build/facades/permissions.d.ts.map +1 -1
- package/build/facades/permissions.js +48 -0
- package/build/facades/permissions.js.map +1 -1
- package/build/facades/phoneNotifications.d.ts +20 -9
- package/build/facades/phoneNotifications.d.ts.map +1 -1
- package/build/facades/phoneNotifications.js +33 -26
- package/build/facades/phoneNotifications.js.map +1 -1
- package/build/facades/settings.d.ts.map +1 -1
- package/build/facades/settings.js +1 -2
- package/build/facades/settings.js.map +1 -1
- package/build/generated/releaseMetadata.js +4 -4
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/index.d.ts +6 -4
- package/build/index.d.ts.map +1 -1
- package/build/index.js +5 -4
- package/build/index.js.map +1 -1
- package/build/react/MentraLiveOtaFlow.js +2 -2
- package/build/react/MentraLiveOtaFlow.js.map +1 -1
- package/build/react/useMentraLiveOta.d.ts.map +1 -1
- package/build/react/useMentraLiveOta.js +8 -7
- package/build/react/useMentraLiveOta.js.map +1 -1
- package/build/runtime/config.d.ts +1 -1
- package/build/runtime/config.d.ts.map +1 -1
- package/build/runtime/config.js.map +1 -1
- package/build/services/AppRegistry.d.ts +4 -1
- package/build/services/AppRegistry.d.ts.map +1 -1
- package/build/services/AppRegistry.js +21 -1
- package/build/services/AppRegistry.js.map +1 -1
- package/build/services/BlobStore.d.ts +2 -2
- package/build/services/BlobStore.js +3 -3
- package/build/services/BlobStore.js.map +1 -1
- package/build/services/CloudClientService.d.ts +7 -3
- package/build/services/CloudClientService.d.ts.map +1 -1
- package/build/services/CloudClientService.js +34 -9
- package/build/services/CloudClientService.js.map +1 -1
- package/build/services/DevServerBridge.d.ts +1 -18
- package/build/services/DevServerBridge.d.ts.map +1 -1
- package/build/services/DevServerBridge.js +9 -8
- package/build/services/DevServerBridge.js.map +1 -1
- package/build/services/DeviceEventRouter.d.ts.map +1 -1
- package/build/services/DeviceEventRouter.js +58 -71
- package/build/services/DeviceEventRouter.js.map +1 -1
- package/build/services/DisplayDiagnostics.d.ts +5 -0
- package/build/services/DisplayDiagnostics.d.ts.map +1 -0
- package/build/services/DisplayDiagnostics.js +105 -0
- package/build/services/DisplayDiagnostics.js.map +1 -0
- package/build/services/DisplayProcessor.d.ts +6 -7
- package/build/services/DisplayProcessor.d.ts.map +1 -1
- package/build/services/DisplayProcessor.js +17 -45
- package/build/services/DisplayProcessor.js.map +1 -1
- package/build/services/GestureDotsService.d.ts +10 -4
- package/build/services/GestureDotsService.d.ts.map +1 -1
- package/build/services/GestureDotsService.js +70 -16
- package/build/services/GestureDotsService.js.map +1 -1
- package/build/services/GlassesKeyboardInput.d.ts +77 -0
- package/build/services/GlassesKeyboardInput.d.ts.map +1 -0
- package/build/services/GlassesKeyboardInput.js +261 -0
- package/build/services/GlassesKeyboardInput.js.map +1 -0
- package/build/services/GlassesSensorService.d.ts +47 -0
- package/build/services/GlassesSensorService.d.ts.map +1 -0
- package/build/services/GlassesSensorService.js +242 -0
- package/build/services/GlassesSensorService.js.map +1 -0
- package/build/services/GlassesTouchInput.d.ts +14 -0
- package/build/services/GlassesTouchInput.d.ts.map +1 -0
- package/build/services/GlassesTouchInput.js +107 -0
- package/build/services/GlassesTouchInput.js.map +1 -0
- package/build/services/HeadingService.d.ts +0 -6
- package/build/services/HeadingService.d.ts.map +1 -1
- package/build/services/HeadingService.js +0 -27
- package/build/services/HeadingService.js.map +1 -1
- package/build/services/HotspotShutdown.d.ts.map +1 -1
- package/build/services/HotspotShutdown.js +2 -1
- package/build/services/HotspotShutdown.js.map +1 -1
- package/build/services/JSCrashloopReportService.js +2 -2
- package/build/services/JSCrashloopReportService.js.map +1 -1
- package/build/services/JSRouter.d.ts +6 -4
- package/build/services/JSRouter.d.ts.map +1 -1
- package/build/services/JSRouter.js +15 -13
- package/build/services/JSRouter.js.map +1 -1
- package/build/services/LocalDisplayManager.d.ts +35 -7
- package/build/services/LocalDisplayManager.d.ts.map +1 -1
- package/build/services/LocalDisplayManager.js +105 -27
- package/build/services/LocalDisplayManager.js.map +1 -1
- package/build/services/LocalMiniappDataMigration.d.ts +1 -1
- package/build/services/LocalMiniappDataMigration.js +1 -1
- package/build/services/LocalMiniappDataMigration.js.map +1 -1
- package/build/services/LocalMiniappRuntime.d.ts +64 -11
- package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
- package/build/services/LocalMiniappRuntime.js +441 -35
- package/build/services/LocalMiniappRuntime.js.map +1 -1
- package/build/services/LocalSttFallbackCoordinator.d.ts +3 -0
- package/build/services/LocalSttFallbackCoordinator.d.ts.map +1 -1
- package/build/services/LocalSttFallbackCoordinator.js +27 -8
- package/build/services/LocalSttFallbackCoordinator.js.map +1 -1
- package/build/services/MemoryStore.d.ts +8 -33
- package/build/services/MemoryStore.d.ts.map +1 -1
- package/build/services/MemoryStore.js +30 -56
- package/build/services/MemoryStore.js.map +1 -1
- package/build/services/MiniappEngine.d.ts +3 -3
- package/build/services/MiniappEngine.js +7 -7
- package/build/services/MiniappEngine.js.map +1 -1
- package/build/services/MiniappLauncher.d.ts +8 -0
- package/build/services/MiniappLauncher.d.ts.map +1 -1
- package/build/services/MiniappLauncher.js +19 -1
- package/build/services/MiniappLauncher.js.map +1 -1
- package/build/services/MirrorService.d.ts +24 -0
- package/build/services/MirrorService.d.ts.map +1 -0
- package/build/services/MirrorService.js +132 -0
- package/build/services/MirrorService.js.map +1 -0
- package/build/services/NativeNavigationService.d.ts +2 -3
- package/build/services/NativeNavigationService.d.ts.map +1 -1
- package/build/services/NativeNavigationService.js +24 -21
- package/build/services/NativeNavigationService.js.map +1 -1
- package/build/services/NavigationHandlers.d.ts.map +1 -1
- package/build/services/NavigationHandlers.js +10 -5
- package/build/services/NavigationHandlers.js.map +1 -1
- package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
- package/build/services/OtaInstallCoordinator.js +24 -23
- package/build/services/OtaInstallCoordinator.js.map +1 -1
- package/build/services/PairedGlassesLatch.d.ts +7 -0
- package/build/services/PairedGlassesLatch.d.ts.map +1 -0
- package/build/services/PairedGlassesLatch.js +38 -0
- package/build/services/PairedGlassesLatch.js.map +1 -0
- package/build/services/PhoneActivity.d.ts +23 -0
- package/build/services/PhoneActivity.d.ts.map +1 -0
- package/build/services/PhoneActivity.js +111 -0
- package/build/services/PhoneActivity.js.map +1 -0
- package/build/services/PhoneCameraFovCoordinator.d.ts.map +1 -1
- package/build/services/PhoneCameraFovCoordinator.js +4 -3
- package/build/services/PhoneCameraFovCoordinator.js.map +1 -1
- package/build/services/PhoneNotificationsSync.d.ts +40 -6
- package/build/services/PhoneNotificationsSync.d.ts.map +1 -1
- package/build/services/PhoneNotificationsSync.js +160 -84
- package/build/services/PhoneNotificationsSync.js.map +1 -1
- package/build/services/PhonePhotoCoordinator.d.ts.map +1 -1
- package/build/services/PhonePhotoCoordinator.js +6 -5
- package/build/services/PhonePhotoCoordinator.js.map +1 -1
- package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
- package/build/services/PhoneStreamCoordinator.js +8 -7
- package/build/services/PhoneStreamCoordinator.js.map +1 -1
- package/build/services/STTModelManager.d.ts +3 -0
- package/build/services/STTModelManager.d.ts.map +1 -1
- package/build/services/STTModelManager.js +15 -1
- package/build/services/STTModelManager.js.map +1 -1
- package/build/services/SceneRenderer.d.ts +43 -2
- package/build/services/SceneRenderer.d.ts.map +1 -1
- package/build/services/SceneRenderer.js +123 -8
- package/build/services/SceneRenderer.js.map +1 -1
- package/build/services/StreamLifecycleController.d.ts.map +1 -1
- package/build/services/StreamLifecycleController.js +6 -14
- package/build/services/StreamLifecycleController.js.map +1 -1
- package/build/services/TTSModelManager.js +1 -1
- package/build/services/TTSModelManager.js.map +1 -1
- package/build/services/UIRouter.d.ts +2 -2
- package/build/services/UIRouter.js +5 -5
- package/build/services/UIRouter.js.map +1 -1
- package/build/services/asg/galleryPathMigration.js +1 -1
- package/build/services/asg/galleryPathMigration.js.map +1 -1
- package/build/services/asg/gallerySyncService.js +2 -2
- package/build/services/asg/gallerySyncService.js.map +1 -1
- package/build/services/asg/localStorageService.d.ts.map +1 -1
- package/build/services/asg/localStorageService.js +3 -3
- package/build/services/asg/localStorageService.js.map +1 -1
- package/build/services/debug/DashboardOpenTrace.d.ts +32 -0
- package/build/services/debug/DashboardOpenTrace.d.ts.map +1 -0
- package/build/services/debug/DashboardOpenTrace.js +128 -0
- package/build/services/debug/DashboardOpenTrace.js.map +1 -0
- package/build/services/debug/dashboardOpenTimeline.d.ts +77 -0
- package/build/services/debug/dashboardOpenTimeline.d.ts.map +1 -0
- package/build/services/debug/dashboardOpenTimeline.js +195 -0
- package/build/services/debug/dashboardOpenTimeline.js.map +1 -0
- package/build/services/effectiveCapabilities.d.ts.map +1 -1
- package/build/services/effectiveCapabilities.js +25 -13
- package/build/services/effectiveCapabilities.js.map +1 -1
- package/build/services/gestureClaims.d.ts +34 -15
- package/build/services/gestureClaims.d.ts.map +1 -1
- package/build/services/gestureClaims.js +42 -21
- package/build/services/gestureClaims.js.map +1 -1
- package/build/services/manifestFields.d.ts +9 -0
- package/build/services/manifestFields.d.ts.map +1 -0
- package/build/services/manifestFields.js +26 -0
- package/build/services/manifestFields.js.map +1 -0
- package/build/services/memoryStoreInstance.d.ts +0 -10
- package/build/services/memoryStoreInstance.d.ts.map +1 -1
- package/build/services/memoryStoreInstance.js +2 -31
- package/build/services/memoryStoreInstance.js.map +1 -1
- package/build/services/mirrorSnapshot.d.ts +16 -0
- package/build/services/mirrorSnapshot.d.ts.map +1 -0
- package/build/services/mirrorSnapshot.js +102 -0
- package/build/services/mirrorSnapshot.js.map +1 -0
- package/build/services/nativeNavigationGate.d.ts +8 -0
- package/build/services/nativeNavigationGate.d.ts.map +1 -0
- package/build/services/nativeNavigationGate.js +12 -0
- package/build/services/nativeNavigationGate.js.map +1 -0
- package/build/services/notificationAppCatalog.d.ts +7 -0
- package/build/services/notificationAppCatalog.d.ts.map +1 -0
- package/build/services/notificationAppCatalog.js +16 -0
- package/build/services/notificationAppCatalog.js.map +1 -0
- package/build/services/notifications/notificationPolicy.d.ts +55 -0
- package/build/services/notifications/notificationPolicy.d.ts.map +1 -0
- package/build/services/notifications/notificationPolicy.js +41 -0
- package/build/services/notifications/notificationPolicy.js.map +1 -0
- package/build/services/pages/OverlayPages.d.ts +26 -0
- package/build/services/pages/OverlayPages.d.ts.map +1 -0
- package/build/services/pages/OverlayPages.js +80 -0
- package/build/services/pages/OverlayPages.js.map +1 -0
- package/build/services/pages/PageHost.d.ts +32 -0
- package/build/services/pages/PageHost.d.ts.map +1 -0
- package/build/services/pages/PageHost.js +99 -0
- package/build/services/pages/PageHost.js.map +1 -0
- package/build/services/pages/overlayApps.d.ts +25 -0
- package/build/services/pages/overlayApps.d.ts.map +1 -0
- package/build/services/pages/overlayApps.js +66 -0
- package/build/services/pages/overlayApps.js.map +1 -0
- package/build/services/pages/pageEligibility.d.ts +9 -0
- package/build/services/pages/pageEligibility.d.ts.map +1 -0
- package/build/services/pages/pageEligibility.js +27 -0
- package/build/services/pages/pageEligibility.js.map +1 -0
- package/build/services/settingsBridge.d.ts +58 -0
- package/build/services/settingsBridge.d.ts.map +1 -0
- package/build/services/settingsBridge.js +90 -0
- package/build/services/settingsBridge.js.map +1 -0
- package/build/services/speakerProfileStoreInstance.js +1 -1
- package/build/services/speakerProfileStoreInstance.js.map +1 -1
- package/build/services/uiShim.d.ts +1 -1
- package/build/services/uiShim.js +4 -4
- package/build/services/uiShim.js.map +1 -1
- package/build/stores/appVisibility.d.ts +28 -0
- package/build/stores/appVisibility.d.ts.map +1 -1
- package/build/stores/appVisibility.js +34 -0
- package/build/stores/appVisibility.js.map +1 -1
- package/build/stores/apps.d.ts +13 -0
- package/build/stores/apps.d.ts.map +1 -1
- package/build/stores/apps.js +66 -12
- package/build/stores/apps.js.map +1 -1
- package/build/stores/bluetoothSettingKeys.js +1 -1
- package/build/stores/bluetoothSettingKeys.js.map +1 -1
- package/build/stores/display.d.ts +3 -3
- package/build/stores/display.d.ts.map +1 -1
- package/build/stores/display.js +16 -4
- package/build/stores/display.js.map +1 -1
- package/build/stores/glasses.d.ts.map +1 -1
- package/build/stores/glasses.js +14 -1
- package/build/stores/glasses.js.map +1 -1
- package/build/stores/settings.d.ts +1 -0
- package/build/stores/settings.d.ts.map +1 -1
- package/build/stores/settings.js +170 -44
- package/build/stores/settings.js.map +1 -1
- package/build/types/applet.d.ts +14 -1
- package/build/types/applet.d.ts.map +1 -1
- package/build/types/applet.js.map +1 -1
- package/build/types/capabilities/even-realities-g2.d.ts.map +1 -1
- package/build/types/capabilities/even-realities-g2.js +5 -0
- package/build/types/capabilities/even-realities-g2.js.map +1 -1
- package/build/types/capabilities/simulated-glasses.d.ts +1 -1
- package/build/types/capabilities/simulated-glasses.d.ts.map +1 -1
- package/build/types/capabilities/simulated-glasses.js +7 -4
- package/build/types/capabilities/simulated-glasses.js.map +1 -1
- package/build/types/hardware.d.ts +20 -1
- package/build/types/hardware.d.ts.map +1 -1
- package/build/types/hardware.js +2 -0
- package/build/types/hardware.js.map +1 -1
- package/build/types/index.d.ts +1 -0
- package/build/types/index.d.ts.map +1 -1
- package/build/types/index.js +1 -0
- package/build/types/index.js.map +1 -1
- package/build/utils/debouncedPatch.d.ts +3 -1
- package/build/utils/debouncedPatch.d.ts.map +1 -1
- package/build/utils/debouncedPatch.js +6 -3
- package/build/utils/debouncedPatch.js.map +1 -1
- package/build/utils/devMiniappLaunch.d.ts.map +1 -1
- package/build/utils/devMiniappLaunch.js +4 -3
- package/build/utils/devMiniappLaunch.js.map +1 -1
- package/build/utils/display/measurer/TextMeasurer.d.ts +2 -159
- package/build/utils/display/measurer/TextMeasurer.d.ts.map +1 -1
- package/build/utils/display/measurer/TextMeasurer.js +2 -272
- package/build/utils/display/measurer/TextMeasurer.js.map +1 -1
- package/build/utils/display/measurer/script-detection.d.ts +1 -52
- package/build/utils/display/measurer/script-detection.d.ts.map +1 -1
- package/build/utils/display/measurer/script-detection.js +2 -183
- package/build/utils/display/measurer/script-detection.js.map +1 -1
- package/build/utils/display/pixelArt.d.ts +3 -0
- package/build/utils/display/pixelArt.d.ts.map +1 -0
- package/build/utils/display/pixelArt.js +3 -0
- package/build/utils/display/pixelArt.js.map +1 -0
- package/build/utils/display/profiles/g1.d.ts +1 -32
- package/build/utils/display/profiles/g1.d.ts.map +1 -1
- package/build/utils/display/profiles/g1.js +2 -212
- package/build/utils/display/profiles/g1.js.map +1 -1
- package/build/utils/display/profiles/g2.d.ts +1 -12
- package/build/utils/display/profiles/g2.d.ts.map +1 -1
- package/build/utils/display/profiles/g2.js +2 -33
- package/build/utils/display/profiles/g2.js.map +1 -1
- package/build/utils/display/profiles/nex.d.ts +1 -9
- package/build/utils/display/profiles/nex.d.ts.map +1 -1
- package/build/utils/display/profiles/nex.js +2 -149
- package/build/utils/display/profiles/nex.js.map +1 -1
- package/build/utils/display/profiles/types.d.ts +1 -102
- package/build/utils/display/profiles/types.d.ts.map +1 -1
- package/build/utils/display/profiles/types.js.map +1 -1
- package/build/utils/display/profiles/z100.d.ts +1 -32
- package/build/utils/display/profiles/z100.d.ts.map +1 -1
- package/build/utils/display/profiles/z100.js +2 -181
- package/build/utils/display/profiles/z100.js.map +1 -1
- package/build/utils/display/scene/degrade.d.ts.map +1 -1
- package/build/utils/display/scene/degrade.js +4 -1
- package/build/utils/display/scene/degrade.js.map +1 -1
- package/build/utils/display/scene/differ.d.ts +13 -1
- package/build/utils/display/scene/differ.d.ts.map +1 -1
- package/build/utils/display/scene/differ.js +22 -0
- package/build/utils/display/scene/differ.js.map +1 -1
- package/build/utils/display/scene/index.d.ts +1 -1
- package/build/utils/display/scene/index.d.ts.map +1 -1
- package/build/utils/display/scene/index.js.map +1 -1
- package/build/utils/display/scene/process.d.ts.map +1 -1
- package/build/utils/display/scene/process.js +183 -11
- package/build/utils/display/scene/process.js.map +1 -1
- package/build/utils/display/scene/store.d.ts +1 -1
- package/build/utils/display/scene/store.d.ts.map +1 -1
- package/build/utils/display/scene/store.js +0 -0
- package/build/utils/display/scene/store.js.map +1 -1
- package/build/utils/display/scene/svgPath.d.ts +9 -0
- package/build/utils/display/scene/svgPath.d.ts.map +1 -0
- package/build/utils/display/scene/svgPath.js +167 -0
- package/build/utils/display/scene/svgPath.js.map +1 -0
- package/build/utils/display/scene/types.d.ts +2 -142
- package/build/utils/display/scene/types.d.ts.map +1 -1
- package/build/utils/display/scene/types.js +0 -0
- package/build/utils/display/scene/types.js.map +1 -1
- package/build/utils/display/wrapper/TextWrapper.d.ts +1 -101
- package/build/utils/display/wrapper/TextWrapper.d.ts.map +1 -1
- package/build/utils/display/wrapper/TextWrapper.js +2 -470
- package/build/utils/display/wrapper/TextWrapper.js.map +1 -1
- package/build/utils/display/wrapper/types.d.ts +2 -74
- package/build/utils/display/wrapper/types.d.ts.map +1 -1
- package/build/utils/display/wrapper/types.js +2 -10
- package/build/utils/display/wrapper/types.js.map +1 -1
- package/build/utils/hardware/hardware.js +1 -1
- package/build/utils/hardware/hardware.js.map +1 -1
- package/build/utils/timers/timers.d.ts.map +1 -1
- package/build/utils/timers/timers.js +26 -4
- package/build/utils/timers/timers.js.map +1 -1
- package/package.json +8 -8
- package/src/engine.ts +24 -15
- package/src/facades/dev.ts +10 -0
- package/src/facades/display.ts +21 -8
- package/src/facades/displayMirror.ts +29 -0
- package/src/facades/glasses.ts +61 -1
- package/src/facades/memory.ts +1 -12
- package/src/facades/miniapps.ts +4 -1
- package/src/facades/pairing.ts +8 -6
- package/src/facades/permissions.ts +46 -0
- package/src/facades/phoneNotifications.ts +45 -26
- package/src/facades/settings.ts +1 -2
- package/src/generated/releaseMetadata.ts +4 -4
- package/src/index.ts +6 -9
- package/src/react/MentraLiveOtaFlow.tsx +2 -2
- package/src/react/useMentraLiveOta.ts +14 -8
- package/src/runtime/config.ts +1 -1
- package/src/services/AppRegistry.ts +43 -7
- package/src/services/BlobStore.ts +3 -3
- package/src/services/CloudClientService.ts +37 -10
- package/src/services/DevServerBridge.ts +12 -10
- package/src/services/DeviceEventRouter.ts +73 -74
- package/src/services/DisplayDiagnostics.ts +107 -0
- package/src/services/DisplayProcessor.ts +20 -55
- package/src/services/GestureDotsService.ts +77 -16
- package/src/services/GlassesKeyboardInput.ts +306 -0
- package/src/services/GlassesSensorService.ts +233 -0
- package/src/services/GlassesTouchInput.ts +128 -0
- package/src/services/HeadingService.ts +0 -24
- package/src/services/HotspotShutdown.ts +3 -1
- package/src/services/JSCrashloopReportService.ts +2 -2
- package/src/services/JSRouter.ts +29 -14
- package/src/services/LocalDisplayManager.ts +112 -26
- package/src/services/LocalMiniappDataMigration.ts +1 -1
- package/src/services/LocalMiniappRuntime.ts +500 -43
- package/src/services/LocalSttFallbackCoordinator.ts +28 -7
- package/src/services/MemoryStore.ts +32 -80
- package/src/services/MiniappEngine.ts +7 -7
- package/src/services/MiniappLauncher.ts +25 -1
- package/src/services/MirrorService.ts +139 -0
- package/src/services/NativeNavigationService.ts +29 -25
- package/src/services/NavigationHandlers.ts +10 -5
- package/src/services/OtaInstallCoordinator.ts +36 -34
- package/src/services/PairedGlassesLatch.ts +39 -0
- package/src/services/PhoneActivity.ts +116 -0
- package/src/services/PhoneCameraFovCoordinator.ts +6 -4
- package/src/services/PhoneNotificationsSync.ts +185 -103
- package/src/services/PhonePhotoCoordinator.ts +9 -10
- package/src/services/PhoneStreamCoordinator.ts +13 -11
- package/src/services/STTModelManager.ts +15 -1
- package/src/services/SceneRenderer.ts +148 -10
- package/src/services/StreamLifecycleController.ts +9 -7
- package/src/services/TTSModelManager.ts +1 -1
- package/src/services/UIRouter.ts +5 -5
- package/src/services/asg/galleryPathMigration.ts +1 -1
- package/src/services/asg/gallerySyncService.ts +2 -2
- package/src/services/asg/localStorageService.ts +3 -3
- package/src/services/debug/DashboardOpenTrace.ts +153 -0
- package/src/services/debug/dashboardOpenTimeline.ts +237 -0
- package/src/services/effectiveCapabilities.ts +32 -13
- package/src/services/gestureClaims.ts +72 -23
- package/src/services/manifestFields.ts +23 -0
- package/src/services/memoryStoreInstance.ts +2 -34
- package/src/services/mirrorSnapshot.ts +116 -0
- package/src/services/nativeNavigationGate.ts +14 -0
- package/src/services/notificationAppCatalog.ts +21 -0
- package/src/services/notifications/notificationPolicy.ts +87 -0
- package/src/services/pages/OverlayPages.ts +86 -0
- package/src/services/pages/PageHost.ts +116 -0
- package/src/services/pages/overlayApps.ts +72 -0
- package/src/services/pages/pageEligibility.ts +30 -0
- package/src/services/settingsBridge.ts +111 -0
- package/src/services/speakerProfileStoreInstance.ts +1 -1
- package/src/services/uiShim.ts +4 -4
- package/src/stores/appVisibility.ts +45 -0
- package/src/stores/apps.ts +110 -32
- package/src/stores/bluetoothSettingKeys.ts +1 -1
- package/src/stores/display.ts +18 -7
- package/src/stores/glasses.ts +15 -1
- package/src/stores/settings.ts +175 -51
- package/src/types/applet.ts +14 -1
- package/src/types/capabilities/even-realities-g2.ts +6 -0
- package/src/types/capabilities/simulated-glasses.ts +8 -4
- package/src/types/hardware.ts +34 -1
- package/src/types/index.ts +1 -0
- package/src/utils/debouncedPatch.ts +8 -4
- package/src/utils/devMiniappLaunch.ts +5 -3
- package/src/utils/display/measurer/TextMeasurer.ts +3 -346
- package/src/utils/display/measurer/script-detection.ts +10 -218
- package/src/utils/display/pixelArt.ts +3 -0
- package/src/utils/display/profiles/g1.ts +2 -236
- package/src/utils/display/profiles/g2.ts +2 -39
- package/src/utils/display/profiles/nex.ts +2 -166
- package/src/utils/display/profiles/types.ts +9 -132
- package/src/utils/display/profiles/z100.ts +2 -198
- package/src/utils/display/scene/degrade.ts +4 -1
- package/src/utils/display/scene/differ.ts +25 -1
- package/src/utils/display/scene/index.ts +5 -0
- package/src/utils/display/scene/process.ts +196 -13
- package/src/utils/display/scene/store.ts +0 -0
- package/src/utils/display/scene/svgPath.ts +163 -0
- package/src/utils/display/scene/types.ts +0 -0
- package/src/utils/display/wrapper/TextWrapper.ts +2 -546
- package/src/utils/display/wrapper/types.ts +3 -102
- package/src/utils/hardware/hardware.ts +1 -1
- package/src/utils/timers/timers.ts +32 -4
- package/build/services/CustomDashboardModel.d.ts +0 -48
- package/build/services/CustomDashboardModel.d.ts.map +0 -1
- package/build/services/CustomDashboardModel.js +0 -73
- package/build/services/CustomDashboardModel.js.map +0 -1
- package/build/services/CustomDashboardService.d.ts +0 -63
- package/build/services/CustomDashboardService.d.ts.map +0 -1
- package/build/services/CustomDashboardService.js +0 -576
- package/build/services/CustomDashboardService.js.map +0 -1
- package/build/services/DashboardCoordinator.d.ts +0 -26
- package/build/services/DashboardCoordinator.d.ts.map +0 -1
- package/build/services/DashboardCoordinator.js +0 -125
- package/build/services/DashboardCoordinator.js.map +0 -1
- package/build/services/iosNotificationAppCatalog.d.ts +0 -13
- package/build/services/iosNotificationAppCatalog.d.ts.map +0 -1
- package/build/services/iosNotificationAppCatalog.js +0 -28
- package/build/services/iosNotificationAppCatalog.js.map +0 -1
- package/src/services/CustomDashboardModel.ts +0 -83
- package/src/services/CustomDashboardService.ts +0 -598
- package/src/services/DashboardCoordinator.ts +0 -121
- package/src/services/iosNotificationAppCatalog.ts +0 -39
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The overlay apps: the connected miniapps whose manifest type is
|
|
3
|
+
* "system_dashboard" (the dashboard, the notifications viewer). They alone
|
|
4
|
+
* may take the overlay slot through `session.display.showView("dashboard")`
|
|
5
|
+
* and have "dashboard" in their `display.views` capability while the
|
|
6
|
+
* glasses are eligible. The runtime adds an app when it connects and
|
|
7
|
+
* removes it when it stops; the engine never knows what any of them draws.
|
|
8
|
+
* Kept free of imports so the runtime and the notification policy can both
|
|
9
|
+
* read it without a cycle.
|
|
10
|
+
*/
|
|
11
|
+
export type DisplayView = "main" | "dashboard";
|
|
12
|
+
export declare function isOverlayApp(packageName: string): boolean;
|
|
13
|
+
export declare function overlayApps(): readonly string[];
|
|
14
|
+
export declare function addOverlayApp(packageName: string): void;
|
|
15
|
+
export declare function removeOverlayApp(packageName: string): void;
|
|
16
|
+
/** Record whether an overlay app subscribes to phone notifications (it is a viewer while it does). */
|
|
17
|
+
export declare function setOverlayViewer(packageName: string, listening: boolean): void;
|
|
18
|
+
/** An overlay app that presents phone notifications is running. */
|
|
19
|
+
export declare function overlayViewerRunning(): boolean;
|
|
20
|
+
export declare function onOverlayAppsChange(listener: () => void): () => void;
|
|
21
|
+
/** The views `packageName` may draw: main for everyone, the dashboard for overlay apps on eligible glasses. */
|
|
22
|
+
export declare function displayViewsFor(packageName: string, eligible: boolean): DisplayView[];
|
|
23
|
+
/** Tests only. */
|
|
24
|
+
export declare function _resetOverlayAppsForTest(): void;
|
|
25
|
+
//# sourceMappingURL=overlayApps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlayApps.d.ts","sourceRoot":"","sources":["../../../src/services/pages/overlayApps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,WAAW,CAAA;AAO9C,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,wBAAgB,WAAW,IAAI,SAAS,MAAM,EAAE,CAE/C;AAED,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAIvD;AAED,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAI1D;AAED,sGAAsG;AACtG,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI,CAK9E;AAED,mEAAmE;AACnE,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAKpE;AAED,+GAA+G;AAC/G,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,WAAW,EAAE,CAErF;AAMD,kBAAkB;AAClB,wBAAgB,wBAAwB,IAAI,IAAI,CAG/C"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The overlay apps: the connected miniapps whose manifest type is
|
|
3
|
+
* "system_dashboard" (the dashboard, the notifications viewer). They alone
|
|
4
|
+
* may take the overlay slot through `session.display.showView("dashboard")`
|
|
5
|
+
* and have "dashboard" in their `display.views` capability while the
|
|
6
|
+
* glasses are eligible. The runtime adds an app when it connects and
|
|
7
|
+
* removes it when it stops; the engine never knows what any of them draws.
|
|
8
|
+
* Kept free of imports so the runtime and the notification policy can both
|
|
9
|
+
* read it without a cycle.
|
|
10
|
+
*/
|
|
11
|
+
const apps = new Set();
|
|
12
|
+
/** Overlay apps listening to the phone's notifications: something on the glasses presents them. */
|
|
13
|
+
const viewers = new Set();
|
|
14
|
+
const listeners = new Set();
|
|
15
|
+
export function isOverlayApp(packageName) {
|
|
16
|
+
return apps.has(packageName);
|
|
17
|
+
}
|
|
18
|
+
export function overlayApps() {
|
|
19
|
+
return [...apps];
|
|
20
|
+
}
|
|
21
|
+
export function addOverlayApp(packageName) {
|
|
22
|
+
if (apps.has(packageName))
|
|
23
|
+
return;
|
|
24
|
+
apps.add(packageName);
|
|
25
|
+
emit();
|
|
26
|
+
}
|
|
27
|
+
export function removeOverlayApp(packageName) {
|
|
28
|
+
viewers.delete(packageName);
|
|
29
|
+
if (!apps.delete(packageName))
|
|
30
|
+
return;
|
|
31
|
+
emit();
|
|
32
|
+
}
|
|
33
|
+
/** Record whether an overlay app subscribes to phone notifications (it is a viewer while it does). */
|
|
34
|
+
export function setOverlayViewer(packageName, listening) {
|
|
35
|
+
const was = viewers.has(packageName);
|
|
36
|
+
if (listening && apps.has(packageName))
|
|
37
|
+
viewers.add(packageName);
|
|
38
|
+
else
|
|
39
|
+
viewers.delete(packageName);
|
|
40
|
+
if (was !== viewers.has(packageName))
|
|
41
|
+
emit();
|
|
42
|
+
}
|
|
43
|
+
/** An overlay app that presents phone notifications is running. */
|
|
44
|
+
export function overlayViewerRunning() {
|
|
45
|
+
return viewers.size > 0;
|
|
46
|
+
}
|
|
47
|
+
export function onOverlayAppsChange(listener) {
|
|
48
|
+
listeners.add(listener);
|
|
49
|
+
return () => {
|
|
50
|
+
listeners.delete(listener);
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/** The views `packageName` may draw: main for everyone, the dashboard for overlay apps on eligible glasses. */
|
|
54
|
+
export function displayViewsFor(packageName, eligible) {
|
|
55
|
+
return apps.has(packageName) && eligible ? ["main", "dashboard"] : ["main"];
|
|
56
|
+
}
|
|
57
|
+
function emit() {
|
|
58
|
+
for (const listener of Array.from(listeners))
|
|
59
|
+
listener();
|
|
60
|
+
}
|
|
61
|
+
/** Tests only. */
|
|
62
|
+
export function _resetOverlayAppsForTest() {
|
|
63
|
+
apps.clear();
|
|
64
|
+
viewers.clear();
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=overlayApps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlayApps.js","sourceRoot":"","sources":["../../../src/services/pages/overlayApps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;AAC9B,mGAAmG;AACnG,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAA;AACjC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAc,CAAA;AAEvC,MAAM,UAAU,YAAY,CAAC,WAAmB;IAC9C,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;AAC9B,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,OAAO,CAAC,GAAG,IAAI,CAAC,CAAA;AAClB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,WAAmB;IAC/C,IAAI,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC;QAAE,OAAM;IACjC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IACrB,IAAI,EAAE,CAAA;AACR,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,WAAmB;IAClD,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;IAC3B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;QAAE,OAAM;IACrC,IAAI,EAAE,CAAA;AACR,CAAC;AAED,sGAAsG;AACtG,MAAM,UAAU,gBAAgB,CAAC,WAAmB,EAAE,SAAkB;IACtE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IACpC,IAAI,SAAS,IAAI,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC;QAAE,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;;QAC3D,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;IAChC,IAAI,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;QAAE,IAAI,EAAE,CAAA;AAC9C,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,oBAAoB;IAClC,OAAO,OAAO,CAAC,IAAI,GAAG,CAAC,CAAA;AACzB,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,QAAoB;IACtD,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACvB,OAAO,GAAG,EAAE;QACV,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC5B,CAAC,CAAA;AACH,CAAC;AAED,+GAA+G;AAC/G,MAAM,UAAU,eAAe,CAAC,WAAmB,EAAE,QAAiB;IACpE,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;AAC7E,CAAC;AAED,SAAS,IAAI;IACX,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;QAAE,QAAQ,EAAE,CAAA;AAC1D,CAAC;AAED,kBAAkB;AAClB,MAAM,UAAU,wBAAwB;IACtC,IAAI,CAAC,KAAK,EAAE,CAAA;IACZ,OAAO,CAAC,KAAK,EAAE,CAAA;AACjB,CAAC","sourcesContent":["/**\n * The overlay apps: the connected miniapps whose manifest type is\n * \"system_dashboard\" (the dashboard, the notifications viewer). They alone\n * may take the overlay slot through `session.display.showView(\"dashboard\")`\n * and have \"dashboard\" in their `display.views` capability while the\n * glasses are eligible. The runtime adds an app when it connects and\n * removes it when it stops; the engine never knows what any of them draws.\n * Kept free of imports so the runtime and the notification policy can both\n * read it without a cycle.\n */\n\nexport type DisplayView = \"main\" | \"dashboard\"\n\nconst apps = new Set<string>()\n/** Overlay apps listening to the phone's notifications: something on the glasses presents them. */\nconst viewers = new Set<string>()\nconst listeners = new Set<() => void>()\n\nexport function isOverlayApp(packageName: string): boolean {\n return apps.has(packageName)\n}\n\nexport function overlayApps(): readonly string[] {\n return [...apps]\n}\n\nexport function addOverlayApp(packageName: string): void {\n if (apps.has(packageName)) return\n apps.add(packageName)\n emit()\n}\n\nexport function removeOverlayApp(packageName: string): void {\n viewers.delete(packageName)\n if (!apps.delete(packageName)) return\n emit()\n}\n\n/** Record whether an overlay app subscribes to phone notifications (it is a viewer while it does). */\nexport function setOverlayViewer(packageName: string, listening: boolean): void {\n const was = viewers.has(packageName)\n if (listening && apps.has(packageName)) viewers.add(packageName)\n else viewers.delete(packageName)\n if (was !== viewers.has(packageName)) emit()\n}\n\n/** An overlay app that presents phone notifications is running. */\nexport function overlayViewerRunning(): boolean {\n return viewers.size > 0\n}\n\nexport function onOverlayAppsChange(listener: () => void): () => void {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n}\n\n/** The views `packageName` may draw: main for everyone, the dashboard for overlay apps on eligible glasses. */\nexport function displayViewsFor(packageName: string, eligible: boolean): DisplayView[] {\n return apps.has(packageName) && eligible ? [\"main\", \"dashboard\"] : [\"main\"]\n}\n\nfunction emit(): void {\n for (const listener of Array.from(listeners)) listener()\n}\n\n/** Tests only. */\nexport function _resetOverlayAppsForTest(): void {\n apps.clear()\n viewers.clear()\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** G2.swift appends this marker after the firmware advertises Glassly CFW capabilities. */
|
|
2
|
+
export declare function isCfwFirmwareVersion(firmwareVersion: string | null | undefined): boolean;
|
|
3
|
+
/** Stock G2 and NIMO are intentionally excluded. */
|
|
4
|
+
export declare function isCustomDashboardEligible(info: {
|
|
5
|
+
model?: string | null;
|
|
6
|
+
firmwareVersion?: string | null;
|
|
7
|
+
}): boolean;
|
|
8
|
+
export declare function pagesEligible(): boolean;
|
|
9
|
+
//# sourceMappingURL=pageEligibility.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pageEligibility.d.ts","sourceRoot":"","sources":["../../../src/services/pages/pageEligibility.ts"],"names":[],"mappings":"AAYA,2FAA2F;AAC3F,wBAAgB,oBAAoB,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAExF;AAED,oDAAoD;AACpD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAC,GAAG,OAAO,CAEjH;AAED,wBAAgB,aAAa,IAAI,OAAO,CAOvC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether the dashboard view may show right now: connected Glassly CFW
|
|
3
|
+
* glasses with the dashboard enabled. The page host reads it before showing
|
|
4
|
+
* a page and hides the showing page when it turns false; the miniapp runtime
|
|
5
|
+
* folds it into the designated app's `display.views` capability. Read at
|
|
6
|
+
* decision time, never cached.
|
|
7
|
+
*/
|
|
8
|
+
import { useGlassesStore } from "../../stores/glasses";
|
|
9
|
+
import { SETTINGS, useSettingsStore } from "../../stores/settings";
|
|
10
|
+
import { DeviceTypes } from "../../types/enums";
|
|
11
|
+
import { isGlassesConnected } from "../GlassesReadiness";
|
|
12
|
+
/** G2.swift appends this marker after the firmware advertises Glassly CFW capabilities. */
|
|
13
|
+
export function isCfwFirmwareVersion(firmwareVersion) {
|
|
14
|
+
return firmwareVersion?.toLowerCase().includes("glassly cfw") === true;
|
|
15
|
+
}
|
|
16
|
+
/** Stock G2 and NIMO are intentionally excluded. */
|
|
17
|
+
export function isCustomDashboardEligible(info) {
|
|
18
|
+
return info.model === DeviceTypes.G2 && isCfwFirmwareVersion(info.firmwareVersion);
|
|
19
|
+
}
|
|
20
|
+
export function pagesEligible() {
|
|
21
|
+
if (useSettingsStore.getState().getSetting(SETTINGS.custom_dashboard_enabled.key) === false)
|
|
22
|
+
return false;
|
|
23
|
+
const state = useGlassesStore.getState();
|
|
24
|
+
return (isGlassesConnected(state.connection) &&
|
|
25
|
+
isCustomDashboardEligible({ model: state.deviceModel, firmwareVersion: state.firmwareVersion }));
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=pageEligibility.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pageEligibility.js","sourceRoot":"","sources":["../../../src/services/pages/pageEligibility.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAC,eAAe,EAAC,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAC,QAAQ,EAAE,gBAAgB,EAAC,MAAM,uBAAuB,CAAA;AAChE,OAAO,EAAC,WAAW,EAAC,MAAM,mBAAmB,CAAA;AAC7C,OAAO,EAAC,kBAAkB,EAAC,MAAM,qBAAqB,CAAA;AAEtD,2FAA2F;AAC3F,MAAM,UAAU,oBAAoB,CAAC,eAA0C;IAC7E,OAAO,eAAe,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,IAAI,CAAA;AACxE,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,yBAAyB,CAAC,IAA8D;IACtG,OAAO,IAAI,CAAC,KAAK,KAAK,WAAW,CAAC,EAAE,IAAI,oBAAoB,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;AACpF,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,IAAI,gBAAgB,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,wBAAwB,CAAC,GAAG,CAAC,KAAK,KAAK;QAAE,OAAO,KAAK,CAAA;IACzG,MAAM,KAAK,GAAG,eAAe,CAAC,QAAQ,EAAE,CAAA;IACxC,OAAO,CACL,kBAAkB,CAAC,KAAK,CAAC,UAAU,CAAC;QACpC,yBAAyB,CAAC,EAAC,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE,eAAe,EAAE,KAAK,CAAC,eAAe,EAAC,CAAC,CAC9F,CAAA;AACH,CAAC","sourcesContent":["/**\n * Whether the dashboard view may show right now: connected Glassly CFW\n * glasses with the dashboard enabled. The page host reads it before showing\n * a page and hides the showing page when it turns false; the miniapp runtime\n * folds it into the designated app's `display.views` capability. Read at\n * decision time, never cached.\n */\nimport {useGlassesStore} from \"../../stores/glasses\"\nimport {SETTINGS, useSettingsStore} from \"../../stores/settings\"\nimport {DeviceTypes} from \"../../types/enums\"\nimport {isGlassesConnected} from \"../GlassesReadiness\"\n\n/** G2.swift appends this marker after the firmware advertises Glassly CFW capabilities. */\nexport function isCfwFirmwareVersion(firmwareVersion: string | null | undefined): boolean {\n return firmwareVersion?.toLowerCase().includes(\"glassly cfw\") === true\n}\n\n/** Stock G2 and NIMO are intentionally excluded. */\nexport function isCustomDashboardEligible(info: {model?: string | null; firmwareVersion?: string | null}): boolean {\n return info.model === DeviceTypes.G2 && isCfwFirmwareVersion(info.firmwareVersion)\n}\n\nexport function pagesEligible(): boolean {\n if (useSettingsStore.getState().getSetting(SETTINGS.custom_dashboard_enabled.key) === false) return false\n const state = useGlassesStore.getState()\n return (\n isGlassesConnected(state.connection) &&\n isCustomDashboardEligible({model: state.deviceModel, firmwareVersion: state.firmwareVersion})\n )\n}\n"]}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The settings bridge's vocabulary (session.settings): which engine settings
|
|
3
|
+
* a system miniapp may read or write, the derived read-only keys the engine
|
|
4
|
+
* computes rather than stores, and the request validation. Pure, so the
|
|
5
|
+
* runtime's handlers stay thin and this can be tested without the native
|
|
6
|
+
* import surface the runtime pulls in.
|
|
7
|
+
*
|
|
8
|
+
* The dashboard miniapp is the consumer: it edits the same dashboard,
|
|
9
|
+
* notification and glasses-menu keys the phone's settings screens used to,
|
|
10
|
+
* through the store, so persistence, server sync and the Bluetooth sync of
|
|
11
|
+
* `menu_apps` behave as if a phone screen wrote them.
|
|
12
|
+
*/
|
|
13
|
+
export type SettingsBridgeAccess = "read" | "write";
|
|
14
|
+
/** Stored settings the bridge serves, by key, with what a system app may do to each. */
|
|
15
|
+
export declare const SETTINGS_BRIDGE_KEYS: Readonly<Record<string, SettingsBridgeAccess>>;
|
|
16
|
+
/**
|
|
17
|
+
* Read-only keys the engine computes: whether the wearer can see the phone,
|
|
18
|
+
* whether the foreground miniapp is drawing on the glasses, and the ring's
|
|
19
|
+
* battery. They change on their own clocks; the runtime pushes them like
|
|
20
|
+
* stored keys.
|
|
21
|
+
*/
|
|
22
|
+
export declare const DERIVED_SETTINGS_KEYS: readonly ["phone_active", "foreground_app_on_screen", "ring_battery"];
|
|
23
|
+
export type DerivedSettingsKey = (typeof DERIVED_SETTINGS_KEYS)[number];
|
|
24
|
+
export declare function isDerivedSettingsKey(key: string): key is DerivedSettingsKey;
|
|
25
|
+
/** What a system app may do with `key`, or null when the bridge does not serve it. */
|
|
26
|
+
export declare function settingsBridgeAccess(key: string): SettingsBridgeAccess | null;
|
|
27
|
+
/** Every key the bridge serves, stored then derived. */
|
|
28
|
+
export declare function allSettingsBridgeKeys(): string[];
|
|
29
|
+
/**
|
|
30
|
+
* The keys a SETTINGS_GET asks for: everything when `requested` is absent,
|
|
31
|
+
* else the known ones among the requested strings (unknown keys are left
|
|
32
|
+
* out, never rejected).
|
|
33
|
+
*/
|
|
34
|
+
export declare function selectSettingsBridgeKeys(requested: unknown): string[];
|
|
35
|
+
export type SettingsSetValidation = {
|
|
36
|
+
ok: true;
|
|
37
|
+
key: string;
|
|
38
|
+
value: unknown;
|
|
39
|
+
} | {
|
|
40
|
+
ok: false;
|
|
41
|
+
code: "INVALID_ARGUMENT" | "NOT_PERMITTED";
|
|
42
|
+
message: string;
|
|
43
|
+
};
|
|
44
|
+
/** A SETTINGS_SET payload: a writable key and a JSON value (undefined is not a value). */
|
|
45
|
+
export declare function validateSettingsSet(payload: Record<string, unknown>): SettingsSetValidation;
|
|
46
|
+
/** The ring's battery as the dashboard shows it: the relayed ring first, else the controller. */
|
|
47
|
+
export interface RingBattery {
|
|
48
|
+
connected: boolean;
|
|
49
|
+
/** -1 when unknown. */
|
|
50
|
+
level: number;
|
|
51
|
+
}
|
|
52
|
+
export declare function ringBatteryFrom(glasses: {
|
|
53
|
+
ringConnected: boolean;
|
|
54
|
+
ringBatteryLevel: number;
|
|
55
|
+
controllerConnected: boolean;
|
|
56
|
+
controllerBatteryLevel: number;
|
|
57
|
+
}): RingBattery;
|
|
58
|
+
//# sourceMappingURL=settingsBridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settingsBridge.d.ts","sourceRoot":"","sources":["../../src/services/settingsBridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,OAAO,CAAA;AAEnD,wFAAwF;AACxF,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAoB/E,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,uEAAwE,CAAA;AAC1G,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEvE,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,IAAI,kBAAkB,CAE3E;AAED,sFAAsF;AACtF,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,oBAAoB,GAAG,IAAI,CAG7E;AAED,wDAAwD;AACxD,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,EAAE,CAIrE;AAED,MAAM,MAAM,qBAAqB,GAC7B;IAAC,EAAE,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAC,GACvC;IAAC,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,kBAAkB,GAAG,eAAe,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,CAAA;AAE5E,0FAA0F;AAC1F,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,qBAAqB,CAY3F;AAED,iGAAiG;AACjG,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,OAAO,CAAA;IAClB,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE;IACvC,aAAa,EAAE,OAAO,CAAA;IACtB,gBAAgB,EAAE,MAAM,CAAA;IACxB,mBAAmB,EAAE,OAAO,CAAA;IAC5B,sBAAsB,EAAE,MAAM,CAAA;CAC/B,GAAG,WAAW,CAMd"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The settings bridge's vocabulary (session.settings): which engine settings
|
|
3
|
+
* a system miniapp may read or write, the derived read-only keys the engine
|
|
4
|
+
* computes rather than stores, and the request validation. Pure, so the
|
|
5
|
+
* runtime's handlers stay thin and this can be tested without the native
|
|
6
|
+
* import surface the runtime pulls in.
|
|
7
|
+
*
|
|
8
|
+
* The dashboard miniapp is the consumer: it edits the same dashboard,
|
|
9
|
+
* notification and glasses-menu keys the phone's settings screens used to,
|
|
10
|
+
* through the store, so persistence, server sync and the Bluetooth sync of
|
|
11
|
+
* `menu_apps` behave as if a phone screen wrote them.
|
|
12
|
+
*/
|
|
13
|
+
/** Stored settings the bridge serves, by key, with what a system app may do to each. */
|
|
14
|
+
export const SETTINGS_BRIDGE_KEYS = {
|
|
15
|
+
// The dashboard's master switch is a phone-side debug knob.
|
|
16
|
+
custom_dashboard_enabled: "read",
|
|
17
|
+
custom_dashboard_clock_style: "write",
|
|
18
|
+
custom_dashboard_clock_show_date: "write",
|
|
19
|
+
custom_dashboard_battery_style: "write",
|
|
20
|
+
custom_dashboard_layout: "write",
|
|
21
|
+
custom_dashboard_calendar_event_count: "write",
|
|
22
|
+
custom_dashboard_calendar_days_ahead: "write",
|
|
23
|
+
contextual_dashboard: "write",
|
|
24
|
+
twelve_hour_time: "write",
|
|
25
|
+
menu_apps: "write",
|
|
26
|
+
notifications_enabled: "write",
|
|
27
|
+
notifications_popups: "write",
|
|
28
|
+
notifications_popup_seconds: "write",
|
|
29
|
+
notifications_hold_during_apps: "write",
|
|
30
|
+
notifications_ignore_while_active: "write",
|
|
31
|
+
notifications_blocklist: "write",
|
|
32
|
+
// Apps the glasses reported posting notifications; the engine records it.
|
|
33
|
+
notification_seen_apps: "read",
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Read-only keys the engine computes: whether the wearer can see the phone,
|
|
37
|
+
* whether the foreground miniapp is drawing on the glasses, and the ring's
|
|
38
|
+
* battery. They change on their own clocks; the runtime pushes them like
|
|
39
|
+
* stored keys.
|
|
40
|
+
*/
|
|
41
|
+
export const DERIVED_SETTINGS_KEYS = ["phone_active", "foreground_app_on_screen", "ring_battery"];
|
|
42
|
+
export function isDerivedSettingsKey(key) {
|
|
43
|
+
return DERIVED_SETTINGS_KEYS.includes(key);
|
|
44
|
+
}
|
|
45
|
+
/** What a system app may do with `key`, or null when the bridge does not serve it. */
|
|
46
|
+
export function settingsBridgeAccess(key) {
|
|
47
|
+
if (isDerivedSettingsKey(key))
|
|
48
|
+
return "read";
|
|
49
|
+
return SETTINGS_BRIDGE_KEYS[key] ?? null;
|
|
50
|
+
}
|
|
51
|
+
/** Every key the bridge serves, stored then derived. */
|
|
52
|
+
export function allSettingsBridgeKeys() {
|
|
53
|
+
return [...Object.keys(SETTINGS_BRIDGE_KEYS), ...DERIVED_SETTINGS_KEYS];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The keys a SETTINGS_GET asks for: everything when `requested` is absent,
|
|
57
|
+
* else the known ones among the requested strings (unknown keys are left
|
|
58
|
+
* out, never rejected).
|
|
59
|
+
*/
|
|
60
|
+
export function selectSettingsBridgeKeys(requested) {
|
|
61
|
+
if (requested === undefined || requested === null)
|
|
62
|
+
return allSettingsBridgeKeys();
|
|
63
|
+
if (!Array.isArray(requested))
|
|
64
|
+
return [];
|
|
65
|
+
return requested.filter((key) => typeof key === "string" && settingsBridgeAccess(key) !== null);
|
|
66
|
+
}
|
|
67
|
+
/** A SETTINGS_SET payload: a writable key and a JSON value (undefined is not a value). */
|
|
68
|
+
export function validateSettingsSet(payload) {
|
|
69
|
+
const key = payload.key;
|
|
70
|
+
if (typeof key !== "string" || !key) {
|
|
71
|
+
return { ok: false, code: "INVALID_ARGUMENT", message: "settings.set requires a key" };
|
|
72
|
+
}
|
|
73
|
+
const access = settingsBridgeAccess(key);
|
|
74
|
+
if (access === null)
|
|
75
|
+
return { ok: false, code: "INVALID_ARGUMENT", message: `Unknown setting "${key}"` };
|
|
76
|
+
if (access !== "write")
|
|
77
|
+
return { ok: false, code: "NOT_PERMITTED", message: `Setting "${key}" is read-only` };
|
|
78
|
+
if (!("value" in payload) || payload.value === undefined) {
|
|
79
|
+
return { ok: false, code: "INVALID_ARGUMENT", message: "settings.set requires a value" };
|
|
80
|
+
}
|
|
81
|
+
return { ok: true, key, value: payload.value };
|
|
82
|
+
}
|
|
83
|
+
export function ringBatteryFrom(glasses) {
|
|
84
|
+
const relayed = glasses.ringConnected && glasses.ringBatteryLevel >= 0;
|
|
85
|
+
return {
|
|
86
|
+
connected: relayed || glasses.controllerConnected,
|
|
87
|
+
level: relayed ? glasses.ringBatteryLevel : glasses.controllerBatteryLevel,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=settingsBridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settingsBridge.js","sourceRoot":"","sources":["../../src/services/settingsBridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,wFAAwF;AACxF,MAAM,CAAC,MAAM,oBAAoB,GAAmD;IAClF,4DAA4D;IAC5D,wBAAwB,EAAE,MAAM;IAChC,4BAA4B,EAAE,OAAO;IACrC,gCAAgC,EAAE,OAAO;IACzC,8BAA8B,EAAE,OAAO;IACvC,uBAAuB,EAAE,OAAO;IAChC,qCAAqC,EAAE,OAAO;IAC9C,oCAAoC,EAAE,OAAO;IAC7C,oBAAoB,EAAE,OAAO;IAC7B,gBAAgB,EAAE,OAAO;IACzB,SAAS,EAAE,OAAO;IAClB,qBAAqB,EAAE,OAAO;IAC9B,oBAAoB,EAAE,OAAO;IAC7B,2BAA2B,EAAE,OAAO;IACpC,8BAA8B,EAAE,OAAO;IACvC,iCAAiC,EAAE,OAAO;IAC1C,uBAAuB,EAAE,OAAO;IAChC,0EAA0E;IAC1E,sBAAsB,EAAE,MAAM;CAC/B,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,cAAc,EAAE,0BAA0B,EAAE,cAAc,CAAU,CAAA;AAG1G,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,OAAQ,qBAA2C,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAA;AACnE,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,IAAI,oBAAoB,CAAC,GAAG,CAAC;QAAE,OAAO,MAAM,CAAA;IAC5C,OAAO,oBAAoB,CAAC,GAAG,CAAC,IAAI,IAAI,CAAA;AAC1C,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,qBAAqB;IACnC,OAAO,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,EAAE,GAAG,qBAAqB,CAAC,CAAA;AACzE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,SAAkB;IACzD,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,qBAAqB,EAAE,CAAA;IACjF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;QAAE,OAAO,EAAE,CAAA;IACxC,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,EAAiB,EAAE,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,oBAAoB,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAA;AAChH,CAAC;AAMD,0FAA0F;AAC1F,MAAM,UAAU,mBAAmB,CAAC,OAAgC;IAClE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAA;IACvB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC;QACpC,OAAO,EAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,6BAA6B,EAAC,CAAA;IACtF,CAAC;IACD,MAAM,MAAM,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAA;IACxC,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,EAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,oBAAoB,GAAG,GAAG,EAAC,CAAA;IACtG,IAAI,MAAM,KAAK,OAAO;QAAE,OAAO,EAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,YAAY,GAAG,gBAAgB,EAAC,CAAA;IAC3G,IAAI,CAAC,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QACzD,OAAO,EAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,+BAA+B,EAAC,CAAA;IACxF,CAAC;IACD,OAAO,EAAC,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAC,CAAA;AAC9C,CAAC;AASD,MAAM,UAAU,eAAe,CAAC,OAK/B;IACC,MAAM,OAAO,GAAG,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,gBAAgB,IAAI,CAAC,CAAA;IACtE,OAAO;QACL,SAAS,EAAE,OAAO,IAAI,OAAO,CAAC,mBAAmB;QACjD,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,sBAAsB;KAC3E,CAAA;AACH,CAAC","sourcesContent":["/**\n * The settings bridge's vocabulary (session.settings): which engine settings\n * a system miniapp may read or write, the derived read-only keys the engine\n * computes rather than stores, and the request validation. Pure, so the\n * runtime's handlers stay thin and this can be tested without the native\n * import surface the runtime pulls in.\n *\n * The dashboard miniapp is the consumer: it edits the same dashboard,\n * notification and glasses-menu keys the phone's settings screens used to,\n * through the store, so persistence, server sync and the Bluetooth sync of\n * `menu_apps` behave as if a phone screen wrote them.\n */\n\nexport type SettingsBridgeAccess = \"read\" | \"write\"\n\n/** Stored settings the bridge serves, by key, with what a system app may do to each. */\nexport const SETTINGS_BRIDGE_KEYS: Readonly<Record<string, SettingsBridgeAccess>> = {\n // The dashboard's master switch is a phone-side debug knob.\n custom_dashboard_enabled: \"read\",\n custom_dashboard_clock_style: \"write\",\n custom_dashboard_clock_show_date: \"write\",\n custom_dashboard_battery_style: \"write\",\n custom_dashboard_layout: \"write\",\n custom_dashboard_calendar_event_count: \"write\",\n custom_dashboard_calendar_days_ahead: \"write\",\n contextual_dashboard: \"write\",\n twelve_hour_time: \"write\",\n menu_apps: \"write\",\n notifications_enabled: \"write\",\n notifications_popups: \"write\",\n notifications_popup_seconds: \"write\",\n notifications_hold_during_apps: \"write\",\n notifications_ignore_while_active: \"write\",\n notifications_blocklist: \"write\",\n // Apps the glasses reported posting notifications; the engine records it.\n notification_seen_apps: \"read\",\n}\n\n/**\n * Read-only keys the engine computes: whether the wearer can see the phone,\n * whether the foreground miniapp is drawing on the glasses, and the ring's\n * battery. They change on their own clocks; the runtime pushes them like\n * stored keys.\n */\nexport const DERIVED_SETTINGS_KEYS = [\"phone_active\", \"foreground_app_on_screen\", \"ring_battery\"] as const\nexport type DerivedSettingsKey = (typeof DERIVED_SETTINGS_KEYS)[number]\n\nexport function isDerivedSettingsKey(key: string): key is DerivedSettingsKey {\n return (DERIVED_SETTINGS_KEYS as readonly string[]).includes(key)\n}\n\n/** What a system app may do with `key`, or null when the bridge does not serve it. */\nexport function settingsBridgeAccess(key: string): SettingsBridgeAccess | null {\n if (isDerivedSettingsKey(key)) return \"read\"\n return SETTINGS_BRIDGE_KEYS[key] ?? null\n}\n\n/** Every key the bridge serves, stored then derived. */\nexport function allSettingsBridgeKeys(): string[] {\n return [...Object.keys(SETTINGS_BRIDGE_KEYS), ...DERIVED_SETTINGS_KEYS]\n}\n\n/**\n * The keys a SETTINGS_GET asks for: everything when `requested` is absent,\n * else the known ones among the requested strings (unknown keys are left\n * out, never rejected).\n */\nexport function selectSettingsBridgeKeys(requested: unknown): string[] {\n if (requested === undefined || requested === null) return allSettingsBridgeKeys()\n if (!Array.isArray(requested)) return []\n return requested.filter((key): key is string => typeof key === \"string\" && settingsBridgeAccess(key) !== null)\n}\n\nexport type SettingsSetValidation =\n | {ok: true; key: string; value: unknown}\n | {ok: false; code: \"INVALID_ARGUMENT\" | \"NOT_PERMITTED\"; message: string}\n\n/** A SETTINGS_SET payload: a writable key and a JSON value (undefined is not a value). */\nexport function validateSettingsSet(payload: Record<string, unknown>): SettingsSetValidation {\n const key = payload.key\n if (typeof key !== \"string\" || !key) {\n return {ok: false, code: \"INVALID_ARGUMENT\", message: \"settings.set requires a key\"}\n }\n const access = settingsBridgeAccess(key)\n if (access === null) return {ok: false, code: \"INVALID_ARGUMENT\", message: `Unknown setting \"${key}\"`}\n if (access !== \"write\") return {ok: false, code: \"NOT_PERMITTED\", message: `Setting \"${key}\" is read-only`}\n if (!(\"value\" in payload) || payload.value === undefined) {\n return {ok: false, code: \"INVALID_ARGUMENT\", message: \"settings.set requires a value\"}\n }\n return {ok: true, key, value: payload.value}\n}\n\n/** The ring's battery as the dashboard shows it: the relayed ring first, else the controller. */\nexport interface RingBattery {\n connected: boolean\n /** -1 when unknown. */\n level: number\n}\n\nexport function ringBatteryFrom(glasses: {\n ringConnected: boolean\n ringBatteryLevel: number\n controllerConnected: boolean\n controllerBatteryLevel: number\n}): RingBattery {\n const relayed = glasses.ringConnected && glasses.ringBatteryLevel >= 0\n return {\n connected: relayed || glasses.controllerConnected,\n level: relayed ? glasses.ringBatteryLevel : glasses.controllerBatteryLevel,\n }\n}\n"]}
|
|
@@ -7,7 +7,7 @@ import { storage as mmkvStorage } from "../utils/storage/storage";
|
|
|
7
7
|
import { cloudClientService } from "./CloudClientService";
|
|
8
8
|
import { SpeakerProfileStore } from "./SpeakerProfileStore";
|
|
9
9
|
export const speakerProfileStore = new SpeakerProfileStore({
|
|
10
|
-
getUserId: () => cloudClientService.
|
|
10
|
+
getUserId: () => cloudClientService.resolveUserId(),
|
|
11
11
|
backend: {
|
|
12
12
|
get(key) {
|
|
13
13
|
const result = mmkvStorage.load(key);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"speakerProfileStoreInstance.js","sourceRoot":"","sources":["../../src/services/speakerProfileStoreInstance.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,OAAO,IAAI,WAAW,EAAC,MAAM,0BAA0B,CAAA;AAC/D,OAAO,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAC,mBAAmB,EAAC,MAAM,uBAAuB,CAAA;AAEzD,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,mBAAmB,CAAC;IACzD,SAAS,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,
|
|
1
|
+
{"version":3,"file":"speakerProfileStoreInstance.js","sourceRoot":"","sources":["../../src/services/speakerProfileStoreInstance.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,OAAO,IAAI,WAAW,EAAC,MAAM,0BAA0B,CAAA;AAC/D,OAAO,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAC,mBAAmB,EAAC,MAAM,uBAAuB,CAAA;AAEzD,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,mBAAmB,CAAC;IACzD,SAAS,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,aAAa,EAAE;IACnD,OAAO,EAAE;QACP,GAAG,CAAC,GAAW;YACb,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAU,GAAG,CAAC,CAAA;YAC7C,OAAO,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA;QAC7C,CAAC;QACD,GAAG,CAAC,GAAW,EAAE,KAAc;YAC7B,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QAC9B,CAAC;QACD,MAAM,CAAC,GAAW;YAChB,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QACzB,CAAC;KACF;CACF,CAAC,CAAA","sourcesContent":["/**\n * The engine's singleton SpeakerProfileStore — device-local voice profiles\n * behind engine.speakers. Lives in its own module (not SpeakerProfileStore.ts)\n * so the store class stays dependency-free for tests.\n */\n\nimport {storage as mmkvStorage} from \"../utils/storage/storage\"\nimport {cloudClientService} from \"./CloudClientService\"\nimport {SpeakerProfileStore} from \"./SpeakerProfileStore\"\n\nexport const speakerProfileStore = new SpeakerProfileStore({\n getUserId: () => cloudClientService.resolveUserId(),\n backend: {\n get(key: string): unknown | null {\n const result = mmkvStorage.load<unknown>(key)\n return result.is_ok() ? result.value : null\n },\n set(key: string, value: unknown): void {\n mmkvStorage.save(key, value)\n },\n remove(key: string): void {\n mmkvStorage.remove(key)\n },\n },\n})\n"]}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - Buffers `glassly.send(channel, payload)` calls until `glassly.ready()`
|
|
11
11
|
* fires + the host acks the channel is open. WebView-side BUFFERS (the
|
|
12
12
|
* WebView is the short-lived side and shouldn't drop user input).
|
|
13
|
-
* - Installs `window.
|
|
13
|
+
* - Installs `window.__host.recv(envelope)` for the host to push
|
|
14
14
|
* background → WebView messages via `webview.injectJavaScript(...)`.
|
|
15
15
|
* - Sends `__heartbeat__` every 5s; host considers the WebView gone
|
|
16
16
|
* after 15s of silence.
|
package/build/services/uiShim.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - Buffers `glassly.send(channel, payload)` calls until `glassly.ready()`
|
|
11
11
|
* fires + the host acks the channel is open. WebView-side BUFFERS (the
|
|
12
12
|
* WebView is the short-lived side and shouldn't drop user input).
|
|
13
|
-
* - Installs `window.
|
|
13
|
+
* - Installs `window.__host.recv(envelope)` for the host to push
|
|
14
14
|
* background → WebView messages via `webview.injectJavaScript(...)`.
|
|
15
15
|
* - Sends `__heartbeat__` every 5s; host considers the WebView gone
|
|
16
16
|
* after 15s of silence.
|
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
export function buildUiShim(options) {
|
|
33
33
|
const packageNameJson = JSON.stringify(options.packageName);
|
|
34
34
|
// The IIFE assembles a typed `glassly` global plus an internal
|
|
35
|
-
// `
|
|
35
|
+
// `__host` for host inbound calls. Quoted strings are JSON-safe so
|
|
36
36
|
// direct injection inside another JS literal also works.
|
|
37
37
|
return `
|
|
38
38
|
(function () {
|
|
39
39
|
if (typeof window === 'undefined') return;
|
|
40
|
-
if (window.glassly && window.
|
|
40
|
+
if (window.glassly && window.__host) return;
|
|
41
41
|
var packageName = ${packageNameJson};
|
|
42
42
|
// Resolve window.ReactNativeWebView.postMessage LAZILY, not once at shim-eval.
|
|
43
43
|
// On Android the shim is injected as a WebViewCompat document-start script
|
|
@@ -362,7 +362,7 @@ export function buildUiShim(options) {
|
|
|
362
362
|
/** @internal — packageName for diagnostic logs only. */
|
|
363
363
|
_packageName: packageName,
|
|
364
364
|
};
|
|
365
|
-
window.
|
|
365
|
+
window.__host = { recv: recv };
|
|
366
366
|
})();
|
|
367
367
|
`.trim();
|
|
368
368
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uiShim.js","sourceRoot":"","sources":["../../src/services/uiShim.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAQH,MAAM,UAAU,WAAW,CAAC,OAAsB;IAChD,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;IAC3D,+DAA+D;IAC/D,sEAAsE;IACtE,yDAAyD;IACzD,OAAO;;;;sBAIa,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsUpC,CAAC,IAAI,EAAE,CAAA;AACR,CAAC","sourcesContent":["/**\n * window.glassly — WebView-side bridge to the per-miniapp background JSContext.\n *\n * Injected into every UI WebView via `injectedJavaScriptBeforeContentLoaded`\n * (iOS) or `injectedJavaScriptObject` + a bundler-emitted inline `<script>`\n * (Android, where the `BeforeContentLoaded` prop is documented unreliable\n * per react-native-webview issues #1099 / #1609).\n *\n * The shim:\n * - Buffers `glassly.send(channel, payload)` calls until `glassly.ready()`\n * fires + the host acks the channel is open. WebView-side BUFFERS (the\n * WebView is the short-lived side and shouldn't drop user input).\n * - Installs `window.__glassly.recv(envelope)` for the host to push\n * background → WebView messages via `webview.injectJavaScript(...)`.\n * - Sends `__heartbeat__` every 5s; host considers the WebView gone\n * after 15s of silence.\n * - Maintains monotonic seq numbers; the host's per-WebView dedup window\n * drops replays during reconnect.\n *\n * This file exports a `buildUiShim()` function returning the JS\n * source as a string. The host's UIRouter wraps it inside the\n * existing WebView setup so a single bundler-time string emission covers\n * both platforms.\n *\n * IMPORTANT: the shim runs in the WebView's bare ECMAScript scope before\n * the miniapp's bundle. It must not import anything; the source is one\n * IIFE. The only injected dependencies are\n * `window.ReactNativeWebView.postMessage` (provided by react-native-webview)\n * and (on Android) `window.ReactNativeWebView.injectedObjectJson()`\n * (provided when the host sets `injectedJavaScriptObject`).\n */\n\nexport interface UiShimOptions {\n packageName: string\n /** @deprecated No longer used — heartbeat removed since WebViews are foreground-only. */\n heartbeatIntervalMs?: number\n}\n\nexport function buildUiShim(options: UiShimOptions): string {\n const packageNameJson = JSON.stringify(options.packageName)\n // The IIFE assembles a typed `glassly` global plus an internal\n // `__glassly` for host inbound calls. Quoted strings are JSON-safe so\n // direct injection inside another JS literal also works.\n return `\n(function () {\n if (typeof window === 'undefined') return;\n if (window.glassly && window.__glassly) return;\n var packageName = ${packageNameJson};\n // Resolve window.ReactNativeWebView.postMessage LAZILY, not once at shim-eval.\n // On Android the shim is injected as a WebViewCompat document-start script\n // (so it beats the page bundle and the ready handshake can't be raced — see\n // the react-native-webview patch). But the order in which that document-start\n // script runs vs. the WebMessageListener that installs\n // window.ReactNativeWebView is not contractually fixed on Android the way it\n // is on iOS (postMessageScript is registered before atStartScript there). If\n // we captured rnPost once and the bridge object wasn't installed yet, every\n // postMessage — including {type:'ready'} — would be silently dropped and the\n // splash would hang forever. Resolving per-call means we always pick up the\n // bridge once it exists, which it reliably does by the time the bundle mounts\n // and calls glassly.ready().\n function getRnPost() {\n try {\n return window.ReactNativeWebView && typeof window.ReactNativeWebView.postMessage === 'function'\n ? window.ReactNativeWebView.postMessage.bind(window.ReactNativeWebView)\n : null;\n } catch (e) { return null; }\n }\n\n // Outbound seq number — purely a log-correlation aid (the host's\n // router doesn't dedup anymore since reconnect can't happen: one\n // WebView, foreground-only, destroyed on close → fresh shim on\n // next open).\n var outboundSeq = 1;\n var ready = false;\n var channelHandlers = Object.create(null);\n var openHandlers = [];\n var closeHandlers = [];\n // Queued glassly.send calls before glassly.ready() acks. FIFO drained\n // on ack. Buffered so user input (button taps, etc.) isn't dropped\n // when the WebView mounts faster than the host expects.\n var outboundQueue = [];\n // Inbound payloads that arrived before any glassly.on subscriber was\n // registered for the channel. The background side fires\n // session.ui.onOpen handlers as soon as the WebView posts {type:'ready'},\n // and on a fast bridge the resulting ui.send round-trips back before\n // React useEffects have had a chance to attach listeners. Without\n // buffering, the very first snapshot (the one a controller pushes from\n // its ui.onOpen handler to hydrate the fresh UI) is silently dropped.\n //\n // Drain policy: the queue for a channel is flushed into the FIRST\n // glassly.on(channel, ...) subscriber, then discarded. Subsequent\n // sends with no listener fall back to the old drop-on-floor behaviour\n // — we don't want a re-subscribe to replay stale state.\n //\n // Cap: 32 entries per channel, oldest dropped on overflow. Bounds the\n // memory cost when a controller pushes to a channel that no UI page\n // ever subscribes to.\n var pendingByChannel = Object.create(null);\n var PENDING_CAP_PER_CHANNEL = 32;\n\n function postEnvelope(envelope) {\n var rnPost = getRnPost();\n if (!rnPost) return;\n try { rnPost(JSON.stringify(envelope)); } catch (_) {}\n }\n\n function send(channel, payload) {\n var seq = outboundSeq++;\n var envelope = { type: 'msg', seq: seq, channel: String(channel), payload: payload };\n if (!ready) {\n outboundQueue.push(envelope);\n return;\n }\n postEnvelope(envelope);\n }\n\n function flushQueue() {\n while (outboundQueue.length > 0) {\n postEnvelope(outboundQueue.shift());\n }\n }\n\n // NOTE: console.* tap lives in miniappGlobals.ts (injected alongside\n // this shim for every UI WebView, two-layer or single-bundle). That\n // shim posts {payload:{type:\"dev_log\", ...}} envelopes which\n // LocalMiniappRuntime forwards to the dev sidecar tagged source:\"ui\".\n // We don't re-wrap here to avoid double-delivery.\n\n function on(channel, cb) {\n if (typeof cb !== 'function') return function () {};\n var list = channelHandlers[channel];\n var firstSubscriber = !list || list.length === 0;\n if (!list) { list = []; channelHandlers[channel] = list; }\n list.push(cb);\n // Drain any payloads buffered before this channel had a listener.\n // Only fired on the first subscriber for the channel — a later\n // re-subscribe (after an unsubscribe) does NOT replay history.\n if (firstSubscriber) {\n var pending = pendingByChannel[channel];\n if (pending) {\n delete pendingByChannel[channel];\n for (var i = 0; i < pending.length; i++) {\n try { cb(pending[i]); } catch (e) {}\n }\n }\n }\n return function () {\n var idx = list.indexOf(cb);\n if (idx >= 0) list.splice(idx, 1);\n };\n }\n\n // ── RPC ─────────────────────────────────────────────────────────────\n // Outbound RPC: every glassly.request() generates a request id, sends a\n // 'msg' envelope tagged with requestId, and stashes a one-shot resolver\n // keyed on the id. The background-side reply is a recv('msg') with the\n // same channel + requestId; we route it directly to the resolver.\n //\n // Cancellation: caller's AbortSignal triggers a 'cancel' envelope to\n // background and rejects the local promise with a DOM-standard\n // AbortError. The background side's UI_CANCEL handler aborts the\n // handler's ctx.signal and drops the reply.\n var rpcCounter = 0;\n var rpcInflight = Object.create(null);\n\n function makeRequestId() {\n rpcCounter += 1;\n return 'r' + rpcCounter + '-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2, 8);\n }\n\n function RpcError(message, code, stage, transport) {\n var e = new Error(message);\n e.name = 'RpcError';\n if (code) {\n try { e.cause = {code: code}; } catch (_) { /* old runtimes */ }\n e.code = code;\n }\n // Diagnostic fields ride as own props so a miniapp can show exactly which\n // pipeline stage and transport failed, not just a message string.\n if (stage) e.stage = stage;\n if (transport) e.transport = transport;\n return e;\n }\n\n function RpcTimeoutError(message) {\n var e = new Error(message || 'RPC timed out');\n e.name = 'RpcTimeoutError';\n return e;\n }\n\n function makeAbortError() {\n var e;\n try { e = new DOMException('aborted', 'AbortError'); } catch (_) {\n e = new Error('aborted');\n e.name = 'AbortError';\n }\n return e;\n }\n\n function request(channel, payload, options) {\n var opts = options || {};\n var signal = opts.signal;\n var timeoutMs = typeof opts.timeout === 'number' ? opts.timeout : null;\n var id = makeRequestId();\n\n return new Promise(function (resolve, reject) {\n var done = false;\n var timeoutHandle = null;\n var abortListener = null;\n\n function cleanup() {\n if (done) return;\n done = true;\n delete rpcInflight[id];\n if (timeoutHandle != null) { clearTimeout(timeoutHandle); timeoutHandle = null; }\n if (signal && abortListener) {\n try { signal.removeEventListener('abort', abortListener); } catch (_) {}\n }\n }\n\n function settle(envelope) {\n if (done) return;\n cleanup();\n if (envelope && envelope.ok === true) {\n resolve(envelope.result);\n } else if (envelope && envelope.ok === false) {\n reject(RpcError(envelope.error && envelope.error.message || 'RPC failed', envelope.error && envelope.error.code, envelope.error && envelope.error.stage, envelope.error && envelope.error.transport));\n } else {\n reject(RpcError('malformed RPC reply'));\n }\n }\n\n rpcInflight[id] = settle;\n\n if (signal) {\n if (signal.aborted) {\n cleanup();\n reject(makeAbortError());\n return;\n }\n abortListener = function () {\n if (done) return;\n cleanup();\n postEnvelope({type: 'cancel', requestId: id});\n reject(makeAbortError());\n };\n try { signal.addEventListener('abort', abortListener); } catch (_) {}\n }\n\n if (timeoutMs != null) {\n timeoutHandle = setTimeout(function () {\n if (done) return;\n cleanup();\n postEnvelope({type: 'cancel', requestId: id});\n reject(RpcTimeoutError());\n }, timeoutMs);\n }\n\n var envelope = {type: 'msg', seq: outboundSeq++, channel: String(channel), payload: payload, requestId: id};\n if (!ready) {\n outboundQueue.push(envelope);\n return;\n }\n postEnvelope(envelope);\n });\n }\n\n function onOpen(cb) {\n if (typeof cb !== 'function') return function () {};\n openHandlers.push(cb);\n if (ready) {\n try { cb(); } catch (e) {}\n }\n return function () {\n var idx = openHandlers.indexOf(cb);\n if (idx >= 0) openHandlers.splice(idx, 1);\n };\n }\n\n function onClose(cb) {\n if (typeof cb !== 'function') return function () {};\n closeHandlers.push(cb);\n return function () {\n var idx = closeHandlers.indexOf(cb);\n if (idx >= 0) closeHandlers.splice(idx, 1);\n };\n }\n\n function readyFn() {\n if (ready) return;\n ready = true;\n postEnvelope({ type: 'ready' });\n flushQueue();\n for (var i = 0; i < openHandlers.length; i++) {\n try { openHandlers[i](); } catch (e) {}\n }\n }\n\n function setBackgroundColorFn(color) {\n // Tells the host what to paint the native WebView layer (the surface\n // exposed during keyboard push-up / resize animations, which page CSS\n // cannot reach). Host validates and falls back to its theme background.\n if (typeof color !== 'string' || !color) return;\n postEnvelope({ type: 'set_background', color: color });\n }\n\n function fireChannel(channel, payload) {\n var list = channelHandlers[channel];\n if (!list || list.length === 0) {\n // No subscriber yet — stash for the first glassly.on(channel, ...).\n // Bounded FIFO: drop the oldest when capped so a stuck channel\n // can't grow unbounded.\n var q = pendingByChannel[channel];\n if (!q) { q = []; pendingByChannel[channel] = q; }\n q.push(payload);\n if (q.length > PENDING_CAP_PER_CHANNEL) q.shift();\n return;\n }\n for (var i = 0; i < list.length; i++) {\n try { list[i](payload); } catch (e) {}\n }\n }\n\n function recv(envelope) {\n if (!envelope || typeof envelope !== 'object') return;\n var type = envelope.type;\n if (type === 'msg' && typeof envelope.channel === 'string') {\n // RPC frames carry a requestId; broadcast frames don't. Treat them\n // as disjoint — never fall through from RPC to broadcast. An orphan\n // RPC reply (caller already aborted/timed out) is silently dropped.\n if (typeof envelope.requestId === 'string') {\n var settle = rpcInflight[envelope.requestId];\n if (settle) settle(envelope.payload);\n return;\n }\n fireChannel(envelope.channel, envelope.payload);\n return;\n }\n if (type === 'open') {\n for (var j = 0; j < openHandlers.length; j++) {\n try { openHandlers[j](); } catch (e) {}\n }\n return;\n }\n if (type === 'close') {\n for (var k = 0; k < closeHandlers.length; k++) {\n try { closeHandlers[k](); } catch (e) {}\n }\n return;\n }\n if (type === 'cancel' && typeof envelope.requestId === 'string') {\n // Background-side cancel (reserved; currently unused). If we had a\n // future bidirectional RPC this would abort an in-flight UI handler.\n return;\n }\n if (type === 'ack') {\n return;\n }\n }\n\n window.glassly = {\n send: send,\n on: on,\n request: request,\n onOpen: onOpen,\n onClose: onClose,\n ready: readyFn,\n setBackgroundColor: setBackgroundColorFn,\n /** @internal — packageName for diagnostic logs only. */\n _packageName: packageName,\n };\n window.__glassly = { recv: recv };\n})();\n`.trim()\n}\n"]}
|
|
1
|
+
{"version":3,"file":"uiShim.js","sourceRoot":"","sources":["../../src/services/uiShim.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAQH,MAAM,UAAU,WAAW,CAAC,OAAsB;IAChD,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;IAC3D,+DAA+D;IAC/D,mEAAmE;IACnE,yDAAyD;IACzD,OAAO;;;;sBAIa,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsUpC,CAAC,IAAI,EAAE,CAAA;AACR,CAAC","sourcesContent":["/**\n * window.glassly — WebView-side bridge to the per-miniapp background JSContext.\n *\n * Injected into every UI WebView via `injectedJavaScriptBeforeContentLoaded`\n * (iOS) or `injectedJavaScriptObject` + a bundler-emitted inline `<script>`\n * (Android, where the `BeforeContentLoaded` prop is documented unreliable\n * per react-native-webview issues #1099 / #1609).\n *\n * The shim:\n * - Buffers `glassly.send(channel, payload)` calls until `glassly.ready()`\n * fires + the host acks the channel is open. WebView-side BUFFERS (the\n * WebView is the short-lived side and shouldn't drop user input).\n * - Installs `window.__host.recv(envelope)` for the host to push\n * background → WebView messages via `webview.injectJavaScript(...)`.\n * - Sends `__heartbeat__` every 5s; host considers the WebView gone\n * after 15s of silence.\n * - Maintains monotonic seq numbers; the host's per-WebView dedup window\n * drops replays during reconnect.\n *\n * This file exports a `buildUiShim()` function returning the JS\n * source as a string. The host's UIRouter wraps it inside the\n * existing WebView setup so a single bundler-time string emission covers\n * both platforms.\n *\n * IMPORTANT: the shim runs in the WebView's bare ECMAScript scope before\n * the miniapp's bundle. It must not import anything; the source is one\n * IIFE. The only injected dependencies are\n * `window.ReactNativeWebView.postMessage` (provided by react-native-webview)\n * and (on Android) `window.ReactNativeWebView.injectedObjectJson()`\n * (provided when the host sets `injectedJavaScriptObject`).\n */\n\nexport interface UiShimOptions {\n packageName: string\n /** @deprecated No longer used — heartbeat removed since WebViews are foreground-only. */\n heartbeatIntervalMs?: number\n}\n\nexport function buildUiShim(options: UiShimOptions): string {\n const packageNameJson = JSON.stringify(options.packageName)\n // The IIFE assembles a typed `glassly` global plus an internal\n // `__host` for host inbound calls. Quoted strings are JSON-safe so\n // direct injection inside another JS literal also works.\n return `\n(function () {\n if (typeof window === 'undefined') return;\n if (window.glassly && window.__host) return;\n var packageName = ${packageNameJson};\n // Resolve window.ReactNativeWebView.postMessage LAZILY, not once at shim-eval.\n // On Android the shim is injected as a WebViewCompat document-start script\n // (so it beats the page bundle and the ready handshake can't be raced — see\n // the react-native-webview patch). But the order in which that document-start\n // script runs vs. the WebMessageListener that installs\n // window.ReactNativeWebView is not contractually fixed on Android the way it\n // is on iOS (postMessageScript is registered before atStartScript there). If\n // we captured rnPost once and the bridge object wasn't installed yet, every\n // postMessage — including {type:'ready'} — would be silently dropped and the\n // splash would hang forever. Resolving per-call means we always pick up the\n // bridge once it exists, which it reliably does by the time the bundle mounts\n // and calls glassly.ready().\n function getRnPost() {\n try {\n return window.ReactNativeWebView && typeof window.ReactNativeWebView.postMessage === 'function'\n ? window.ReactNativeWebView.postMessage.bind(window.ReactNativeWebView)\n : null;\n } catch (e) { return null; }\n }\n\n // Outbound seq number — purely a log-correlation aid (the host's\n // router doesn't dedup anymore since reconnect can't happen: one\n // WebView, foreground-only, destroyed on close → fresh shim on\n // next open).\n var outboundSeq = 1;\n var ready = false;\n var channelHandlers = Object.create(null);\n var openHandlers = [];\n var closeHandlers = [];\n // Queued glassly.send calls before glassly.ready() acks. FIFO drained\n // on ack. Buffered so user input (button taps, etc.) isn't dropped\n // when the WebView mounts faster than the host expects.\n var outboundQueue = [];\n // Inbound payloads that arrived before any glassly.on subscriber was\n // registered for the channel. The background side fires\n // session.ui.onOpen handlers as soon as the WebView posts {type:'ready'},\n // and on a fast bridge the resulting ui.send round-trips back before\n // React useEffects have had a chance to attach listeners. Without\n // buffering, the very first snapshot (the one a controller pushes from\n // its ui.onOpen handler to hydrate the fresh UI) is silently dropped.\n //\n // Drain policy: the queue for a channel is flushed into the FIRST\n // glassly.on(channel, ...) subscriber, then discarded. Subsequent\n // sends with no listener fall back to the old drop-on-floor behaviour\n // — we don't want a re-subscribe to replay stale state.\n //\n // Cap: 32 entries per channel, oldest dropped on overflow. Bounds the\n // memory cost when a controller pushes to a channel that no UI page\n // ever subscribes to.\n var pendingByChannel = Object.create(null);\n var PENDING_CAP_PER_CHANNEL = 32;\n\n function postEnvelope(envelope) {\n var rnPost = getRnPost();\n if (!rnPost) return;\n try { rnPost(JSON.stringify(envelope)); } catch (_) {}\n }\n\n function send(channel, payload) {\n var seq = outboundSeq++;\n var envelope = { type: 'msg', seq: seq, channel: String(channel), payload: payload };\n if (!ready) {\n outboundQueue.push(envelope);\n return;\n }\n postEnvelope(envelope);\n }\n\n function flushQueue() {\n while (outboundQueue.length > 0) {\n postEnvelope(outboundQueue.shift());\n }\n }\n\n // NOTE: console.* tap lives in miniappGlobals.ts (injected alongside\n // this shim for every UI WebView, two-layer or single-bundle). That\n // shim posts {payload:{type:\"dev_log\", ...}} envelopes which\n // LocalMiniappRuntime forwards to the dev sidecar tagged source:\"ui\".\n // We don't re-wrap here to avoid double-delivery.\n\n function on(channel, cb) {\n if (typeof cb !== 'function') return function () {};\n var list = channelHandlers[channel];\n var firstSubscriber = !list || list.length === 0;\n if (!list) { list = []; channelHandlers[channel] = list; }\n list.push(cb);\n // Drain any payloads buffered before this channel had a listener.\n // Only fired on the first subscriber for the channel — a later\n // re-subscribe (after an unsubscribe) does NOT replay history.\n if (firstSubscriber) {\n var pending = pendingByChannel[channel];\n if (pending) {\n delete pendingByChannel[channel];\n for (var i = 0; i < pending.length; i++) {\n try { cb(pending[i]); } catch (e) {}\n }\n }\n }\n return function () {\n var idx = list.indexOf(cb);\n if (idx >= 0) list.splice(idx, 1);\n };\n }\n\n // ── RPC ─────────────────────────────────────────────────────────────\n // Outbound RPC: every glassly.request() generates a request id, sends a\n // 'msg' envelope tagged with requestId, and stashes a one-shot resolver\n // keyed on the id. The background-side reply is a recv('msg') with the\n // same channel + requestId; we route it directly to the resolver.\n //\n // Cancellation: caller's AbortSignal triggers a 'cancel' envelope to\n // background and rejects the local promise with a DOM-standard\n // AbortError. The background side's UI_CANCEL handler aborts the\n // handler's ctx.signal and drops the reply.\n var rpcCounter = 0;\n var rpcInflight = Object.create(null);\n\n function makeRequestId() {\n rpcCounter += 1;\n return 'r' + rpcCounter + '-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2, 8);\n }\n\n function RpcError(message, code, stage, transport) {\n var e = new Error(message);\n e.name = 'RpcError';\n if (code) {\n try { e.cause = {code: code}; } catch (_) { /* old runtimes */ }\n e.code = code;\n }\n // Diagnostic fields ride as own props so a miniapp can show exactly which\n // pipeline stage and transport failed, not just a message string.\n if (stage) e.stage = stage;\n if (transport) e.transport = transport;\n return e;\n }\n\n function RpcTimeoutError(message) {\n var e = new Error(message || 'RPC timed out');\n e.name = 'RpcTimeoutError';\n return e;\n }\n\n function makeAbortError() {\n var e;\n try { e = new DOMException('aborted', 'AbortError'); } catch (_) {\n e = new Error('aborted');\n e.name = 'AbortError';\n }\n return e;\n }\n\n function request(channel, payload, options) {\n var opts = options || {};\n var signal = opts.signal;\n var timeoutMs = typeof opts.timeout === 'number' ? opts.timeout : null;\n var id = makeRequestId();\n\n return new Promise(function (resolve, reject) {\n var done = false;\n var timeoutHandle = null;\n var abortListener = null;\n\n function cleanup() {\n if (done) return;\n done = true;\n delete rpcInflight[id];\n if (timeoutHandle != null) { clearTimeout(timeoutHandle); timeoutHandle = null; }\n if (signal && abortListener) {\n try { signal.removeEventListener('abort', abortListener); } catch (_) {}\n }\n }\n\n function settle(envelope) {\n if (done) return;\n cleanup();\n if (envelope && envelope.ok === true) {\n resolve(envelope.result);\n } else if (envelope && envelope.ok === false) {\n reject(RpcError(envelope.error && envelope.error.message || 'RPC failed', envelope.error && envelope.error.code, envelope.error && envelope.error.stage, envelope.error && envelope.error.transport));\n } else {\n reject(RpcError('malformed RPC reply'));\n }\n }\n\n rpcInflight[id] = settle;\n\n if (signal) {\n if (signal.aborted) {\n cleanup();\n reject(makeAbortError());\n return;\n }\n abortListener = function () {\n if (done) return;\n cleanup();\n postEnvelope({type: 'cancel', requestId: id});\n reject(makeAbortError());\n };\n try { signal.addEventListener('abort', abortListener); } catch (_) {}\n }\n\n if (timeoutMs != null) {\n timeoutHandle = setTimeout(function () {\n if (done) return;\n cleanup();\n postEnvelope({type: 'cancel', requestId: id});\n reject(RpcTimeoutError());\n }, timeoutMs);\n }\n\n var envelope = {type: 'msg', seq: outboundSeq++, channel: String(channel), payload: payload, requestId: id};\n if (!ready) {\n outboundQueue.push(envelope);\n return;\n }\n postEnvelope(envelope);\n });\n }\n\n function onOpen(cb) {\n if (typeof cb !== 'function') return function () {};\n openHandlers.push(cb);\n if (ready) {\n try { cb(); } catch (e) {}\n }\n return function () {\n var idx = openHandlers.indexOf(cb);\n if (idx >= 0) openHandlers.splice(idx, 1);\n };\n }\n\n function onClose(cb) {\n if (typeof cb !== 'function') return function () {};\n closeHandlers.push(cb);\n return function () {\n var idx = closeHandlers.indexOf(cb);\n if (idx >= 0) closeHandlers.splice(idx, 1);\n };\n }\n\n function readyFn() {\n if (ready) return;\n ready = true;\n postEnvelope({ type: 'ready' });\n flushQueue();\n for (var i = 0; i < openHandlers.length; i++) {\n try { openHandlers[i](); } catch (e) {}\n }\n }\n\n function setBackgroundColorFn(color) {\n // Tells the host what to paint the native WebView layer (the surface\n // exposed during keyboard push-up / resize animations, which page CSS\n // cannot reach). Host validates and falls back to its theme background.\n if (typeof color !== 'string' || !color) return;\n postEnvelope({ type: 'set_background', color: color });\n }\n\n function fireChannel(channel, payload) {\n var list = channelHandlers[channel];\n if (!list || list.length === 0) {\n // No subscriber yet — stash for the first glassly.on(channel, ...).\n // Bounded FIFO: drop the oldest when capped so a stuck channel\n // can't grow unbounded.\n var q = pendingByChannel[channel];\n if (!q) { q = []; pendingByChannel[channel] = q; }\n q.push(payload);\n if (q.length > PENDING_CAP_PER_CHANNEL) q.shift();\n return;\n }\n for (var i = 0; i < list.length; i++) {\n try { list[i](payload); } catch (e) {}\n }\n }\n\n function recv(envelope) {\n if (!envelope || typeof envelope !== 'object') return;\n var type = envelope.type;\n if (type === 'msg' && typeof envelope.channel === 'string') {\n // RPC frames carry a requestId; broadcast frames don't. Treat them\n // as disjoint — never fall through from RPC to broadcast. An orphan\n // RPC reply (caller already aborted/timed out) is silently dropped.\n if (typeof envelope.requestId === 'string') {\n var settle = rpcInflight[envelope.requestId];\n if (settle) settle(envelope.payload);\n return;\n }\n fireChannel(envelope.channel, envelope.payload);\n return;\n }\n if (type === 'open') {\n for (var j = 0; j < openHandlers.length; j++) {\n try { openHandlers[j](); } catch (e) {}\n }\n return;\n }\n if (type === 'close') {\n for (var k = 0; k < closeHandlers.length; k++) {\n try { closeHandlers[k](); } catch (e) {}\n }\n return;\n }\n if (type === 'cancel' && typeof envelope.requestId === 'string') {\n // Background-side cancel (reserved; currently unused). If we had a\n // future bidirectional RPC this would abort an in-flight UI handler.\n return;\n }\n if (type === 'ack') {\n return;\n }\n }\n\n window.glassly = {\n send: send,\n on: on,\n request: request,\n onOpen: onOpen,\n onClose: onClose,\n ready: readyFn,\n setBackgroundColor: setBackgroundColorFn,\n /** @internal — packageName for diagnostic logs only. */\n _packageName: packageName,\n };\n window.__host = { recv: recv };\n})();\n`.trim()\n}\n"]}
|
|
@@ -1,3 +1,31 @@
|
|
|
1
1
|
/** Combine registry-enforced visibility with the user's home-screen choice. */
|
|
2
2
|
export declare const resolveHiddenStatus: (registryHidden: boolean, userHidden: boolean) => boolean;
|
|
3
|
+
/**
|
|
4
|
+
* Miniapps that start off the primary home screen. They stay listed under
|
|
5
|
+
* "view all apps", where "Add to Home" saves an explicit choice that wins
|
|
6
|
+
* over this default from then on.
|
|
7
|
+
*/
|
|
8
|
+
export declare const DEFAULT_HIDDEN_PACKAGES: ReadonlySet<string>;
|
|
9
|
+
/** The home-screen visibility of an app the user has never hidden or added. */
|
|
10
|
+
export declare const defaultHiddenStatus: (packageName: string) => boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Miniapps that exist only for developers: the Miniapp Developer launcher and
|
|
13
|
+
* the bundled sample/test miniapps. They are projected into the app store
|
|
14
|
+
* only while the `dev_tools` setting is on; off, they are absent from every
|
|
15
|
+
* launcher surface (home, all apps, glasses menu, AI listing), not merely
|
|
16
|
+
* hidden from the primary home screen.
|
|
17
|
+
*/
|
|
18
|
+
export declare const DEV_TOOLS_PACKAGES: ReadonlySet<string>;
|
|
19
|
+
/** True when the app is dev-only and developer tools are off. */
|
|
20
|
+
export declare const isGatedByDevTools: (packageName: string, devToolsEnabled: boolean) => boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Miniapps that unlock once a real pair of glasses has been paired on this
|
|
23
|
+
* phone (`has_paired_glasses`, latched by PairedGlassesLatch and never
|
|
24
|
+
* cleared, so forgetting the glasses keeps them). Developer tools open them
|
|
25
|
+
* early. Until either, they are absent from every launcher surface like the
|
|
26
|
+
* dev-only set above.
|
|
27
|
+
*/
|
|
28
|
+
export declare const PAIRED_GLASSES_PACKAGES: ReadonlySet<string>;
|
|
29
|
+
/** True when the app waits on a pairing that hasn't happened and dev tools are off. */
|
|
30
|
+
export declare const isGatedUntilPaired: (packageName: string, devToolsEnabled: boolean, hasPairedGlasses: boolean) => boolean;
|
|
3
31
|
//# sourceMappingURL=appVisibility.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"appVisibility.d.ts","sourceRoot":"","sources":["../../src/stores/appVisibility.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,GAAI,gBAAgB,OAAO,EAAE,YAAY,OAAO,KAAG,OACrD,CAAA"}
|
|
1
|
+
{"version":3,"file":"appVisibility.d.ts","sourceRoot":"","sources":["../../src/stores/appVisibility.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,GAAI,gBAAgB,OAAO,EAAE,YAAY,OAAO,KAAG,OACrD,CAAA;AAE9B;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,MAAM,CAA2D,CAAA;AAEnH,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,GAAI,aAAa,MAAM,KAAG,OAAmD,CAAA;AAE7G;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAMjD,CAAA;AAEF,iEAAiE;AACjE,eAAO,MAAM,iBAAiB,GAAI,aAAa,MAAM,EAAE,iBAAiB,OAAO,KAAG,OACzB,CAAA;AAEzD;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,MAAM,CAAkC,CAAA;AAE1F,uFAAuF;AACvF,eAAO,MAAM,kBAAkB,GAC7B,aAAa,MAAM,EACnB,iBAAiB,OAAO,EACxB,kBAAkB,OAAO,KACxB,OAA4F,CAAA"}
|
|
@@ -1,3 +1,37 @@
|
|
|
1
1
|
/** Combine registry-enforced visibility with the user's home-screen choice. */
|
|
2
2
|
export const resolveHiddenStatus = (registryHidden, userHidden) => registryHidden || userHidden;
|
|
3
|
+
/**
|
|
4
|
+
* Miniapps that start off the primary home screen. They stay listed under
|
|
5
|
+
* "view all apps", where "Add to Home" saves an explicit choice that wins
|
|
6
|
+
* over this default from then on.
|
|
7
|
+
*/
|
|
8
|
+
export const DEFAULT_HIDDEN_PACKAGES = new Set(["com.glassly.camera", "com.glassly.recorder"]);
|
|
9
|
+
/** The home-screen visibility of an app the user has never hidden or added. */
|
|
10
|
+
export const defaultHiddenStatus = (packageName) => DEFAULT_HIDDEN_PACKAGES.has(packageName);
|
|
11
|
+
/**
|
|
12
|
+
* Miniapps that exist only for developers: the Miniapp Developer launcher and
|
|
13
|
+
* the bundled sample/test miniapps. They are projected into the app store
|
|
14
|
+
* only while the `dev_tools` setting is on; off, they are absent from every
|
|
15
|
+
* launcher surface (home, all apps, glasses menu, AI listing), not merely
|
|
16
|
+
* hidden from the primary home screen.
|
|
17
|
+
*/
|
|
18
|
+
export const DEV_TOOLS_PACKAGES = new Set([
|
|
19
|
+
"com.glassly.miniappdev",
|
|
20
|
+
"com.glassly.example",
|
|
21
|
+
"com.glassly.tetris",
|
|
22
|
+
"com.glassly.compass",
|
|
23
|
+
"com.glassly.showcase",
|
|
24
|
+
]);
|
|
25
|
+
/** True when the app is dev-only and developer tools are off. */
|
|
26
|
+
export const isGatedByDevTools = (packageName, devToolsEnabled) => !devToolsEnabled && DEV_TOOLS_PACKAGES.has(packageName);
|
|
27
|
+
/**
|
|
28
|
+
* Miniapps that unlock once a real pair of glasses has been paired on this
|
|
29
|
+
* phone (`has_paired_glasses`, latched by PairedGlassesLatch and never
|
|
30
|
+
* cleared, so forgetting the glasses keeps them). Developer tools open them
|
|
31
|
+
* early. Until either, they are absent from every launcher surface like the
|
|
32
|
+
* dev-only set above.
|
|
33
|
+
*/
|
|
34
|
+
export const PAIRED_GLASSES_PACKAGES = new Set(["com.glassly.store"]);
|
|
35
|
+
/** True when the app waits on a pairing that hasn't happened and dev tools are off. */
|
|
36
|
+
export const isGatedUntilPaired = (packageName, devToolsEnabled, hasPairedGlasses) => !devToolsEnabled && !hasPairedGlasses && PAIRED_GLASSES_PACKAGES.has(packageName);
|
|
3
37
|
//# sourceMappingURL=appVisibility.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"appVisibility.js","sourceRoot":"","sources":["../../src/stores/appVisibility.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,cAAuB,EAAE,UAAmB,EAAW,EAAE,CAC3F,cAAc,IAAI,UAAU,CAAA","sourcesContent":["/** Combine registry-enforced visibility with the user's home-screen choice. */\nexport const resolveHiddenStatus = (registryHidden: boolean, userHidden: boolean): boolean =>\n registryHidden || userHidden\n"]}
|
|
1
|
+
{"version":3,"file":"appVisibility.js","sourceRoot":"","sources":["../../src/stores/appVisibility.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,cAAuB,EAAE,UAAmB,EAAW,EAAE,CAC3F,cAAc,IAAI,UAAU,CAAA;AAE9B;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAwB,IAAI,GAAG,CAAC,CAAC,oBAAoB,EAAE,sBAAsB,CAAC,CAAC,CAAA;AAEnH,+EAA+E;AAC/E,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,WAAmB,EAAW,EAAE,CAAC,uBAAuB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;AAE7G;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAwB,IAAI,GAAG,CAAC;IAC7D,wBAAwB;IACxB,qBAAqB;IACrB,oBAAoB;IACpB,qBAAqB;IACrB,sBAAsB;CACvB,CAAC,CAAA;AAEF,iEAAiE;AACjE,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,WAAmB,EAAE,eAAwB,EAAW,EAAE,CAC1F,CAAC,eAAe,IAAI,kBAAkB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;AAEzD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAwB,IAAI,GAAG,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAA;AAE1F,uFAAuF;AACvF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,WAAmB,EACnB,eAAwB,EACxB,gBAAyB,EAChB,EAAE,CAAC,CAAC,eAAe,IAAI,CAAC,gBAAgB,IAAI,uBAAuB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA","sourcesContent":["/** Combine registry-enforced visibility with the user's home-screen choice. */\nexport const resolveHiddenStatus = (registryHidden: boolean, userHidden: boolean): boolean =>\n registryHidden || userHidden\n\n/**\n * Miniapps that start off the primary home screen. They stay listed under\n * \"view all apps\", where \"Add to Home\" saves an explicit choice that wins\n * over this default from then on.\n */\nexport const DEFAULT_HIDDEN_PACKAGES: ReadonlySet<string> = new Set([\"com.glassly.camera\", \"com.glassly.recorder\"])\n\n/** The home-screen visibility of an app the user has never hidden or added. */\nexport const defaultHiddenStatus = (packageName: string): boolean => DEFAULT_HIDDEN_PACKAGES.has(packageName)\n\n/**\n * Miniapps that exist only for developers: the Miniapp Developer launcher and\n * the bundled sample/test miniapps. They are projected into the app store\n * only while the `dev_tools` setting is on; off, they are absent from every\n * launcher surface (home, all apps, glasses menu, AI listing), not merely\n * hidden from the primary home screen.\n */\nexport const DEV_TOOLS_PACKAGES: ReadonlySet<string> = new Set([\n \"com.glassly.miniappdev\",\n \"com.glassly.example\",\n \"com.glassly.tetris\",\n \"com.glassly.compass\",\n \"com.glassly.showcase\",\n])\n\n/** True when the app is dev-only and developer tools are off. */\nexport const isGatedByDevTools = (packageName: string, devToolsEnabled: boolean): boolean =>\n !devToolsEnabled && DEV_TOOLS_PACKAGES.has(packageName)\n\n/**\n * Miniapps that unlock once a real pair of glasses has been paired on this\n * phone (`has_paired_glasses`, latched by PairedGlassesLatch and never\n * cleared, so forgetting the glasses keeps them). Developer tools open them\n * early. Until either, they are absent from every launcher surface like the\n * dev-only set above.\n */\nexport const PAIRED_GLASSES_PACKAGES: ReadonlySet<string> = new Set([\"com.glassly.store\"])\n\n/** True when the app waits on a pairing that hasn't happened and dev tools are off. */\nexport const isGatedUntilPaired = (\n packageName: string,\n devToolsEnabled: boolean,\n hasPairedGlasses: boolean,\n): boolean => !devToolsEnabled && !hasPairedGlasses && PAIRED_GLASSES_PACKAGES.has(packageName)\n"]}
|
package/build/stores/apps.d.ts
CHANGED
|
@@ -11,8 +11,11 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { AsyncResult, Result } from "typesafe-ts";
|
|
13
13
|
import type { ClientApp } from "../types/applet";
|
|
14
|
+
import type { MiniappLaunchSource } from "@glassly/miniapp";
|
|
14
15
|
export interface StartOptions {
|
|
15
16
|
skipNavigation?: boolean;
|
|
17
|
+
/** Reported to the miniapp on connect. Defaults to "phone". */
|
|
18
|
+
launchSource?: MiniappLaunchSource;
|
|
16
19
|
}
|
|
17
20
|
export interface AppStoreHooks {
|
|
18
21
|
/**
|
|
@@ -60,6 +63,13 @@ interface AppStatusState {
|
|
|
60
63
|
saveScreenshot: (packageName: string, screenshot: string) => Promise<void>;
|
|
61
64
|
setHiddenStatus: (packageName: string, status: boolean) => void;
|
|
62
65
|
getHiddenStatus: (packageName: string) => boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Mark a miniapp persistent: it starts at launch and only stops from the
|
|
68
|
+
* app switcher's persistent pill (its card cannot be swiped away and the
|
|
69
|
+
* capsule close minimizes it). Turning it on starts the app; turning it
|
|
70
|
+
* off leaves it running. Persists the wearer's choice beside the hidden flag.
|
|
71
|
+
*/
|
|
72
|
+
setPersistent: (packageName: string, status: boolean) => Promise<void>;
|
|
63
73
|
/** Replace the whole apps array. Hosts use this when their extra source changes. */
|
|
64
74
|
setApps: (apps: ClientApp[]) => void;
|
|
65
75
|
}
|
|
@@ -85,7 +95,10 @@ export declare const useInstall: () => (url: string, opts?: {
|
|
|
85
95
|
versionOverride?: string;
|
|
86
96
|
}) => AsyncResult<void, Error>;
|
|
87
97
|
export declare const useUninstall: () => (packageName: string, version?: string) => AsyncResult<void, Error>;
|
|
98
|
+
/** Every running app; each one has a card in the app switcher tray. */
|
|
88
99
|
export declare const useActiveApps: () => ClientApp[];
|
|
100
|
+
/** Persistent apps whose background task is running, card or no card. */
|
|
101
|
+
export declare const useRunningPersistentApps: () => ClientApp[];
|
|
89
102
|
export declare const useActiveBackgroundApps: () => ClientApp[];
|
|
90
103
|
export declare const useBackgroundApps: () => {
|
|
91
104
|
active: ClientApp[];
|