@glassly/engine 0.1.0-dev.99 → 0.2.8-dev.445
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localStorageService.d.ts","sourceRoot":"","sources":["../../../src/services/asg/localStorageService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAA;AAGzC,OAAO,EAAwB,mBAAmB,EAAC,MAAM,yBAAyB,CAAA;AAGlF,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,mBAAmB,CAAA;CACnC;AAED,UAAU,SAAS;IACjB,cAAc,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE;QACX,IAAI,EAAE,MAAM,CAAA;QACZ,QAAQ,EAAE,MAAM,CAAA;QAChB,EAAE,EAAE,MAAM,CAAA;KACX,CAAA;CACF;AAED,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAyB;IAC9D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAmB;IAClD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAkB;IAChD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAmB;IAClD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAwC;IAC9E,OAAO,CAAC,QAAQ,CAAC,cAAc,
|
|
1
|
+
{"version":3,"file":"localStorageService.d.ts","sourceRoot":"","sources":["../../../src/services/asg/localStorageService.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,8 +14,8 @@ export class LocalStorageService {
|
|
|
14
14
|
CLIENT_ID_KEY = "asg_client_id";
|
|
15
15
|
SYNC_QUEUE_KEY = "asg_sync_queue";
|
|
16
16
|
QUARANTINED_FILES_KEY = "asg_quarantined_downloaded_files_v1";
|
|
17
|
-
ASG_PHOTOS_DIR = `${RNFS.DocumentDirectoryPath}/
|
|
18
|
-
ASG_THUMBNAILS_DIR = `${RNFS.DocumentDirectoryPath}/
|
|
17
|
+
ASG_PHOTOS_DIR = `${RNFS.DocumentDirectoryPath}/Photos`;
|
|
18
|
+
ASG_THUMBNAILS_DIR = `${RNFS.DocumentDirectoryPath}/Photos/thumbnails`;
|
|
19
19
|
constructor() {
|
|
20
20
|
this.initializeDirectories();
|
|
21
21
|
}
|
|
@@ -198,7 +198,7 @@ export class LocalStorageService {
|
|
|
198
198
|
const missingCaptureIds = [];
|
|
199
199
|
let didMigrate = false;
|
|
200
200
|
// Normalize every record before saving. This fixes the old read-absolute/write-one-relative
|
|
201
|
-
// bug and migrates stale iOS container UUID paths via their Documents/
|
|
201
|
+
// bug and migrates stale iOS container UUID paths via their Documents/Photos suffix.
|
|
202
202
|
for (const [name, file] of Object.entries(files)) {
|
|
203
203
|
const relativePath = this.toPortableRelativePath(file.filePath);
|
|
204
204
|
const relativeThumbnailPath = file.thumbnailPath
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localStorageService.js","sourceRoot":"","sources":["../../../src/services/asg/localStorageService.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Local Storage Service for ASG Gallery\n * Manages downloaded files and sync state\n */\n\nimport * as RNFS from \"@dr.pogodin/react-native-fs\"\n\nimport {PhotoInfo} from \"../../types/asg\"\nimport {BgTimer} from \"../../utils/timers\"\nimport {storage, StorageValueNotFoundError} from \"../../utils/storage\"\nimport {galleryTransferLedger, GalleryAssetReceipt} from \"./galleryTransferLedger\"\nimport {toPortableGalleryPath} from \"./galleryPathMigration\"\n\nexport interface DownloadedFile {\n name: string\n filePath: string // Path to file on filesystem\n size: number\n modified: number\n mime_type: string\n is_video: boolean\n thumbnailPath?: string // Path to thumbnail file\n downloaded_at: number\n glassesModel?: string // Model of glasses that captured this media\n duration?: number // Video duration in milliseconds\n capture_id?: string // Capture folder name (when synced via capture-aware pipeline)\n assetReceipt?: GalleryAssetReceipt\n}\n\ninterface SyncState {\n last_sync_time: number\n client_id: string\n total_downloaded: number\n total_size: number\n}\n\nexport interface SyncQueueData {\n files: PhotoInfo[]\n currentIndex: number\n startedAt: number\n hotspotInfo: {\n ssid: string\n password: string\n ip: string\n }\n}\n\nexport class LocalStorageService {\n private static instance: LocalStorageService\n private readonly DOWNLOADED_FILES_KEY = \"asg_downloaded_files\"\n private readonly SYNC_STATE_KEY = \"asg_sync_state\"\n private readonly CLIENT_ID_KEY = \"asg_client_id\"\n private readonly SYNC_QUEUE_KEY = \"asg_sync_queue\"\n private readonly QUARANTINED_FILES_KEY = \"asg_quarantined_downloaded_files_v1\"\n private readonly ASG_PHOTOS_DIR = `${RNFS.DocumentDirectoryPath}/GlasslyPhotos`\n private readonly ASG_THUMBNAILS_DIR = `${RNFS.DocumentDirectoryPath}/GlasslyPhotos/thumbnails`\n\n private constructor() {\n this.initializeDirectories()\n }\n\n static getInstance(): LocalStorageService {\n if (!LocalStorageService.instance) {\n LocalStorageService.instance = new LocalStorageService()\n }\n return LocalStorageService.instance\n }\n\n /**\n * Initialize ASG photo directories\n */\n private async initializeDirectories(): Promise<void> {\n try {\n // Create main photos directory if it doesn't exist\n const photoDirExists = await RNFS.exists(this.ASG_PHOTOS_DIR)\n if (!photoDirExists) {\n await RNFS.mkdir(this.ASG_PHOTOS_DIR)\n console.log(`[LocalStorage] Created Glassly photos directory: ${this.ASG_PHOTOS_DIR}`)\n }\n\n // Create thumbnails directory if it doesn't exist\n const thumbDirExists = await RNFS.exists(this.ASG_THUMBNAILS_DIR)\n if (!thumbDirExists) {\n await RNFS.mkdir(this.ASG_THUMBNAILS_DIR)\n console.log(`[LocalStorage] Created Glassly thumbnails directory: ${this.ASG_THUMBNAILS_DIR}`)\n }\n } catch (error) {\n console.error(\"[LocalStorage] Error initializing directories:\", error)\n }\n }\n\n /**\n * Get the full file path for a photo\n */\n getPhotoFilePath(filename: string): string {\n return `${this.ASG_PHOTOS_DIR}/${filename}`\n }\n\n /**\n * Get the full file path for a thumbnail\n */\n getThumbnailFilePath(filename: string): string {\n return `${this.ASG_THUMBNAILS_DIR}/${filename}_thumb.jpg`\n }\n\n /**\n * Initialize client ID if not exists\n */\n async initializeClientId(): Promise<string> {\n let res = storage.load<string>(this.CLIENT_ID_KEY)\n let clientId\n if (res.is_error()) {\n clientId = `mobile_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`\n storage.save(this.CLIENT_ID_KEY, clientId)\n } else {\n clientId = res.value\n }\n return clientId\n }\n\n /**\n * Get current sync state\n */\n async getSyncState(): Promise<SyncState> {\n const clientId = await this.initializeClientId()\n const res = storage.load<SyncState>(this.SYNC_STATE_KEY)\n\n if (res.is_error()) {\n // A missing key is the expected first-sync state (fresh install / never\n // synced) — start from scratch quietly. Real storage failures still log.\n if (!(res.error instanceof StorageValueNotFoundError)) {\n console.error(\"Error getting sync state:\", res.error)\n }\n return {\n last_sync_time: 0,\n client_id: clientId,\n total_downloaded: 0,\n total_size: 0,\n }\n }\n\n const syncState = res.value\n return {...syncState, client_id: clientId}\n }\n\n /**\n * Update sync state\n */\n async updateSyncState(updates: Partial<SyncState>): Promise<void> {\n try {\n const currentState = await this.getSyncState()\n const newState = {...currentState, ...updates}\n await storage.save(this.SYNC_STATE_KEY, newState)\n } catch (error) {\n console.error(\"Error updating sync state:\", error)\n throw error\n }\n }\n\n /**\n * Save downloaded file (only metadata, file should already be written to filesystem)\n */\n async saveDownloadedFile(file: DownloadedFile): Promise<void> {\n try {\n const rawFiles = this.loadRawDownloadedFiles()\n const files: Record<string, DownloadedFile> = {}\n const quarantined = this.loadQuarantinedFiles()\n const missingCaptureIds: string[] = []\n for (const [name, existing] of Object.entries(rawFiles)) {\n const existingPath = this.toPortableRelativePath(existing.filePath)\n const existingThumbnail = existing.thumbnailPath\n ? this.toPortableRelativePath(existing.thumbnailPath) || undefined\n : undefined\n if (!existingPath) {\n quarantined[name] = existing\n missingCaptureIds.push(name)\n continue\n }\n files[name] = {...existing, filePath: existingPath, thumbnailPath: existingThumbnail}\n }\n\n // 🔍 DIAGNOSTIC: Check if file already exists\n // const existingFile = files[file.name]\n // if (existingFile) {\n // console.log(`[LocalStorage] ⚠️ WARNING: File ${file.name} ALREADY EXISTS - will be REPLACED!`)\n // console.log(`[LocalStorage] 📁 Existing file:`)\n // console.log(`[LocalStorage] - Downloaded at: ${new Date(existingFile.downloaded_at).toISOString()}`)\n // console.log(`[LocalStorage] - Modified: ${new Date(existingFile.modified).toISOString()}`)\n // console.log(`[LocalStorage] - Size: ${existingFile.size} bytes`)\n // console.log(`[LocalStorage] - Path: ${existingFile.filePath}`)\n // console.log(`[LocalStorage] 📁 New file:`)\n // console.log(`[LocalStorage] - Downloaded at: ${new Date(file.downloaded_at).toISOString()}`)\n // console.log(`[LocalStorage] - Modified: ${new Date(file.modified).toISOString()}`)\n // console.log(`[LocalStorage] - Size: ${file.size} bytes`)\n // console.log(`[LocalStorage] - Path: ${file.filePath}`)\n // console.log(`[LocalStorage] 🔄 This will OVERWRITE the existing entry!`)\n // } else {\n // console.log(`[LocalStorage] ✅ File ${file.name} is NEW - saving metadata`)\n // }\n\n // Store relative paths to handle iOS app container changes between launches\n // Convert absolute paths to relative (remove DocumentDirectoryPath prefix)\n const relativePath = this.toPortableRelativePath(file.filePath)\n const relativeThumbnailPath = file.thumbnailPath\n ? this.toPortableRelativePath(file.thumbnailPath) || undefined\n : undefined\n\n if (!relativePath) {\n throw new Error(`Cannot persist non-portable gallery path: ${file.filePath}`)\n }\n\n files[file.name] = {\n ...file,\n // Store relative paths instead of absolute\n filePath: relativePath,\n thumbnailPath: relativeThumbnailPath,\n }\n const saveResult = storage.save(this.DOWNLOADED_FILES_KEY, files)\n if (saveResult.is_error()) throw saveResult.error\n const quarantineResult = storage.save(this.QUARANTINED_FILES_KEY, quarantined)\n if (quarantineResult.is_error()) throw quarantineResult.error\n for (const captureId of missingCaptureIds) {\n galleryTransferLedger.releaseMissingLocalCommit(captureId, true)\n }\n // console.log(`[LocalStorage] 💾 Saved metadata for ${file.name} with relative path: ${relativePath}`)\n } catch (error) {\n console.error(\"Error saving downloaded file metadata:\", error)\n throw error\n }\n }\n\n /**\n * Get all downloaded files\n */\n async getDownloadedFiles(): Promise<Record<string, DownloadedFile>> {\n const res = storage.load<Record<string, DownloadedFile>>(this.DOWNLOADED_FILES_KEY)\n if (res.is_error()) {\n // Not an error - just means no files have been downloaded yet (first use)\n // Only log as debug, not error, since this is expected on first launch\n console.log(\"[LocalStorage] No downloaded files found (first use or empty gallery)\")\n return {}\n }\n\n const files = res.value\n const reconstructedFiles: Record<string, DownloadedFile> = {}\n const normalizedFiles: Record<string, DownloadedFile> = {}\n const quarantined = this.loadQuarantinedFiles()\n const missingCaptureIds: string[] = []\n let didMigrate = false\n\n // Normalize every record before saving. This fixes the old read-absolute/write-one-relative\n // bug and migrates stale iOS container UUID paths via their Documents/GlasslyPhotos suffix.\n for (const [name, file] of Object.entries(files as Record<string, DownloadedFile>)) {\n const relativePath = this.toPortableRelativePath(file.filePath)\n const relativeThumbnailPath = file.thumbnailPath\n ? this.toPortableRelativePath(file.thumbnailPath) || undefined\n : undefined\n if (!relativePath) {\n quarantined[name] = {...file, downloaded_at: file.downloaded_at || Date.now()}\n missingCaptureIds.push(name)\n didMigrate = true\n continue\n }\n const absolutePath = `${RNFS.DocumentDirectoryPath}/${relativePath}`\n const absoluteThumbnailPath = relativeThumbnailPath\n ? `${RNFS.DocumentDirectoryPath}/${relativeThumbnailPath}`\n : undefined\n\n normalizedFiles[name] = {\n ...file,\n filePath: relativePath,\n thumbnailPath: relativeThumbnailPath,\n }\n\n reconstructedFiles[name] = {\n ...file,\n filePath: absolutePath,\n thumbnailPath: absoluteThumbnailPath,\n }\n if (file.filePath !== relativePath || file.thumbnailPath !== relativeThumbnailPath) didMigrate = true\n }\n\n if (didMigrate) {\n const saveResult = storage.save(this.DOWNLOADED_FILES_KEY, normalizedFiles)\n if (saveResult.is_error()) throw saveResult.error\n const quarantineResult = storage.save(this.QUARANTINED_FILES_KEY, quarantined)\n if (quarantineResult.is_error()) throw quarantineResult.error\n for (const captureId of missingCaptureIds) {\n galleryTransferLedger.releaseMissingLocalCommit(captureId, true)\n }\n }\n\n return reconstructedFiles\n }\n\n /**\n * Reconcile the remote manifest against the app-local gallery index before ledger filtering.\n * Android backup/restore and data-preserving reinstalls can restore MMKV ledger rows without\n * restoring app-private media. Only captures currently advertised by the glasses are released,\n * so acknowledged captures that remain in glasses trash are not resurrected unnecessarily.\n */\n async reconcileRemoteCaptures(\n captureIds: string[],\n downloadedFiles?: Record<string, DownloadedFile>,\n ): Promise<number> {\n const localFiles = downloadedFiles || (await this.getDownloadedFiles())\n let released = 0\n for (const captureId of captureIds) {\n const entry = galleryTransferLedger.get(captureId)\n if (!entry || !galleryTransferLedger.isLocallyCommitted(captureId)) continue\n const localFile = localFiles[captureId]\n const localFileExists = localFile?.filePath ? await RNFS.exists(localFile.filePath).catch(() => false) : false\n if (localFileExists) continue\n\n // The transfer ledger and gallery index are persisted independently. A crash can leave the\n // committed media in place after its index write was lost, so repair the index from the\n // ledger before deciding that the capture needs to be restored from the glasses.\n const committedPath = entry.finalPath?.replace(/^file:\\/\\//, \"\")\n const committedFileExists = committedPath ? await RNFS.exists(committedPath).catch(() => false) : false\n if (committedPath && committedFileExists) {\n try {\n const stat = await RNFS.stat(committedPath)\n const size = Number(stat.size)\n if (Number.isFinite(size) && size > 0) {\n const recovered = this.convertToDownloadedFile(\n {\n name: captureId,\n url: \"\",\n download: \"\",\n size,\n modified: entry.timestamp,\n mime_type: entry.captureType === \"video\" ? \"video/mp4\" : \"image/jpeg\",\n is_video: entry.captureType === \"video\",\n filePath: committedPath,\n },\n committedPath,\n entry.thumbnailPath,\n )\n recovered.capture_id = captureId\n recovered.assetReceipt = entry.assetReceipt\n await this.saveDownloadedFile(recovered)\n localFiles[captureId] = recovered\n continue\n }\n } catch (error) {\n console.warn(`[LocalStorage] Could not recover gallery index for ${captureId}:`, error)\n }\n }\n galleryTransferLedger.releaseMissingLocalCommit(captureId, true)\n released++\n }\n if (released > 0) {\n console.warn(`[LocalStorage] Released ${released} stale gallery ledger commit(s) missing local media`)\n }\n return released\n }\n\n /**\n * Get downloaded file by name\n */\n async getDownloadedFile(fileName: string): Promise<DownloadedFile | null> {\n try {\n const files = await this.getDownloadedFiles()\n return files[fileName] || null\n } catch (error) {\n console.error(\"Error getting downloaded file:\", error)\n return null\n }\n }\n\n /** Persist a durable camera-roll receipt without replacing the local-file generation. */\n async updateDownloadedFileAssetReceipt(fileName: string, assetReceipt: GalleryAssetReceipt): Promise<void> {\n const files = await this.getDownloadedFiles()\n const file = files[fileName]\n if (!file) throw new Error(`Downloaded file is missing: ${fileName}`)\n await this.saveDownloadedFile({...file, assetReceipt})\n }\n\n /**\n * Delete downloaded file (both metadata and actual files)\n */\n async deleteDownloadedFile(fileName: string): Promise<boolean> {\n try {\n const files = await this.getDownloadedFiles()\n if (files[fileName]) {\n const file = files[fileName]\n\n // Delete actual file from filesystem\n if (file.filePath && (await RNFS.exists(file.filePath))) {\n await RNFS.unlink(file.filePath)\n console.log(`[LocalStorage] Deleted file: ${file.filePath}`)\n }\n\n // Delete thumbnail if exists\n if (file.thumbnailPath && (await RNFS.exists(file.thumbnailPath))) {\n await RNFS.unlink(file.thumbnailPath)\n console.log(`[LocalStorage] Deleted thumbnail: ${file.thumbnailPath}`)\n }\n\n // Delete metadata - need to get raw data to maintain relative paths\n const res = storage.load<Record<string, DownloadedFile>>(this.DOWNLOADED_FILES_KEY)\n if (res.is_error()) {\n console.error(\"Error loading downloaded files:\", res.error)\n return false\n }\n const rawFiles = res.value\n delete rawFiles[fileName]\n await storage.save(this.DOWNLOADED_FILES_KEY, rawFiles)\n galleryTransferLedger.releaseMissingLocalCommit(fileName)\n return true\n }\n return false\n } catch (error) {\n console.error(\"Error deleting downloaded file:\", error)\n return false\n }\n }\n\n /** Preserve unresolved metadata for repair instead of silently deleting it from the gallery. */\n async quarantineDownloadedFile(fileName: string, reason: string): Promise<void> {\n const rawFiles = this.loadRawDownloadedFiles()\n const file = rawFiles[fileName]\n if (!file) return\n const quarantined = this.loadQuarantinedFiles()\n quarantined[fileName] = {...file, quarantineReason: reason} as DownloadedFile\n delete rawFiles[fileName]\n const quarantineResult = storage.save(this.QUARANTINED_FILES_KEY, quarantined)\n if (quarantineResult.is_error()) throw quarantineResult.error\n const filesResult = storage.save(this.DOWNLOADED_FILES_KEY, rawFiles)\n if (filesResult.is_error()) throw filesResult.error\n galleryTransferLedger.releaseMissingLocalCommit(fileName, true)\n }\n\n async getQuarantinedDownloadedFiles(): Promise<Record<string, DownloadedFile>> {\n return this.loadQuarantinedFiles()\n }\n\n /**\n * Convert PhotoInfo to DownloadedFile (assumes files are already saved to filesystem)\n */\n convertToDownloadedFile(\n photoInfo: PhotoInfo,\n filePath: string,\n thumbnailPath?: string,\n glassesModel?: string,\n ): DownloadedFile {\n return {\n name: photoInfo.name,\n filePath: filePath,\n size: photoInfo.size,\n modified: new Date(photoInfo.modified).getTime(),\n mime_type: photoInfo.mime_type || (photoInfo.is_video ? \"video/mp4\" : \"image/jpeg\"),\n is_video: photoInfo.is_video || false,\n thumbnailPath: thumbnailPath,\n downloaded_at: Date.now(),\n glassesModel: glassesModel || photoInfo.glassesModel,\n duration: photoInfo.duration,\n }\n }\n\n /**\n * Convert DownloadedFile to PhotoInfo\n */\n convertToPhotoInfo(downloadedFile: DownloadedFile): PhotoInfo {\n // Use file:// URLs for local files\n // On iOS, ensure we have proper file:// URL format with correct number of slashes\n const fileUrl = downloadedFile.filePath.startsWith(\"file://\")\n ? downloadedFile.filePath\n : downloadedFile.filePath.startsWith(\"/\")\n ? `file://${downloadedFile.filePath}` // Path already has leading slash\n : `file:///${downloadedFile.filePath}` // Path needs leading slash\n\n const thumbnailUrl = downloadedFile.thumbnailPath\n ? downloadedFile.thumbnailPath.startsWith(\"file://\")\n ? downloadedFile.thumbnailPath\n : downloadedFile.thumbnailPath.startsWith(\"/\")\n ? `file://${downloadedFile.thumbnailPath}` // Path already has leading slash\n : `file:///${downloadedFile.thumbnailPath}` // Path needs leading slash\n : undefined\n\n return {\n name: downloadedFile.name,\n url: fileUrl,\n download: fileUrl,\n size: downloadedFile.size,\n modified: new Date(downloadedFile.modified).toISOString(),\n mime_type: downloadedFile.mime_type,\n is_video: downloadedFile.is_video,\n thumbnail_data: undefined,\n downloaded_at: downloadedFile.downloaded_at,\n filePath: downloadedFile.filePath,\n glassesModel: downloadedFile.glassesModel,\n thumbnailPath: thumbnailUrl, // Use the file:// URL version for thumbnailPath\n duration: downloadedFile.duration,\n }\n }\n\n /**\n * Get storage statistics\n */\n async getStorageStats(): Promise<{\n total_files: number\n total_size: number\n last_sync: number\n }> {\n try {\n const files = await this.getDownloadedFiles()\n const syncState = await this.getSyncState()\n\n const totalSize = Object.values(files).reduce((sum, file) => sum + file.size, 0)\n\n return {\n total_files: Object.keys(files).length,\n total_size: totalSize,\n last_sync: syncState.last_sync_time,\n }\n } catch (error) {\n console.error(\"Error getting storage stats:\", error)\n return {\n total_files: 0,\n total_size: 0,\n last_sync: 0,\n }\n }\n }\n\n /**\n * Clear all downloaded files (both metadata and actual files)\n */\n async clearAllFiles(): Promise<void> {\n // Nuke the entire photos directory (includes thumbnails subdirectory)\n // This is more reliable than deleting individual files, which can miss orphaned thumbnails\n try {\n if (await RNFS.exists(this.ASG_PHOTOS_DIR)) {\n await RNFS.unlink(this.ASG_PHOTOS_DIR)\n console.log(\"[LocalStorage] Deleted entire photos directory\")\n }\n } catch (error) {\n console.error(\"[LocalStorage] Error deleting photos directory:\", error)\n }\n\n // Recreate empty directories\n await this.initializeDirectories()\n\n // Clear metadata\n const res = await storage.remove(this.DOWNLOADED_FILES_KEY)\n if (res.is_error()) {\n console.error(\"[LocalStorage] Error clearing downloaded files:\", res.error)\n throw res.error\n }\n storage.remove(this.QUARANTINED_FILES_KEY)\n galleryTransferLedger.releaseAllMissingLocalCommits()\n console.log(\"[LocalStorage] Cleared all downloaded files and thumbnails\")\n }\n\n // ============================================\n // Sync Queue Persistence (for background sync resume)\n // ============================================\n\n /**\n * Save sync queue for potential resume after app restart\n */\n async saveSyncQueue(queue: SyncQueueData): Promise<void> {\n try {\n await storage.save(this.SYNC_QUEUE_KEY, queue)\n console.log(`[LocalStorage] Saved sync queue: ${queue.files.length} files, index ${queue.currentIndex}`)\n } catch (error) {\n console.error(\"[LocalStorage] Error saving sync queue:\", error)\n throw error\n }\n }\n\n /**\n * Get saved sync queue (for resume on app restart)\n */\n async getSyncQueue(): Promise<SyncQueueData | null> {\n try {\n const res = storage.load<SyncQueueData>(this.SYNC_QUEUE_KEY)\n if (res.is_error()) {\n // No queue saved - this is normal\n return null\n }\n const queue = res.value\n console.log(`[LocalStorage] Loaded sync queue: ${queue.files.length} files, index ${queue.currentIndex}`)\n return queue\n } catch (error) {\n console.error(\"[LocalStorage] Error loading sync queue:\", error)\n return null\n }\n }\n\n /**\n * Update the current index of the sync queue (called after each file completes)\n */\n async updateSyncQueueIndex(newIndex: number): Promise<void> {\n // S6: Let errors propagate — caller uses .catch() for non-critical updates\n const queue = await this.getSyncQueue()\n if (queue) {\n queue.currentIndex = newIndex\n await this.saveSyncQueue(queue)\n }\n }\n\n /**\n * Clear sync queue (called on sync complete or cancel)\n */\n async clearSyncQueue(): Promise<void> {\n // S6: Retry up to 3 times to ensure queue is cleared\n for (let attempt = 1; attempt <= 3; attempt++) {\n try {\n const res = await storage.remove(this.SYNC_QUEUE_KEY)\n if (res.is_error()) {\n console.error(`[LocalStorage] Error clearing sync queue (attempt ${attempt}/3):`, res.error)\n if (attempt < 3) continue\n return\n }\n console.log(\"[LocalStorage] Cleared sync queue\")\n return\n } catch (error) {\n console.error(`[LocalStorage] Error clearing sync queue (attempt ${attempt}/3):`, error)\n if (attempt < 3) {\n await new Promise<void>((resolve) => BgTimer.setTimeout(() => resolve(), 100))\n }\n }\n }\n }\n\n /**\n * Check if there's a resumable sync queue\n */\n async hasResumableSyncQueue(): Promise<boolean> {\n const queue = await this.getSyncQueue()\n if (!queue) return false\n // Has resumable queue if there are still files to process\n return queue.currentIndex < queue.files.length\n }\n\n private loadRawDownloadedFiles(): Record<string, DownloadedFile> {\n const result = storage.load<Record<string, DownloadedFile>>(this.DOWNLOADED_FILES_KEY)\n return result.is_error() ? {} : result.value\n }\n\n private loadQuarantinedFiles(): Record<string, DownloadedFile> {\n const result = storage.load<Record<string, DownloadedFile>>(this.QUARANTINED_FILES_KEY)\n return result.is_error() ? {} : result.value\n }\n\n private toPortableRelativePath(path: string): string | null {\n return toPortableGalleryPath(path, RNFS.DocumentDirectoryPath)\n }\n}\n\nexport const localStorageService = LocalStorageService.getInstance()\n"]}
|
|
1
|
+
{"version":3,"file":"localStorageService.js","sourceRoot":"","sources":["../../../src/services/asg/localStorageService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,IAAI,MAAM,6BAA6B,CAAA;AAGnD,OAAO,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAA;AAC1C,OAAO,EAAC,OAAO,EAAE,yBAAyB,EAAC,MAAM,qBAAqB,CAAA;AACtE,OAAO,EAAC,qBAAqB,EAAsB,MAAM,yBAAyB,CAAA;AAClF,OAAO,EAAC,qBAAqB,EAAC,MAAM,wBAAwB,CAAA;AAmC5D,MAAM,OAAO,mBAAmB;IACtB,MAAM,CAAC,QAAQ,CAAqB;IAC3B,oBAAoB,GAAG,sBAAsB,CAAA;IAC7C,cAAc,GAAG,gBAAgB,CAAA;IACjC,aAAa,GAAG,eAAe,CAAA;IAC/B,cAAc,GAAG,gBAAgB,CAAA;IACjC,qBAAqB,GAAG,qCAAqC,CAAA;IAC7D,cAAc,GAAG,GAAG,IAAI,CAAC,qBAAqB,SAAS,CAAA;IACvD,kBAAkB,GAAG,GAAG,IAAI,CAAC,qBAAqB,oBAAoB,CAAA;IAEvF;QACE,IAAI,CAAC,qBAAqB,EAAE,CAAA;IAC9B,CAAC;IAED,MAAM,CAAC,WAAW;QAChB,IAAI,CAAC,mBAAmB,CAAC,QAAQ,EAAE,CAAC;YAClC,mBAAmB,CAAC,QAAQ,GAAG,IAAI,mBAAmB,EAAE,CAAA;QAC1D,CAAC;QACD,OAAO,mBAAmB,CAAC,QAAQ,CAAA;IACrC,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,qBAAqB;QACjC,IAAI,CAAC;YACH,mDAAmD;YACnD,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;YAC7D,IAAI,CAAC,cAAc,EAAE,CAAC;gBACpB,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;gBACrC,OAAO,CAAC,GAAG,CAAC,oDAAoD,IAAI,CAAC,cAAc,EAAE,CAAC,CAAA;YACxF,CAAC;YAED,kDAAkD;YAClD,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;YACjE,IAAI,CAAC,cAAc,EAAE,CAAC;gBACpB,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;gBACzC,OAAO,CAAC,GAAG,CAAC,wDAAwD,IAAI,CAAC,kBAAkB,EAAE,CAAC,CAAA;YAChG,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,gDAAgD,EAAE,KAAK,CAAC,CAAA;QACxE,CAAC;IACH,CAAC;IAED;;OAEG;IACH,gBAAgB,CAAC,QAAgB;QAC/B,OAAO,GAAG,IAAI,CAAC,cAAc,IAAI,QAAQ,EAAE,CAAA;IAC7C,CAAC;IAED;;OAEG;IACH,oBAAoB,CAAC,QAAgB;QACnC,OAAO,GAAG,IAAI,CAAC,kBAAkB,IAAI,QAAQ,YAAY,CAAA;IAC3D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,kBAAkB;QACtB,IAAI,GAAG,GAAG,OAAO,CAAC,IAAI,CAAS,IAAI,CAAC,aAAa,CAAC,CAAA;QAClD,IAAI,QAAQ,CAAA;QACZ,IAAI,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC;YACnB,QAAQ,GAAG,UAAU,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAA;YAC5E,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAA;QAC5C,CAAC;aAAM,CAAC;YACN,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAA;QACtB,CAAC;QACD,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY;QAChB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAA;QAChD,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAY,IAAI,CAAC,cAAc,CAAC,CAAA;QAExD,IAAI,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC;YACnB,wEAAwE;YACxE,yEAAyE;YACzE,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,YAAY,yBAAyB,CAAC,EAAE,CAAC;gBACtD,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,GAAG,CAAC,KAAK,CAAC,CAAA;YACvD,CAAC;YACD,OAAO;gBACL,cAAc,EAAE,CAAC;gBACjB,SAAS,EAAE,QAAQ;gBACnB,gBAAgB,EAAE,CAAC;gBACnB,UAAU,EAAE,CAAC;aACd,CAAA;QACH,CAAC;QAED,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAA;QAC3B,OAAO,EAAC,GAAG,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAC,CAAA;IAC5C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CAAC,OAA2B;QAC/C,IAAI,CAAC;YACH,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAA;YAC9C,MAAM,QAAQ,GAAG,EAAC,GAAG,YAAY,EAAE,GAAG,OAAO,EAAC,CAAA;YAC9C,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAA;QACnD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAA;YAClD,MAAM,KAAK,CAAA;QACb,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,kBAAkB,CAAC,IAAoB;QAC3C,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,IAAI,CAAC,sBAAsB,EAAE,CAAA;YAC9C,MAAM,KAAK,GAAmC,EAAE,CAAA;YAChD,MAAM,WAAW,GAAG,IAAI,CAAC,oBAAoB,EAAE,CAAA;YAC/C,MAAM,iBAAiB,GAAa,EAAE,CAAA;YACtC,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACxD,MAAM,YAAY,GAAG,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;gBACnE,MAAM,iBAAiB,GAAG,QAAQ,CAAC,aAAa;oBAC9C,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,SAAS;oBAClE,CAAC,CAAC,SAAS,CAAA;gBACb,IAAI,CAAC,YAAY,EAAE,CAAC;oBAClB,WAAW,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAA;oBAC5B,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;oBAC5B,SAAQ;gBACV,CAAC;gBACD,KAAK,CAAC,IAAI,CAAC,GAAG,EAAC,GAAG,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAC,CAAA;YACvF,CAAC;YAED,8CAA8C;YAC9C,wCAAwC;YACxC,sBAAsB;YACtB,mGAAmG;YACnG,sDAAsD;YACtD,8GAA8G;YAC9G,oGAAoG;YACpG,0EAA0E;YAC1E,wEAAwE;YACxE,iDAAiD;YACjD,sGAAsG;YACtG,4FAA4F;YAC5F,kEAAkE;YAClE,gEAAgE;YAChE,+EAA+E;YAC/E,WAAW;YACX,+EAA+E;YAC/E,IAAI;YAEJ,4EAA4E;YAC5E,2EAA2E;YAC3E,MAAM,YAAY,GAAG,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAC/D,MAAM,qBAAqB,GAAG,IAAI,CAAC,aAAa;gBAC9C,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,SAAS;gBAC9D,CAAC,CAAC,SAAS,CAAA;YAEb,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,MAAM,IAAI,KAAK,CAAC,6CAA6C,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAA;YAC/E,CAAC;YAED,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;gBACjB,GAAG,IAAI;gBACP,2CAA2C;gBAC3C,QAAQ,EAAE,YAAY;gBACtB,aAAa,EAAE,qBAAqB;aACrC,CAAA;YACD,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAA;YACjE,IAAI,UAAU,CAAC,QAAQ,EAAE;gBAAE,MAAM,UAAU,CAAC,KAAK,CAAA;YACjD,MAAM,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,qBAAqB,EAAE,WAAW,CAAC,CAAA;YAC9E,IAAI,gBAAgB,CAAC,QAAQ,EAAE;gBAAE,MAAM,gBAAgB,CAAC,KAAK,CAAA;YAC7D,KAAK,MAAM,SAAS,IAAI,iBAAiB,EAAE,CAAC;gBAC1C,qBAAqB,CAAC,yBAAyB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;YAClE,CAAC;YACD,uGAAuG;QACzG,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,wCAAwC,EAAE,KAAK,CAAC,CAAA;YAC9D,MAAM,KAAK,CAAA;QACb,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,kBAAkB;QACtB,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAiC,IAAI,CAAC,oBAAoB,CAAC,CAAA;QACnF,IAAI,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC;YACnB,0EAA0E;YAC1E,uEAAuE;YACvE,OAAO,CAAC,GAAG,CAAC,uEAAuE,CAAC,CAAA;YACpF,OAAO,EAAE,CAAA;QACX,CAAC;QAED,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAA;QACvB,MAAM,kBAAkB,GAAmC,EAAE,CAAA;QAC7D,MAAM,eAAe,GAAmC,EAAE,CAAA;QAC1D,MAAM,WAAW,GAAG,IAAI,CAAC,oBAAoB,EAAE,CAAA;QAC/C,MAAM,iBAAiB,GAAa,EAAE,CAAA;QACtC,IAAI,UAAU,GAAG,KAAK,CAAA;QAEtB,4FAA4F;QAC5F,qFAAqF;QACrF,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAuC,CAAC,EAAE,CAAC;YACnF,MAAM,YAAY,GAAG,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAC/D,MAAM,qBAAqB,GAAG,IAAI,CAAC,aAAa;gBAC9C,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,SAAS;gBAC9D,CAAC,CAAC,SAAS,CAAA;YACb,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,WAAW,CAAC,IAAI,CAAC,GAAG,EAAC,GAAG,IAAI,EAAE,aAAa,EAAE,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,GAAG,EAAE,EAAC,CAAA;gBAC9E,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;gBAC5B,UAAU,GAAG,IAAI,CAAA;gBACjB,SAAQ;YACV,CAAC;YACD,MAAM,YAAY,GAAG,GAAG,IAAI,CAAC,qBAAqB,IAAI,YAAY,EAAE,CAAA;YACpE,MAAM,qBAAqB,GAAG,qBAAqB;gBACjD,CAAC,CAAC,GAAG,IAAI,CAAC,qBAAqB,IAAI,qBAAqB,EAAE;gBAC1D,CAAC,CAAC,SAAS,CAAA;YAEb,eAAe,CAAC,IAAI,CAAC,GAAG;gBACtB,GAAG,IAAI;gBACP,QAAQ,EAAE,YAAY;gBACtB,aAAa,EAAE,qBAAqB;aACrC,CAAA;YAED,kBAAkB,CAAC,IAAI,CAAC,GAAG;gBACzB,GAAG,IAAI;gBACP,QAAQ,EAAE,YAAY;gBACtB,aAAa,EAAE,qBAAqB;aACrC,CAAA;YACD,IAAI,IAAI,CAAC,QAAQ,KAAK,YAAY,IAAI,IAAI,CAAC,aAAa,KAAK,qBAAqB;gBAAE,UAAU,GAAG,IAAI,CAAA;QACvG,CAAC;QAED,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,eAAe,CAAC,CAAA;YAC3E,IAAI,UAAU,CAAC,QAAQ,EAAE;gBAAE,MAAM,UAAU,CAAC,KAAK,CAAA;YACjD,MAAM,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,qBAAqB,EAAE,WAAW,CAAC,CAAA;YAC9E,IAAI,gBAAgB,CAAC,QAAQ,EAAE;gBAAE,MAAM,gBAAgB,CAAC,KAAK,CAAA;YAC7D,KAAK,MAAM,SAAS,IAAI,iBAAiB,EAAE,CAAC;gBAC1C,qBAAqB,CAAC,yBAAyB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;YAClE,CAAC;QACH,CAAC;QAED,OAAO,kBAAkB,CAAA;IAC3B,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,uBAAuB,CAC3B,UAAoB,EACpB,eAAgD;QAEhD,MAAM,UAAU,GAAG,eAAe,IAAI,CAAC,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC,CAAA;QACvE,IAAI,QAAQ,GAAG,CAAC,CAAA;QAChB,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,MAAM,KAAK,GAAG,qBAAqB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;YAClD,IAAI,CAAC,KAAK,IAAI,CAAC,qBAAqB,CAAC,kBAAkB,CAAC,SAAS,CAAC;gBAAE,SAAQ;YAC5E,MAAM,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC,CAAA;YACvC,MAAM,eAAe,GAAG,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;YAC9G,IAAI,eAAe;gBAAE,SAAQ;YAE7B,2FAA2F;YAC3F,wFAAwF;YACxF,iFAAiF;YACjF,MAAM,aAAa,GAAG,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAA;YAChE,MAAM,mBAAmB,GAAG,aAAa,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;YACvG,IAAI,aAAa,IAAI,mBAAmB,EAAE,CAAC;gBACzC,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;oBAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;oBAC9B,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;wBACtC,MAAM,SAAS,GAAG,IAAI,CAAC,uBAAuB,CAC5C;4BACE,IAAI,EAAE,SAAS;4BACf,GAAG,EAAE,EAAE;4BACP,QAAQ,EAAE,EAAE;4BACZ,IAAI;4BACJ,QAAQ,EAAE,KAAK,CAAC,SAAS;4BACzB,SAAS,EAAE,KAAK,CAAC,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY;4BACrE,QAAQ,EAAE,KAAK,CAAC,WAAW,KAAK,OAAO;4BACvC,QAAQ,EAAE,aAAa;yBACxB,EACD,aAAa,EACb,KAAK,CAAC,aAAa,CACpB,CAAA;wBACD,SAAS,CAAC,UAAU,GAAG,SAAS,CAAA;wBAChC,SAAS,CAAC,YAAY,GAAG,KAAK,CAAC,YAAY,CAAA;wBAC3C,MAAM,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAA;wBACxC,UAAU,CAAC,SAAS,CAAC,GAAG,SAAS,CAAA;wBACjC,SAAQ;oBACV,CAAC;gBACH,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,IAAI,CAAC,sDAAsD,SAAS,GAAG,EAAE,KAAK,CAAC,CAAA;gBACzF,CAAC;YACH,CAAC;YACD,qBAAqB,CAAC,yBAAyB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;YAChE,QAAQ,EAAE,CAAA;QACZ,CAAC;QACD,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,CAAC,2BAA2B,QAAQ,qDAAqD,CAAC,CAAA;QACxG,CAAC;QACD,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,iBAAiB,CAAC,QAAgB;QACtC,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAA;YAC7C,OAAO,KAAK,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAA;QAChC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,KAAK,CAAC,CAAA;YACtD,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IAED,yFAAyF;IACzF,KAAK,CAAC,gCAAgC,CAAC,QAAgB,EAAE,YAAiC;QACxF,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAA;QAC7C,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAA;QAC5B,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,QAAQ,EAAE,CAAC,CAAA;QACrE,MAAM,IAAI,CAAC,kBAAkB,CAAC,EAAC,GAAG,IAAI,EAAE,YAAY,EAAC,CAAC,CAAA;IACxD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,oBAAoB,CAAC,QAAgB;QACzC,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAA;YAC7C,IAAI,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACpB,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAA;gBAE5B,qCAAqC;gBACrC,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;oBACxD,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;oBAChC,OAAO,CAAC,GAAG,CAAC,gCAAgC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAA;gBAC9D,CAAC;gBAED,6BAA6B;gBAC7B,IAAI,IAAI,CAAC,aAAa,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC;oBAClE,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;oBACrC,OAAO,CAAC,GAAG,CAAC,qCAAqC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAA;gBACxE,CAAC;gBAED,oEAAoE;gBACpE,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAiC,IAAI,CAAC,oBAAoB,CAAC,CAAA;gBACnF,IAAI,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC;oBACnB,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAA;oBAC3D,OAAO,KAAK,CAAA;gBACd,CAAC;gBACD,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAA;gBAC1B,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAA;gBACzB,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAC,CAAA;gBACvD,qBAAqB,CAAC,yBAAyB,CAAC,QAAQ,CAAC,CAAA;gBACzD,OAAO,IAAI,CAAA;YACb,CAAC;YACD,OAAO,KAAK,CAAA;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,KAAK,CAAC,CAAA;YACvD,OAAO,KAAK,CAAA;QACd,CAAC;IACH,CAAC;IAED,gGAAgG;IAChG,KAAK,CAAC,wBAAwB,CAAC,QAAgB,EAAE,MAAc;QAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,sBAAsB,EAAE,CAAA;QAC9C,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAA;QAC/B,IAAI,CAAC,IAAI;YAAE,OAAM;QACjB,MAAM,WAAW,GAAG,IAAI,CAAC,oBAAoB,EAAE,CAAA;QAC/C,WAAW,CAAC,QAAQ,CAAC,GAAG,EAAC,GAAG,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAmB,CAAA;QAC7E,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAA;QACzB,MAAM,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,qBAAqB,EAAE,WAAW,CAAC,CAAA;QAC9E,IAAI,gBAAgB,CAAC,QAAQ,EAAE;YAAE,MAAM,gBAAgB,CAAC,KAAK,CAAA;QAC7D,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAC,CAAA;QACrE,IAAI,WAAW,CAAC,QAAQ,EAAE;YAAE,MAAM,WAAW,CAAC,KAAK,CAAA;QACnD,qBAAqB,CAAC,yBAAyB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;IACjE,CAAC;IAED,KAAK,CAAC,6BAA6B;QACjC,OAAO,IAAI,CAAC,oBAAoB,EAAE,CAAA;IACpC,CAAC;IAED;;OAEG;IACH,uBAAuB,CACrB,SAAoB,EACpB,QAAgB,EAChB,aAAsB,EACtB,YAAqB;QAErB,OAAO;YACL,IAAI,EAAE,SAAS,CAAC,IAAI;YACpB,QAAQ,EAAE,QAAQ;YAClB,IAAI,EAAE,SAAS,CAAC,IAAI;YACpB,QAAQ,EAAE,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE;YAChD,SAAS,EAAE,SAAS,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC;YACnF,QAAQ,EAAE,SAAS,CAAC,QAAQ,IAAI,KAAK;YACrC,aAAa,EAAE,aAAa;YAC5B,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE;YACzB,YAAY,EAAE,YAAY,IAAI,SAAS,CAAC,YAAY;YACpD,QAAQ,EAAE,SAAS,CAAC,QAAQ;SAC7B,CAAA;IACH,CAAC;IAED;;OAEG;IACH,kBAAkB,CAAC,cAA8B;QAC/C,mCAAmC;QACnC,kFAAkF;QAClF,MAAM,OAAO,GAAG,cAAc,CAAC,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC;YAC3D,CAAC,CAAC,cAAc,CAAC,QAAQ;YACzB,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC;gBACvC,CAAC,CAAC,UAAU,cAAc,CAAC,QAAQ,EAAE,CAAC,iCAAiC;gBACvE,CAAC,CAAC,WAAW,cAAc,CAAC,QAAQ,EAAE,CAAA,CAAC,2BAA2B;QAEtE,MAAM,YAAY,GAAG,cAAc,CAAC,aAAa;YAC/C,CAAC,CAAC,cAAc,CAAC,aAAa,CAAC,UAAU,CAAC,SAAS,CAAC;gBAClD,CAAC,CAAC,cAAc,CAAC,aAAa;gBAC9B,CAAC,CAAC,cAAc,CAAC,aAAa,CAAC,UAAU,CAAC,GAAG,CAAC;oBAC5C,CAAC,CAAC,UAAU,cAAc,CAAC,aAAa,EAAE,CAAC,iCAAiC;oBAC5E,CAAC,CAAC,WAAW,cAAc,CAAC,aAAa,EAAE,CAAC,2BAA2B;YAC3E,CAAC,CAAC,SAAS,CAAA;QAEb,OAAO;YACL,IAAI,EAAE,cAAc,CAAC,IAAI;YACzB,GAAG,EAAE,OAAO;YACZ,QAAQ,EAAE,OAAO;YACjB,IAAI,EAAE,cAAc,CAAC,IAAI;YACzB,QAAQ,EAAE,IAAI,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE;YACzD,SAAS,EAAE,cAAc,CAAC,SAAS;YACnC,QAAQ,EAAE,cAAc,CAAC,QAAQ;YACjC,cAAc,EAAE,SAAS;YACzB,aAAa,EAAE,cAAc,CAAC,aAAa;YAC3C,QAAQ,EAAE,cAAc,CAAC,QAAQ;YACjC,YAAY,EAAE,cAAc,CAAC,YAAY;YACzC,aAAa,EAAE,YAAY,EAAE,gDAAgD;YAC7E,QAAQ,EAAE,cAAc,CAAC,QAAQ;SAClC,CAAA;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe;QAKnB,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAA;YAC7C,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAA;YAE3C,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;YAEhF,OAAO;gBACL,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM;gBACtC,UAAU,EAAE,SAAS;gBACrB,SAAS,EAAE,SAAS,CAAC,cAAc;aACpC,CAAA;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAA;YACpD,OAAO;gBACL,WAAW,EAAE,CAAC;gBACd,UAAU,EAAE,CAAC;gBACb,SAAS,EAAE,CAAC;aACb,CAAA;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa;QACjB,sEAAsE;QACtE,2FAA2F;QAC3F,IAAI,CAAC;YACH,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;gBAC3C,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;gBACtC,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAA;YAC/D,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,iDAAiD,EAAE,KAAK,CAAC,CAAA;QACzE,CAAC;QAED,6BAA6B;QAC7B,MAAM,IAAI,CAAC,qBAAqB,EAAE,CAAA;QAElC,iBAAiB;QACjB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAA;QAC3D,IAAI,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC;YACnB,OAAO,CAAC,KAAK,CAAC,iDAAiD,EAAE,GAAG,CAAC,KAAK,CAAC,CAAA;YAC3E,MAAM,GAAG,CAAC,KAAK,CAAA;QACjB,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAA;QAC1C,qBAAqB,CAAC,6BAA6B,EAAE,CAAA;QACrD,OAAO,CAAC,GAAG,CAAC,4DAA4D,CAAC,CAAA;IAC3E,CAAC;IAED,+CAA+C;IAC/C,sDAAsD;IACtD,+CAA+C;IAE/C;;OAEG;IACH,KAAK,CAAC,aAAa,CAAC,KAAoB;QACtC,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,KAAK,CAAC,CAAA;YAC9C,OAAO,CAAC,GAAG,CAAC,oCAAoC,KAAK,CAAC,KAAK,CAAC,MAAM,iBAAiB,KAAK,CAAC,YAAY,EAAE,CAAC,CAAA;QAC1G,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,yCAAyC,EAAE,KAAK,CAAC,CAAA;YAC/D,MAAM,KAAK,CAAA;QACb,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAgB,IAAI,CAAC,cAAc,CAAC,CAAA;YAC5D,IAAI,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC;gBACnB,kCAAkC;gBAClC,OAAO,IAAI,CAAA;YACb,CAAC;YACD,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAA;YACvB,OAAO,CAAC,GAAG,CAAC,qCAAqC,KAAK,CAAC,KAAK,CAAC,MAAM,iBAAiB,KAAK,CAAC,YAAY,EAAE,CAAC,CAAA;YACzG,OAAO,KAAK,CAAA;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,0CAA0C,EAAE,KAAK,CAAC,CAAA;YAChE,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,oBAAoB,CAAC,QAAgB;QACzC,2EAA2E;QAC3E,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAA;QACvC,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,CAAC,YAAY,GAAG,QAAQ,CAAA;YAC7B,MAAM,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;QACjC,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc;QAClB,qDAAqD;QACrD,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;YAC9C,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;gBACrD,IAAI,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC;oBACnB,OAAO,CAAC,KAAK,CAAC,qDAAqD,OAAO,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,CAAA;oBAC5F,IAAI,OAAO,GAAG,CAAC;wBAAE,SAAQ;oBACzB,OAAM;gBACR,CAAC;gBACD,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAA;gBAChD,OAAM;YACR,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,qDAAqD,OAAO,MAAM,EAAE,KAAK,CAAC,CAAA;gBACxF,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;oBAChB,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC,CAAA;gBAChF,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,qBAAqB;QACzB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAA;QACvC,IAAI,CAAC,KAAK;YAAE,OAAO,KAAK,CAAA;QACxB,0DAA0D;QAC1D,OAAO,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAA;IAChD,CAAC;IAEO,sBAAsB;QAC5B,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAiC,IAAI,CAAC,oBAAoB,CAAC,CAAA;QACtF,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAA;IAC9C,CAAC;IAEO,oBAAoB;QAC1B,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAiC,IAAI,CAAC,qBAAqB,CAAC,CAAA;QACvF,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAA;IAC9C,CAAC;IAEO,sBAAsB,CAAC,IAAY;QACzC,OAAO,qBAAqB,CAAC,IAAI,EAAE,IAAI,CAAC,qBAAqB,CAAC,CAAA;IAChE,CAAC;CACF;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG,mBAAmB,CAAC,WAAW,EAAE,CAAA","sourcesContent":["/**\n * Local Storage Service for ASG Gallery\n * Manages downloaded files and sync state\n */\n\nimport * as RNFS from \"@dr.pogodin/react-native-fs\"\n\nimport {PhotoInfo} from \"../../types/asg\"\nimport {BgTimer} from \"../../utils/timers\"\nimport {storage, StorageValueNotFoundError} from \"../../utils/storage\"\nimport {galleryTransferLedger, GalleryAssetReceipt} from \"./galleryTransferLedger\"\nimport {toPortableGalleryPath} from \"./galleryPathMigration\"\n\nexport interface DownloadedFile {\n name: string\n filePath: string // Path to file on filesystem\n size: number\n modified: number\n mime_type: string\n is_video: boolean\n thumbnailPath?: string // Path to thumbnail file\n downloaded_at: number\n glassesModel?: string // Model of glasses that captured this media\n duration?: number // Video duration in milliseconds\n capture_id?: string // Capture folder name (when synced via capture-aware pipeline)\n assetReceipt?: GalleryAssetReceipt\n}\n\ninterface SyncState {\n last_sync_time: number\n client_id: string\n total_downloaded: number\n total_size: number\n}\n\nexport interface SyncQueueData {\n files: PhotoInfo[]\n currentIndex: number\n startedAt: number\n hotspotInfo: {\n ssid: string\n password: string\n ip: string\n }\n}\n\nexport class LocalStorageService {\n private static instance: LocalStorageService\n private readonly DOWNLOADED_FILES_KEY = \"asg_downloaded_files\"\n private readonly SYNC_STATE_KEY = \"asg_sync_state\"\n private readonly CLIENT_ID_KEY = \"asg_client_id\"\n private readonly SYNC_QUEUE_KEY = \"asg_sync_queue\"\n private readonly QUARANTINED_FILES_KEY = \"asg_quarantined_downloaded_files_v1\"\n private readonly ASG_PHOTOS_DIR = `${RNFS.DocumentDirectoryPath}/Photos`\n private readonly ASG_THUMBNAILS_DIR = `${RNFS.DocumentDirectoryPath}/Photos/thumbnails`\n\n private constructor() {\n this.initializeDirectories()\n }\n\n static getInstance(): LocalStorageService {\n if (!LocalStorageService.instance) {\n LocalStorageService.instance = new LocalStorageService()\n }\n return LocalStorageService.instance\n }\n\n /**\n * Initialize ASG photo directories\n */\n private async initializeDirectories(): Promise<void> {\n try {\n // Create main photos directory if it doesn't exist\n const photoDirExists = await RNFS.exists(this.ASG_PHOTOS_DIR)\n if (!photoDirExists) {\n await RNFS.mkdir(this.ASG_PHOTOS_DIR)\n console.log(`[LocalStorage] Created Glassly photos directory: ${this.ASG_PHOTOS_DIR}`)\n }\n\n // Create thumbnails directory if it doesn't exist\n const thumbDirExists = await RNFS.exists(this.ASG_THUMBNAILS_DIR)\n if (!thumbDirExists) {\n await RNFS.mkdir(this.ASG_THUMBNAILS_DIR)\n console.log(`[LocalStorage] Created Glassly thumbnails directory: ${this.ASG_THUMBNAILS_DIR}`)\n }\n } catch (error) {\n console.error(\"[LocalStorage] Error initializing directories:\", error)\n }\n }\n\n /**\n * Get the full file path for a photo\n */\n getPhotoFilePath(filename: string): string {\n return `${this.ASG_PHOTOS_DIR}/${filename}`\n }\n\n /**\n * Get the full file path for a thumbnail\n */\n getThumbnailFilePath(filename: string): string {\n return `${this.ASG_THUMBNAILS_DIR}/${filename}_thumb.jpg`\n }\n\n /**\n * Initialize client ID if not exists\n */\n async initializeClientId(): Promise<string> {\n let res = storage.load<string>(this.CLIENT_ID_KEY)\n let clientId\n if (res.is_error()) {\n clientId = `mobile_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`\n storage.save(this.CLIENT_ID_KEY, clientId)\n } else {\n clientId = res.value\n }\n return clientId\n }\n\n /**\n * Get current sync state\n */\n async getSyncState(): Promise<SyncState> {\n const clientId = await this.initializeClientId()\n const res = storage.load<SyncState>(this.SYNC_STATE_KEY)\n\n if (res.is_error()) {\n // A missing key is the expected first-sync state (fresh install / never\n // synced) — start from scratch quietly. Real storage failures still log.\n if (!(res.error instanceof StorageValueNotFoundError)) {\n console.error(\"Error getting sync state:\", res.error)\n }\n return {\n last_sync_time: 0,\n client_id: clientId,\n total_downloaded: 0,\n total_size: 0,\n }\n }\n\n const syncState = res.value\n return {...syncState, client_id: clientId}\n }\n\n /**\n * Update sync state\n */\n async updateSyncState(updates: Partial<SyncState>): Promise<void> {\n try {\n const currentState = await this.getSyncState()\n const newState = {...currentState, ...updates}\n await storage.save(this.SYNC_STATE_KEY, newState)\n } catch (error) {\n console.error(\"Error updating sync state:\", error)\n throw error\n }\n }\n\n /**\n * Save downloaded file (only metadata, file should already be written to filesystem)\n */\n async saveDownloadedFile(file: DownloadedFile): Promise<void> {\n try {\n const rawFiles = this.loadRawDownloadedFiles()\n const files: Record<string, DownloadedFile> = {}\n const quarantined = this.loadQuarantinedFiles()\n const missingCaptureIds: string[] = []\n for (const [name, existing] of Object.entries(rawFiles)) {\n const existingPath = this.toPortableRelativePath(existing.filePath)\n const existingThumbnail = existing.thumbnailPath\n ? this.toPortableRelativePath(existing.thumbnailPath) || undefined\n : undefined\n if (!existingPath) {\n quarantined[name] = existing\n missingCaptureIds.push(name)\n continue\n }\n files[name] = {...existing, filePath: existingPath, thumbnailPath: existingThumbnail}\n }\n\n // 🔍 DIAGNOSTIC: Check if file already exists\n // const existingFile = files[file.name]\n // if (existingFile) {\n // console.log(`[LocalStorage] ⚠️ WARNING: File ${file.name} ALREADY EXISTS - will be REPLACED!`)\n // console.log(`[LocalStorage] 📁 Existing file:`)\n // console.log(`[LocalStorage] - Downloaded at: ${new Date(existingFile.downloaded_at).toISOString()}`)\n // console.log(`[LocalStorage] - Modified: ${new Date(existingFile.modified).toISOString()}`)\n // console.log(`[LocalStorage] - Size: ${existingFile.size} bytes`)\n // console.log(`[LocalStorage] - Path: ${existingFile.filePath}`)\n // console.log(`[LocalStorage] 📁 New file:`)\n // console.log(`[LocalStorage] - Downloaded at: ${new Date(file.downloaded_at).toISOString()}`)\n // console.log(`[LocalStorage] - Modified: ${new Date(file.modified).toISOString()}`)\n // console.log(`[LocalStorage] - Size: ${file.size} bytes`)\n // console.log(`[LocalStorage] - Path: ${file.filePath}`)\n // console.log(`[LocalStorage] 🔄 This will OVERWRITE the existing entry!`)\n // } else {\n // console.log(`[LocalStorage] ✅ File ${file.name} is NEW - saving metadata`)\n // }\n\n // Store relative paths to handle iOS app container changes between launches\n // Convert absolute paths to relative (remove DocumentDirectoryPath prefix)\n const relativePath = this.toPortableRelativePath(file.filePath)\n const relativeThumbnailPath = file.thumbnailPath\n ? this.toPortableRelativePath(file.thumbnailPath) || undefined\n : undefined\n\n if (!relativePath) {\n throw new Error(`Cannot persist non-portable gallery path: ${file.filePath}`)\n }\n\n files[file.name] = {\n ...file,\n // Store relative paths instead of absolute\n filePath: relativePath,\n thumbnailPath: relativeThumbnailPath,\n }\n const saveResult = storage.save(this.DOWNLOADED_FILES_KEY, files)\n if (saveResult.is_error()) throw saveResult.error\n const quarantineResult = storage.save(this.QUARANTINED_FILES_KEY, quarantined)\n if (quarantineResult.is_error()) throw quarantineResult.error\n for (const captureId of missingCaptureIds) {\n galleryTransferLedger.releaseMissingLocalCommit(captureId, true)\n }\n // console.log(`[LocalStorage] 💾 Saved metadata for ${file.name} with relative path: ${relativePath}`)\n } catch (error) {\n console.error(\"Error saving downloaded file metadata:\", error)\n throw error\n }\n }\n\n /**\n * Get all downloaded files\n */\n async getDownloadedFiles(): Promise<Record<string, DownloadedFile>> {\n const res = storage.load<Record<string, DownloadedFile>>(this.DOWNLOADED_FILES_KEY)\n if (res.is_error()) {\n // Not an error - just means no files have been downloaded yet (first use)\n // Only log as debug, not error, since this is expected on first launch\n console.log(\"[LocalStorage] No downloaded files found (first use or empty gallery)\")\n return {}\n }\n\n const files = res.value\n const reconstructedFiles: Record<string, DownloadedFile> = {}\n const normalizedFiles: Record<string, DownloadedFile> = {}\n const quarantined = this.loadQuarantinedFiles()\n const missingCaptureIds: string[] = []\n let didMigrate = false\n\n // Normalize every record before saving. This fixes the old read-absolute/write-one-relative\n // bug and migrates stale iOS container UUID paths via their Documents/Photos suffix.\n for (const [name, file] of Object.entries(files as Record<string, DownloadedFile>)) {\n const relativePath = this.toPortableRelativePath(file.filePath)\n const relativeThumbnailPath = file.thumbnailPath\n ? this.toPortableRelativePath(file.thumbnailPath) || undefined\n : undefined\n if (!relativePath) {\n quarantined[name] = {...file, downloaded_at: file.downloaded_at || Date.now()}\n missingCaptureIds.push(name)\n didMigrate = true\n continue\n }\n const absolutePath = `${RNFS.DocumentDirectoryPath}/${relativePath}`\n const absoluteThumbnailPath = relativeThumbnailPath\n ? `${RNFS.DocumentDirectoryPath}/${relativeThumbnailPath}`\n : undefined\n\n normalizedFiles[name] = {\n ...file,\n filePath: relativePath,\n thumbnailPath: relativeThumbnailPath,\n }\n\n reconstructedFiles[name] = {\n ...file,\n filePath: absolutePath,\n thumbnailPath: absoluteThumbnailPath,\n }\n if (file.filePath !== relativePath || file.thumbnailPath !== relativeThumbnailPath) didMigrate = true\n }\n\n if (didMigrate) {\n const saveResult = storage.save(this.DOWNLOADED_FILES_KEY, normalizedFiles)\n if (saveResult.is_error()) throw saveResult.error\n const quarantineResult = storage.save(this.QUARANTINED_FILES_KEY, quarantined)\n if (quarantineResult.is_error()) throw quarantineResult.error\n for (const captureId of missingCaptureIds) {\n galleryTransferLedger.releaseMissingLocalCommit(captureId, true)\n }\n }\n\n return reconstructedFiles\n }\n\n /**\n * Reconcile the remote manifest against the app-local gallery index before ledger filtering.\n * Android backup/restore and data-preserving reinstalls can restore MMKV ledger rows without\n * restoring app-private media. Only captures currently advertised by the glasses are released,\n * so acknowledged captures that remain in glasses trash are not resurrected unnecessarily.\n */\n async reconcileRemoteCaptures(\n captureIds: string[],\n downloadedFiles?: Record<string, DownloadedFile>,\n ): Promise<number> {\n const localFiles = downloadedFiles || (await this.getDownloadedFiles())\n let released = 0\n for (const captureId of captureIds) {\n const entry = galleryTransferLedger.get(captureId)\n if (!entry || !galleryTransferLedger.isLocallyCommitted(captureId)) continue\n const localFile = localFiles[captureId]\n const localFileExists = localFile?.filePath ? await RNFS.exists(localFile.filePath).catch(() => false) : false\n if (localFileExists) continue\n\n // The transfer ledger and gallery index are persisted independently. A crash can leave the\n // committed media in place after its index write was lost, so repair the index from the\n // ledger before deciding that the capture needs to be restored from the glasses.\n const committedPath = entry.finalPath?.replace(/^file:\\/\\//, \"\")\n const committedFileExists = committedPath ? await RNFS.exists(committedPath).catch(() => false) : false\n if (committedPath && committedFileExists) {\n try {\n const stat = await RNFS.stat(committedPath)\n const size = Number(stat.size)\n if (Number.isFinite(size) && size > 0) {\n const recovered = this.convertToDownloadedFile(\n {\n name: captureId,\n url: \"\",\n download: \"\",\n size,\n modified: entry.timestamp,\n mime_type: entry.captureType === \"video\" ? \"video/mp4\" : \"image/jpeg\",\n is_video: entry.captureType === \"video\",\n filePath: committedPath,\n },\n committedPath,\n entry.thumbnailPath,\n )\n recovered.capture_id = captureId\n recovered.assetReceipt = entry.assetReceipt\n await this.saveDownloadedFile(recovered)\n localFiles[captureId] = recovered\n continue\n }\n } catch (error) {\n console.warn(`[LocalStorage] Could not recover gallery index for ${captureId}:`, error)\n }\n }\n galleryTransferLedger.releaseMissingLocalCommit(captureId, true)\n released++\n }\n if (released > 0) {\n console.warn(`[LocalStorage] Released ${released} stale gallery ledger commit(s) missing local media`)\n }\n return released\n }\n\n /**\n * Get downloaded file by name\n */\n async getDownloadedFile(fileName: string): Promise<DownloadedFile | null> {\n try {\n const files = await this.getDownloadedFiles()\n return files[fileName] || null\n } catch (error) {\n console.error(\"Error getting downloaded file:\", error)\n return null\n }\n }\n\n /** Persist a durable camera-roll receipt without replacing the local-file generation. */\n async updateDownloadedFileAssetReceipt(fileName: string, assetReceipt: GalleryAssetReceipt): Promise<void> {\n const files = await this.getDownloadedFiles()\n const file = files[fileName]\n if (!file) throw new Error(`Downloaded file is missing: ${fileName}`)\n await this.saveDownloadedFile({...file, assetReceipt})\n }\n\n /**\n * Delete downloaded file (both metadata and actual files)\n */\n async deleteDownloadedFile(fileName: string): Promise<boolean> {\n try {\n const files = await this.getDownloadedFiles()\n if (files[fileName]) {\n const file = files[fileName]\n\n // Delete actual file from filesystem\n if (file.filePath && (await RNFS.exists(file.filePath))) {\n await RNFS.unlink(file.filePath)\n console.log(`[LocalStorage] Deleted file: ${file.filePath}`)\n }\n\n // Delete thumbnail if exists\n if (file.thumbnailPath && (await RNFS.exists(file.thumbnailPath))) {\n await RNFS.unlink(file.thumbnailPath)\n console.log(`[LocalStorage] Deleted thumbnail: ${file.thumbnailPath}`)\n }\n\n // Delete metadata - need to get raw data to maintain relative paths\n const res = storage.load<Record<string, DownloadedFile>>(this.DOWNLOADED_FILES_KEY)\n if (res.is_error()) {\n console.error(\"Error loading downloaded files:\", res.error)\n return false\n }\n const rawFiles = res.value\n delete rawFiles[fileName]\n await storage.save(this.DOWNLOADED_FILES_KEY, rawFiles)\n galleryTransferLedger.releaseMissingLocalCommit(fileName)\n return true\n }\n return false\n } catch (error) {\n console.error(\"Error deleting downloaded file:\", error)\n return false\n }\n }\n\n /** Preserve unresolved metadata for repair instead of silently deleting it from the gallery. */\n async quarantineDownloadedFile(fileName: string, reason: string): Promise<void> {\n const rawFiles = this.loadRawDownloadedFiles()\n const file = rawFiles[fileName]\n if (!file) return\n const quarantined = this.loadQuarantinedFiles()\n quarantined[fileName] = {...file, quarantineReason: reason} as DownloadedFile\n delete rawFiles[fileName]\n const quarantineResult = storage.save(this.QUARANTINED_FILES_KEY, quarantined)\n if (quarantineResult.is_error()) throw quarantineResult.error\n const filesResult = storage.save(this.DOWNLOADED_FILES_KEY, rawFiles)\n if (filesResult.is_error()) throw filesResult.error\n galleryTransferLedger.releaseMissingLocalCommit(fileName, true)\n }\n\n async getQuarantinedDownloadedFiles(): Promise<Record<string, DownloadedFile>> {\n return this.loadQuarantinedFiles()\n }\n\n /**\n * Convert PhotoInfo to DownloadedFile (assumes files are already saved to filesystem)\n */\n convertToDownloadedFile(\n photoInfo: PhotoInfo,\n filePath: string,\n thumbnailPath?: string,\n glassesModel?: string,\n ): DownloadedFile {\n return {\n name: photoInfo.name,\n filePath: filePath,\n size: photoInfo.size,\n modified: new Date(photoInfo.modified).getTime(),\n mime_type: photoInfo.mime_type || (photoInfo.is_video ? \"video/mp4\" : \"image/jpeg\"),\n is_video: photoInfo.is_video || false,\n thumbnailPath: thumbnailPath,\n downloaded_at: Date.now(),\n glassesModel: glassesModel || photoInfo.glassesModel,\n duration: photoInfo.duration,\n }\n }\n\n /**\n * Convert DownloadedFile to PhotoInfo\n */\n convertToPhotoInfo(downloadedFile: DownloadedFile): PhotoInfo {\n // Use file:// URLs for local files\n // On iOS, ensure we have proper file:// URL format with correct number of slashes\n const fileUrl = downloadedFile.filePath.startsWith(\"file://\")\n ? downloadedFile.filePath\n : downloadedFile.filePath.startsWith(\"/\")\n ? `file://${downloadedFile.filePath}` // Path already has leading slash\n : `file:///${downloadedFile.filePath}` // Path needs leading slash\n\n const thumbnailUrl = downloadedFile.thumbnailPath\n ? downloadedFile.thumbnailPath.startsWith(\"file://\")\n ? downloadedFile.thumbnailPath\n : downloadedFile.thumbnailPath.startsWith(\"/\")\n ? `file://${downloadedFile.thumbnailPath}` // Path already has leading slash\n : `file:///${downloadedFile.thumbnailPath}` // Path needs leading slash\n : undefined\n\n return {\n name: downloadedFile.name,\n url: fileUrl,\n download: fileUrl,\n size: downloadedFile.size,\n modified: new Date(downloadedFile.modified).toISOString(),\n mime_type: downloadedFile.mime_type,\n is_video: downloadedFile.is_video,\n thumbnail_data: undefined,\n downloaded_at: downloadedFile.downloaded_at,\n filePath: downloadedFile.filePath,\n glassesModel: downloadedFile.glassesModel,\n thumbnailPath: thumbnailUrl, // Use the file:// URL version for thumbnailPath\n duration: downloadedFile.duration,\n }\n }\n\n /**\n * Get storage statistics\n */\n async getStorageStats(): Promise<{\n total_files: number\n total_size: number\n last_sync: number\n }> {\n try {\n const files = await this.getDownloadedFiles()\n const syncState = await this.getSyncState()\n\n const totalSize = Object.values(files).reduce((sum, file) => sum + file.size, 0)\n\n return {\n total_files: Object.keys(files).length,\n total_size: totalSize,\n last_sync: syncState.last_sync_time,\n }\n } catch (error) {\n console.error(\"Error getting storage stats:\", error)\n return {\n total_files: 0,\n total_size: 0,\n last_sync: 0,\n }\n }\n }\n\n /**\n * Clear all downloaded files (both metadata and actual files)\n */\n async clearAllFiles(): Promise<void> {\n // Nuke the entire photos directory (includes thumbnails subdirectory)\n // This is more reliable than deleting individual files, which can miss orphaned thumbnails\n try {\n if (await RNFS.exists(this.ASG_PHOTOS_DIR)) {\n await RNFS.unlink(this.ASG_PHOTOS_DIR)\n console.log(\"[LocalStorage] Deleted entire photos directory\")\n }\n } catch (error) {\n console.error(\"[LocalStorage] Error deleting photos directory:\", error)\n }\n\n // Recreate empty directories\n await this.initializeDirectories()\n\n // Clear metadata\n const res = await storage.remove(this.DOWNLOADED_FILES_KEY)\n if (res.is_error()) {\n console.error(\"[LocalStorage] Error clearing downloaded files:\", res.error)\n throw res.error\n }\n storage.remove(this.QUARANTINED_FILES_KEY)\n galleryTransferLedger.releaseAllMissingLocalCommits()\n console.log(\"[LocalStorage] Cleared all downloaded files and thumbnails\")\n }\n\n // ============================================\n // Sync Queue Persistence (for background sync resume)\n // ============================================\n\n /**\n * Save sync queue for potential resume after app restart\n */\n async saveSyncQueue(queue: SyncQueueData): Promise<void> {\n try {\n await storage.save(this.SYNC_QUEUE_KEY, queue)\n console.log(`[LocalStorage] Saved sync queue: ${queue.files.length} files, index ${queue.currentIndex}`)\n } catch (error) {\n console.error(\"[LocalStorage] Error saving sync queue:\", error)\n throw error\n }\n }\n\n /**\n * Get saved sync queue (for resume on app restart)\n */\n async getSyncQueue(): Promise<SyncQueueData | null> {\n try {\n const res = storage.load<SyncQueueData>(this.SYNC_QUEUE_KEY)\n if (res.is_error()) {\n // No queue saved - this is normal\n return null\n }\n const queue = res.value\n console.log(`[LocalStorage] Loaded sync queue: ${queue.files.length} files, index ${queue.currentIndex}`)\n return queue\n } catch (error) {\n console.error(\"[LocalStorage] Error loading sync queue:\", error)\n return null\n }\n }\n\n /**\n * Update the current index of the sync queue (called after each file completes)\n */\n async updateSyncQueueIndex(newIndex: number): Promise<void> {\n // S6: Let errors propagate — caller uses .catch() for non-critical updates\n const queue = await this.getSyncQueue()\n if (queue) {\n queue.currentIndex = newIndex\n await this.saveSyncQueue(queue)\n }\n }\n\n /**\n * Clear sync queue (called on sync complete or cancel)\n */\n async clearSyncQueue(): Promise<void> {\n // S6: Retry up to 3 times to ensure queue is cleared\n for (let attempt = 1; attempt <= 3; attempt++) {\n try {\n const res = await storage.remove(this.SYNC_QUEUE_KEY)\n if (res.is_error()) {\n console.error(`[LocalStorage] Error clearing sync queue (attempt ${attempt}/3):`, res.error)\n if (attempt < 3) continue\n return\n }\n console.log(\"[LocalStorage] Cleared sync queue\")\n return\n } catch (error) {\n console.error(`[LocalStorage] Error clearing sync queue (attempt ${attempt}/3):`, error)\n if (attempt < 3) {\n await new Promise<void>((resolve) => BgTimer.setTimeout(() => resolve(), 100))\n }\n }\n }\n }\n\n /**\n * Check if there's a resumable sync queue\n */\n async hasResumableSyncQueue(): Promise<boolean> {\n const queue = await this.getSyncQueue()\n if (!queue) return false\n // Has resumable queue if there are still files to process\n return queue.currentIndex < queue.files.length\n }\n\n private loadRawDownloadedFiles(): Record<string, DownloadedFile> {\n const result = storage.load<Record<string, DownloadedFile>>(this.DOWNLOADED_FILES_KEY)\n return result.is_error() ? {} : result.value\n }\n\n private loadQuarantinedFiles(): Record<string, DownloadedFile> {\n const result = storage.load<Record<string, DownloadedFile>>(this.QUARANTINED_FILES_KEY)\n return result.is_error() ? {} : result.value\n }\n\n private toPortableRelativePath(path: string): string | null {\n return toPortableGalleryPath(path, RNFS.DocumentDirectoryPath)\n }\n}\n\nexport const localStorageService = LocalStorageService.getInstance()\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type DashboardOpenTrace, type DashboardOpenTrigger } from "./dashboardOpenTimeline";
|
|
2
|
+
export interface DashboardOpenReport {
|
|
3
|
+
title: string;
|
|
4
|
+
body: string;
|
|
5
|
+
trace: DashboardOpenTrace;
|
|
6
|
+
}
|
|
7
|
+
declare class DashboardOpenTracer {
|
|
8
|
+
private readonly timeline;
|
|
9
|
+
private listeners;
|
|
10
|
+
private lastOpenAt;
|
|
11
|
+
private overlayConnectedAt;
|
|
12
|
+
private glassesConnectedAt;
|
|
13
|
+
private frameSubs;
|
|
14
|
+
private unsubs;
|
|
15
|
+
/** Track the context an open is judged against. Idempotent; returns the stop. */
|
|
16
|
+
start(): () => void;
|
|
17
|
+
stop(): void;
|
|
18
|
+
onReport(listener: (report: DashboardOpenReport) => void): () => void;
|
|
19
|
+
/** An opening gesture reached the phone; `nativeAt` is native's receipt time when the event has one. */
|
|
20
|
+
trigger(trigger: DashboardOpenTrigger, nativeAt?: number): void;
|
|
21
|
+
showViewRequested(packageName: string): void;
|
|
22
|
+
slotGranted(): void;
|
|
23
|
+
frameSent(seq: number): void;
|
|
24
|
+
private watchFrames;
|
|
25
|
+
private unwatchFrames;
|
|
26
|
+
private report;
|
|
27
|
+
private syncOverlayApps;
|
|
28
|
+
private syncGlasses;
|
|
29
|
+
}
|
|
30
|
+
declare const dashboardOpenTrace: DashboardOpenTracer;
|
|
31
|
+
export default dashboardOpenTrace;
|
|
32
|
+
//# sourceMappingURL=DashboardOpenTrace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DashboardOpenTrace.d.ts","sourceRoot":"","sources":["../../../src/services/debug/DashboardOpenTrace.ts"],"names":[],"mappings":"AAeA,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EAC1B,MAAM,yBAAyB,CAAA;AAIhC,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,kBAAkB,CAAA;CAC1B;AAED,cAAM,mBAAmB;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAKvB;IACF,OAAO,CAAC,SAAS,CAAmD;IACpE,OAAO,CAAC,UAAU,CAAsB;IACxC,OAAO,CAAC,kBAAkB,CAA4B;IACtD,OAAO,CAAC,kBAAkB,CAAsB;IAChD,OAAO,CAAC,SAAS,CAAkC;IACnD,OAAO,CAAC,MAAM,CAAwB;IAEtC,iFAAiF;IACjF,KAAK,IAAI,MAAM,IAAI;IAenB,IAAI,IAAI,IAAI;IAOZ,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,GAAG,MAAM,IAAI;IAOrE,wGAAwG;IACxG,OAAO,CAAC,OAAO,EAAE,oBAAoB,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAe/D,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAI5C,WAAW,IAAI,IAAI;IAKnB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAQ5B,OAAO,CAAC,WAAW;IAgBnB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,MAAM;IAOd,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,WAAW;CAIpB;AAED,QAAA,MAAM,kBAAkB,qBAA4B,CAAA;AACpD,eAAe,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard open timing (Debug Settings): stamps a dashboard open from the
|
|
3
|
+
* gesture reaching the phone to the glasses presenting the first overlay
|
|
4
|
+
* frame, logs it, and hands it to the host, which posts it as a phone
|
|
5
|
+
* notification. Only a gesture with the setting on starts a trace; every
|
|
6
|
+
* other entry is a no-op while none runs.
|
|
7
|
+
*/
|
|
8
|
+
import BluetoothSdk from "@glassly/bluetooth-sdk/internal";
|
|
9
|
+
import { useDisplayStore } from "../../stores/display";
|
|
10
|
+
import { useGlassesStore } from "../../stores/glasses";
|
|
11
|
+
import { SETTINGS, useSettingsStore } from "../../stores/settings";
|
|
12
|
+
import { BgTimer } from "../../utils/timers";
|
|
13
|
+
import { isGlassesConnected } from "../GlassesReadiness";
|
|
14
|
+
import { onOverlayAppsChange, overlayApps } from "../pages/overlayApps";
|
|
15
|
+
import { DashboardOpenTimeline, formatDashboardOpenTrace, } from "./dashboardOpenTimeline";
|
|
16
|
+
const LOG_TAG = "DashboardOpenTrace";
|
|
17
|
+
class DashboardOpenTracer {
|
|
18
|
+
timeline = new DashboardOpenTimeline({
|
|
19
|
+
now: () => Date.now(),
|
|
20
|
+
setTimeout: (callback, ms) => BgTimer.setTimeout(callback, ms),
|
|
21
|
+
clearTimeout: (handle) => BgTimer.clearTimeout(handle),
|
|
22
|
+
onFinished: (trace) => this.report(trace),
|
|
23
|
+
});
|
|
24
|
+
listeners = new Set();
|
|
25
|
+
lastOpenAt = null;
|
|
26
|
+
overlayConnectedAt = new Map();
|
|
27
|
+
glassesConnectedAt = null;
|
|
28
|
+
frameSubs = [];
|
|
29
|
+
unsubs = [];
|
|
30
|
+
/** Track the context an open is judged against. Idempotent; returns the stop. */
|
|
31
|
+
start() {
|
|
32
|
+
if (this.unsubs.length === 0) {
|
|
33
|
+
this.syncOverlayApps();
|
|
34
|
+
this.syncGlasses(isGlassesConnected(useGlassesStore.getState().connection));
|
|
35
|
+
this.unsubs.push(onOverlayAppsChange(() => this.syncOverlayApps()), useGlassesStore.subscribe((state) => isGlassesConnected(state.connection), (connected) => this.syncGlasses(connected)));
|
|
36
|
+
}
|
|
37
|
+
return () => this.stop();
|
|
38
|
+
}
|
|
39
|
+
stop() {
|
|
40
|
+
for (const unsub of this.unsubs)
|
|
41
|
+
unsub();
|
|
42
|
+
this.unsubs = [];
|
|
43
|
+
this.timeline.cancel();
|
|
44
|
+
this.unwatchFrames();
|
|
45
|
+
}
|
|
46
|
+
onReport(listener) {
|
|
47
|
+
this.listeners.add(listener);
|
|
48
|
+
return () => {
|
|
49
|
+
this.listeners.delete(listener);
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** An opening gesture reached the phone; `nativeAt` is native's receipt time when the event has one. */
|
|
53
|
+
trigger(trigger, nativeAt) {
|
|
54
|
+
if (useSettingsStore.getState().getSetting(SETTINGS.debug_dashboard_open_timing.key) !== true)
|
|
55
|
+
return;
|
|
56
|
+
// With a page up the gesture moves within the dashboard or closes it.
|
|
57
|
+
if (useDisplayStore.getState().overlayOwner !== null)
|
|
58
|
+
return;
|
|
59
|
+
const now = Date.now();
|
|
60
|
+
this.timeline.trigger(trigger, {
|
|
61
|
+
sinceLastOpenMs: this.lastOpenAt === null ? null : now - this.lastOpenAt,
|
|
62
|
+
glassesUpMs: this.glassesConnectedAt === null ? null : now - this.glassesConnectedAt,
|
|
63
|
+
}, nativeAt);
|
|
64
|
+
}
|
|
65
|
+
showViewRequested(packageName) {
|
|
66
|
+
this.timeline.showViewRequested(this.overlayConnectedAt.get(packageName) ?? null);
|
|
67
|
+
}
|
|
68
|
+
slotGranted() {
|
|
69
|
+
this.lastOpenAt = Date.now();
|
|
70
|
+
this.timeline.slotGranted();
|
|
71
|
+
}
|
|
72
|
+
frameSent(seq) {
|
|
73
|
+
if (!this.timeline.tracing || this.timeline.frameSeq !== null)
|
|
74
|
+
return;
|
|
75
|
+
this.timeline.frameSent(seq);
|
|
76
|
+
if (this.timeline.frameSeq !== null)
|
|
77
|
+
this.watchFrames();
|
|
78
|
+
}
|
|
79
|
+
// Raw device events rather than SceneRenderer.whenPresented: that keeps one
|
|
80
|
+
// waiter per seq, and the display manager's awaited render already holds it.
|
|
81
|
+
watchFrames() {
|
|
82
|
+
if (this.frameSubs.length > 0)
|
|
83
|
+
return;
|
|
84
|
+
this.frameSubs.push(BluetoothSdk.addListener("scene_frame_presented", (event) => {
|
|
85
|
+
this.timeline.framePresented(event.seq, event.presented, event.reason);
|
|
86
|
+
}), BluetoothSdk.addListener("scene_settled", (event) => {
|
|
87
|
+
const frameSeq = this.timeline.frameSeq;
|
|
88
|
+
if (frameSeq === null)
|
|
89
|
+
return;
|
|
90
|
+
// The device echoes the low 16 bits of the frame number.
|
|
91
|
+
const ahead = (event.tag - frameSeq) & 0xffff;
|
|
92
|
+
if (ahead < 0x8000)
|
|
93
|
+
this.timeline.frameSettled(frameSeq + ahead);
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
unwatchFrames() {
|
|
97
|
+
for (const sub of this.frameSubs)
|
|
98
|
+
sub.remove();
|
|
99
|
+
this.frameSubs = [];
|
|
100
|
+
}
|
|
101
|
+
report(trace) {
|
|
102
|
+
this.unwatchFrames();
|
|
103
|
+
const { title, body } = formatDashboardOpenTrace(trace);
|
|
104
|
+
console.log(`${LOG_TAG}: ${title} | ${body.split("\n").join(" | ")}`);
|
|
105
|
+
for (const listener of Array.from(this.listeners))
|
|
106
|
+
listener({ title, body, trace });
|
|
107
|
+
}
|
|
108
|
+
syncOverlayApps() {
|
|
109
|
+
const running = new Set(overlayApps());
|
|
110
|
+
for (const packageName of this.overlayConnectedAt.keys()) {
|
|
111
|
+
if (!running.has(packageName))
|
|
112
|
+
this.overlayConnectedAt.delete(packageName);
|
|
113
|
+
}
|
|
114
|
+
for (const packageName of running) {
|
|
115
|
+
if (!this.overlayConnectedAt.has(packageName))
|
|
116
|
+
this.overlayConnectedAt.set(packageName, Date.now());
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
syncGlasses(connected) {
|
|
120
|
+
if (!connected)
|
|
121
|
+
this.glassesConnectedAt = null;
|
|
122
|
+
else if (this.glassesConnectedAt === null)
|
|
123
|
+
this.glassesConnectedAt = Date.now();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const dashboardOpenTrace = new DashboardOpenTracer();
|
|
127
|
+
export default dashboardOpenTrace;
|
|
128
|
+
//# sourceMappingURL=DashboardOpenTrace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DashboardOpenTrace.js","sourceRoot":"","sources":["../../../src/services/debug/DashboardOpenTrace.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Dashboard open timing (Debug Settings): stamps a dashboard open from the\n * gesture reaching the phone to the glasses presenting the first overlay\n * frame, logs it, and hands it to the host, which posts it as a phone\n * notification. Only a gesture with the setting on starts a trace; every\n * other entry is a no-op while none runs.\n */\nimport BluetoothSdk from \"@glassly/bluetooth-sdk/internal\"\n\nimport {useDisplayStore} from \"../../stores/display\"\nimport {useGlassesStore} from \"../../stores/glasses\"\nimport {SETTINGS, useSettingsStore} from \"../../stores/settings\"\nimport {BgTimer} from \"../../utils/timers\"\nimport {isGlassesConnected} from \"../GlassesReadiness\"\nimport {onOverlayAppsChange, overlayApps} from \"../pages/overlayApps\"\nimport {\n DashboardOpenTimeline,\n formatDashboardOpenTrace,\n type DashboardOpenTrace,\n type DashboardOpenTrigger,\n} from \"./dashboardOpenTimeline\"\n\nconst LOG_TAG = \"DashboardOpenTrace\"\n\nexport interface DashboardOpenReport {\n title: string\n body: string\n trace: DashboardOpenTrace\n}\n\nclass DashboardOpenTracer {\n private readonly timeline = new DashboardOpenTimeline({\n now: () => Date.now(),\n setTimeout: (callback, ms) => BgTimer.setTimeout(callback, ms),\n clearTimeout: (handle) => BgTimer.clearTimeout(handle),\n onFinished: (trace) => this.report(trace),\n })\n private listeners = new Set<(report: DashboardOpenReport) => void>()\n private lastOpenAt: number | null = null\n private overlayConnectedAt = new Map<string, number>()\n private glassesConnectedAt: number | null = null\n private frameSubs: Array<{remove: () => void}> = []\n private unsubs: Array<() => void> = []\n\n /** Track the context an open is judged against. Idempotent; returns the stop. */\n start(): () => void {\n if (this.unsubs.length === 0) {\n this.syncOverlayApps()\n this.syncGlasses(isGlassesConnected(useGlassesStore.getState().connection))\n this.unsubs.push(\n onOverlayAppsChange(() => this.syncOverlayApps()),\n useGlassesStore.subscribe(\n (state) => isGlassesConnected(state.connection),\n (connected) => this.syncGlasses(connected),\n ),\n )\n }\n return () => this.stop()\n }\n\n stop(): void {\n for (const unsub of this.unsubs) unsub()\n this.unsubs = []\n this.timeline.cancel()\n this.unwatchFrames()\n }\n\n onReport(listener: (report: DashboardOpenReport) => void): () => void {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n /** An opening gesture reached the phone; `nativeAt` is native's receipt time when the event has one. */\n trigger(trigger: DashboardOpenTrigger, nativeAt?: number): void {\n if (useSettingsStore.getState().getSetting(SETTINGS.debug_dashboard_open_timing.key) !== true) return\n // With a page up the gesture moves within the dashboard or closes it.\n if (useDisplayStore.getState().overlayOwner !== null) return\n const now = Date.now()\n this.timeline.trigger(\n trigger,\n {\n sinceLastOpenMs: this.lastOpenAt === null ? null : now - this.lastOpenAt,\n glassesUpMs: this.glassesConnectedAt === null ? null : now - this.glassesConnectedAt,\n },\n nativeAt,\n )\n }\n\n showViewRequested(packageName: string): void {\n this.timeline.showViewRequested(this.overlayConnectedAt.get(packageName) ?? null)\n }\n\n slotGranted(): void {\n this.lastOpenAt = Date.now()\n this.timeline.slotGranted()\n }\n\n frameSent(seq: number): void {\n if (!this.timeline.tracing || this.timeline.frameSeq !== null) return\n this.timeline.frameSent(seq)\n if (this.timeline.frameSeq !== null) this.watchFrames()\n }\n\n // Raw device events rather than SceneRenderer.whenPresented: that keeps one\n // waiter per seq, and the display manager's awaited render already holds it.\n private watchFrames(): void {\n if (this.frameSubs.length > 0) return\n this.frameSubs.push(\n BluetoothSdk.addListener(\"scene_frame_presented\", (event) => {\n this.timeline.framePresented(event.seq, event.presented, event.reason)\n }),\n BluetoothSdk.addListener(\"scene_settled\", (event) => {\n const frameSeq = this.timeline.frameSeq\n if (frameSeq === null) return\n // The device echoes the low 16 bits of the frame number.\n const ahead = (event.tag - frameSeq) & 0xffff\n if (ahead < 0x8000) this.timeline.frameSettled(frameSeq + ahead)\n }),\n )\n }\n\n private unwatchFrames(): void {\n for (const sub of this.frameSubs) sub.remove()\n this.frameSubs = []\n }\n\n private report(trace: DashboardOpenTrace): void {\n this.unwatchFrames()\n const {title, body} = formatDashboardOpenTrace(trace)\n console.log(`${LOG_TAG}: ${title} | ${body.split(\"\\n\").join(\" | \")}`)\n for (const listener of Array.from(this.listeners)) listener({title, body, trace})\n }\n\n private syncOverlayApps(): void {\n const running = new Set(overlayApps())\n for (const packageName of this.overlayConnectedAt.keys()) {\n if (!running.has(packageName)) this.overlayConnectedAt.delete(packageName)\n }\n for (const packageName of running) {\n if (!this.overlayConnectedAt.has(packageName)) this.overlayConnectedAt.set(packageName, Date.now())\n }\n }\n\n private syncGlasses(connected: boolean): void {\n if (!connected) this.glassesConnectedAt = null\n else if (this.glassesConnectedAt === null) this.glassesConnectedAt = Date.now()\n }\n}\n\nconst dashboardOpenTrace = new DashboardOpenTracer()\nexport default dashboardOpenTrace\n"]}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stage timeline of one dashboard open, for the dashboard open timing debug
|
|
3
|
+
* setting. The clock starts when the opening gesture reaches the phone (or
|
|
4
|
+
* when native received it, if the event carries that time); every stage is
|
|
5
|
+
* stamped as ms after that. No I/O: DashboardOpenTrace.ts feeds it.
|
|
6
|
+
*/
|
|
7
|
+
export type DashboardOpenTrigger = "head-up" | "double-tap";
|
|
8
|
+
/** In order. `js` exists only when the gesture carried a native receipt time; `settled` needs CFW rev 27+. */
|
|
9
|
+
export declare const DASHBOARD_OPEN_STAGES: readonly ["js", "showView", "slot", "frame", "presented", "settled"];
|
|
10
|
+
export type DashboardOpenStage = (typeof DASHBOARD_OPEN_STAGES)[number];
|
|
11
|
+
export interface DashboardOpenTrace {
|
|
12
|
+
trigger: DashboardOpenTrigger;
|
|
13
|
+
/** Further triggers of the same kind before the dashboard asked for the view. */
|
|
14
|
+
repeats: number;
|
|
15
|
+
stages: Partial<Record<DashboardOpenStage, number>>;
|
|
16
|
+
/** The first required stage that never arrived; absent once the glasses presented the frame. */
|
|
17
|
+
stalledAt?: DashboardOpenStage;
|
|
18
|
+
/** What the glasses said when they reported the frame not presented. */
|
|
19
|
+
reason?: string;
|
|
20
|
+
/** Since the overlay slot was last granted; null when it hasn't been this session. */
|
|
21
|
+
sinceLastOpenMs: number | null;
|
|
22
|
+
/** How long the requesting overlay app had been connected at the gesture; negative when it connected after. */
|
|
23
|
+
appUpMs: number | null;
|
|
24
|
+
/** How long the glasses had been connected at the gesture. */
|
|
25
|
+
glassesUpMs: number | null;
|
|
26
|
+
}
|
|
27
|
+
export interface DashboardOpenTimelineDeps {
|
|
28
|
+
now(): number;
|
|
29
|
+
setTimeout: (callback: () => void, ms: number) => number;
|
|
30
|
+
clearTimeout: (handle: number) => void;
|
|
31
|
+
/** A finished open. A gesture the dashboard never answered with showView is dropped silently. */
|
|
32
|
+
onFinished(trace: DashboardOpenTrace): void;
|
|
33
|
+
}
|
|
34
|
+
/** A gesture not answered with showView by then did not open the dashboard; a later stage missing by then stalled. */
|
|
35
|
+
export declare const OPEN_WINDOW_MS = 15000;
|
|
36
|
+
/** How long to wait for the settle report once the frame was presented. */
|
|
37
|
+
export declare const SETTLE_GRACE_MS = 2000;
|
|
38
|
+
export declare class DashboardOpenTimeline {
|
|
39
|
+
private readonly deps;
|
|
40
|
+
private active;
|
|
41
|
+
constructor(deps: DashboardOpenTimelineDeps);
|
|
42
|
+
get tracing(): boolean;
|
|
43
|
+
/** The seq of the open's first overlay frame, once sent. */
|
|
44
|
+
get frameSeq(): number | null;
|
|
45
|
+
/**
|
|
46
|
+
* An opening gesture reached the phone. While an earlier one still waits
|
|
47
|
+
* for showView, the same gesture again only counts as a repeat (the clock
|
|
48
|
+
* keeps the first); a different gesture restarts the clock. Ignored once
|
|
49
|
+
* the open is under way.
|
|
50
|
+
*/
|
|
51
|
+
trigger(trigger: DashboardOpenTrigger, context: {
|
|
52
|
+
sinceLastOpenMs: number | null;
|
|
53
|
+
glassesUpMs: number | null;
|
|
54
|
+
}, nativeAt?: number): void;
|
|
55
|
+
/** An overlay app asked for the dashboard view; `appConnectedAt` is when it connected, if known. */
|
|
56
|
+
showViewRequested(appConnectedAt: number | null): void;
|
|
57
|
+
slotGranted(): void;
|
|
58
|
+
/** The first overlay frame after the grant left for the glasses. */
|
|
59
|
+
frameSent(seq: number): void;
|
|
60
|
+
/**
|
|
61
|
+
* The glasses reported a frame. A later frame presented folds ours in; ours
|
|
62
|
+
* not presented is noted, and the window still waits for a later one.
|
|
63
|
+
*/
|
|
64
|
+
framePresented(seq: number, presented: boolean, reason?: string): void;
|
|
65
|
+
/** The glasses finished the animations of frame `seq` (and every frame before it). */
|
|
66
|
+
frameSettled(seq: number): void;
|
|
67
|
+
cancel(): void;
|
|
68
|
+
private stamp;
|
|
69
|
+
private expire;
|
|
70
|
+
private finish;
|
|
71
|
+
}
|
|
72
|
+
/** Notification title and body: the headline, the stage timeline, then the context that separates cold opens from warm ones. */
|
|
73
|
+
export declare function formatDashboardOpenTrace(trace: DashboardOpenTrace): {
|
|
74
|
+
title: string;
|
|
75
|
+
body: string;
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=dashboardOpenTimeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboardOpenTimeline.d.ts","sourceRoot":"","sources":["../../../src/services/debug/dashboardOpenTimeline.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,YAAY,CAAA;AAE3D,8GAA8G;AAC9G,eAAO,MAAM,qBAAqB,sEAAuE,CAAA;AACzG,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAA;AAcvE,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,oBAAoB,CAAA;IAC7B,iFAAiF;IACjF,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC,CAAA;IACnD,gGAAgG;IAChG,SAAS,CAAC,EAAE,kBAAkB,CAAA;IAC9B,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,sFAAsF;IACtF,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,+GAA+G;IAC/G,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,8DAA8D;IAC9D,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAC3B;AAED,MAAM,WAAW,yBAAyB;IACxC,GAAG,IAAI,MAAM,CAAA;IACb,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK,MAAM,CAAA;IACxD,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IACtC,iGAAiG;IACjG,UAAU,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAAA;CAC5C;AAED,sHAAsH;AACtH,eAAO,MAAM,cAAc,QAAS,CAAA;AACpC,2EAA2E;AAC3E,eAAO,MAAM,eAAe,OAAQ,CAAA;AAWpC,qBAAa,qBAAqB;IAGpB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFjC,OAAO,CAAC,MAAM,CAA0B;gBAEX,IAAI,EAAE,yBAAyB;IAE5D,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,4DAA4D;IAC5D,IAAI,QAAQ,IAAI,MAAM,GAAG,IAAI,CAE5B;IAED;;;;;OAKG;IACH,OAAO,CACL,OAAO,EAAE,oBAAoB,EAC7B,OAAO,EAAE;QAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;KAAC,EACrE,QAAQ,CAAC,EAAE,MAAM,GAChB,IAAI;IAqBP,oGAAoG;IACpG,iBAAiB,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAOtD,WAAW,IAAI,IAAI;IAInB,oEAAoE;IACpE,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAO5B;;;OAGG;IACH,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAatE,sFAAsF;IACtF,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAQ/B,MAAM,IAAI,IAAI;IAMd,OAAO,CAAC,KAAK;IAMb,OAAO,CAAC,MAAM;IAUd,OAAO,CAAC,MAAM;CAWf;AAED,gIAAgI;AAChI,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,kBAAkB,GAAG;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CA+BjG"}
|