@glassly/engine 0.3.5-dev.805 → 0.3.5-dev.807

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;AA8C5G,eAAO,MAAM,MAAM;IACjB,2EAA2E;;IAE3E,8EAA8E;;IAE9E;iDAC6C;;IAkG7C;;yCAEqC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAoCrC,kEAAkE;;;;;;;;;;;;;;;;;;IAElE,wEAAwE;;;;;;;;IAExE,sEAAsE;;;;;;;;;;;;IAEtE,qFAAqF;;;;gBAnInB,CAAC;mBAEjE,CADC;;;gBAGmD,CAAC;mBACjD,CAAC;;;;;;;;;;;;;;;;;IAgIP,qEAAqE;;;;IAErE,sFAAsF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAEtF,6EAA6E;;;;;;;;;;;;IAE7E,iFAAiF;;;;;;;;;;;;;;;;;;;;;;;;IAEjF,8CAA8C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAE9C,uDAAuD;;;;;;;;;;;;;;;;IAEvD,8EAA8E;;;;;;;;IAE9E,qFAAqF;;;;IAErF,4EAA4E;;;;;;;;;;;IAE5E,+EAA+E;;;;;;;;;;;;;;;IAE/E,kFAAkF;;;;;+BAzJpE,CAAC;;;+BAU+C,CAAC;;;;;;;;;;;;IAiJ/D,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;AA+C5G,eAAO,MAAM,MAAM;IACjB,2EAA2E;;IAE3E,8EAA8E;;IAE9E;iDAC6C;;IAyG7C;;yCAEqC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAoCrC,kEAAkE;;;;;;;;;;;;;;;;;;IAElE,wEAAwE;;;;;;;;IAExE,sEAAsE;;;;;;;;;;;;IAEtE,qFAAqF;;;;gBA3IhD,CAAC;mBAAiB,CAAC;;;gBAIrC,CAAC;mBAAkB,CAAA;;;;;;;;;;;;;;;;;IAyItC,qEAAqE;;;;IAErE,sFAAsF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAEtF,6EAA6E;;;;;;;;;;;;IAE7E,iFAAiF;;;;;;;;;;;;;;;;;;;;;;;;IAEjF,8CAA8C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAE9C,uDAAuD;;;;;;;;;;;;;;;;IAEvD,8EAA8E;;;;;;;;IAE9E,qFAAqF;;;;IAErF,4EAA4E;;;;;;;;;;;IAE5E,+EAA+E;;;;;;;;;;;;;;;IAE/E,kFAAkF;;;;;+BAlKnE,CAAC;;;+BAUd,CAAA;;;;;;;;;;;;IA0JF,mFAAmF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAGpF,CAAA"}
package/build/engine.js CHANGED
@@ -13,6 +13,7 @@ import { cloudClientService } from "./services/CloudClientService";
13
13
  import { hydrateDeviceStore, demoteOrphanedDefaultWearable } from "./services/DeviceStoreHydration";
14
14
  import { startPairedGlassesLatch, stopPairedGlassesLatch } from "./services/PairedGlassesLatch";
15
15
  import { startMiniappPauseCoordinator, stopMiniappPauseCoordinator } from "./services/MiniappPauseCoordinator";
16
+ import { nativeRestoreLaunchQuery, reconnectAfterBluetoothRestoreLaunch } from "./services/BluetoothRestoreLaunch";
16
17
  import { startGlassesSettingsSync, stopGlassesSettingsSync } from "./services/GlassesSettingsSync";
17
18
  import { startGlassesStatusProjection, stopGlassesStatusProjection } from "./services/GlassesStatusProjection";
18
19
  import { startOtaService, stopOtaService } from "./services/OtaService";
@@ -109,6 +110,13 @@ export const engine = {
109
110
  // Pause local miniapps while the paired glasses stay disconnected. Reads
110
111
  // the pairing identity, so after the settings load like the latch.
111
112
  startMiniappPauseCoordinator();
113
+ // iOS relaunched the app in the background to hand back a preserved glasses link:
114
+ // no screen will ask to connect, so the engine does. Not awaited; start() must not
115
+ // wait on a BLE handshake.
116
+ void reconnectAfterBluetoothRestoreLaunch({
117
+ launchedForRestore: nativeRestoreLaunchQuery(),
118
+ connectDefault: () => glasses.connectDefault(),
119
+ });
112
120
  // Project the glasses' OTA events into the store for the engine.ota read surface.
113
121
  startOtaService();
114
122
  // Forward glasses mic_lc3 frames to the v2 cloud session so cloud transcription
@@ -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 {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 {startAppleWatchLink, stopAppleWatchLink} from \"./services/appleWatch/AppleWatchLink\"\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 {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 // 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 // Apple Watch remote (iOS): status and mirror frames out, wrist commands in.\n startAppleWatchLink()\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(\"apple watch link\", stopAppleWatchLink)\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 /** 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 {startAppleWatchLink, stopAppleWatchLink} from \"./services/appleWatch/AppleWatchLink\"\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 {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 // Apple Watch remote (iOS): status and mirror frames out, wrist commands in.\n startAppleWatchLink()\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(\"apple watch link\", stopAppleWatchLink)\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 /** 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.3.5",
4
- "releaseIdentity": "0.3.5-dev.805",
5
- "releaseSetId": "glassly-0.3.5-dev.805",
6
- "sourceCommit": "e9628b858b8739865c3bf8802f68c939d38ed71e",
4
+ "releaseIdentity": "0.3.5-dev.807",
5
+ "releaseSetId": "glassly-0.3.5-dev.807",
6
+ "sourceCommit": "2cb6911244cbf49adb78bf687f5be9049aa49f55",
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,eAAe;IAClC,cAAc,EAAE,uBAAuB;IACvC,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.3.5\",\n \"releaseIdentity\": \"0.3.5-dev.805\",\n \"releaseSetId\": \"glassly-0.3.5-dev.805\",\n \"sourceCommit\": \"e9628b858b8739865c3bf8802f68c939d38ed71e\",\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,eAAe;IAClC,cAAc,EAAE,uBAAuB;IACvC,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.3.5\",\n \"releaseIdentity\": \"0.3.5-dev.807\",\n \"releaseSetId\": \"glassly-0.3.5-dev.807\",\n \"sourceCommit\": \"2cb6911244cbf49adb78bf687f5be9049aa49f55\",\n \"otaManifestUrl\": null,\n \"otaManifestSha256\": null\n})\n"]}
@@ -0,0 +1,8 @@
1
+ type Deps = {
2
+ launchedForRestore: () => Promise<boolean>;
3
+ connectDefault: () => Promise<void>;
4
+ };
5
+ export declare function reconnectAfterBluetoothRestoreLaunch(deps: Deps): Promise<boolean>;
6
+ export declare function nativeRestoreLaunchQuery(): () => Promise<boolean>;
7
+ export {};
8
+ //# sourceMappingURL=BluetoothRestoreLaunch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BluetoothRestoreLaunch.d.ts","sourceRoot":"","sources":["../../src/services/BluetoothRestoreLaunch.ts"],"names":[],"mappings":"AAWA,KAAK,IAAI,GAAG;IACV,kBAAkB,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IAC1C,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CACpC,CAAA;AAED,wBAAsB,oCAAoC,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAgBvF;AAED,wBAAgB,wBAAwB,IAAI,MAAM,OAAO,CAAC,OAAO,CAAC,CAEjE"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Reconnect the glasses when iOS relaunched the app for a preserved link.
3
+ *
4
+ * With CoreBluetooth state restoration, iOS keeps the lens connections after
5
+ * it terminates the app and relaunches it in the background on the next
6
+ * peripheral event. No screen mounts on that launch, so the host's usual
7
+ * "connect on the home screen" never runs; the engine asks native whether this
8
+ * is such a launch and connects the default wearable itself.
9
+ */
10
+ import BluetoothSdk from "@glassly/bluetooth-sdk/internal";
11
+ export async function reconnectAfterBluetoothRestoreLaunch(deps) {
12
+ let launched = false;
13
+ try {
14
+ launched = await deps.launchedForRestore();
15
+ }
16
+ catch (error) {
17
+ console.warn("BluetoothRestoreLaunch: restore-launch query failed:", error instanceof Error ? error.message : error);
18
+ return false;
19
+ }
20
+ if (!launched)
21
+ return false;
22
+ console.log("BluetoothRestoreLaunch: relaunched for a preserved glasses link; reconnecting");
23
+ try {
24
+ await deps.connectDefault();
25
+ }
26
+ catch (error) {
27
+ console.warn("BluetoothRestoreLaunch: reconnect failed:", error instanceof Error ? error.message : error);
28
+ }
29
+ return true;
30
+ }
31
+ export function nativeRestoreLaunchQuery() {
32
+ return () => BluetoothSdk.consumeBluetoothRestoreLaunch();
33
+ }
34
+ //# sourceMappingURL=BluetoothRestoreLaunch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BluetoothRestoreLaunch.js","sourceRoot":"","sources":["../../src/services/BluetoothRestoreLaunch.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,YAAY,MAAM,iCAAiC,CAAA;AAO1D,MAAM,CAAC,KAAK,UAAU,oCAAoC,CAAC,IAAU;IACnE,IAAI,QAAQ,GAAG,KAAK,CAAA;IACpB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAA;IAC5C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,sDAAsD,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;QACpH,OAAO,KAAK,CAAA;IACd,CAAC;IACD,IAAI,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAA;IAC3B,OAAO,CAAC,GAAG,CAAC,+EAA+E,CAAC,CAAA;IAC5F,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,cAAc,EAAE,CAAA;IAC7B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,2CAA2C,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;IAC3G,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,UAAU,wBAAwB;IACtC,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,6BAA6B,EAAE,CAAA;AAC3D,CAAC","sourcesContent":["/**\n * Reconnect the glasses when iOS relaunched the app for a preserved link.\n *\n * With CoreBluetooth state restoration, iOS keeps the lens connections after\n * it terminates the app and relaunches it in the background on the next\n * peripheral event. No screen mounts on that launch, so the host's usual\n * \"connect on the home screen\" never runs; the engine asks native whether this\n * is such a launch and connects the default wearable itself.\n */\nimport BluetoothSdk from \"@glassly/bluetooth-sdk/internal\"\n\ntype Deps = {\n launchedForRestore: () => Promise<boolean>\n connectDefault: () => Promise<void>\n}\n\nexport async function reconnectAfterBluetoothRestoreLaunch(deps: Deps): Promise<boolean> {\n let launched = false\n try {\n launched = await deps.launchedForRestore()\n } catch (error) {\n console.warn(\"BluetoothRestoreLaunch: restore-launch query failed:\", error instanceof Error ? error.message : error)\n return false\n }\n if (!launched) return false\n console.log(\"BluetoothRestoreLaunch: relaunched for a preserved glasses link; reconnecting\")\n try {\n await deps.connectDefault()\n } catch (error) {\n console.warn(\"BluetoothRestoreLaunch: reconnect failed:\", error instanceof Error ? error.message : error)\n }\n return true\n}\n\nexport function nativeRestoreLaunchQuery(): () => Promise<boolean> {\n return () => BluetoothSdk.consumeBluetoothRestoreLaunch()\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glassly/engine",
3
- "version": "0.3.5-dev.805",
3
+ "version": "0.3.5-dev.807",
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.3.5-dev.805",
101
- "@glassly/cloud-client": "0.3.5-dev.805",
102
- "@glassly/cloud-protocol": "0.3.5-dev.805",
103
- "@glassly/crust": "0.3.5-dev.805",
104
- "@glassly/miniapp": "0.3.5-dev.805",
100
+ "@glassly/bluetooth-sdk": "0.3.5-dev.807",
101
+ "@glassly/cloud-client": "0.3.5-dev.807",
102
+ "@glassly/cloud-protocol": "0.3.5-dev.807",
103
+ "@glassly/crust": "0.3.5-dev.807",
104
+ "@glassly/miniapp": "0.3.5-dev.807",
105
105
  "buffer": "^6.0.3",
106
106
  "events": "^3.3.0",
107
107
  "react-native-marked": "8.1.1",
108
108
  "semver": "^7.7.4",
109
109
  "typesafe-ts": "^1.7.1",
110
- "@glassly/llm-providers": "0.3.5-dev.805",
110
+ "@glassly/llm-providers": "0.3.5-dev.807",
111
111
  "@huggingface/jinja": "^0.5.9",
112
112
  "jsonrepair": "^3.12.0"
113
113
  },
package/src/engine.ts CHANGED
@@ -13,6 +13,7 @@ import {cloudClientService} from "./services/CloudClientService"
13
13
  import {hydrateDeviceStore, demoteOrphanedDefaultWearable} from "./services/DeviceStoreHydration"
14
14
  import {startPairedGlassesLatch, stopPairedGlassesLatch} from "./services/PairedGlassesLatch"
15
15
  import {startMiniappPauseCoordinator, stopMiniappPauseCoordinator} from "./services/MiniappPauseCoordinator"
16
+ import {nativeRestoreLaunchQuery, reconnectAfterBluetoothRestoreLaunch} from "./services/BluetoothRestoreLaunch"
16
17
  import {startGlassesSettingsSync, stopGlassesSettingsSync} from "./services/GlassesSettingsSync"
17
18
  import {startGlassesStatusProjection, stopGlassesStatusProjection} from "./services/GlassesStatusProjection"
18
19
  import {startOtaService, stopOtaService} from "./services/OtaService"
@@ -109,6 +110,13 @@ export const engine = {
109
110
  // Pause local miniapps while the paired glasses stay disconnected. Reads
110
111
  // the pairing identity, so after the settings load like the latch.
111
112
  startMiniappPauseCoordinator()
113
+ // iOS relaunched the app in the background to hand back a preserved glasses link:
114
+ // no screen will ask to connect, so the engine does. Not awaited; start() must not
115
+ // wait on a BLE handshake.
116
+ void reconnectAfterBluetoothRestoreLaunch({
117
+ launchedForRestore: nativeRestoreLaunchQuery(),
118
+ connectDefault: () => glasses.connectDefault(),
119
+ })
112
120
  // Project the glasses' OTA events into the store for the engine.ota read surface.
113
121
  startOtaService()
114
122
  // Forward glasses mic_lc3 frames to the v2 cloud session so cloud transcription
@@ -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.3.5",
15
- "releaseIdentity": "0.3.5-dev.805",
16
- "releaseSetId": "glassly-0.3.5-dev.805",
17
- "sourceCommit": "e9628b858b8739865c3bf8802f68c939d38ed71e",
15
+ "releaseIdentity": "0.3.5-dev.807",
16
+ "releaseSetId": "glassly-0.3.5-dev.807",
17
+ "sourceCommit": "2cb6911244cbf49adb78bf687f5be9049aa49f55",
18
18
  "otaManifestUrl": null,
19
19
  "otaManifestSha256": null
20
20
  })
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Reconnect the glasses when iOS relaunched the app for a preserved link.
3
+ *
4
+ * With CoreBluetooth state restoration, iOS keeps the lens connections after
5
+ * it terminates the app and relaunches it in the background on the next
6
+ * peripheral event. No screen mounts on that launch, so the host's usual
7
+ * "connect on the home screen" never runs; the engine asks native whether this
8
+ * is such a launch and connects the default wearable itself.
9
+ */
10
+ import BluetoothSdk from "@glassly/bluetooth-sdk/internal"
11
+
12
+ type Deps = {
13
+ launchedForRestore: () => Promise<boolean>
14
+ connectDefault: () => Promise<void>
15
+ }
16
+
17
+ export async function reconnectAfterBluetoothRestoreLaunch(deps: Deps): Promise<boolean> {
18
+ let launched = false
19
+ try {
20
+ launched = await deps.launchedForRestore()
21
+ } catch (error) {
22
+ console.warn("BluetoothRestoreLaunch: restore-launch query failed:", error instanceof Error ? error.message : error)
23
+ return false
24
+ }
25
+ if (!launched) return false
26
+ console.log("BluetoothRestoreLaunch: relaunched for a preserved glasses link; reconnecting")
27
+ try {
28
+ await deps.connectDefault()
29
+ } catch (error) {
30
+ console.warn("BluetoothRestoreLaunch: reconnect failed:", error instanceof Error ? error.message : error)
31
+ }
32
+ return true
33
+ }
34
+
35
+ export function nativeRestoreLaunchQuery(): () => Promise<boolean> {
36
+ return () => BluetoothSdk.consumeBluetoothRestoreLaunch()
37
+ }