@glassly/engine 0.4.0-dev.1029 → 0.4.0-dev.1030

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.
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAC,SAAS,EAAkD,aAAa,EAAC,MAAM,qBAAqB,CAAA;AAgD5G,eAAO,MAAM,MAAM;IACjB,2EAA2E;;IAE3E,8EAA8E;;IAE9E;iDAC6C;;IAyG7C;;yCAEqC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAoCrC,kEAAkE;;;;;;;;;;;;;;;;;;;;;;;IAElE,wEAAwE;;;;;;;;IAExE,sEAAsE;;;;;;;;;;;;IAEtE,qFAAqF;;;;gBA3IpE,CAAC;mBAAiB,CAAC;;;gBAMlC,CAFF;mBAAiB,CAAC;;;;;;;;;;;;;;;;;IAyIlB,qEAAqE;;;;IAErE,sFAAsF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAEtF,6EAA6E;;;;;;;;;;;;IAE7E,iFAAiF;;;;;;;;;;;;;;;;;;;;;;;;IAEjF,8CAA8C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAE9C,uDAAuD;;;;;;;;;;;;;;;;IAEvD,8EAA8E;;;;;;;;IAE9E,qFAAqF;;;;IAErF,4EAA4E;;;;;;;;;;;IAE5E,+EAA+E;;;;;;;;;;;;;;;IAE/E,qGAAqG;;;;;;IAErG,kFAAkF;;;;;+BArKjE,CAAC;;;+BAUiC,CAAC;;;;;;;;;;;;IA6JpD,mFAAmF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAGpF,CAAA"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAC,SAAS,EAAkD,aAAa,EAAC,MAAM,qBAAqB,CAAA;AAgD5G,eAAO,MAAM,MAAM;IACjB,2EAA2E;;IAE3E,8EAA8E;;IAE9E;iDAC6C;;IA2G7C;;yCAEqC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAoCrC,kEAAkE;;;;;;;;;;;;;;;;;;;;;;;IAElE,wEAAwE;;;;;;;;IAExE,sEAAsE;;;;;;;;;;;;IAEtE,qFAAqF;;;;gBA7IpE,CAAC;mBAAiB,CAAC;;;gBAMlC,CAFF;mBAAiB,CAAC;;;;;;;;;;;;;;;;;IA2IlB,qEAAqE;;;;IAErE,sFAAsF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAEtF,6EAA6E;;;;;;;;;;;;IAE7E,iFAAiF;;;;;;;;;;;;;;;;;;;;;;;;IAEjF,8CAA8C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAE9C,uDAAuD;;;;;;;;;;;;;;;;IAEvD,8EAA8E;;;;;;;;IAE9E,qFAAqF;;;;IAErF,4EAA4E;;;;;;;;;;;IAE5E,+EAA+E;;;;;;;;;;;;;;;IAE/E,qGAAqG;;;;;;IAErG,kFAAkF;;;;;+BAvKjE,CAAC;;;+BAUiC,CAAC;;;;;;;;;;;;IA+JpD,mFAAmF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAGpF,CAAA"}
package/build/engine.js CHANGED
@@ -129,9 +129,11 @@ export const engine = {
129
129
  // Not awaited: the exchange behind it is a Core round trip with no client
130
130
  // deadline, and start() must resolve offline. The glasses get the token
131
131
  // when it lands; identity resolution joins the same single-flight exchange.
132
- void cloudClientService.syncCoreTokenToBluetooth().catch((error) => {
133
- console.warn("engine.start: initial Cloud core token sync failed:", error instanceof Error ? error.message : error);
134
- });
132
+ if (!cloudClientService.isCloudDisabled()) {
133
+ void cloudClientService.syncCoreTokenToBluetooth().catch((error) => {
134
+ console.warn("engine.start: initial Cloud core token sync failed:", error instanceof Error ? error.message : error);
135
+ });
136
+ }
135
137
  startSupportProfileSync();
136
138
  // Push device-setting changes to the glasses for ANY host, so
137
139
  // engine.glasses.settings.set() reaches the device (not just the Glassly app).
@@ -1 +1 @@
1
- {"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `engine` — the namespaced OEM-facing engine API (the \"(A) host API\" from the\n * Phase-1 contract). Host UI calls `engine.<domain>.<method>()`; each domain is a\n * typed facade over the runtime. (Exported from the `@glassly/engine` module, whose\n * name stays `engine` in code; the public API surface is `engine`.)\n *\n * It grows one facade at a time. The migration-era flat store/service exports\n * remain in a private Glassly host package; they shrink as screens move onto\n * `engine.*`.\n */\nimport {configure, start as bootstrapStart, stop as bootstrapStop, updateUiSeams} from \"./runtime/bootstrap\"\nimport {cloudClientService} from \"./services/CloudClientService\"\nimport {hydrateDeviceStore, demoteOrphanedDefaultWearable} from \"./services/DeviceStoreHydration\"\nimport {startPairedGlassesLatch, stopPairedGlassesLatch} from \"./services/PairedGlassesLatch\"\nimport {startMiniappPauseCoordinator, stopMiniappPauseCoordinator} from \"./services/MiniappPauseCoordinator\"\nimport {nativeRestoreLaunchQuery, reconnectAfterBluetoothRestoreLaunch} from \"./services/BluetoothRestoreLaunch\"\nimport {startGlassesSettingsSync, stopGlassesSettingsSync} from \"./services/GlassesSettingsSync\"\nimport {startGlassesStatusProjection, stopGlassesStatusProjection} from \"./services/GlassesStatusProjection\"\nimport {startOtaService, stopOtaService} from \"./services/OtaService\"\nimport {startAudioCloudUplink, stopAudioCloudUplink} from \"./services/AudioCloudUplink\"\nimport sonioxDirectService from \"./services/soniox/SonioxDirectService\"\nimport {startSupportProfileSync, stopSupportProfileSync} from \"./services/SupportProfileSync\"\nimport {startDeviceEventRouter, stopDeviceEventRouter} from \"./services/DeviceEventRouter\"\nimport {startPhoneActivityTracking, stopPhoneActivityTracking} from \"./services/PhoneActivity\"\nimport {startPhoneNotificationsSync, stopPhoneNotificationsSync} from \"./services/PhoneNotificationsSync\"\nimport {startSpeakerIdSync, stopSpeakerIdSync} from \"./services/SpeakerIdSync\"\nimport {startNeuralBandSettingsSync, stopNeuralBandSettingsSync} from \"./services/neuralBand/NeuralBandSettingsSync\"\nimport {startWatchLink, stopWatchLink} from \"./services/watch/WatchLink\"\nimport {startCaptionsTesterReportService, stopCaptionsTesterReportService} from \"./services/CaptionsTesterReportService\"\nimport {startJSCrashloopReportService, stopJSCrashloopReportService} from \"./services/JSCrashloopReportService\"\nimport {ensureMiniappEngine, stopMiniappEngine} from \"./services/MiniappEngine\"\nimport localMiniappRuntime from \"./services/LocalMiniappRuntime\"\nimport displayProcessor from \"./services/DisplayProcessor\"\nimport {gallerySyncService} from \"./services/asg/gallerySyncService\"\nimport {glasses} from \"./facades/glasses\"\nimport {display} from \"./facades/display\"\nimport {speech} from \"./facades/speech\"\nimport {ai} from \"./facades/ai\"\nimport {session} from \"./facades/session\"\nimport {settings} from \"./facades/settings\"\nimport {dev} from \"./facades/dev\"\nimport {reports} from \"./facades/reports\"\nimport {ota} from \"./facades/ota\"\nimport {gallery} from \"./facades/gallery\"\nimport {miniapps} from \"./facades/miniapps\"\nimport {pairing} from \"./facades/pairing\"\nimport {phoneNotifications} from \"./facades/phoneNotifications\"\nimport {permissions} from \"./facades/permissions\"\nimport {notifications} from \"./facades/notifications\"\nimport {maps} from \"./facades/maps\"\nimport {memory} from \"./facades/memory\"\nimport {backup} from \"./facades/backup\"\nimport {speakers} from \"./facades/speakers\"\nimport {providerKeys} from \"./facades/providerKeys\"\nimport {logBuffer} from \"./utils/devLogging\"\nimport pageHost from \"./services/pages/PageHost\"\nimport gestureDotsService from \"./services/GestureDotsService\"\n\nexport const engine = {\n /** Front door — hand engine auth + config, then start/stop the runtime. */\n configure,\n /** Merge host-UI seams on a running runtime (scan overlay, wifi setup, …). */\n updateUiSeams,\n /** Start the runtime: mark started + construct/connect the cloud client + begin\n * syncing device settings to the glasses. */\n async start() {\n // Reports attach recent phone logs, so engine owns console interception for\n // OEM hosts too. Idempotent; the Glassly host may start it earlier.\n logBuffer.startConsoleInterception()\n await bootstrapStart()\n // Construct + connect the cloud client so the documented configure()+start()\n // lifecycle yields a live engine.session for OEMs. Idempotent for repeated\n // start() calls.\n cloudClientService.init()\n // Project native device status -> the engine stores (the inbound feed the rest\n // of the runtime reads). Established first so the stores are live before the\n // syncs below react to them.\n startGlassesStatusProjection((changed) => localMiniappRuntime.forwardEvent(\"glasses_connection_state\", changed))\n // Lock + foreground state, read by the dashboard's notification gate and\n // the G2 notification ctrl below; up before either consumer.\n startPhoneActivityTracking()\n // The overlay slot's owner: the designated dashboard miniapp's page shows\n // through it (ADR-0006), so it is up before the miniapp runtime.\n pageHost.start()\n gestureDotsService.start()\n // Route the rest of the inbound device events (wifi/hotspot/gallery -> stores+bus,\n // photo/stream -> coordinators, button/touch/accel/head -> miniapps, save_setting ->\n // store, miniapp_selected -> launcher) so a bare OEM gets device data, not just the\n // Glassly app's MantleManager.\n startDeviceEventRouter()\n // Hydration contract: the native DeviceStore is in-memory and starts empty\n // every launch; seed it from the persisted settings BEFORE start() resolves\n // so every post-start getDefaultDevice() read is a trustworthy two-state\n // answer (no false \"absent\" for genuinely-paired users at cold start).\n // Ordered before startGlassesSettingsSync so the settings load can't\n // double-push through the change subscription. A failed hydration must not\n // brick the runtime: start() continues, and the guards that consume\n // hasDefaultDevice() see the rejection and fail open.\n try {\n await hydrateDeviceStore()\n // Boot repair: a persisted default_wearable without a native default\n // device (identity abandoned mid-pairing, or resurrected from the server\n // before identity stopped syncing) demotes to pending_wearable so hosts\n // render finish-pairing instead of a connect that would throw.\n await demoteOrphanedDefaultWearable()\n } catch (error) {\n console.warn(\"engine.start: device-store hydration failed:\", error instanceof Error ? error.message : error)\n }\n // After the settings load so an already-paired phone latches on this start.\n startPairedGlassesLatch()\n // Pause local miniapps while the paired glasses stay disconnected. Reads\n // the pairing identity, so after the settings load like the latch.\n startMiniappPauseCoordinator()\n // iOS relaunched the app in the background to hand back a preserved glasses link:\n // no screen will ask to connect, so the engine does. Not awaited; start() must not\n // wait on a BLE handshake.\n void reconnectAfterBluetoothRestoreLaunch({\n launchedForRestore: nativeRestoreLaunchQuery(),\n connectDefault: () => glasses.connectDefault(),\n })\n // Project the glasses' OTA events into the store for the engine.ota read surface.\n startOtaService()\n // Forward glasses mic_lc3 frames to the v2 cloud session so cloud transcription\n // works for any host (not just the Glassly app's host-side MantleManager fork).\n startAudioCloudUplink()\n // Phone -> Soniox direct transcription (user-supplied API key). Started\n // after device-store hydration so the persisted key is already loaded.\n sonioxDirectService.start()\n // Not awaited: the exchange behind it is a Core round trip with no client\n // deadline, and start() must resolve offline. The glasses get the token\n // when it lands; identity resolution joins the same single-flight exchange.\n void cloudClientService.syncCoreTokenToBluetooth().catch((error) => {\n console.warn(\n \"engine.start: initial Cloud core token sync failed:\",\n error instanceof Error ? error.message : error,\n )\n })\n startSupportProfileSync()\n // Push device-setting changes to the glasses for ANY host, so\n // engine.glasses.settings.set() reaches the device (not just the Glassly app).\n startGlassesSettingsSync()\n // Same for phone-notification config -> the native listener (Android).\n startPhoneNotificationsSync()\n // On-device speaker identification: sync the enabled setting + enrolled\n // profile centroids to the native SpeakerIdEngine, and start the resolver\n // that annotates cloud transcripts with resolved speaker identities.\n startSpeakerIdSync()\n // Meta Neural Band: push the air mouse and wearing-hand settings to the band on connect.\n startNeuralBandSettingsSync()\n // Watch remote (Apple Watch on iOS, Wear OS on Android): status and mirror frames out, wrist commands in.\n startWatchLink()\n // Android internal/e2e: laptop captions tester can broadcast a failure intent;\n // engine owns turning that into a Cloud report.\n startCaptionsTesterReportService()\n // JSRuntime crashloop-disabled is runtime state; engine owns filing the\n // automatic report while hosts only render alert/telemetry side effects.\n startJSCrashloopReportService()\n // Bring up the local-miniapp engine so a bare OEM can run JSRuntime miniapps:\n // the LocalMiniappRuntime (registry + WebView bridge), the JSRuntime router\n // (crust-bound spawn/dispatch pump + launcher wiring), the DisplayProcessor\n // (layout arbitration over the engine stores), and the gallery-sync service.\n // All idempotent — when the Glassly app's host bootstrap also calls these, the\n // second call is a no-op. Host-only crashloop telemetry is attached\n // separately by the Glassly app.\n localMiniappRuntime.initialize()\n ensureMiniappEngine()\n displayProcessor.attachToRuntime()\n gallerySyncService.initialize()\n },\n /** Stop the runtime: tear down the settings sync + cloud client + mark stopped.\n * Each step is guarded so one failing teardown can't skip the rest and leak\n * the remaining runtime services. */\n async stop() {\n const safely = async (label: string, step: () => unknown): Promise<void> => {\n try {\n await step()\n } catch (error) {\n console.warn(`engine.stop: ${label} failed:`, error)\n }\n }\n await safely(\"glasses settings sync\", stopGlassesSettingsSync)\n await safely(\"paired glasses latch\", stopPairedGlassesLatch)\n await safely(\"miniapp pause coordinator\", stopMiniappPauseCoordinator)\n await safely(\"glasses status projection\", stopGlassesStatusProjection)\n await safely(\"device event router\", stopDeviceEventRouter)\n await safely(\"page host\", () => pageHost.stop())\n await safely(\"gesture dots service\", () => gestureDotsService.stop())\n await safely(\"ota service\", stopOtaService)\n await safely(\"audio cloud uplink\", stopAudioCloudUplink)\n await safely(\"soniox direct service\", () => sonioxDirectService.stop())\n await safely(\"support profile sync\", stopSupportProfileSync)\n await safely(\"phone notifications sync\", stopPhoneNotificationsSync)\n await safely(\"phone activity tracking\", stopPhoneActivityTracking)\n await safely(\"speaker id sync\", stopSpeakerIdSync)\n await safely(\"neural band settings sync\", stopNeuralBandSettingsSync)\n await safely(\"watch link\", stopWatchLink)\n await safely(\"captions tester report service\", stopCaptionsTesterReportService)\n await safely(\"js crashloop report service\", stopJSCrashloopReportService)\n await safely(\"miniapp engine\", stopMiniappEngine)\n await safely(\"local miniapp runtime\", () => localMiniappRuntime.cleanup())\n await safely(\"display processor\", () => displayProcessor.detachFromRuntime())\n await safely(\"gallery sync service\", () => gallerySyncService.cleanup())\n await safely(\"cloud client\", () => cloudClientService.shutdown())\n await safely(\"bootstrap\", bootstrapStop)\n },\n glasses,\n speech,\n /** On-device LLM model management (Settings > Offline Models). */\n ai,\n /** Cloud live-session status + account ops — engine owns the client. */\n session,\n /** Typed keyed user settings over the engine-owned settings store. */\n settings,\n /** Developer/debug surface (backend+cloud URL overrides, reconnect, min version). */\n dev,\n /** Bug-report, automatic runtime report, and feedback submission. */\n reports,\n /** Firmware OTA read/observe surface (updateAvailable/status + on* subscriptions). */\n ota,\n /** Gallery sync: status/onStatus · onNotice (host renders) · sync/cancel. */\n gallery,\n /** Miniapp lifecycle (the WebView bridge primitives are exported separately). */\n miniapps,\n /** First-time glasses discovery + pairing. */\n pairing,\n /** Phone→glasses notification forwarding (Android). */\n phoneNotifications,\n /** OS permissions (check/request/openSettings + per-miniapp requirements). */\n permissions,\n /** Inbound alerts engine→host (crashloop, version-incompatible, connection loss). */\n notifications,\n /** Maps providers — user-supplied Mapbox access token (Settings > Keys). */\n maps,\n /** Shared user-scoped memory timeline (Settings > Memory + session.memory). */\n memory,\n /** Whole-app backup file: settings, miniapp storage, installed list, memory (Settings > Profile). */\n backup,\n /** Device-local voice profiles for on-device speaker ID (Settings > Speakers). */\n speakers,\n /** AI/voice provider key validation — user-supplied keys (Settings > API Keys). */\n providerKeys,\n display,\n}\n"]}
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `engine` — the namespaced OEM-facing engine API (the \"(A) host API\" from the\n * Phase-1 contract). Host UI calls `engine.<domain>.<method>()`; each domain is a\n * typed facade over the runtime. (Exported from the `@glassly/engine` module, whose\n * name stays `engine` in code; the public API surface is `engine`.)\n *\n * It grows one facade at a time. The migration-era flat store/service exports\n * remain in a private Glassly host package; they shrink as screens move onto\n * `engine.*`.\n */\nimport {configure, start as bootstrapStart, stop as bootstrapStop, updateUiSeams} from \"./runtime/bootstrap\"\nimport {cloudClientService} from \"./services/CloudClientService\"\nimport {hydrateDeviceStore, demoteOrphanedDefaultWearable} from \"./services/DeviceStoreHydration\"\nimport {startPairedGlassesLatch, stopPairedGlassesLatch} from \"./services/PairedGlassesLatch\"\nimport {startMiniappPauseCoordinator, stopMiniappPauseCoordinator} from \"./services/MiniappPauseCoordinator\"\nimport {nativeRestoreLaunchQuery, reconnectAfterBluetoothRestoreLaunch} from \"./services/BluetoothRestoreLaunch\"\nimport {startGlassesSettingsSync, stopGlassesSettingsSync} from \"./services/GlassesSettingsSync\"\nimport {startGlassesStatusProjection, stopGlassesStatusProjection} from \"./services/GlassesStatusProjection\"\nimport {startOtaService, stopOtaService} from \"./services/OtaService\"\nimport {startAudioCloudUplink, stopAudioCloudUplink} from \"./services/AudioCloudUplink\"\nimport sonioxDirectService from \"./services/soniox/SonioxDirectService\"\nimport {startSupportProfileSync, stopSupportProfileSync} from \"./services/SupportProfileSync\"\nimport {startDeviceEventRouter, stopDeviceEventRouter} from \"./services/DeviceEventRouter\"\nimport {startPhoneActivityTracking, stopPhoneActivityTracking} from \"./services/PhoneActivity\"\nimport {startPhoneNotificationsSync, stopPhoneNotificationsSync} from \"./services/PhoneNotificationsSync\"\nimport {startSpeakerIdSync, stopSpeakerIdSync} from \"./services/SpeakerIdSync\"\nimport {startNeuralBandSettingsSync, stopNeuralBandSettingsSync} from \"./services/neuralBand/NeuralBandSettingsSync\"\nimport {startWatchLink, stopWatchLink} from \"./services/watch/WatchLink\"\nimport {startCaptionsTesterReportService, stopCaptionsTesterReportService} from \"./services/CaptionsTesterReportService\"\nimport {startJSCrashloopReportService, stopJSCrashloopReportService} from \"./services/JSCrashloopReportService\"\nimport {ensureMiniappEngine, stopMiniappEngine} from \"./services/MiniappEngine\"\nimport localMiniappRuntime from \"./services/LocalMiniappRuntime\"\nimport displayProcessor from \"./services/DisplayProcessor\"\nimport {gallerySyncService} from \"./services/asg/gallerySyncService\"\nimport {glasses} from \"./facades/glasses\"\nimport {display} from \"./facades/display\"\nimport {speech} from \"./facades/speech\"\nimport {ai} from \"./facades/ai\"\nimport {session} from \"./facades/session\"\nimport {settings} from \"./facades/settings\"\nimport {dev} from \"./facades/dev\"\nimport {reports} from \"./facades/reports\"\nimport {ota} from \"./facades/ota\"\nimport {gallery} from \"./facades/gallery\"\nimport {miniapps} from \"./facades/miniapps\"\nimport {pairing} from \"./facades/pairing\"\nimport {phoneNotifications} from \"./facades/phoneNotifications\"\nimport {permissions} from \"./facades/permissions\"\nimport {notifications} from \"./facades/notifications\"\nimport {maps} from \"./facades/maps\"\nimport {memory} from \"./facades/memory\"\nimport {backup} from \"./facades/backup\"\nimport {speakers} from \"./facades/speakers\"\nimport {providerKeys} from \"./facades/providerKeys\"\nimport {logBuffer} from \"./utils/devLogging\"\nimport pageHost from \"./services/pages/PageHost\"\nimport gestureDotsService from \"./services/GestureDotsService\"\n\nexport const engine = {\n /** Front door — hand engine auth + config, then start/stop the runtime. */\n configure,\n /** Merge host-UI seams on a running runtime (scan overlay, wifi setup, …). */\n updateUiSeams,\n /** Start the runtime: mark started + construct/connect the cloud client + begin\n * syncing device settings to the glasses. */\n async start() {\n // Reports attach recent phone logs, so engine owns console interception for\n // OEM hosts too. Idempotent; the Glassly host may start it earlier.\n logBuffer.startConsoleInterception()\n await bootstrapStart()\n // Construct + connect the cloud client so the documented configure()+start()\n // lifecycle yields a live engine.session for OEMs. Idempotent for repeated\n // start() calls.\n cloudClientService.init()\n // Project native device status -> the engine stores (the inbound feed the rest\n // of the runtime reads). Established first so the stores are live before the\n // syncs below react to them.\n startGlassesStatusProjection((changed) => localMiniappRuntime.forwardEvent(\"glasses_connection_state\", changed))\n // Lock + foreground state, read by the dashboard's notification gate and\n // the G2 notification ctrl below; up before either consumer.\n startPhoneActivityTracking()\n // The overlay slot's owner: the designated dashboard miniapp's page shows\n // through it (ADR-0006), so it is up before the miniapp runtime.\n pageHost.start()\n gestureDotsService.start()\n // Route the rest of the inbound device events (wifi/hotspot/gallery -> stores+bus,\n // photo/stream -> coordinators, button/touch/accel/head -> miniapps, save_setting ->\n // store, miniapp_selected -> launcher) so a bare OEM gets device data, not just the\n // Glassly app's MantleManager.\n startDeviceEventRouter()\n // Hydration contract: the native DeviceStore is in-memory and starts empty\n // every launch; seed it from the persisted settings BEFORE start() resolves\n // so every post-start getDefaultDevice() read is a trustworthy two-state\n // answer (no false \"absent\" for genuinely-paired users at cold start).\n // Ordered before startGlassesSettingsSync so the settings load can't\n // double-push through the change subscription. A failed hydration must not\n // brick the runtime: start() continues, and the guards that consume\n // hasDefaultDevice() see the rejection and fail open.\n try {\n await hydrateDeviceStore()\n // Boot repair: a persisted default_wearable without a native default\n // device (identity abandoned mid-pairing, or resurrected from the server\n // before identity stopped syncing) demotes to pending_wearable so hosts\n // render finish-pairing instead of a connect that would throw.\n await demoteOrphanedDefaultWearable()\n } catch (error) {\n console.warn(\"engine.start: device-store hydration failed:\", error instanceof Error ? error.message : error)\n }\n // After the settings load so an already-paired phone latches on this start.\n startPairedGlassesLatch()\n // Pause local miniapps while the paired glasses stay disconnected. Reads\n // the pairing identity, so after the settings load like the latch.\n startMiniappPauseCoordinator()\n // iOS relaunched the app in the background to hand back a preserved glasses link:\n // no screen will ask to connect, so the engine does. Not awaited; start() must not\n // wait on a BLE handshake.\n void reconnectAfterBluetoothRestoreLaunch({\n launchedForRestore: nativeRestoreLaunchQuery(),\n connectDefault: () => glasses.connectDefault(),\n })\n // Project the glasses' OTA events into the store for the engine.ota read surface.\n startOtaService()\n // Forward glasses mic_lc3 frames to the v2 cloud session so cloud transcription\n // works for any host (not just the Glassly app's host-side MantleManager fork).\n startAudioCloudUplink()\n // Phone -> Soniox direct transcription (user-supplied API key). Started\n // after device-store hydration so the persisted key is already loaded.\n sonioxDirectService.start()\n // Not awaited: the exchange behind it is a Core round trip with no client\n // deadline, and start() must resolve offline. The glasses get the token\n // when it lands; identity resolution joins the same single-flight exchange.\n if (!cloudClientService.isCloudDisabled()) {\n void cloudClientService.syncCoreTokenToBluetooth().catch((error) => {\n console.warn(\n \"engine.start: initial Cloud core token sync failed:\",\n error instanceof Error ? error.message : error,\n )\n })\n }\n startSupportProfileSync()\n // Push device-setting changes to the glasses for ANY host, so\n // engine.glasses.settings.set() reaches the device (not just the Glassly app).\n startGlassesSettingsSync()\n // Same for phone-notification config -> the native listener (Android).\n startPhoneNotificationsSync()\n // On-device speaker identification: sync the enabled setting + enrolled\n // profile centroids to the native SpeakerIdEngine, and start the resolver\n // that annotates cloud transcripts with resolved speaker identities.\n startSpeakerIdSync()\n // Meta Neural Band: push the air mouse and wearing-hand settings to the band on connect.\n startNeuralBandSettingsSync()\n // Watch remote (Apple Watch on iOS, Wear OS on Android): status and mirror frames out, wrist commands in.\n startWatchLink()\n // Android internal/e2e: laptop captions tester can broadcast a failure intent;\n // engine owns turning that into a Cloud report.\n startCaptionsTesterReportService()\n // JSRuntime crashloop-disabled is runtime state; engine owns filing the\n // automatic report while hosts only render alert/telemetry side effects.\n startJSCrashloopReportService()\n // Bring up the local-miniapp engine so a bare OEM can run JSRuntime miniapps:\n // the LocalMiniappRuntime (registry + WebView bridge), the JSRuntime router\n // (crust-bound spawn/dispatch pump + launcher wiring), the DisplayProcessor\n // (layout arbitration over the engine stores), and the gallery-sync service.\n // All idempotent — when the Glassly app's host bootstrap also calls these, the\n // second call is a no-op. Host-only crashloop telemetry is attached\n // separately by the Glassly app.\n localMiniappRuntime.initialize()\n ensureMiniappEngine()\n displayProcessor.attachToRuntime()\n gallerySyncService.initialize()\n },\n /** Stop the runtime: tear down the settings sync + cloud client + mark stopped.\n * Each step is guarded so one failing teardown can't skip the rest and leak\n * the remaining runtime services. */\n async stop() {\n const safely = async (label: string, step: () => unknown): Promise<void> => {\n try {\n await step()\n } catch (error) {\n console.warn(`engine.stop: ${label} failed:`, error)\n }\n }\n await safely(\"glasses settings sync\", stopGlassesSettingsSync)\n await safely(\"paired glasses latch\", stopPairedGlassesLatch)\n await safely(\"miniapp pause coordinator\", stopMiniappPauseCoordinator)\n await safely(\"glasses status projection\", stopGlassesStatusProjection)\n await safely(\"device event router\", stopDeviceEventRouter)\n await safely(\"page host\", () => pageHost.stop())\n await safely(\"gesture dots service\", () => gestureDotsService.stop())\n await safely(\"ota service\", stopOtaService)\n await safely(\"audio cloud uplink\", stopAudioCloudUplink)\n await safely(\"soniox direct service\", () => sonioxDirectService.stop())\n await safely(\"support profile sync\", stopSupportProfileSync)\n await safely(\"phone notifications sync\", stopPhoneNotificationsSync)\n await safely(\"phone activity tracking\", stopPhoneActivityTracking)\n await safely(\"speaker id sync\", stopSpeakerIdSync)\n await safely(\"neural band settings sync\", stopNeuralBandSettingsSync)\n await safely(\"watch link\", stopWatchLink)\n await safely(\"captions tester report service\", stopCaptionsTesterReportService)\n await safely(\"js crashloop report service\", stopJSCrashloopReportService)\n await safely(\"miniapp engine\", stopMiniappEngine)\n await safely(\"local miniapp runtime\", () => localMiniappRuntime.cleanup())\n await safely(\"display processor\", () => displayProcessor.detachFromRuntime())\n await safely(\"gallery sync service\", () => gallerySyncService.cleanup())\n await safely(\"cloud client\", () => cloudClientService.shutdown())\n await safely(\"bootstrap\", bootstrapStop)\n },\n glasses,\n speech,\n /** On-device LLM model management (Settings > Offline Models). */\n ai,\n /** Cloud live-session status + account ops — engine owns the client. */\n session,\n /** Typed keyed user settings over the engine-owned settings store. */\n settings,\n /** Developer/debug surface (backend+cloud URL overrides, reconnect, min version). */\n dev,\n /** Bug-report, automatic runtime report, and feedback submission. */\n reports,\n /** Firmware OTA read/observe surface (updateAvailable/status + on* subscriptions). */\n ota,\n /** Gallery sync: status/onStatus · onNotice (host renders) · sync/cancel. */\n gallery,\n /** Miniapp lifecycle (the WebView bridge primitives are exported separately). */\n miniapps,\n /** First-time glasses discovery + pairing. */\n pairing,\n /** Phone→glasses notification forwarding (Android). */\n phoneNotifications,\n /** OS permissions (check/request/openSettings + per-miniapp requirements). */\n permissions,\n /** Inbound alerts engine→host (crashloop, version-incompatible, connection loss). */\n notifications,\n /** Maps providers — user-supplied Mapbox access token (Settings > Keys). */\n maps,\n /** Shared user-scoped memory timeline (Settings > Memory + session.memory). */\n memory,\n /** Whole-app backup file: settings, miniapp storage, installed list, memory (Settings > Profile). */\n backup,\n /** Device-local voice profiles for on-device speaker ID (Settings > Speakers). */\n speakers,\n /** AI/voice provider key validation — user-supplied keys (Settings > API Keys). */\n providerKeys,\n display,\n}\n"]}
@@ -1,9 +1,9 @@
1
1
  export const ENGINE_RELEASE_METADATA = Object.freeze({
2
2
  "schemaVersion": 1,
3
3
  "familyBaseVersion": "0.4.0",
4
- "releaseIdentity": "0.4.0-dev.1029",
5
- "releaseSetId": "glassly-0.4.0-dev.1029",
6
- "sourceCommit": "d166c3bc3c30f7c5ef90313ce0156b14ee51a127",
4
+ "releaseIdentity": "0.4.0-dev.1030",
5
+ "releaseSetId": "glassly-0.4.0-dev.1030",
6
+ "sourceCommit": "5f4d8792ed56abb1483e8353e3c7aca1d5e66fd7",
7
7
  "otaManifestUrl": null,
8
8
  "otaManifestSha256": null
9
9
  });
@@ -1 +1 @@
1
- {"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,uBAAuB,GAAoC,MAAM,CAAC,MAAM,CAAC;IACpF,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,gBAAgB;IACnC,cAAc,EAAE,wBAAwB;IACxC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,IAAI;IACtB,mBAAmB,EAAE,IAAI;CAC1B,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface EngineReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const ENGINE_RELEASE_METADATA: Readonly<EngineReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"0.4.0\",\n \"releaseIdentity\": \"0.4.0-dev.1029\",\n \"releaseSetId\": \"glassly-0.4.0-dev.1029\",\n \"sourceCommit\": \"d166c3bc3c30f7c5ef90313ce0156b14ee51a127\",\n \"otaManifestUrl\": null,\n \"otaManifestSha256\": null\n})\n"]}
1
+ {"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,uBAAuB,GAAoC,MAAM,CAAC,MAAM,CAAC;IACpF,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,gBAAgB;IACnC,cAAc,EAAE,wBAAwB;IACxC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,IAAI;IACtB,mBAAmB,EAAE,IAAI;CAC1B,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface EngineReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const ENGINE_RELEASE_METADATA: Readonly<EngineReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"0.4.0\",\n \"releaseIdentity\": \"0.4.0-dev.1030\",\n \"releaseSetId\": \"glassly-0.4.0-dev.1030\",\n \"sourceCommit\": \"5f4d8792ed56abb1483e8353e3c7aca1d5e66fd7\",\n \"otaManifestUrl\": null,\n \"otaManifestSha256\": null\n})\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"CloudClientService.d.ts","sourceRoot":"","sources":["../../src/services/CloudClientService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CloudClientService.d.ts","sourceRoot":"","sources":["../../src/services/CloudClientService.ts"],"names":[],"mappings":"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"}
@@ -161,10 +161,17 @@ function resolveEndpoints() {
161
161
  runtime: cfg.runtimeUrl?.trim() || FALLBACK_RUNTIME_URL,
162
162
  };
163
163
  }
164
- function getCoreClient() {
164
+ // Via init(), never construct(): init() holds the disable-cloud gate, and a
165
+ // client built past it opens the runtime socket and retries it forever.
166
+ function requireClient() {
165
167
  if (!client)
166
- construct();
167
- const core = client?.core;
168
+ cloudClientService.init();
169
+ if (!client)
170
+ throw new Error("Glassly cloud is disabled");
171
+ return client;
172
+ }
173
+ function getCoreClient() {
174
+ const core = requireClient().core;
168
175
  if (!core)
169
176
  throw new Error("cloud client core not configured");
170
177
  return core;
@@ -178,11 +185,7 @@ function syncCoreAccessTokenToBluetooth() {
178
185
  return coreTokenSyncPromise;
179
186
  }
180
187
  async function syncCoreAccessTokenToBluetoothInternal() {
181
- if (!client)
182
- construct();
183
- const c = client;
184
- if (!c)
185
- throw new Error("cloud client not initialized");
188
+ const c = requireClient();
186
189
  const token = await c.auth.getCoreToken();
187
190
  if (c !== client) {
188
191
  throw new Error("cloud client changed while syncing core token");
@@ -1 +1 @@
1
- {"version":3,"file":"CloudClientService.js","sourceRoot":"","sources":["../../src/services/CloudClientService.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Owns the singleton `@glassly/cloud-client` (CloudClient) for the engine runtime\n * — the keystone move that pulls backend comms INTO engine.\n *\n * engine constructs the client from engine-owned pieces (the native UDP socket,\n * the MMKV secure store, the cloud-status store) plus the two things the host\n * provides through the engine front door: `auth.getSubjectToken` (the one\n * permanent seam — the OEM owns login) and the resolved cloud endpoints\n * (`config.coreUrl/runtimeUrl`, computed host-side from dev/settings). On init it\n * exposes cloud runtime methods directly from this service, so the host no longer\n * injects a cloud adapter — engine owns construction and wiring.\n *\n * The local-miniapp path drives the cloud's transcription/translation through\n * this service.\n */\nimport {CloudClient, setNativeHttp, setNativeUdp, setSecureStorage} from \"@glassly/cloud-client/react-native\"\nimport type {\n PreinstalledMiniappRegistry,\n RuntimeSnapshot,\n StoreCatalogResponse,\n StoreListing,\n StoreReleasesResponse,\n} from \"@glassly/cloud-client/react-native\"\nimport type {SubjectTokenType} from \"@glassly/cloud-client\"\nimport {AppState, Platform} from \"react-native\"\nimport type {AudioSubscription, QuotaStatusPayload, TranscriptionData, TranslationData} from \"@glassly/cloud-protocol\"\n\nimport BluetoothSdk from \"@glassly/bluetooth-sdk/internal\"\nimport CrustModule from \"@glassly/crust\"\nimport {getAuth, getConfigValues} from \"../runtime/bootstrap\"\nimport {useSettingsStore, SETTINGS} from \"../stores/settings\"\nimport {type CloudClientStatusSnapshot, type MiniappAuthToken} from \"../runtime/config\"\nimport {createCloudUdpSocket} from \"../utils/cloudClient/RnUdpAdapter\"\nimport {cloudSecureStore} from \"../utils/cloudClient/cloudSecureStore\"\nimport {storage as mmkvStorage} from \"../utils/storage\"\nimport {useCloudClientStatusStore} from \"../stores/cloudClientStatus\"\nimport {islandNotifications} from \"./NotificationsEmitter\"\nimport {BgTimer} from \"../utils/timers\"\nimport {logCloudTranscriptMetric} from \"./CloudTranscriptE2EMetrics\"\nimport {isLocalUserId, LocalMiniappUserIdentity} from \"./LocalMiniappUserIdentity\"\nimport {migrateLocalMiniappData, type LocalMiniappDataMigrationBackend} from \"./LocalMiniappDataMigration\"\nimport {nativeHttpResponseBody} from \"./NativeHttpResponse\"\n\nconst LOG_TAG = \"cloudClient\"\ntype CloudCore = NonNullable<CloudClient[\"core\"]>\n\n// Persistent cloud-disconnect detector: the cloud-client reconnect loop is infinite\n// and never surfaces a \"giving up\" signal, so \"persistent failure\" = the session has\n// been continuously NOT connected for this long. A quick reconnect cancels it; brief\n// flaps that recover don't fire. Raised as engine.notifications(connection_failed_persistent).\nconst CLOUD_PERSISTENT_FAILURE_MS = 60_000\nconst LOCAL_MINIAPP_USER_ID_KEY = \"glassly.localMiniapp.userId\"\n\n/** Cancel the pending persistent-failure alarm + re-arm for the next outage. */\nfunction clearPersistentFailureAlarm(): void {\n if (persistentFailureTimer) {\n BgTimer.clearTimeout(persistentFailureTimer)\n persistentFailureTimer = null\n }\n persistentFailureNotified = false\n}\n\ntype Lc3FrameSizeBytes = 20 | 40 | 60\n\n// Neutral last-ditch fallbacks (reachable under `adb reverse`) for when the host\n// passes no endpoints. The host normally resolves the real URLs (dev override /\n// Metro host / env) and hands them in via `engine.configure({config})`.\nconst FALLBACK_CORE_URL = \"http://localhost:3000\"\nconst FALLBACK_RUNTIME_URL = \"http://localhost:3001\"\nconst LOCAL_AUTH_PORT = 3002\n\nlet client: CloudClient | null = null\nlet connected = false\n/** The cloud closed us for a newer socket; the client stays down until reconnect(). */\nlet superseded = false\nlet persistentFailureTimer: ReturnType<typeof BgTimer.setTimeout> | null = null\nlet persistentFailureNotified = false\nlet audioSubscriptions: AudioSubscription[] = []\nlet transportsReady = false\n/** Endpoints to build with — seeded from config, overridable via reconnect(). */\nlet endpointsOverride: {core: string; runtime: string} | null = null\nlet runtimeStatusUnsubscribe: (() => void) | null = null\nlet transcriptUnsubscribe: (() => void) | null = null\nlet translationUnsubscribe: (() => void) | null = null\nlet quotaUnsubscribe: (() => void) | null = null\nlet authStateUnsubscribe: (() => void) | null = null\nlet localDevRuntimeToken: {runtimeUrl: string; token: string; expiresAtMs: number} | null = null\nlet lc3FrameSizeUnsubscribe: (() => void) | null = null\nlet disableCloudUnsubscribe: (() => void) | null = null\nlet foregroundUnsubscribe: (() => void) | null = null\nlet coreTokenSyncPromise: Promise<string> | null = null\n/**\n * A device-local namespace (`local_…`) whose data still needs to be adopted\n * into the account namespace. Set when a sign-in displaces a local id; cleared\n * once {@link adoptLocalNamespace} has moved the data.\n */\nlet pendingLocalNamespace: string | null = null\n\n/**\n * Moves blob bytes between user directories during namespace adoption.\n * Registered by LocalMiniappRuntime (which owns the BlobStore instance) so this\n * service doesn't import it and create a cycle. Absent in tests / before the\n * runtime boots, in which case only the key-value stores migrate.\n */\ntype BlobNamespaceMigrator = (fromUserId: string, toUserId: string) => {moved: number; skipped: number}\nlet blobNamespaceMigrator: BlobNamespaceMigrator | null = null\n\n/**\n * Register the blob-bytes half of namespace adoption. Called by\n * LocalMiniappRuntime at construction — it owns the BlobStore instance, and\n * having it push the hook here keeps this service from importing the runtime.\n */\nexport function setBlobNamespaceMigrator(migrator: BlobNamespaceMigrator | null): void {\n blobNamespaceMigrator = migrator\n}\n\n/** Result-free view of MMKV, as the migration's plain get/set/remove/keys. */\nconst migrationBackend: LocalMiniappDataMigrationBackend = {\n get(key: string): unknown | null {\n const result = mmkvStorage.load<unknown>(key)\n return result.is_ok() ? result.value : null\n },\n set(key: string, value: unknown): void {\n const result = mmkvStorage.save(key, value)\n if (result.is_error()) throw result.error\n },\n remove(key: string): void {\n const result = mmkvStorage.remove(key)\n if (result.is_error()) throw result.error\n },\n keys(): string[] {\n return mmkvStorage.getAllKeys()\n },\n}\n\n/**\n * Adopt data written under a device-local namespace into the signed-in\n * account's, so miniapp state created while cloud was disabled survives\n * sign-in. No-op unless a sign-in actually displaced a local id.\n */\nfunction adoptLocalNamespace(coreUserId: string): void {\n const from = pendingLocalNamespace\n if (!from) return\n // Clear first: a failure must not re-run on every subsequent resolve, and the\n // migration is idempotent anyway.\n pendingLocalNamespace = null\n if (!coreUserId || from === coreUserId) return\n\n try {\n const keys = migrateLocalMiniappData(migrationBackend, from, coreUserId)\n const blobs = blobNamespaceMigrator?.(from, coreUserId) ?? {moved: 0, skipped: 0}\n if (keys.moved || keys.skipped || blobs.moved || blobs.skipped) {\n console.log(\n `${LOG_TAG}: adopted local miniapp data into account namespace ` +\n `(keys ${keys.moved} moved/${keys.skipped} skipped, blobs ${blobs.moved} moved/${blobs.skipped} skipped)`,\n )\n }\n } catch (err) {\n console.warn(`${LOG_TAG}: local namespace adoption failed: ${(err as Error)?.message ?? err}`)\n }\n}\n\nconst localMiniappUserIdentity = new LocalMiniappUserIdentity({\n get(): string | null {\n const result = mmkvStorage.load<string>(LOCAL_MINIAPP_USER_ID_KEY)\n return result.is_ok() ? result.value : null\n },\n set(userId: string): void {\n const result = mmkvStorage.save(LOCAL_MINIAPP_USER_ID_KEY, userId)\n if (result.is_error()) throw result.error\n },\n remove(): void {\n const result = mmkvStorage.remove(LOCAL_MINIAPP_USER_ID_KEY)\n if (result.is_error()) throw result.error\n },\n})\n\nconst transcriptListeners = new Set<(d: TranscriptionData) => void>()\nconst translationListeners = new Set<(d: TranslationData) => void>()\nconst quotaListeners = new Set<(d: QuotaStatusPayload) => void>()\nconst statusListeners = new Set<(snapshot: CloudClientStatusSnapshot) => void>()\nconst connectionListeners = new Set<(connected: boolean) => void>()\n\nfunction resolveEndpoints(): {core: string; runtime: string} {\n if (endpointsOverride) return endpointsOverride\n const cfg = getConfigValues()\n return {\n core: cfg.coreUrl?.trim() || FALLBACK_CORE_URL,\n runtime: cfg.runtimeUrl?.trim() || FALLBACK_RUNTIME_URL,\n }\n}\n\nfunction getCoreClient(): CloudCore {\n if (!client) construct()\n const core = client?.core\n if (!core) throw new Error(\"cloud client core not configured\")\n return core\n}\n\nfunction syncCoreAccessTokenToBluetooth(): Promise<string> {\n if (coreTokenSyncPromise) return coreTokenSyncPromise\n\n coreTokenSyncPromise = syncCoreAccessTokenToBluetoothInternal().finally(() => {\n coreTokenSyncPromise = null\n })\n return coreTokenSyncPromise\n}\n\nasync function syncCoreAccessTokenToBluetoothInternal(): Promise<string> {\n if (!client) construct()\n const c = client\n if (!c) throw new Error(\"cloud client not initialized\")\n\n const token = await c.auth.getCoreToken()\n if (c !== client) {\n throw new Error(\"cloud client changed while syncing core token\")\n }\n adoptLocalNamespace(c.auth.identity.userId)\n localMiniappUserIdentity.remember(c.auth.identity.userId)\n const result = await useSettingsStore.getState().setSetting(SETTINGS.core_token.key, token, false)\n if (result.is_error()) {\n throw result.error\n }\n\n try {\n await BluetoothSdk.updateBluetoothSettings({[SETTINGS.core_token.key]: token})\n } catch (err) {\n console.warn(`${LOG_TAG}: direct Bluetooth core_token sync failed: ${(err as Error)?.message ?? err}`)\n }\n\n return token\n}\n\nfunction frameSizeBytes(): Lc3FrameSizeBytes {\n // Read LIVE from the engine settings store (the source of truth) so a\n // reconnect after a glasses swap (G1=20 ↔ G2=40) picks up the new frame size,\n // not the one-time engine.configure({config}) snapshot. Falls back to the\n // config value (set at boot) then 20 when the setting is unset.\n const fromSettings = useSettingsStore.getState().getSetting(SETTINGS.lc3_frame_size.key)\n const size = fromSettings ?? getConfigValues().audioFrameSizeBytes\n return size === 20 || size === 40 || size === 60 ? size : 20\n}\n\nasync function getSubjectToken(): Promise<{token: string; type: SubjectTokenType}> {\n const a = getAuth()\n if (!a) throw new Error(\"cloudClient: engine.configure({auth}) not called\")\n const r = await a.getSubjectToken()\n // IslandAuth's SubjectTokenType is intentionally open (`string & {}`) so OEMs\n // can use other token kinds; cloud-client's is a closed union. The host's\n // actual value (\"supabase\") is valid — narrow at this boundary.\n return {token: r.token, type: r.type as SubjectTokenType}\n}\n\nfunction normalizeExpiresAt(expiresAt: number): number {\n return expiresAt < 10_000_000_000 ? expiresAt * 1000 : expiresAt\n}\n\nfunction shouldUseLocalDevRuntimeToken(endpoints: {runtime: string}): boolean {\n if (!__DEV__) return false\n try {\n const host = new URL(endpoints.runtime).hostname\n return host === \"localhost\" || host === \"127.0.0.1\" || host === \"10.0.2.2\"\n } catch {\n return false\n }\n}\n\nasync function getLocalDevRuntimeToken(runtimeEndpoint: string, opts?: {forceRefresh?: boolean}): Promise<string> {\n const now = Date.now()\n if (\n !opts?.forceRefresh &&\n localDevRuntimeToken?.runtimeUrl === runtimeEndpoint &&\n localDevRuntimeToken.expiresAtMs - now > 60_000\n ) {\n return localDevRuntimeToken.token\n }\n\n const base = new URL(runtimeEndpoint)\n base.port = String(LOCAL_AUTH_PORT)\n base.pathname = \"/api/dev/runtime-token\"\n base.search = new URLSearchParams({userId: \"local-phone-user\", tenantId: \"glassly\"}).toString()\n\n const res = await fetch(base.toString())\n if (!res.ok) {\n throw new Error(`cloudClient: local dev runtime token failed (${res.status})`)\n }\n const body = (await res.json()) as {access_token?: string; expires_in?: number}\n if (!body.access_token) {\n throw new Error(\"cloudClient: local dev runtime token response missing access_token\")\n }\n localDevRuntimeToken = {\n runtimeUrl: runtimeEndpoint,\n token: body.access_token,\n expiresAtMs: now + (body.expires_in ?? 300) * 1000,\n }\n return body.access_token\n}\n\nfunction toCloudClientStatusSnapshot(snapshot: RuntimeSnapshot): CloudClientStatusSnapshot {\n return {status: snapshot.status, audioTransport: snapshot.audioTransport}\n}\n\nfunction currentRuntimeStatus(): CloudClientStatusSnapshot {\n const state = useCloudClientStatusStore.getState()\n return {status: state.status, audioTransport: state.audioTransport}\n}\n\nfunction setRuntimeStatus(snapshot: RuntimeSnapshot): void {\n useCloudClientStatusStore.getState().setSnapshot(snapshot)\n emitStatus(toCloudClientStatusSnapshot(snapshot))\n}\n\nfunction resetRuntimeStatus(): void {\n useCloudClientStatusStore.getState().reset()\n emitStatus(currentRuntimeStatus())\n}\n\nfunction stringifyMeta(meta: unknown): string {\n if (!meta || typeof meta !== \"object\") return \"\"\n try {\n return ` ${JSON.stringify(meta)}`\n } catch {\n return \"\"\n }\n}\n\nconst cloudLogger = {\n debug: (msg: string, meta?: unknown) => console.log(`${LOG_TAG}: debug: ${msg}${stringifyMeta(meta)}`),\n info: (msg: string, meta?: unknown) => console.log(`${LOG_TAG}: info: ${msg}${stringifyMeta(meta)}`),\n warn: (msg: string, meta?: unknown) => console.warn(`${LOG_TAG}: warn: ${msg}${stringifyMeta(meta)}`),\n error: (msg: string, meta?: unknown) => console.warn(`${LOG_TAG}: error: ${msg}${stringifyMeta(meta)}`),\n}\n\nfunction notifyConnectionListeners(next: boolean): void {\n for (const l of connectionListeners) {\n try {\n l(next)\n } catch (err) {\n console.warn(`${LOG_TAG}: connection listener threw: ${(err as Error)?.message ?? err}`)\n }\n }\n}\n\nfunction extractUnsubscribe(sub: unknown): (() => void) | null {\n const candidates: unknown[] = []\n const s = sub as Record<string, unknown> | null | undefined\n if (s && typeof s === \"object\") {\n candidates.push(s)\n candidates.push((s.value as Record<string, unknown>)?.subscription)\n candidates.push((s.data as Record<string, unknown>)?.subscription)\n candidates.push(s.subscription)\n }\n for (const c of candidates) {\n const unsub = (c as {unsubscribe?: unknown})?.unsubscribe\n if (typeof unsub === \"function\") return unsub as () => void\n }\n return null\n}\n\nfunction ensureAuthWatch(): void {\n if (authStateUnsubscribe) return\n authStateUnsubscribe = () => {}\n\n const auth = getAuth()\n if (!auth?.onStateChange) return\n\n let reconnectPending = false\n try {\n const sub = auth.onStateChange((event, session) => {\n if (event === \"SIGNED_OUT\") {\n localMiniappUserIdentity.forget()\n return\n }\n // A new sign-in may belong to a different account. Force the next\n // storage request to resolve and persist that account's Core identity.\n // A device-local namespace is remembered first so the data written while\n // cloud was off can follow the user into the account (see\n // adoptLocalNamespace).\n if (event === \"SIGNED_IN\") {\n const local = localMiniappUserIdentity.get()\n if (local && isLocalUserId(local)) pendingLocalNamespace = local\n localMiniappUserIdentity.forget()\n }\n if (!session?.token) return\n if (connected || reconnectPending) return\n\n reconnectPending = true\n console.log(`${LOG_TAG}: auth session available (${event}) while disconnected — reconnecting`)\n try {\n cloudClientService.reconnect()\n } finally {\n BgTimer.setTimeout(() => {\n reconnectPending = false\n }, 0)\n }\n })\n\n const unsub = extractUnsubscribe(sub)\n if (unsub) authStateUnsubscribe = unsub\n } catch (err) {\n console.warn(`${LOG_TAG}: auth watch subscribe failed: ${(err as Error)?.message ?? err}`)\n }\n}\n\nfunction stopAuthWatch(): void {\n authStateUnsubscribe?.()\n authStateUnsubscribe = null\n}\n\nfunction emitTranscript(data: TranscriptionData): void {\n for (const l of transcriptListeners) {\n try {\n l(data)\n } catch (err) {\n console.warn(`${LOG_TAG}: transcript listener threw: ${(err as Error)?.message ?? err}`)\n }\n }\n}\n\nfunction emitTranslation(data: TranslationData): void {\n for (const l of translationListeners) {\n try {\n l(data)\n } catch (err) {\n console.warn(`${LOG_TAG}: translation listener threw: ${(err as Error)?.message ?? err}`)\n }\n }\n}\n\nfunction emitQuota(data: QuotaStatusPayload): void {\n for (const l of quotaListeners) {\n try {\n l(data)\n } catch (err) {\n console.warn(`${LOG_TAG}: quota listener threw: ${(err as Error)?.message ?? err}`)\n }\n }\n}\n\nfunction emitStatus(snapshot: CloudClientStatusSnapshot): void {\n for (const l of statusListeners) {\n try {\n l(snapshot)\n } catch (err) {\n console.warn(`${LOG_TAG}: status listener threw: ${(err as Error)?.message ?? err}`)\n }\n }\n}\n\nfunction ensureTransports(): void {\n if (transportsReady) return\n transportsReady = true\n setNativeUdp(() => createCloudUdpSocket())\n setSecureStorage(cloudSecureStore)\n if (Platform.OS !== \"android\") return\n setNativeHttp(async (input, init) => {\n if (typeof input !== \"string\" || (init?.body != null && typeof init.body !== \"string\")) {\n return globalThis.fetch(input, init)\n }\n const headers = Object.fromEntries(new Headers(init?.headers).entries())\n const result = await CrustModule.nativeHttpRequest(\n init?.method ?? \"GET\",\n input,\n headers,\n (init?.body as string | undefined) ?? null,\n )\n return new Response(nativeHttpResponseBody(result.status, result.body), {\n status: result.status,\n statusText: result.statusText,\n headers: result.headers,\n })\n })\n}\n\nfunction clearRuntimeEventSubscriptions(): void {\n runtimeStatusUnsubscribe?.()\n runtimeStatusUnsubscribe = null\n transcriptUnsubscribe?.()\n transcriptUnsubscribe = null\n translationUnsubscribe?.()\n translationUnsubscribe = null\n quotaUnsubscribe?.()\n quotaUnsubscribe = null\n}\n\n/**\n * The user's hard \"never talk to Glassly cloud\" stance (Settings > Privacy).\n * Read imperatively at every would-be-connect point rather than cached, so\n * flipping the toggle takes effect without a restart. `=== true` because\n * getSetting is `any` and an unhydrated store must not read as \"disabled\".\n */\nfunction cloudDisabled(): boolean {\n return useSettingsStore.getState().getSetting(SETTINGS.disable_cloud.key) === true\n}\n\nfunction startLc3FrameSizeWatcher(): void {\n if (lc3FrameSizeUnsubscribe) return\n\n let last = frameSizeBytes()\n lc3FrameSizeUnsubscribe = useSettingsStore.subscribe(\n (state) => state.getSetting(SETTINGS.lc3_frame_size.key),\n () => {\n const next = frameSizeBytes()\n if (next === last) return\n last = next\n if (!client) return\n console.log(`${LOG_TAG}: LC3 frame size changed to ${next}; reconnecting runtime`)\n cloudClientService.reconnect()\n },\n )\n}\n\nfunction stopLc3FrameSizeWatcher(): void {\n lc3FrameSizeUnsubscribe?.()\n lc3FrameSizeUnsubscribe = null\n}\n\n/**\n * Reclaim a superseded session only on foreground: the user picked this phone\n * up, and a reclaim on any other signal would fight the newer socket.\n */\nfunction startForegroundWatcher(): void {\n if (foregroundUnsubscribe) return\n\n const subscription = AppState.addEventListener(\"change\", (state) => {\n if (state !== \"active\" || !superseded || !client) return\n console.log(`${LOG_TAG}: foregrounded after supersede; reconnecting runtime`)\n cloudClientService.reconnect()\n })\n foregroundUnsubscribe = () => subscription.remove()\n}\n\nfunction stopForegroundWatcher(): void {\n foregroundUnsubscribe?.()\n foregroundUnsubscribe = null\n}\n\n/**\n * Apply a mid-session flip of the Privacy toggle without a restart: turning it\n * on tears the live client down, turning it back off reconnects. Installed by\n * init() on BOTH branches — when cloud starts disabled there is no client to\n * hang the watcher off, but we still need to notice the user re-enabling it.\n */\nfunction startDisableCloudWatcher(): void {\n if (disableCloudUnsubscribe) return\n\n let last = cloudDisabled()\n disableCloudUnsubscribe = useSettingsStore.subscribe(\n (state) => state.getSetting(SETTINGS.disable_cloud.key),\n () => {\n const next = cloudDisabled()\n if (next === last) return\n last = next\n if (next) {\n console.log(`${LOG_TAG}: cloud disabled — tearing down client`)\n cloudClientService.stop()\n } else {\n console.log(`${LOG_TAG}: cloud re-enabled — reconnecting`)\n cloudClientService.init()\n }\n },\n )\n}\n\nfunction stopDisableCloudWatcher(): void {\n disableCloudUnsubscribe?.()\n disableCloudUnsubscribe = null\n}\n\nfunction construct(): void {\n ensureTransports()\n\n const endpoints = resolveEndpoints()\n console.log(`${LOG_TAG}: endpoints ${JSON.stringify(endpoints)}`)\n\n const coreAuth = {getSubjectToken}\n const auth = shouldUseLocalDevRuntimeToken(endpoints)\n ? {\n core: coreAuth,\n runtime: {getToken: (opts?: {forceRefresh?: boolean}) => getLocalDevRuntimeToken(endpoints.runtime, opts)},\n }\n : {core: coreAuth, runtime: {source: \"core\" as const}}\n\n client = new CloudClient({\n endpoints,\n // The phone LC3-encodes mic audio (even in phone/simulated mode); announce\n // LC3 at 16 kHz with the frame size the encoder emits.\n audio: {codec: \"lc3\", sampleRate: 16000, frameSizeBytes: frameSizeBytes()},\n auth,\n timers: {\n setTimeout: (callback, delayMs) => BgTimer.setTimeout(callback, delayMs),\n clearTimeout: (handle) => BgTimer.clearTimeout(handle as number),\n setInterval: (callback, intervalMs) => BgTimer.setInterval(callback, intervalMs),\n clearInterval: (handle) => BgTimer.clearInterval(handle as number),\n },\n logger: cloudLogger,\n })\n\n const c = client\n clearRuntimeEventSubscriptions()\n runtimeStatusUnsubscribe = c.runtime.onStatusChanged((status) => {\n if (c !== client) return\n setRuntimeStatus(status)\n })\n transcriptUnsubscribe = c.runtime.onTranscript((data) => {\n if (c !== client) return\n logCloudTranscriptMetric(data)\n emitTranscript(data)\n })\n translationUnsubscribe = c.runtime.onTranslation((data) => {\n if (c !== client) return\n emitTranslation(data)\n })\n quotaUnsubscribe = c.runtime.onQuota((data) => {\n if (c !== client) return\n emitQuota(data)\n })\n setRuntimeStatus(c.runtime.getStatus())\n\n c.runtime.onConnected(() => {\n if (c !== client) return\n connected = true\n superseded = false\n console.log(`${LOG_TAG}: runtime connected`)\n console.log(`${LOG_TAG}: debug: ws-session-debug connected`)\n // Cloud is up — cancel any pending persistent-failure alarm and re-arm for the\n // next outage.\n clearPersistentFailureAlarm()\n // Re-apply the authoritative subscription set, including the empty set, so\n // a fresh phone launch clears any stale server-side audio subscriptions.\n c.runtime\n .setSubscriptions(audioSubscriptions)\n .catch((err) =>\n console.warn(`${LOG_TAG}: re-applying queued subscriptions failed: ${(err as Error)?.message ?? err}`),\n )\n notifyConnectionListeners(true)\n })\n c.runtime.onDisconnected((info) => {\n if (c !== client) return\n connected = false\n superseded = /superseded by newer session/i.test(info.reason)\n console.log(`${LOG_TAG}: runtime disconnected (${info.reason})`)\n console.log(`${LOG_TAG}: debug: ws-session-debug disconnected reason=${info.reason} willStayDown=${superseded}`)\n // Arm the persistent-failure alarm once; if we're still down when it fires, raise\n // the notification. A reconnect within the window cancels it (onConnected above).\n if (!persistentFailureTimer && !persistentFailureNotified) {\n persistentFailureTimer = BgTimer.setTimeout(() => {\n persistentFailureTimer = null\n if (connected) return\n persistentFailureNotified = true\n islandNotifications.emit({\n kind: \"connection_failed_persistent\",\n reason: `Cloud session has been disconnected for over ${Math.round(CLOUD_PERSISTENT_FAILURE_MS / 1000)}s`,\n metadata: {downForMs: CLOUD_PERSISTENT_FAILURE_MS, lastReason: info.reason},\n timestamp: Date.now(),\n })\n }, CLOUD_PERSISTENT_FAILURE_MS)\n }\n notifyConnectionListeners(false)\n })\n c.runtime.onError((err) => {\n console.warn(`${LOG_TAG}: runtime error: ${err.code}`)\n })\n\n // Dead credentials (refresh AND subject exchange both failed). Surface to\n // the host so it can force a re-login — otherwise the app looks signed-in\n // while every cloud feature silently fails. Fires at most once per client\n // instance (the auth module latches until a successful exchange).\n c.auth.onExpired(() => {\n if (c !== client) return\n console.warn(`${LOG_TAG}: cloud session expired beyond recovery — notifying host`)\n getAuth()?.onSessionExpired?.()\n })\n\n // Best-effort connect. Do not crash the app if the dev cloud is unreachable.\n c.runtime\n .connect()\n .then(() => console.log(`${LOG_TAG}: connect() resolved`))\n .catch((err) => console.warn(`${LOG_TAG}: connect() failed: ${err?.message ?? err}`))\n\n syncCoreAccessTokenToBluetooth().catch((err) =>\n console.warn(`${LOG_TAG}: initial Bluetooth core_token sync failed: ${(err as Error)?.message ?? err}`),\n )\n\n startLc3FrameSizeWatcher()\n startForegroundWatcher()\n}\n\n/**\n * engine's cloud client. Owns the singleton CloudClient, its connection state,\n * and the runtime-hook wiring.\n */\nexport const cloudClientService = {\n /**\n * Construct (once) + connect the client. Idempotent. Best-effort connect — a\n * failure is logged and the app keeps running. Requires\n * `engine.configure({auth, config})` first.\n */\n init(): void {\n if (client) return\n // Privacy stance wins over every caller, including the lazy `if (!client)\n // this.init()` paths below — this is the one chokepoint where the client\n // gets built, so refusing here keeps the socket from ever opening.\n if (cloudDisabled()) {\n console.log(`${LOG_TAG}: init skipped — cloud disabled in Privacy settings`)\n startDisableCloudWatcher()\n return\n }\n ensureAuthWatch()\n startDisableCloudWatcher()\n construct()\n },\n\n /** True when the user has turned Glassly cloud off entirely. */\n isCloudDisabled(): boolean {\n return cloudDisabled()\n },\n\n /**\n * Tear down + rebuild. Pass new endpoints to switch URLs; pass `null` to CLEAR\n * a prior override and fall back to the boot config (so cleared/default cloud\n * URLs don't keep reconnecting to a stale override); omit to keep the current.\n */\n reconnect(endpoints?: {core: string; runtime: string} | null): void {\n const prevCore = resolveEndpoints().core\n if (endpoints !== undefined) endpointsOverride = endpoints\n // Tokens are minted per backend (per-env signing keys + user DB), so a\n // core switch makes the persisted refresh token dead weight the new\n // backend will reject. Drop it so the client goes straight to a subject\n // exchange instead of burning a round trip on a guaranteed invalid_grant.\n // Key literal matches cloud-client's token-store.ts REFRESH_TOKEN_KEY.\n if (resolveEndpoints().core !== prevCore) {\n console.log(`${LOG_TAG}: core endpoint changed — dropping persisted cloud refresh token`)\n void cloudSecureStore.delete(\"glassly.cloud-client.refreshToken\")\n }\n try {\n client?.runtime.close()\n } catch (err) {\n console.warn(`${LOG_TAG}: reconnect close() failed: ${(err as Error)?.message ?? err}`)\n }\n clearRuntimeEventSubscriptions()\n clearPersistentFailureAlarm()\n\n const wasConnected = connected\n client = null\n localDevRuntimeToken = null\n connected = false\n superseded = false\n resetRuntimeStatus()\n if (wasConnected) notifyConnectionListeners(false)\n\n // Same gate as init(): endpoint changes / LC3 reconnects must not resurrect\n // a connection the user has switched off.\n if (cloudDisabled()) {\n console.log(`${LOG_TAG}: reconnect skipped — cloud disabled in Privacy settings`)\n return\n }\n construct()\n },\n\n async getPreinstalledMiniappRegistry(): Promise<PreinstalledMiniappRegistry> {\n if (!client) this.init()\n const c = client\n if (!c?.core) throw new Error(\"cloud client core is unavailable\")\n return c.core.miniapps.getRegistry()\n },\n\n async getStoreCatalog(): Promise<StoreCatalogResponse> {\n if (!client) this.init()\n const c = client\n if (!c?.core) throw new Error(\"cloud client core is unavailable\")\n return c.core.store.list()\n },\n\n async getStoreListing(packageName: string): Promise<StoreListing> {\n if (!client) this.init()\n const c = client\n if (!c?.core) throw new Error(\"cloud client core is unavailable\")\n return c.core.store.get(packageName)\n },\n\n async getStoreReleases(packageName: string): Promise<StoreReleasesResponse> {\n if (!client) this.init()\n const c = client\n if (!c?.core) throw new Error(\"cloud client core is unavailable\")\n return c.core.store.releases(packageName)\n },\n\n /** Bytes of a store icon or screenshot; these routes need the user Bearer. */\n async fetchStoreAsset(url: string): Promise<Uint8Array> {\n if (!client) this.init()\n const c = client\n if (!c?.core) throw new Error(\"cloud client core is unavailable\")\n return c.core.store.fetchAsset(url)\n },\n\n /**\n * Resolve the stable Core-owned Glassly user id.\n *\n * Storage must use this identity rather than the short-lived Core access\n * token. A previously verified id is restored from MMKV so local miniapps\n * remain available after an offline process restart. On first sign-in,\n * callers join the auth module's single-flight exchange/refresh instead of\n * falling back to an anonymous namespace.\n */\n async resolveUserId(): Promise<string> {\n // With cloud off there is no client to exchange a token with and never will\n // be, so the online path below would throw on every storage call and take\n // offline-capable local miniapps down with it. Fall back to a device-local\n // namespace instead — a cached Core id still wins inside resolveLocal().\n if (cloudDisabled()) return localMiniappUserIdentity.resolveLocal()\n\n return localMiniappUserIdentity.resolve(async () => {\n if (!client) this.init()\n const c = client\n if (!c) throw new Error(\"cloud client not initialized\")\n\n await c.auth.getCoreToken()\n if (c !== client) throw new Error(\"cloud client changed while resolving user identity\")\n // Runs before resolve() persists the id, so the local namespace is adopted\n // whichever path reaches Core identity first (this or the token sync).\n adoptLocalNamespace(c.auth.identity.userId)\n return c.auth.identity.userId\n })\n },\n\n /** Read the stable Glassly user id after async identity resolution. */\n getUserId(): string {\n // Mirrors resolveUserId(): with cloud off, minting is synchronous and\n // cannot fail, so sync callers (BlobStore) don't depend on an async resolve\n // having run first.\n if (cloudDisabled()) return localMiniappUserIdentity.resolveLocal()\n const userId = localMiniappUserIdentity.get()\n if (!userId) throw new Error(\"Glassly user identity is unavailable\")\n return userId\n },\n\n async getMiniappAuthToken(\n packageName: string,\n opts?: {minTtlMs?: number; devAttestation?: string},\n ): Promise<MiniappAuthToken> {\n if (!client) this.init()\n const c = client\n if (!c) throw new Error(\"cloud client not initialized\")\n\n const {token, expiresAt} = await c.auth.getMiniappToken(packageName, opts)\n const identity = c.auth.identity\n return {\n userId: identity.userId,\n tenantId: identity.tenantId,\n token,\n expiresAt: normalizeExpiresAt(expiresAt),\n }\n },\n\n /**\n * Tear down the client + connection (the engine.stop() lifecycle).\n *\n * Deliberately leaves the disable-cloud watcher installed: this is also the\n * teardown the Privacy toggle triggers, and dropping the subscription here\n * would strand the app disconnected until restart when the user flips the\n * toggle back off. `shutdown()` is the full-stop variant that removes it.\n */\n stop(): void {\n try {\n client?.runtime.close()\n } catch (err) {\n console.warn(`${LOG_TAG}: stop close() failed: ${(err as Error)?.message ?? err}`)\n }\n stopLc3FrameSizeWatcher()\n stopForegroundWatcher()\n stopAuthWatch()\n clearRuntimeEventSubscriptions()\n clearPersistentFailureAlarm()\n const wasConnected = connected\n client = null\n superseded = false\n // stop() is part of the logout lifecycle and runs before the host emits\n // SIGNED_OUT. Remove the persisted namespace owner here so a later account\n // can never inherit it. A force-stop/process kill does not call stop(), so\n // the cached id still survives the offline cold-start case.\n localMiniappUserIdentity.forget()\n localDevRuntimeToken = null\n connected = false\n resetRuntimeStatus()\n if (wasConnected) notifyConnectionListeners(false)\n },\n\n /** `stop()` plus the disable-cloud watcher — for a genuine engine teardown. */\n shutdown(): void {\n this.stop()\n stopDisableCloudWatcher()\n // The next engine.start() is configured afresh; an override left by a\n // reconnect() in this process would otherwise outrank the new config\n // and keep the client on the previous backend.\n endpointsOverride = null\n },\n\n /** Device-side managed photo: presign now, deliver bytes, await ready. */\n startManagedPhoto(opts: Record<string, unknown> = {}) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.startManagedPhoto(opts)\n },\n awaitManagedPhotoReady(requestId: string) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.awaitManagedPhotoReady(requestId)\n },\n\n /** Managed stream: provision ingest+playback on the runtime. */\n startManagedStream(opts: Record<string, unknown> = {}) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.startManagedStream(opts)\n },\n getManagedStreamStatus(streamId: string) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.getManagedStreamStatus(streamId)\n },\n stopManagedStream(streamId: string) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.stopManagedStream(streamId)\n },\n\n /** Current live-session connection state (handshake completed). */\n isConnected(): boolean {\n return connected\n },\n\n /** Subscribe to connection-state transitions. Returns an unsubscribe fn. */\n onConnectionChange(listener: (connected: boolean) => void): () => void {\n connectionListeners.add(listener)\n return () => {\n connectionListeners.delete(listener)\n }\n },\n\n /** Replace the v2 cloud's audio subscription set for the live session. */\n async setSubscriptions(subs: AudioSubscription[]): Promise<void> {\n // Cache unconditionally so the desired set survives a not-yet-connected\n // session and reconnects; the onConnected handler re-applies the cached set.\n audioSubscriptions = subs\n const c = client\n if (connected && c) {\n await c.runtime.setSubscriptions(subs)\n }\n },\n\n sendAudioFrame(frame: Uint8Array): void {\n client?.runtime.sendAudioFrame(frame)\n },\n\n onTranscript(cb: (d: TranscriptionData) => void): () => void {\n transcriptListeners.add(cb)\n return () => {\n transcriptListeners.delete(cb)\n }\n },\n\n onTranslation(cb: (d: TranslationData) => void): () => void {\n translationListeners.add(cb)\n return () => {\n translationListeners.delete(cb)\n }\n },\n\n /** Plan-quota block/unblock pushes for metered cloud streams. */\n onQuota(cb: (d: QuotaStatusPayload) => void): () => void {\n quotaListeners.add(cb)\n return () => {\n quotaListeners.delete(cb)\n }\n },\n\n getStatus(): CloudClientStatusSnapshot {\n return currentRuntimeStatus()\n },\n\n getCoreUrl(): string {\n return resolveEndpoints().core\n },\n\n syncCoreTokenToBluetooth(): Promise<string> {\n return syncCoreAccessTokenToBluetooth()\n },\n\n onStatusChanged(cb: (snapshot: CloudClientStatusSnapshot) => void): () => void {\n statusListeners.add(cb)\n return () => {\n statusListeners.delete(cb)\n }\n },\n\n tts: {\n speak(text: string, options?: Parameters<CloudClient[\"runtime\"][\"tts\"][\"speak\"]>[1]) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.tts.speak(text, options)\n },\n },\n\n llm: {\n /**\n * One completion turn through the cloud LLM service. `userApiKey` is the\n * user's own provider key when they've saved one; the cloud bills that key\n * instead of the platform's and skips metering. It rides as a header, never\n * in the request body.\n */\n complete(\n req: Parameters<CloudClient[\"runtime\"][\"llm\"][\"complete\"]>[0],\n opts?: Parameters<CloudClient[\"runtime\"][\"llm\"][\"complete\"]>[1],\n ) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.llm.complete(req, opts)\n },\n\n /** One agentic visual-generation run. Long-running; see cloud-client docs. */\n generate(\n req: Parameters<CloudClient[\"runtime\"][\"llm\"][\"generate\"]>[0],\n opts?: Parameters<CloudClient[\"runtime\"][\"llm\"][\"generate\"]>[1],\n ) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.llm.generate(req, opts)\n },\n\n /** Start a pollable generate job (async flavor; 404 on old clouds). */\n startGenerateJob(\n req: Parameters<CloudClient[\"runtime\"][\"llm\"][\"startGenerateJob\"]>[0],\n opts?: Parameters<CloudClient[\"runtime\"][\"llm\"][\"startGenerateJob\"]>[1],\n ) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.llm.startGenerateJob(req, opts)\n },\n\n generateJobStatus(jobId: string) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.llm.generateJobStatus(jobId)\n },\n\n cancelGenerateJob(jobId: string) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.llm.cancelGenerateJob(jobId)\n },\n },\n\n maps: {\n directions(req: Parameters<CloudClient[\"runtime\"][\"maps\"][\"directions\"]>[0]) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.maps.directions(req)\n },\n reverseGeocode(coord: Parameters<CloudClient[\"runtime\"][\"maps\"][\"reverseGeocode\"]>[0]) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.maps.reverseGeocode(coord)\n },\n placeAutocomplete(req: Parameters<CloudClient[\"runtime\"][\"maps\"][\"placeAutocomplete\"]>[0]) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.maps.placeAutocomplete(req)\n },\n placeDetails(req: Parameters<CloudClient[\"runtime\"][\"maps\"][\"placeDetails\"]>[0]) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.maps.placeDetails(req)\n },\n /**\n * The deployment's public map render token ({provider, token}) for the\n * consumers that can't be proxied (tiles, native nav SDK). `token` null =\n * this deployment serves none. See MapboxTokenService for the caching\n * consumer.\n */\n renderToken() {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.maps.renderToken()\n },\n },\n\n core: {\n reports: {\n submit(...args: Parameters<CloudCore[\"reports\"][\"submit\"]>) {\n return getCoreClient().reports.submit(...args)\n },\n addLogs(...args: Parameters<CloudCore[\"reports\"][\"addLogs\"]>) {\n return getCoreClient().reports.addLogs(...args)\n },\n addScreenshots(...args: Parameters<CloudCore[\"reports\"][\"addScreenshots\"]>) {\n return getCoreClient().reports.addScreenshots(...args)\n },\n complete(...args: Parameters<CloudCore[\"reports\"][\"complete\"]>) {\n return getCoreClient().reports.complete(...args)\n },\n },\n supportProfile: {\n update(...args: Parameters<CloudCore[\"supportProfile\"][\"update\"]>) {\n return getCoreClient().supportProfile.update(...args)\n },\n },\n },\n\n hasAudioSubscriptions(): boolean {\n return audioSubscriptions.length > 0\n },\n}\n"]}
1
+ {"version":3,"file":"CloudClientService.js","sourceRoot":"","sources":["../../src/services/CloudClientService.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Owns the singleton `@glassly/cloud-client` (CloudClient) for the engine runtime\n * — the keystone move that pulls backend comms INTO engine.\n *\n * engine constructs the client from engine-owned pieces (the native UDP socket,\n * the MMKV secure store, the cloud-status store) plus the two things the host\n * provides through the engine front door: `auth.getSubjectToken` (the one\n * permanent seam — the OEM owns login) and the resolved cloud endpoints\n * (`config.coreUrl/runtimeUrl`, computed host-side from dev/settings). On init it\n * exposes cloud runtime methods directly from this service, so the host no longer\n * injects a cloud adapter — engine owns construction and wiring.\n *\n * The local-miniapp path drives the cloud's transcription/translation through\n * this service.\n */\nimport {CloudClient, setNativeHttp, setNativeUdp, setSecureStorage} from \"@glassly/cloud-client/react-native\"\nimport type {\n PreinstalledMiniappRegistry,\n RuntimeSnapshot,\n StoreCatalogResponse,\n StoreListing,\n StoreReleasesResponse,\n} from \"@glassly/cloud-client/react-native\"\nimport type {SubjectTokenType} from \"@glassly/cloud-client\"\nimport {AppState, Platform} from \"react-native\"\nimport type {AudioSubscription, QuotaStatusPayload, TranscriptionData, TranslationData} from \"@glassly/cloud-protocol\"\n\nimport BluetoothSdk from \"@glassly/bluetooth-sdk/internal\"\nimport CrustModule from \"@glassly/crust\"\nimport {getAuth, getConfigValues} from \"../runtime/bootstrap\"\nimport {useSettingsStore, SETTINGS} from \"../stores/settings\"\nimport {type CloudClientStatusSnapshot, type MiniappAuthToken} from \"../runtime/config\"\nimport {createCloudUdpSocket} from \"../utils/cloudClient/RnUdpAdapter\"\nimport {cloudSecureStore} from \"../utils/cloudClient/cloudSecureStore\"\nimport {storage as mmkvStorage} from \"../utils/storage\"\nimport {useCloudClientStatusStore} from \"../stores/cloudClientStatus\"\nimport {islandNotifications} from \"./NotificationsEmitter\"\nimport {BgTimer} from \"../utils/timers\"\nimport {logCloudTranscriptMetric} from \"./CloudTranscriptE2EMetrics\"\nimport {isLocalUserId, LocalMiniappUserIdentity} from \"./LocalMiniappUserIdentity\"\nimport {migrateLocalMiniappData, type LocalMiniappDataMigrationBackend} from \"./LocalMiniappDataMigration\"\nimport {nativeHttpResponseBody} from \"./NativeHttpResponse\"\n\nconst LOG_TAG = \"cloudClient\"\ntype CloudCore = NonNullable<CloudClient[\"core\"]>\n\n// Persistent cloud-disconnect detector: the cloud-client reconnect loop is infinite\n// and never surfaces a \"giving up\" signal, so \"persistent failure\" = the session has\n// been continuously NOT connected for this long. A quick reconnect cancels it; brief\n// flaps that recover don't fire. Raised as engine.notifications(connection_failed_persistent).\nconst CLOUD_PERSISTENT_FAILURE_MS = 60_000\nconst LOCAL_MINIAPP_USER_ID_KEY = \"glassly.localMiniapp.userId\"\n\n/** Cancel the pending persistent-failure alarm + re-arm for the next outage. */\nfunction clearPersistentFailureAlarm(): void {\n if (persistentFailureTimer) {\n BgTimer.clearTimeout(persistentFailureTimer)\n persistentFailureTimer = null\n }\n persistentFailureNotified = false\n}\n\ntype Lc3FrameSizeBytes = 20 | 40 | 60\n\n// Neutral last-ditch fallbacks (reachable under `adb reverse`) for when the host\n// passes no endpoints. The host normally resolves the real URLs (dev override /\n// Metro host / env) and hands them in via `engine.configure({config})`.\nconst FALLBACK_CORE_URL = \"http://localhost:3000\"\nconst FALLBACK_RUNTIME_URL = \"http://localhost:3001\"\nconst LOCAL_AUTH_PORT = 3002\n\nlet client: CloudClient | null = null\nlet connected = false\n/** The cloud closed us for a newer socket; the client stays down until reconnect(). */\nlet superseded = false\nlet persistentFailureTimer: ReturnType<typeof BgTimer.setTimeout> | null = null\nlet persistentFailureNotified = false\nlet audioSubscriptions: AudioSubscription[] = []\nlet transportsReady = false\n/** Endpoints to build with — seeded from config, overridable via reconnect(). */\nlet endpointsOverride: {core: string; runtime: string} | null = null\nlet runtimeStatusUnsubscribe: (() => void) | null = null\nlet transcriptUnsubscribe: (() => void) | null = null\nlet translationUnsubscribe: (() => void) | null = null\nlet quotaUnsubscribe: (() => void) | null = null\nlet authStateUnsubscribe: (() => void) | null = null\nlet localDevRuntimeToken: {runtimeUrl: string; token: string; expiresAtMs: number} | null = null\nlet lc3FrameSizeUnsubscribe: (() => void) | null = null\nlet disableCloudUnsubscribe: (() => void) | null = null\nlet foregroundUnsubscribe: (() => void) | null = null\nlet coreTokenSyncPromise: Promise<string> | null = null\n/**\n * A device-local namespace (`local_…`) whose data still needs to be adopted\n * into the account namespace. Set when a sign-in displaces a local id; cleared\n * once {@link adoptLocalNamespace} has moved the data.\n */\nlet pendingLocalNamespace: string | null = null\n\n/**\n * Moves blob bytes between user directories during namespace adoption.\n * Registered by LocalMiniappRuntime (which owns the BlobStore instance) so this\n * service doesn't import it and create a cycle. Absent in tests / before the\n * runtime boots, in which case only the key-value stores migrate.\n */\ntype BlobNamespaceMigrator = (fromUserId: string, toUserId: string) => {moved: number; skipped: number}\nlet blobNamespaceMigrator: BlobNamespaceMigrator | null = null\n\n/**\n * Register the blob-bytes half of namespace adoption. Called by\n * LocalMiniappRuntime at construction — it owns the BlobStore instance, and\n * having it push the hook here keeps this service from importing the runtime.\n */\nexport function setBlobNamespaceMigrator(migrator: BlobNamespaceMigrator | null): void {\n blobNamespaceMigrator = migrator\n}\n\n/** Result-free view of MMKV, as the migration's plain get/set/remove/keys. */\nconst migrationBackend: LocalMiniappDataMigrationBackend = {\n get(key: string): unknown | null {\n const result = mmkvStorage.load<unknown>(key)\n return result.is_ok() ? result.value : null\n },\n set(key: string, value: unknown): void {\n const result = mmkvStorage.save(key, value)\n if (result.is_error()) throw result.error\n },\n remove(key: string): void {\n const result = mmkvStorage.remove(key)\n if (result.is_error()) throw result.error\n },\n keys(): string[] {\n return mmkvStorage.getAllKeys()\n },\n}\n\n/**\n * Adopt data written under a device-local namespace into the signed-in\n * account's, so miniapp state created while cloud was disabled survives\n * sign-in. No-op unless a sign-in actually displaced a local id.\n */\nfunction adoptLocalNamespace(coreUserId: string): void {\n const from = pendingLocalNamespace\n if (!from) return\n // Clear first: a failure must not re-run on every subsequent resolve, and the\n // migration is idempotent anyway.\n pendingLocalNamespace = null\n if (!coreUserId || from === coreUserId) return\n\n try {\n const keys = migrateLocalMiniappData(migrationBackend, from, coreUserId)\n const blobs = blobNamespaceMigrator?.(from, coreUserId) ?? {moved: 0, skipped: 0}\n if (keys.moved || keys.skipped || blobs.moved || blobs.skipped) {\n console.log(\n `${LOG_TAG}: adopted local miniapp data into account namespace ` +\n `(keys ${keys.moved} moved/${keys.skipped} skipped, blobs ${blobs.moved} moved/${blobs.skipped} skipped)`,\n )\n }\n } catch (err) {\n console.warn(`${LOG_TAG}: local namespace adoption failed: ${(err as Error)?.message ?? err}`)\n }\n}\n\nconst localMiniappUserIdentity = new LocalMiniappUserIdentity({\n get(): string | null {\n const result = mmkvStorage.load<string>(LOCAL_MINIAPP_USER_ID_KEY)\n return result.is_ok() ? result.value : null\n },\n set(userId: string): void {\n const result = mmkvStorage.save(LOCAL_MINIAPP_USER_ID_KEY, userId)\n if (result.is_error()) throw result.error\n },\n remove(): void {\n const result = mmkvStorage.remove(LOCAL_MINIAPP_USER_ID_KEY)\n if (result.is_error()) throw result.error\n },\n})\n\nconst transcriptListeners = new Set<(d: TranscriptionData) => void>()\nconst translationListeners = new Set<(d: TranslationData) => void>()\nconst quotaListeners = new Set<(d: QuotaStatusPayload) => void>()\nconst statusListeners = new Set<(snapshot: CloudClientStatusSnapshot) => void>()\nconst connectionListeners = new Set<(connected: boolean) => void>()\n\nfunction resolveEndpoints(): {core: string; runtime: string} {\n if (endpointsOverride) return endpointsOverride\n const cfg = getConfigValues()\n return {\n core: cfg.coreUrl?.trim() || FALLBACK_CORE_URL,\n runtime: cfg.runtimeUrl?.trim() || FALLBACK_RUNTIME_URL,\n }\n}\n\n// Via init(), never construct(): init() holds the disable-cloud gate, and a\n// client built past it opens the runtime socket and retries it forever.\nfunction requireClient(): CloudClient {\n if (!client) cloudClientService.init()\n if (!client) throw new Error(\"Glassly cloud is disabled\")\n return client\n}\n\nfunction getCoreClient(): CloudCore {\n const core = requireClient().core\n if (!core) throw new Error(\"cloud client core not configured\")\n return core\n}\n\nfunction syncCoreAccessTokenToBluetooth(): Promise<string> {\n if (coreTokenSyncPromise) return coreTokenSyncPromise\n\n coreTokenSyncPromise = syncCoreAccessTokenToBluetoothInternal().finally(() => {\n coreTokenSyncPromise = null\n })\n return coreTokenSyncPromise\n}\n\nasync function syncCoreAccessTokenToBluetoothInternal(): Promise<string> {\n const c = requireClient()\n\n const token = await c.auth.getCoreToken()\n if (c !== client) {\n throw new Error(\"cloud client changed while syncing core token\")\n }\n adoptLocalNamespace(c.auth.identity.userId)\n localMiniappUserIdentity.remember(c.auth.identity.userId)\n const result = await useSettingsStore.getState().setSetting(SETTINGS.core_token.key, token, false)\n if (result.is_error()) {\n throw result.error\n }\n\n try {\n await BluetoothSdk.updateBluetoothSettings({[SETTINGS.core_token.key]: token})\n } catch (err) {\n console.warn(`${LOG_TAG}: direct Bluetooth core_token sync failed: ${(err as Error)?.message ?? err}`)\n }\n\n return token\n}\n\nfunction frameSizeBytes(): Lc3FrameSizeBytes {\n // Read LIVE from the engine settings store (the source of truth) so a\n // reconnect after a glasses swap (G1=20 ↔ G2=40) picks up the new frame size,\n // not the one-time engine.configure({config}) snapshot. Falls back to the\n // config value (set at boot) then 20 when the setting is unset.\n const fromSettings = useSettingsStore.getState().getSetting(SETTINGS.lc3_frame_size.key)\n const size = fromSettings ?? getConfigValues().audioFrameSizeBytes\n return size === 20 || size === 40 || size === 60 ? size : 20\n}\n\nasync function getSubjectToken(): Promise<{token: string; type: SubjectTokenType}> {\n const a = getAuth()\n if (!a) throw new Error(\"cloudClient: engine.configure({auth}) not called\")\n const r = await a.getSubjectToken()\n // IslandAuth's SubjectTokenType is intentionally open (`string & {}`) so OEMs\n // can use other token kinds; cloud-client's is a closed union. The host's\n // actual value (\"supabase\") is valid — narrow at this boundary.\n return {token: r.token, type: r.type as SubjectTokenType}\n}\n\nfunction normalizeExpiresAt(expiresAt: number): number {\n return expiresAt < 10_000_000_000 ? expiresAt * 1000 : expiresAt\n}\n\nfunction shouldUseLocalDevRuntimeToken(endpoints: {runtime: string}): boolean {\n if (!__DEV__) return false\n try {\n const host = new URL(endpoints.runtime).hostname\n return host === \"localhost\" || host === \"127.0.0.1\" || host === \"10.0.2.2\"\n } catch {\n return false\n }\n}\n\nasync function getLocalDevRuntimeToken(runtimeEndpoint: string, opts?: {forceRefresh?: boolean}): Promise<string> {\n const now = Date.now()\n if (\n !opts?.forceRefresh &&\n localDevRuntimeToken?.runtimeUrl === runtimeEndpoint &&\n localDevRuntimeToken.expiresAtMs - now > 60_000\n ) {\n return localDevRuntimeToken.token\n }\n\n const base = new URL(runtimeEndpoint)\n base.port = String(LOCAL_AUTH_PORT)\n base.pathname = \"/api/dev/runtime-token\"\n base.search = new URLSearchParams({userId: \"local-phone-user\", tenantId: \"glassly\"}).toString()\n\n const res = await fetch(base.toString())\n if (!res.ok) {\n throw new Error(`cloudClient: local dev runtime token failed (${res.status})`)\n }\n const body = (await res.json()) as {access_token?: string; expires_in?: number}\n if (!body.access_token) {\n throw new Error(\"cloudClient: local dev runtime token response missing access_token\")\n }\n localDevRuntimeToken = {\n runtimeUrl: runtimeEndpoint,\n token: body.access_token,\n expiresAtMs: now + (body.expires_in ?? 300) * 1000,\n }\n return body.access_token\n}\n\nfunction toCloudClientStatusSnapshot(snapshot: RuntimeSnapshot): CloudClientStatusSnapshot {\n return {status: snapshot.status, audioTransport: snapshot.audioTransport}\n}\n\nfunction currentRuntimeStatus(): CloudClientStatusSnapshot {\n const state = useCloudClientStatusStore.getState()\n return {status: state.status, audioTransport: state.audioTransport}\n}\n\nfunction setRuntimeStatus(snapshot: RuntimeSnapshot): void {\n useCloudClientStatusStore.getState().setSnapshot(snapshot)\n emitStatus(toCloudClientStatusSnapshot(snapshot))\n}\n\nfunction resetRuntimeStatus(): void {\n useCloudClientStatusStore.getState().reset()\n emitStatus(currentRuntimeStatus())\n}\n\nfunction stringifyMeta(meta: unknown): string {\n if (!meta || typeof meta !== \"object\") return \"\"\n try {\n return ` ${JSON.stringify(meta)}`\n } catch {\n return \"\"\n }\n}\n\nconst cloudLogger = {\n debug: (msg: string, meta?: unknown) => console.log(`${LOG_TAG}: debug: ${msg}${stringifyMeta(meta)}`),\n info: (msg: string, meta?: unknown) => console.log(`${LOG_TAG}: info: ${msg}${stringifyMeta(meta)}`),\n warn: (msg: string, meta?: unknown) => console.warn(`${LOG_TAG}: warn: ${msg}${stringifyMeta(meta)}`),\n error: (msg: string, meta?: unknown) => console.warn(`${LOG_TAG}: error: ${msg}${stringifyMeta(meta)}`),\n}\n\nfunction notifyConnectionListeners(next: boolean): void {\n for (const l of connectionListeners) {\n try {\n l(next)\n } catch (err) {\n console.warn(`${LOG_TAG}: connection listener threw: ${(err as Error)?.message ?? err}`)\n }\n }\n}\n\nfunction extractUnsubscribe(sub: unknown): (() => void) | null {\n const candidates: unknown[] = []\n const s = sub as Record<string, unknown> | null | undefined\n if (s && typeof s === \"object\") {\n candidates.push(s)\n candidates.push((s.value as Record<string, unknown>)?.subscription)\n candidates.push((s.data as Record<string, unknown>)?.subscription)\n candidates.push(s.subscription)\n }\n for (const c of candidates) {\n const unsub = (c as {unsubscribe?: unknown})?.unsubscribe\n if (typeof unsub === \"function\") return unsub as () => void\n }\n return null\n}\n\nfunction ensureAuthWatch(): void {\n if (authStateUnsubscribe) return\n authStateUnsubscribe = () => {}\n\n const auth = getAuth()\n if (!auth?.onStateChange) return\n\n let reconnectPending = false\n try {\n const sub = auth.onStateChange((event, session) => {\n if (event === \"SIGNED_OUT\") {\n localMiniappUserIdentity.forget()\n return\n }\n // A new sign-in may belong to a different account. Force the next\n // storage request to resolve and persist that account's Core identity.\n // A device-local namespace is remembered first so the data written while\n // cloud was off can follow the user into the account (see\n // adoptLocalNamespace).\n if (event === \"SIGNED_IN\") {\n const local = localMiniappUserIdentity.get()\n if (local && isLocalUserId(local)) pendingLocalNamespace = local\n localMiniappUserIdentity.forget()\n }\n if (!session?.token) return\n if (connected || reconnectPending) return\n\n reconnectPending = true\n console.log(`${LOG_TAG}: auth session available (${event}) while disconnected — reconnecting`)\n try {\n cloudClientService.reconnect()\n } finally {\n BgTimer.setTimeout(() => {\n reconnectPending = false\n }, 0)\n }\n })\n\n const unsub = extractUnsubscribe(sub)\n if (unsub) authStateUnsubscribe = unsub\n } catch (err) {\n console.warn(`${LOG_TAG}: auth watch subscribe failed: ${(err as Error)?.message ?? err}`)\n }\n}\n\nfunction stopAuthWatch(): void {\n authStateUnsubscribe?.()\n authStateUnsubscribe = null\n}\n\nfunction emitTranscript(data: TranscriptionData): void {\n for (const l of transcriptListeners) {\n try {\n l(data)\n } catch (err) {\n console.warn(`${LOG_TAG}: transcript listener threw: ${(err as Error)?.message ?? err}`)\n }\n }\n}\n\nfunction emitTranslation(data: TranslationData): void {\n for (const l of translationListeners) {\n try {\n l(data)\n } catch (err) {\n console.warn(`${LOG_TAG}: translation listener threw: ${(err as Error)?.message ?? err}`)\n }\n }\n}\n\nfunction emitQuota(data: QuotaStatusPayload): void {\n for (const l of quotaListeners) {\n try {\n l(data)\n } catch (err) {\n console.warn(`${LOG_TAG}: quota listener threw: ${(err as Error)?.message ?? err}`)\n }\n }\n}\n\nfunction emitStatus(snapshot: CloudClientStatusSnapshot): void {\n for (const l of statusListeners) {\n try {\n l(snapshot)\n } catch (err) {\n console.warn(`${LOG_TAG}: status listener threw: ${(err as Error)?.message ?? err}`)\n }\n }\n}\n\nfunction ensureTransports(): void {\n if (transportsReady) return\n transportsReady = true\n setNativeUdp(() => createCloudUdpSocket())\n setSecureStorage(cloudSecureStore)\n if (Platform.OS !== \"android\") return\n setNativeHttp(async (input, init) => {\n if (typeof input !== \"string\" || (init?.body != null && typeof init.body !== \"string\")) {\n return globalThis.fetch(input, init)\n }\n const headers = Object.fromEntries(new Headers(init?.headers).entries())\n const result = await CrustModule.nativeHttpRequest(\n init?.method ?? \"GET\",\n input,\n headers,\n (init?.body as string | undefined) ?? null,\n )\n return new Response(nativeHttpResponseBody(result.status, result.body), {\n status: result.status,\n statusText: result.statusText,\n headers: result.headers,\n })\n })\n}\n\nfunction clearRuntimeEventSubscriptions(): void {\n runtimeStatusUnsubscribe?.()\n runtimeStatusUnsubscribe = null\n transcriptUnsubscribe?.()\n transcriptUnsubscribe = null\n translationUnsubscribe?.()\n translationUnsubscribe = null\n quotaUnsubscribe?.()\n quotaUnsubscribe = null\n}\n\n/**\n * The user's hard \"never talk to Glassly cloud\" stance (Settings > Privacy).\n * Read imperatively at every would-be-connect point rather than cached, so\n * flipping the toggle takes effect without a restart. `=== true` because\n * getSetting is `any` and an unhydrated store must not read as \"disabled\".\n */\nfunction cloudDisabled(): boolean {\n return useSettingsStore.getState().getSetting(SETTINGS.disable_cloud.key) === true\n}\n\nfunction startLc3FrameSizeWatcher(): void {\n if (lc3FrameSizeUnsubscribe) return\n\n let last = frameSizeBytes()\n lc3FrameSizeUnsubscribe = useSettingsStore.subscribe(\n (state) => state.getSetting(SETTINGS.lc3_frame_size.key),\n () => {\n const next = frameSizeBytes()\n if (next === last) return\n last = next\n if (!client) return\n console.log(`${LOG_TAG}: LC3 frame size changed to ${next}; reconnecting runtime`)\n cloudClientService.reconnect()\n },\n )\n}\n\nfunction stopLc3FrameSizeWatcher(): void {\n lc3FrameSizeUnsubscribe?.()\n lc3FrameSizeUnsubscribe = null\n}\n\n/**\n * Reclaim a superseded session only on foreground: the user picked this phone\n * up, and a reclaim on any other signal would fight the newer socket.\n */\nfunction startForegroundWatcher(): void {\n if (foregroundUnsubscribe) return\n\n const subscription = AppState.addEventListener(\"change\", (state) => {\n if (state !== \"active\" || !superseded || !client) return\n console.log(`${LOG_TAG}: foregrounded after supersede; reconnecting runtime`)\n cloudClientService.reconnect()\n })\n foregroundUnsubscribe = () => subscription.remove()\n}\n\nfunction stopForegroundWatcher(): void {\n foregroundUnsubscribe?.()\n foregroundUnsubscribe = null\n}\n\n/**\n * Apply a mid-session flip of the Privacy toggle without a restart: turning it\n * on tears the live client down, turning it back off reconnects. Installed by\n * init() on BOTH branches — when cloud starts disabled there is no client to\n * hang the watcher off, but we still need to notice the user re-enabling it.\n */\nfunction startDisableCloudWatcher(): void {\n if (disableCloudUnsubscribe) return\n\n let last = cloudDisabled()\n disableCloudUnsubscribe = useSettingsStore.subscribe(\n (state) => state.getSetting(SETTINGS.disable_cloud.key),\n () => {\n const next = cloudDisabled()\n if (next === last) return\n last = next\n if (next) {\n console.log(`${LOG_TAG}: cloud disabled — tearing down client`)\n cloudClientService.stop()\n } else {\n console.log(`${LOG_TAG}: cloud re-enabled — reconnecting`)\n cloudClientService.init()\n }\n },\n )\n}\n\nfunction stopDisableCloudWatcher(): void {\n disableCloudUnsubscribe?.()\n disableCloudUnsubscribe = null\n}\n\nfunction construct(): void {\n ensureTransports()\n\n const endpoints = resolveEndpoints()\n console.log(`${LOG_TAG}: endpoints ${JSON.stringify(endpoints)}`)\n\n const coreAuth = {getSubjectToken}\n const auth = shouldUseLocalDevRuntimeToken(endpoints)\n ? {\n core: coreAuth,\n runtime: {getToken: (opts?: {forceRefresh?: boolean}) => getLocalDevRuntimeToken(endpoints.runtime, opts)},\n }\n : {core: coreAuth, runtime: {source: \"core\" as const}}\n\n client = new CloudClient({\n endpoints,\n // The phone LC3-encodes mic audio (even in phone/simulated mode); announce\n // LC3 at 16 kHz with the frame size the encoder emits.\n audio: {codec: \"lc3\", sampleRate: 16000, frameSizeBytes: frameSizeBytes()},\n auth,\n timers: {\n setTimeout: (callback, delayMs) => BgTimer.setTimeout(callback, delayMs),\n clearTimeout: (handle) => BgTimer.clearTimeout(handle as number),\n setInterval: (callback, intervalMs) => BgTimer.setInterval(callback, intervalMs),\n clearInterval: (handle) => BgTimer.clearInterval(handle as number),\n },\n logger: cloudLogger,\n })\n\n const c = client\n clearRuntimeEventSubscriptions()\n runtimeStatusUnsubscribe = c.runtime.onStatusChanged((status) => {\n if (c !== client) return\n setRuntimeStatus(status)\n })\n transcriptUnsubscribe = c.runtime.onTranscript((data) => {\n if (c !== client) return\n logCloudTranscriptMetric(data)\n emitTranscript(data)\n })\n translationUnsubscribe = c.runtime.onTranslation((data) => {\n if (c !== client) return\n emitTranslation(data)\n })\n quotaUnsubscribe = c.runtime.onQuota((data) => {\n if (c !== client) return\n emitQuota(data)\n })\n setRuntimeStatus(c.runtime.getStatus())\n\n c.runtime.onConnected(() => {\n if (c !== client) return\n connected = true\n superseded = false\n console.log(`${LOG_TAG}: runtime connected`)\n console.log(`${LOG_TAG}: debug: ws-session-debug connected`)\n // Cloud is up — cancel any pending persistent-failure alarm and re-arm for the\n // next outage.\n clearPersistentFailureAlarm()\n // Re-apply the authoritative subscription set, including the empty set, so\n // a fresh phone launch clears any stale server-side audio subscriptions.\n c.runtime\n .setSubscriptions(audioSubscriptions)\n .catch((err) =>\n console.warn(`${LOG_TAG}: re-applying queued subscriptions failed: ${(err as Error)?.message ?? err}`),\n )\n notifyConnectionListeners(true)\n })\n c.runtime.onDisconnected((info) => {\n if (c !== client) return\n connected = false\n superseded = /superseded by newer session/i.test(info.reason)\n console.log(`${LOG_TAG}: runtime disconnected (${info.reason})`)\n console.log(`${LOG_TAG}: debug: ws-session-debug disconnected reason=${info.reason} willStayDown=${superseded}`)\n // Arm the persistent-failure alarm once; if we're still down when it fires, raise\n // the notification. A reconnect within the window cancels it (onConnected above).\n if (!persistentFailureTimer && !persistentFailureNotified) {\n persistentFailureTimer = BgTimer.setTimeout(() => {\n persistentFailureTimer = null\n if (connected) return\n persistentFailureNotified = true\n islandNotifications.emit({\n kind: \"connection_failed_persistent\",\n reason: `Cloud session has been disconnected for over ${Math.round(CLOUD_PERSISTENT_FAILURE_MS / 1000)}s`,\n metadata: {downForMs: CLOUD_PERSISTENT_FAILURE_MS, lastReason: info.reason},\n timestamp: Date.now(),\n })\n }, CLOUD_PERSISTENT_FAILURE_MS)\n }\n notifyConnectionListeners(false)\n })\n c.runtime.onError((err) => {\n console.warn(`${LOG_TAG}: runtime error: ${err.code}`)\n })\n\n // Dead credentials (refresh AND subject exchange both failed). Surface to\n // the host so it can force a re-login — otherwise the app looks signed-in\n // while every cloud feature silently fails. Fires at most once per client\n // instance (the auth module latches until a successful exchange).\n c.auth.onExpired(() => {\n if (c !== client) return\n console.warn(`${LOG_TAG}: cloud session expired beyond recovery — notifying host`)\n getAuth()?.onSessionExpired?.()\n })\n\n // Best-effort connect. Do not crash the app if the dev cloud is unreachable.\n c.runtime\n .connect()\n .then(() => console.log(`${LOG_TAG}: connect() resolved`))\n .catch((err) => console.warn(`${LOG_TAG}: connect() failed: ${err?.message ?? err}`))\n\n syncCoreAccessTokenToBluetooth().catch((err) =>\n console.warn(`${LOG_TAG}: initial Bluetooth core_token sync failed: ${(err as Error)?.message ?? err}`),\n )\n\n startLc3FrameSizeWatcher()\n startForegroundWatcher()\n}\n\n/**\n * engine's cloud client. Owns the singleton CloudClient, its connection state,\n * and the runtime-hook wiring.\n */\nexport const cloudClientService = {\n /**\n * Construct (once) + connect the client. Idempotent. Best-effort connect — a\n * failure is logged and the app keeps running. Requires\n * `engine.configure({auth, config})` first.\n */\n init(): void {\n if (client) return\n // Privacy stance wins over every caller, including the lazy `if (!client)\n // this.init()` paths below — this is the one chokepoint where the client\n // gets built, so refusing here keeps the socket from ever opening.\n if (cloudDisabled()) {\n console.log(`${LOG_TAG}: init skipped — cloud disabled in Privacy settings`)\n startDisableCloudWatcher()\n return\n }\n ensureAuthWatch()\n startDisableCloudWatcher()\n construct()\n },\n\n /** True when the user has turned Glassly cloud off entirely. */\n isCloudDisabled(): boolean {\n return cloudDisabled()\n },\n\n /**\n * Tear down + rebuild. Pass new endpoints to switch URLs; pass `null` to CLEAR\n * a prior override and fall back to the boot config (so cleared/default cloud\n * URLs don't keep reconnecting to a stale override); omit to keep the current.\n */\n reconnect(endpoints?: {core: string; runtime: string} | null): void {\n const prevCore = resolveEndpoints().core\n if (endpoints !== undefined) endpointsOverride = endpoints\n // Tokens are minted per backend (per-env signing keys + user DB), so a\n // core switch makes the persisted refresh token dead weight the new\n // backend will reject. Drop it so the client goes straight to a subject\n // exchange instead of burning a round trip on a guaranteed invalid_grant.\n // Key literal matches cloud-client's token-store.ts REFRESH_TOKEN_KEY.\n if (resolveEndpoints().core !== prevCore) {\n console.log(`${LOG_TAG}: core endpoint changed — dropping persisted cloud refresh token`)\n void cloudSecureStore.delete(\"glassly.cloud-client.refreshToken\")\n }\n try {\n client?.runtime.close()\n } catch (err) {\n console.warn(`${LOG_TAG}: reconnect close() failed: ${(err as Error)?.message ?? err}`)\n }\n clearRuntimeEventSubscriptions()\n clearPersistentFailureAlarm()\n\n const wasConnected = connected\n client = null\n localDevRuntimeToken = null\n connected = false\n superseded = false\n resetRuntimeStatus()\n if (wasConnected) notifyConnectionListeners(false)\n\n // Same gate as init(): endpoint changes / LC3 reconnects must not resurrect\n // a connection the user has switched off.\n if (cloudDisabled()) {\n console.log(`${LOG_TAG}: reconnect skipped — cloud disabled in Privacy settings`)\n return\n }\n construct()\n },\n\n async getPreinstalledMiniappRegistry(): Promise<PreinstalledMiniappRegistry> {\n if (!client) this.init()\n const c = client\n if (!c?.core) throw new Error(\"cloud client core is unavailable\")\n return c.core.miniapps.getRegistry()\n },\n\n async getStoreCatalog(): Promise<StoreCatalogResponse> {\n if (!client) this.init()\n const c = client\n if (!c?.core) throw new Error(\"cloud client core is unavailable\")\n return c.core.store.list()\n },\n\n async getStoreListing(packageName: string): Promise<StoreListing> {\n if (!client) this.init()\n const c = client\n if (!c?.core) throw new Error(\"cloud client core is unavailable\")\n return c.core.store.get(packageName)\n },\n\n async getStoreReleases(packageName: string): Promise<StoreReleasesResponse> {\n if (!client) this.init()\n const c = client\n if (!c?.core) throw new Error(\"cloud client core is unavailable\")\n return c.core.store.releases(packageName)\n },\n\n /** Bytes of a store icon or screenshot; these routes need the user Bearer. */\n async fetchStoreAsset(url: string): Promise<Uint8Array> {\n if (!client) this.init()\n const c = client\n if (!c?.core) throw new Error(\"cloud client core is unavailable\")\n return c.core.store.fetchAsset(url)\n },\n\n /**\n * Resolve the stable Core-owned Glassly user id.\n *\n * Storage must use this identity rather than the short-lived Core access\n * token. A previously verified id is restored from MMKV so local miniapps\n * remain available after an offline process restart. On first sign-in,\n * callers join the auth module's single-flight exchange/refresh instead of\n * falling back to an anonymous namespace.\n */\n async resolveUserId(): Promise<string> {\n // With cloud off there is no client to exchange a token with and never will\n // be, so the online path below would throw on every storage call and take\n // offline-capable local miniapps down with it. Fall back to a device-local\n // namespace instead — a cached Core id still wins inside resolveLocal().\n if (cloudDisabled()) return localMiniappUserIdentity.resolveLocal()\n\n return localMiniappUserIdentity.resolve(async () => {\n if (!client) this.init()\n const c = client\n if (!c) throw new Error(\"cloud client not initialized\")\n\n await c.auth.getCoreToken()\n if (c !== client) throw new Error(\"cloud client changed while resolving user identity\")\n // Runs before resolve() persists the id, so the local namespace is adopted\n // whichever path reaches Core identity first (this or the token sync).\n adoptLocalNamespace(c.auth.identity.userId)\n return c.auth.identity.userId\n })\n },\n\n /** Read the stable Glassly user id after async identity resolution. */\n getUserId(): string {\n // Mirrors resolveUserId(): with cloud off, minting is synchronous and\n // cannot fail, so sync callers (BlobStore) don't depend on an async resolve\n // having run first.\n if (cloudDisabled()) return localMiniappUserIdentity.resolveLocal()\n const userId = localMiniappUserIdentity.get()\n if (!userId) throw new Error(\"Glassly user identity is unavailable\")\n return userId\n },\n\n async getMiniappAuthToken(\n packageName: string,\n opts?: {minTtlMs?: number; devAttestation?: string},\n ): Promise<MiniappAuthToken> {\n if (!client) this.init()\n const c = client\n if (!c) throw new Error(\"cloud client not initialized\")\n\n const {token, expiresAt} = await c.auth.getMiniappToken(packageName, opts)\n const identity = c.auth.identity\n return {\n userId: identity.userId,\n tenantId: identity.tenantId,\n token,\n expiresAt: normalizeExpiresAt(expiresAt),\n }\n },\n\n /**\n * Tear down the client + connection (the engine.stop() lifecycle).\n *\n * Deliberately leaves the disable-cloud watcher installed: this is also the\n * teardown the Privacy toggle triggers, and dropping the subscription here\n * would strand the app disconnected until restart when the user flips the\n * toggle back off. `shutdown()` is the full-stop variant that removes it.\n */\n stop(): void {\n try {\n client?.runtime.close()\n } catch (err) {\n console.warn(`${LOG_TAG}: stop close() failed: ${(err as Error)?.message ?? err}`)\n }\n stopLc3FrameSizeWatcher()\n stopForegroundWatcher()\n stopAuthWatch()\n clearRuntimeEventSubscriptions()\n clearPersistentFailureAlarm()\n const wasConnected = connected\n client = null\n superseded = false\n // stop() is part of the logout lifecycle and runs before the host emits\n // SIGNED_OUT. Remove the persisted namespace owner here so a later account\n // can never inherit it. A force-stop/process kill does not call stop(), so\n // the cached id still survives the offline cold-start case.\n localMiniappUserIdentity.forget()\n localDevRuntimeToken = null\n connected = false\n resetRuntimeStatus()\n if (wasConnected) notifyConnectionListeners(false)\n },\n\n /** `stop()` plus the disable-cloud watcher — for a genuine engine teardown. */\n shutdown(): void {\n this.stop()\n stopDisableCloudWatcher()\n // The next engine.start() is configured afresh; an override left by a\n // reconnect() in this process would otherwise outrank the new config\n // and keep the client on the previous backend.\n endpointsOverride = null\n },\n\n /** Device-side managed photo: presign now, deliver bytes, await ready. */\n startManagedPhoto(opts: Record<string, unknown> = {}) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.startManagedPhoto(opts)\n },\n awaitManagedPhotoReady(requestId: string) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.awaitManagedPhotoReady(requestId)\n },\n\n /** Managed stream: provision ingest+playback on the runtime. */\n startManagedStream(opts: Record<string, unknown> = {}) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.startManagedStream(opts)\n },\n getManagedStreamStatus(streamId: string) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.getManagedStreamStatus(streamId)\n },\n stopManagedStream(streamId: string) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.stopManagedStream(streamId)\n },\n\n /** Current live-session connection state (handshake completed). */\n isConnected(): boolean {\n return connected\n },\n\n /** Subscribe to connection-state transitions. Returns an unsubscribe fn. */\n onConnectionChange(listener: (connected: boolean) => void): () => void {\n connectionListeners.add(listener)\n return () => {\n connectionListeners.delete(listener)\n }\n },\n\n /** Replace the v2 cloud's audio subscription set for the live session. */\n async setSubscriptions(subs: AudioSubscription[]): Promise<void> {\n // Cache unconditionally so the desired set survives a not-yet-connected\n // session and reconnects; the onConnected handler re-applies the cached set.\n audioSubscriptions = subs\n const c = client\n if (connected && c) {\n await c.runtime.setSubscriptions(subs)\n }\n },\n\n sendAudioFrame(frame: Uint8Array): void {\n client?.runtime.sendAudioFrame(frame)\n },\n\n onTranscript(cb: (d: TranscriptionData) => void): () => void {\n transcriptListeners.add(cb)\n return () => {\n transcriptListeners.delete(cb)\n }\n },\n\n onTranslation(cb: (d: TranslationData) => void): () => void {\n translationListeners.add(cb)\n return () => {\n translationListeners.delete(cb)\n }\n },\n\n /** Plan-quota block/unblock pushes for metered cloud streams. */\n onQuota(cb: (d: QuotaStatusPayload) => void): () => void {\n quotaListeners.add(cb)\n return () => {\n quotaListeners.delete(cb)\n }\n },\n\n getStatus(): CloudClientStatusSnapshot {\n return currentRuntimeStatus()\n },\n\n getCoreUrl(): string {\n return resolveEndpoints().core\n },\n\n syncCoreTokenToBluetooth(): Promise<string> {\n return syncCoreAccessTokenToBluetooth()\n },\n\n onStatusChanged(cb: (snapshot: CloudClientStatusSnapshot) => void): () => void {\n statusListeners.add(cb)\n return () => {\n statusListeners.delete(cb)\n }\n },\n\n tts: {\n speak(text: string, options?: Parameters<CloudClient[\"runtime\"][\"tts\"][\"speak\"]>[1]) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.tts.speak(text, options)\n },\n },\n\n llm: {\n /**\n * One completion turn through the cloud LLM service. `userApiKey` is the\n * user's own provider key when they've saved one; the cloud bills that key\n * instead of the platform's and skips metering. It rides as a header, never\n * in the request body.\n */\n complete(\n req: Parameters<CloudClient[\"runtime\"][\"llm\"][\"complete\"]>[0],\n opts?: Parameters<CloudClient[\"runtime\"][\"llm\"][\"complete\"]>[1],\n ) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.llm.complete(req, opts)\n },\n\n /** One agentic visual-generation run. Long-running; see cloud-client docs. */\n generate(\n req: Parameters<CloudClient[\"runtime\"][\"llm\"][\"generate\"]>[0],\n opts?: Parameters<CloudClient[\"runtime\"][\"llm\"][\"generate\"]>[1],\n ) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.llm.generate(req, opts)\n },\n\n /** Start a pollable generate job (async flavor; 404 on old clouds). */\n startGenerateJob(\n req: Parameters<CloudClient[\"runtime\"][\"llm\"][\"startGenerateJob\"]>[0],\n opts?: Parameters<CloudClient[\"runtime\"][\"llm\"][\"startGenerateJob\"]>[1],\n ) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.llm.startGenerateJob(req, opts)\n },\n\n generateJobStatus(jobId: string) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.llm.generateJobStatus(jobId)\n },\n\n cancelGenerateJob(jobId: string) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.llm.cancelGenerateJob(jobId)\n },\n },\n\n maps: {\n directions(req: Parameters<CloudClient[\"runtime\"][\"maps\"][\"directions\"]>[0]) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.maps.directions(req)\n },\n reverseGeocode(coord: Parameters<CloudClient[\"runtime\"][\"maps\"][\"reverseGeocode\"]>[0]) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.maps.reverseGeocode(coord)\n },\n placeAutocomplete(req: Parameters<CloudClient[\"runtime\"][\"maps\"][\"placeAutocomplete\"]>[0]) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.maps.placeAutocomplete(req)\n },\n placeDetails(req: Parameters<CloudClient[\"runtime\"][\"maps\"][\"placeDetails\"]>[0]) {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.maps.placeDetails(req)\n },\n /**\n * The deployment's public map render token ({provider, token}) for the\n * consumers that can't be proxied (tiles, native nav SDK). `token` null =\n * this deployment serves none. See MapboxTokenService for the caching\n * consumer.\n */\n renderToken() {\n if (!client) throw new Error(\"cloud client not connected\")\n return client.runtime.maps.renderToken()\n },\n },\n\n core: {\n reports: {\n submit(...args: Parameters<CloudCore[\"reports\"][\"submit\"]>) {\n return getCoreClient().reports.submit(...args)\n },\n addLogs(...args: Parameters<CloudCore[\"reports\"][\"addLogs\"]>) {\n return getCoreClient().reports.addLogs(...args)\n },\n addScreenshots(...args: Parameters<CloudCore[\"reports\"][\"addScreenshots\"]>) {\n return getCoreClient().reports.addScreenshots(...args)\n },\n complete(...args: Parameters<CloudCore[\"reports\"][\"complete\"]>) {\n return getCoreClient().reports.complete(...args)\n },\n },\n supportProfile: {\n update(...args: Parameters<CloudCore[\"supportProfile\"][\"update\"]>) {\n return getCoreClient().supportProfile.update(...args)\n },\n },\n },\n\n hasAudioSubscriptions(): boolean {\n return audioSubscriptions.length > 0\n },\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"SupportProfileSync.d.ts","sourceRoot":"","sources":["../../src/services/SupportProfileSync.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,uBAAuB,CAAA;AAwB5D;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAO9C;AAED,wBAAgB,sBAAsB,IAAI,IAAI,CAgB7C;AA+ED,wBAAgB,iCAAiC,CAAC,MAAM,EAAE;IACxD,MAAM,EAAE,UAAU,GAAG,cAAc,GAAG,OAAO,CAAA;CAC9C,GAAG,MAAM,GAAG,IAAI,CAGhB;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,mBAAmB,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED,wBAAgB,aAAa,CAAC,UAAU,OAAa,GAAG,iBAAiB,CAoCxE;AAED,sGAAsG;AACtG,wBAAgB,qCAAqC,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAiBzF;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,CAEvE"}
1
+ {"version":3,"file":"SupportProfileSync.d.ts","sourceRoot":"","sources":["../../src/services/SupportProfileSync.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,uBAAuB,CAAA;AAwB5D;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAO9C;AAED,wBAAgB,sBAAsB,IAAI,IAAI,CAgB7C;AAiFD,wBAAgB,iCAAiC,CAAC,MAAM,EAAE;IACxD,MAAM,EAAE,UAAU,GAAG,cAAc,GAAG,OAAO,CAAA;CAC9C,GAAG,MAAM,GAAG,IAAI,CAGhB;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,mBAAmB,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED,wBAAgB,aAAa,CAAC,UAAU,OAAa,GAAG,iBAAiB,CAoCxE;AAED,sGAAsG;AACtG,wBAAgB,qCAAqC,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAiBzF;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,CAEvE"}
@@ -83,6 +83,9 @@ function armDebounce(generation) {
83
83
  async function sendCurrentSnapshot(force, generation = syncGeneration) {
84
84
  if (!unsubscribe || generation !== syncGeneration)
85
85
  return;
86
+ // Every send would fail into the retry backoff with no client to send through.
87
+ if (cloudClientService.isCloudDisabled())
88
+ return;
86
89
  if (sendingGeneration === generation) {
87
90
  const fingerprint = snapshotFingerprint(buildSnapshot());
88
91
  if (fingerprint !== lastSentFingerprint)
@@ -1 +1 @@
1
- {"version":3,"file":"SupportProfileSync.js","sourceRoot":"","sources":["../../src/services/SupportProfileSync.ts"],"names":[],"mappings":"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","sourcesContent":["import Constants from \"expo-constants\"\nimport * as Device from \"expo-device\"\nimport {Platform} from \"react-native\"\nimport type {SupportStateInput} from \"@glassly/cloud-client\"\n\nimport {useGlassesStore} from \"../stores/glasses\"\nimport {BgTimer} from \"../utils/timers\"\nimport {cloudClientService} from \"./CloudClientService\"\n\nconst ENGINE_VERSION = (require(\"../../package.json\") as {version?: string}).version\nconst BLUETOOTH_SDK_VERSION = (require(\"@glassly/bluetooth-sdk/package.json\") as {version?: string}).version\nconst DEBOUNCE_MS = 2_000\nconst RETRY_MS = 30_000\nconst HEARTBEAT_MS = 6 * 60 * 60_000\n\nlet unsubscribe: (() => void) | null = null\nlet debounceTimer: number | null = null\nlet retryTimer: number | null = null\nlet heartbeatTimer: number | null = null\nlet lastSentFingerprint: string | null = null\nlet queuedFingerprint: string | null = null\nlet sendingGeneration: number | null = null\nlet syncGeneration = 0\nlet consecutiveSendFailures = 0\nlet lastFailure: {code: string; stage: string} | null = null\nlet lastConnectionState: string | null = null\n\n/**\n * Keep Cloud's canonical support snapshot current without creating an event\n * stream from noisy store updates. Only the explicitly selected fields below\n * leave the phone; Wi-Fi, Bluetooth addresses, location and diagnostics do not.\n */\nexport function startSupportProfileSync(): void {\n if (unsubscribe) return\n const generation = ++syncGeneration\n lastConnectionState = useGlassesStore.getState().connection.state\n unsubscribe = useGlassesStore.subscribe(() => handleGlassesStoreChange(generation))\n heartbeatTimer = BgTimer.setInterval(() => void sendCurrentSnapshot(true, generation), HEARTBEAT_MS)\n void sendCurrentSnapshot(true, generation)\n}\n\nexport function stopSupportProfileSync(): void {\n syncGeneration += 1\n unsubscribe?.()\n unsubscribe = null\n if (debounceTimer !== null) BgTimer.clearTimeout(debounceTimer)\n if (retryTimer !== null) BgTimer.clearTimeout(retryTimer)\n if (heartbeatTimer !== null) BgTimer.clearInterval(heartbeatTimer)\n debounceTimer = null\n retryTimer = null\n heartbeatTimer = null\n lastSentFingerprint = null\n queuedFingerprint = null\n sendingGeneration = null\n consecutiveSendFailures = 0\n lastFailure = null\n lastConnectionState = null\n}\n\nfunction handleGlassesStoreChange(generation: number): void {\n if (!unsubscribe || generation !== syncGeneration) return\n const connectionState = useGlassesStore.getState().connection.state\n if (connectionState === \"connected\" && lastConnectionState !== \"connected\") lastFailure = null\n lastConnectionState = connectionState\n scheduleMeaningfulUpdate(generation)\n}\n\nfunction scheduleMeaningfulUpdate(generation = syncGeneration): void {\n if (!unsubscribe || generation !== syncGeneration) return\n const fingerprint = snapshotFingerprint(buildSnapshot())\n if (fingerprint === lastSentFingerprint) return\n queuedFingerprint = fingerprint\n armDebounce(generation)\n}\n\nfunction armDebounce(generation: number): void {\n if (debounceTimer !== null) BgTimer.clearTimeout(debounceTimer)\n debounceTimer = BgTimer.setTimeout(() => {\n debounceTimer = null\n void sendCurrentSnapshot(false, generation)\n }, DEBOUNCE_MS)\n}\n\nasync function sendCurrentSnapshot(force: boolean, generation = syncGeneration): Promise<void> {\n if (!unsubscribe || generation !== syncGeneration) return\n if (sendingGeneration === generation) {\n const fingerprint = snapshotFingerprint(buildSnapshot())\n if (fingerprint !== lastSentFingerprint) queuedFingerprint = fingerprint\n return\n }\n const snapshot = buildSnapshot()\n const fingerprint = snapshotFingerprint(snapshot)\n if (!force && fingerprint === lastSentFingerprint) return\n\n sendingGeneration = generation\n let retryDelayMs: number | null = null\n try {\n const result = await cloudClientService.core.supportProfile.update(snapshot)\n if (generation !== syncGeneration || !unsubscribe) return\n consecutiveSendFailures = 0\n retryDelayMs = retryDelayForSupportProfileResult(result)\n if (retryDelayMs === null) {\n lastSentFingerprint = fingerprint\n if (queuedFingerprint === fingerprint) queuedFingerprint = null\n if (retryTimer !== null) BgTimer.clearTimeout(retryTimer)\n retryTimer = null\n }\n } catch (error) {\n if (generation !== syncGeneration || !unsubscribe) return\n consecutiveSendFailures += 1\n retryDelayMs = retryDelayForSendFailure(consecutiveSendFailures)\n console.warn(\n `supportProfile: Cloud update failed (retry in ${Math.round(retryDelayMs / 1_000)}s):`,\n error instanceof Error ? error.message : error,\n )\n } finally {\n const generationIsActive = generation === syncGeneration && sendingGeneration === generation && Boolean(unsubscribe)\n if (generationIsActive) {\n sendingGeneration = null\n if (retryDelayMs !== null) {\n if (retryTimer !== null) BgTimer.clearTimeout(retryTimer)\n retryTimer = BgTimer.setTimeout(() => {\n retryTimer = null\n void sendCurrentSnapshot(true, generation)\n }, retryDelayMs)\n } else {\n const currentFingerprint = snapshotFingerprint(buildSnapshot())\n if (currentFingerprint !== lastSentFingerprint) {\n queuedFingerprint = currentFingerprint\n if (retryTimer === null) armDebounce(generation)\n }\n }\n }\n }\n}\n\nexport function retryDelayForSupportProfileResult(result: {\n status: \"accepted\" | \"deduplicated\" | \"stale\"\n}): number | null {\n if (result.status === \"accepted\" || result.status === \"deduplicated\") return null\n return RETRY_MS\n}\n\n/**\n * Support freshness is not worth an aggressive retry loop. A snapshot the\n * server keeps rejecting (skewed clock, deleted account, signed-out host)\n * backs off exponentially until it converges on the heartbeat cadence.\n */\nexport function retryDelayForSendFailure(consecutiveFailures: number): number {\n return Math.min(HEARTBEAT_MS, RETRY_MS * 2 ** Math.min(Math.max(consecutiveFailures, 1) - 1, 10))\n}\n\nexport function buildSnapshot(observedAt = new Date()): SupportStateInput {\n const glasses = useGlassesStore.getState()\n const device = {\n hardwareId: optional(glasses.serialNumber),\n model: optional(glasses.deviceModel),\n androidVersion: optional(glasses.androidVersion),\n firmwareVersion: optional(glasses.firmwareVersion),\n mtkFirmwareVersion: optional(glasses.mtkFirmwareVersion),\n besFirmwareVersion: optional(glasses.besFirmwareVersion),\n appVersion: optional(glasses.appVersion),\n buildNumber: optional(glasses.buildNumber),\n }\n const hasDevice = Object.values(device).some(Boolean)\n const constants = Constants as typeof Constants & {\n nativeAppVersion?: string | null\n nativeBuildVersion?: string | null\n }\n return {\n observedAt: observedAt.toISOString(),\n host: {\n appVersion: optional(constants.nativeAppVersion ?? Constants.expoConfig?.version),\n appBuild: optional(constants.nativeBuildVersion),\n engineVersion: optional(ENGINE_VERSION),\n bluetoothSdkVersion: optional(BLUETOOTH_SDK_VERSION),\n phonePlatform: Platform.OS === \"ios\" || Platform.OS === \"android\" ? Platform.OS : \"unknown\",\n phoneModel: optional(Device.modelName),\n phoneOsVersion: optional(\n Platform.OS === \"android\"\n ? String((Platform.constants as {Release?: string} | undefined)?.Release ?? Platform.Version)\n : String(Platform.Version),\n ),\n connectionState: glasses.connection.state,\n ...(lastFailure ? {failureCode: lastFailure.code, failureStage: lastFailure.stage} : {}),\n },\n ...(hasDevice ? {device} : {}),\n }\n}\n\n/** Record only normalized connection failures; arbitrary exception messages never leave the phone. */\nexport function recordSupportProfileConnectionFailure(error: unknown, stage: string): void {\n const rawCode =\n typeof error === \"object\" && error && \"code\" in error ? String((error as {code?: unknown}).code ?? \"\") : \"\"\n const message = error instanceof Error ? `${error.name} ${error.message}`.toLowerCase() : \"\"\n const code = /^[a-zA-Z0-9_.-]{1,64}$/.test(rawCode)\n ? rawCode.toLowerCase()\n : message.includes(\"permission\")\n ? \"permission_denied\"\n : message.includes(\"bluetooth\") && (message.includes(\"off\") || message.includes(\"unavailable\"))\n ? \"bluetooth_unavailable\"\n : message.includes(\"not found\") || message.includes(\"no default\")\n ? \"device_not_found\"\n : message.includes(\"timeout\")\n ? \"connect_timeout\"\n : \"connect_failed\"\n lastFailure = {code, stage: stage.replace(/[^a-zA-Z0-9_.-]/g, \"_\").slice(0, 64)}\n scheduleMeaningfulUpdate()\n}\n\nexport function snapshotFingerprint(snapshot: SupportStateInput): string {\n return JSON.stringify({host: snapshot.host, device: snapshot.device})\n}\n\nfunction optional(value: string | null | undefined): string | undefined {\n const trimmed = value?.trim()\n return trimmed ? trimmed.slice(0, 128) : undefined\n}\n"]}
1
+ {"version":3,"file":"SupportProfileSync.js","sourceRoot":"","sources":["../../src/services/SupportProfileSync.ts"],"names":[],"mappings":"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","sourcesContent":["import Constants from \"expo-constants\"\nimport * as Device from \"expo-device\"\nimport {Platform} from \"react-native\"\nimport type {SupportStateInput} from \"@glassly/cloud-client\"\n\nimport {useGlassesStore} from \"../stores/glasses\"\nimport {BgTimer} from \"../utils/timers\"\nimport {cloudClientService} from \"./CloudClientService\"\n\nconst ENGINE_VERSION = (require(\"../../package.json\") as {version?: string}).version\nconst BLUETOOTH_SDK_VERSION = (require(\"@glassly/bluetooth-sdk/package.json\") as {version?: string}).version\nconst DEBOUNCE_MS = 2_000\nconst RETRY_MS = 30_000\nconst HEARTBEAT_MS = 6 * 60 * 60_000\n\nlet unsubscribe: (() => void) | null = null\nlet debounceTimer: number | null = null\nlet retryTimer: number | null = null\nlet heartbeatTimer: number | null = null\nlet lastSentFingerprint: string | null = null\nlet queuedFingerprint: string | null = null\nlet sendingGeneration: number | null = null\nlet syncGeneration = 0\nlet consecutiveSendFailures = 0\nlet lastFailure: {code: string; stage: string} | null = null\nlet lastConnectionState: string | null = null\n\n/**\n * Keep Cloud's canonical support snapshot current without creating an event\n * stream from noisy store updates. Only the explicitly selected fields below\n * leave the phone; Wi-Fi, Bluetooth addresses, location and diagnostics do not.\n */\nexport function startSupportProfileSync(): void {\n if (unsubscribe) return\n const generation = ++syncGeneration\n lastConnectionState = useGlassesStore.getState().connection.state\n unsubscribe = useGlassesStore.subscribe(() => handleGlassesStoreChange(generation))\n heartbeatTimer = BgTimer.setInterval(() => void sendCurrentSnapshot(true, generation), HEARTBEAT_MS)\n void sendCurrentSnapshot(true, generation)\n}\n\nexport function stopSupportProfileSync(): void {\n syncGeneration += 1\n unsubscribe?.()\n unsubscribe = null\n if (debounceTimer !== null) BgTimer.clearTimeout(debounceTimer)\n if (retryTimer !== null) BgTimer.clearTimeout(retryTimer)\n if (heartbeatTimer !== null) BgTimer.clearInterval(heartbeatTimer)\n debounceTimer = null\n retryTimer = null\n heartbeatTimer = null\n lastSentFingerprint = null\n queuedFingerprint = null\n sendingGeneration = null\n consecutiveSendFailures = 0\n lastFailure = null\n lastConnectionState = null\n}\n\nfunction handleGlassesStoreChange(generation: number): void {\n if (!unsubscribe || generation !== syncGeneration) return\n const connectionState = useGlassesStore.getState().connection.state\n if (connectionState === \"connected\" && lastConnectionState !== \"connected\") lastFailure = null\n lastConnectionState = connectionState\n scheduleMeaningfulUpdate(generation)\n}\n\nfunction scheduleMeaningfulUpdate(generation = syncGeneration): void {\n if (!unsubscribe || generation !== syncGeneration) return\n const fingerprint = snapshotFingerprint(buildSnapshot())\n if (fingerprint === lastSentFingerprint) return\n queuedFingerprint = fingerprint\n armDebounce(generation)\n}\n\nfunction armDebounce(generation: number): void {\n if (debounceTimer !== null) BgTimer.clearTimeout(debounceTimer)\n debounceTimer = BgTimer.setTimeout(() => {\n debounceTimer = null\n void sendCurrentSnapshot(false, generation)\n }, DEBOUNCE_MS)\n}\n\nasync function sendCurrentSnapshot(force: boolean, generation = syncGeneration): Promise<void> {\n if (!unsubscribe || generation !== syncGeneration) return\n // Every send would fail into the retry backoff with no client to send through.\n if (cloudClientService.isCloudDisabled()) return\n if (sendingGeneration === generation) {\n const fingerprint = snapshotFingerprint(buildSnapshot())\n if (fingerprint !== lastSentFingerprint) queuedFingerprint = fingerprint\n return\n }\n const snapshot = buildSnapshot()\n const fingerprint = snapshotFingerprint(snapshot)\n if (!force && fingerprint === lastSentFingerprint) return\n\n sendingGeneration = generation\n let retryDelayMs: number | null = null\n try {\n const result = await cloudClientService.core.supportProfile.update(snapshot)\n if (generation !== syncGeneration || !unsubscribe) return\n consecutiveSendFailures = 0\n retryDelayMs = retryDelayForSupportProfileResult(result)\n if (retryDelayMs === null) {\n lastSentFingerprint = fingerprint\n if (queuedFingerprint === fingerprint) queuedFingerprint = null\n if (retryTimer !== null) BgTimer.clearTimeout(retryTimer)\n retryTimer = null\n }\n } catch (error) {\n if (generation !== syncGeneration || !unsubscribe) return\n consecutiveSendFailures += 1\n retryDelayMs = retryDelayForSendFailure(consecutiveSendFailures)\n console.warn(\n `supportProfile: Cloud update failed (retry in ${Math.round(retryDelayMs / 1_000)}s):`,\n error instanceof Error ? error.message : error,\n )\n } finally {\n const generationIsActive = generation === syncGeneration && sendingGeneration === generation && Boolean(unsubscribe)\n if (generationIsActive) {\n sendingGeneration = null\n if (retryDelayMs !== null) {\n if (retryTimer !== null) BgTimer.clearTimeout(retryTimer)\n retryTimer = BgTimer.setTimeout(() => {\n retryTimer = null\n void sendCurrentSnapshot(true, generation)\n }, retryDelayMs)\n } else {\n const currentFingerprint = snapshotFingerprint(buildSnapshot())\n if (currentFingerprint !== lastSentFingerprint) {\n queuedFingerprint = currentFingerprint\n if (retryTimer === null) armDebounce(generation)\n }\n }\n }\n }\n}\n\nexport function retryDelayForSupportProfileResult(result: {\n status: \"accepted\" | \"deduplicated\" | \"stale\"\n}): number | null {\n if (result.status === \"accepted\" || result.status === \"deduplicated\") return null\n return RETRY_MS\n}\n\n/**\n * Support freshness is not worth an aggressive retry loop. A snapshot the\n * server keeps rejecting (skewed clock, deleted account, signed-out host)\n * backs off exponentially until it converges on the heartbeat cadence.\n */\nexport function retryDelayForSendFailure(consecutiveFailures: number): number {\n return Math.min(HEARTBEAT_MS, RETRY_MS * 2 ** Math.min(Math.max(consecutiveFailures, 1) - 1, 10))\n}\n\nexport function buildSnapshot(observedAt = new Date()): SupportStateInput {\n const glasses = useGlassesStore.getState()\n const device = {\n hardwareId: optional(glasses.serialNumber),\n model: optional(glasses.deviceModel),\n androidVersion: optional(glasses.androidVersion),\n firmwareVersion: optional(glasses.firmwareVersion),\n mtkFirmwareVersion: optional(glasses.mtkFirmwareVersion),\n besFirmwareVersion: optional(glasses.besFirmwareVersion),\n appVersion: optional(glasses.appVersion),\n buildNumber: optional(glasses.buildNumber),\n }\n const hasDevice = Object.values(device).some(Boolean)\n const constants = Constants as typeof Constants & {\n nativeAppVersion?: string | null\n nativeBuildVersion?: string | null\n }\n return {\n observedAt: observedAt.toISOString(),\n host: {\n appVersion: optional(constants.nativeAppVersion ?? Constants.expoConfig?.version),\n appBuild: optional(constants.nativeBuildVersion),\n engineVersion: optional(ENGINE_VERSION),\n bluetoothSdkVersion: optional(BLUETOOTH_SDK_VERSION),\n phonePlatform: Platform.OS === \"ios\" || Platform.OS === \"android\" ? Platform.OS : \"unknown\",\n phoneModel: optional(Device.modelName),\n phoneOsVersion: optional(\n Platform.OS === \"android\"\n ? String((Platform.constants as {Release?: string} | undefined)?.Release ?? Platform.Version)\n : String(Platform.Version),\n ),\n connectionState: glasses.connection.state,\n ...(lastFailure ? {failureCode: lastFailure.code, failureStage: lastFailure.stage} : {}),\n },\n ...(hasDevice ? {device} : {}),\n }\n}\n\n/** Record only normalized connection failures; arbitrary exception messages never leave the phone. */\nexport function recordSupportProfileConnectionFailure(error: unknown, stage: string): void {\n const rawCode =\n typeof error === \"object\" && error && \"code\" in error ? String((error as {code?: unknown}).code ?? \"\") : \"\"\n const message = error instanceof Error ? `${error.name} ${error.message}`.toLowerCase() : \"\"\n const code = /^[a-zA-Z0-9_.-]{1,64}$/.test(rawCode)\n ? rawCode.toLowerCase()\n : message.includes(\"permission\")\n ? \"permission_denied\"\n : message.includes(\"bluetooth\") && (message.includes(\"off\") || message.includes(\"unavailable\"))\n ? \"bluetooth_unavailable\"\n : message.includes(\"not found\") || message.includes(\"no default\")\n ? \"device_not_found\"\n : message.includes(\"timeout\")\n ? \"connect_timeout\"\n : \"connect_failed\"\n lastFailure = {code, stage: stage.replace(/[^a-zA-Z0-9_.-]/g, \"_\").slice(0, 64)}\n scheduleMeaningfulUpdate()\n}\n\nexport function snapshotFingerprint(snapshot: SupportStateInput): string {\n return JSON.stringify({host: snapshot.host, device: snapshot.device})\n}\n\nfunction optional(value: string | null | undefined): string | undefined {\n const trimmed = value?.trim()\n return trimmed ? trimmed.slice(0, 128) : undefined\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glassly/engine",
3
- "version": "0.4.0-dev.1029",
3
+ "version": "0.4.0-dev.1030",
4
4
  "description": "Glassly Engine — miniapp registry, WebView bridge, and miniapp store",
5
5
  "main": "build/index.js",
6
6
  "react-native": "src/index.ts",
@@ -97,17 +97,17 @@
97
97
  "registry": "https://registry.npmjs.org/"
98
98
  },
99
99
  "dependencies": {
100
- "@glassly/bluetooth-sdk": "0.4.0-dev.1029",
101
- "@glassly/cloud-client": "0.4.0-dev.1029",
102
- "@glassly/cloud-protocol": "0.4.0-dev.1029",
103
- "@glassly/crust": "0.4.0-dev.1029",
104
- "@glassly/miniapp": "0.4.0-dev.1029",
100
+ "@glassly/bluetooth-sdk": "0.4.0-dev.1030",
101
+ "@glassly/cloud-client": "0.4.0-dev.1030",
102
+ "@glassly/cloud-protocol": "0.4.0-dev.1030",
103
+ "@glassly/crust": "0.4.0-dev.1030",
104
+ "@glassly/miniapp": "0.4.0-dev.1030",
105
105
  "buffer": "^6.0.3",
106
106
  "events": "^3.3.0",
107
107
  "react-native-marked": "8.3.2",
108
108
  "semver": "^7.7.4",
109
109
  "typesafe-ts": "^1.7.1",
110
- "@glassly/llm-providers": "0.4.0-dev.1029",
110
+ "@glassly/llm-providers": "0.4.0-dev.1030",
111
111
  "@huggingface/jinja": "^0.5.9",
112
112
  "jsonrepair": "^3.12.0"
113
113
  },
package/src/engine.ts CHANGED
@@ -129,12 +129,14 @@ export const engine = {
129
129
  // Not awaited: the exchange behind it is a Core round trip with no client
130
130
  // deadline, and start() must resolve offline. The glasses get the token
131
131
  // when it lands; identity resolution joins the same single-flight exchange.
132
- void cloudClientService.syncCoreTokenToBluetooth().catch((error) => {
133
- console.warn(
134
- "engine.start: initial Cloud core token sync failed:",
135
- error instanceof Error ? error.message : error,
136
- )
137
- })
132
+ if (!cloudClientService.isCloudDisabled()) {
133
+ void cloudClientService.syncCoreTokenToBluetooth().catch((error) => {
134
+ console.warn(
135
+ "engine.start: initial Cloud core token sync failed:",
136
+ error instanceof Error ? error.message : error,
137
+ )
138
+ })
139
+ }
138
140
  startSupportProfileSync()
139
141
  // Push device-setting changes to the glasses for ANY host, so
140
142
  // engine.glasses.settings.set() reaches the device (not just the Glassly app).
@@ -12,9 +12,9 @@ export interface EngineReleaseMetadata {
12
12
  export const ENGINE_RELEASE_METADATA: Readonly<EngineReleaseMetadata> = Object.freeze({
13
13
  "schemaVersion": 1,
14
14
  "familyBaseVersion": "0.4.0",
15
- "releaseIdentity": "0.4.0-dev.1029",
16
- "releaseSetId": "glassly-0.4.0-dev.1029",
17
- "sourceCommit": "d166c3bc3c30f7c5ef90313ce0156b14ee51a127",
15
+ "releaseIdentity": "0.4.0-dev.1030",
16
+ "releaseSetId": "glassly-0.4.0-dev.1030",
17
+ "sourceCommit": "5f4d8792ed56abb1483e8353e3c7aca1d5e66fd7",
18
18
  "otaManifestUrl": null,
19
19
  "otaManifestSha256": null
20
20
  })
@@ -190,9 +190,16 @@ function resolveEndpoints(): {core: string; runtime: string} {
190
190
  }
191
191
  }
192
192
 
193
+ // Via init(), never construct(): init() holds the disable-cloud gate, and a
194
+ // client built past it opens the runtime socket and retries it forever.
195
+ function requireClient(): CloudClient {
196
+ if (!client) cloudClientService.init()
197
+ if (!client) throw new Error("Glassly cloud is disabled")
198
+ return client
199
+ }
200
+
193
201
  function getCoreClient(): CloudCore {
194
- if (!client) construct()
195
- const core = client?.core
202
+ const core = requireClient().core
196
203
  if (!core) throw new Error("cloud client core not configured")
197
204
  return core
198
205
  }
@@ -207,9 +214,7 @@ function syncCoreAccessTokenToBluetooth(): Promise<string> {
207
214
  }
208
215
 
209
216
  async function syncCoreAccessTokenToBluetoothInternal(): Promise<string> {
210
- if (!client) construct()
211
- const c = client
212
- if (!c) throw new Error("cloud client not initialized")
217
+ const c = requireClient()
213
218
 
214
219
  const token = await c.auth.getCoreToken()
215
220
  if (c !== client) {
@@ -83,6 +83,8 @@ function armDebounce(generation: number): void {
83
83
 
84
84
  async function sendCurrentSnapshot(force: boolean, generation = syncGeneration): Promise<void> {
85
85
  if (!unsubscribe || generation !== syncGeneration) return
86
+ // Every send would fail into the retry backoff with no client to send through.
87
+ if (cloudClientService.isCloudDisabled()) return
86
88
  if (sendingGeneration === generation) {
87
89
  const fingerprint = snapshotFingerprint(buildSnapshot())
88
90
  if (fingerprint !== lastSentFingerprint) queuedFingerprint = fingerprint