@mentra/engine 3.2.0-dev.259 → 3.2.0-dev.262

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/build/facades/displayMirror.js +1 -1
  2. package/build/facades/displayMirror.js.map +1 -1
  3. package/build/generated/releaseMetadata.js +5 -5
  4. package/build/generated/releaseMetadata.js.map +1 -1
  5. package/build/services/AcsMeetingService.d.ts +25 -1
  6. package/build/services/AcsMeetingService.d.ts.map +1 -1
  7. package/build/services/AcsMeetingService.js +41 -3
  8. package/build/services/AcsMeetingService.js.map +1 -1
  9. package/build/services/DisplayProcessor.d.ts +1 -1
  10. package/build/services/DisplayProcessor.js.map +1 -1
  11. package/build/services/LocalDisplayManager.d.ts +0 -4
  12. package/build/services/LocalDisplayManager.d.ts.map +1 -1
  13. package/build/services/LocalDisplayManager.js +2 -7
  14. package/build/services/LocalDisplayManager.js.map +1 -1
  15. package/build/services/LocalMiniappRuntime.d.ts +39 -24
  16. package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
  17. package/build/services/LocalMiniappRuntime.js +293 -123
  18. package/build/services/LocalMiniappRuntime.js.map +1 -1
  19. package/build/services/MentraJSRouter.d.ts +5 -9
  20. package/build/services/MentraJSRouter.d.ts.map +1 -1
  21. package/build/services/MentraJSRouter.js +5 -9
  22. package/build/services/MentraJSRouter.js.map +1 -1
  23. package/build/services/MentraUIRouter.d.ts +9 -12
  24. package/build/services/MentraUIRouter.d.ts.map +1 -1
  25. package/build/services/MentraUIRouter.js +9 -12
  26. package/build/services/MentraUIRouter.js.map +1 -1
  27. package/build/services/MiniappLauncher.d.ts +6 -9
  28. package/build/services/MiniappLauncher.d.ts.map +1 -1
  29. package/build/services/MiniappLauncher.js +6 -9
  30. package/build/services/MiniappLauncher.js.map +1 -1
  31. package/build/services/MiniappLiveness.d.ts +11 -0
  32. package/build/services/MiniappLiveness.d.ts.map +1 -1
  33. package/build/services/MiniappLiveness.js +11 -0
  34. package/build/services/MiniappLiveness.js.map +1 -1
  35. package/build/services/PhoneLocationService.d.ts +2 -2
  36. package/build/services/PhoneLocationService.d.ts.map +1 -1
  37. package/build/services/PhoneLocationService.js +5 -9
  38. package/build/services/PhoneLocationService.js.map +1 -1
  39. package/build/services/PhoneStreamCoordinator.d.ts +14 -3
  40. package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
  41. package/build/services/PhoneStreamCoordinator.js +28 -6
  42. package/build/services/PhoneStreamCoordinator.js.map +1 -1
  43. package/build/services/SoftapCallTransport.d.ts +87 -7
  44. package/build/services/SoftapCallTransport.d.ts.map +1 -1
  45. package/build/services/SoftapCallTransport.js +229 -28
  46. package/build/services/SoftapCallTransport.js.map +1 -1
  47. package/build/services/slimStreamStatus.d.ts +4 -1
  48. package/build/services/slimStreamStatus.d.ts.map +1 -1
  49. package/build/services/slimStreamStatus.js +4 -1
  50. package/build/services/slimStreamStatus.js.map +1 -1
  51. package/build/stores/apps.js +2 -2
  52. package/build/stores/apps.js.map +1 -1
  53. package/build/utils/miniappGlobals.d.ts +3 -5
  54. package/build/utils/miniappGlobals.d.ts.map +1 -1
  55. package/build/utils/miniappGlobals.js +16 -16
  56. package/build/utils/miniappGlobals.js.map +1 -1
  57. package/package.json +8 -8
  58. package/src/facades/displayMirror.ts +1 -1
  59. package/src/generated/releaseMetadata.ts +5 -5
  60. package/src/services/AcsMeetingService.ts +51 -3
  61. package/src/services/DisplayProcessor.ts +1 -1
  62. package/src/services/LocalDisplayManager.ts +2 -7
  63. package/src/services/LocalMiniappRuntime.ts +305 -133
  64. package/src/services/MentraJSRouter.ts +5 -9
  65. package/src/services/MentraUIRouter.ts +9 -12
  66. package/src/services/MiniappLauncher.ts +6 -9
  67. package/src/services/MiniappLiveness.ts +18 -0
  68. package/src/services/PhoneLocationService.ts +5 -9
  69. package/src/services/PhoneStreamCoordinator.ts +28 -7
  70. package/src/services/SoftapCallTransport.ts +274 -32
  71. package/src/services/slimStreamStatus.ts +4 -1
  72. package/src/stores/apps.ts +2 -2
  73. package/src/utils/miniappGlobals.ts +16 -16
@@ -23,10 +23,9 @@
23
23
  * Host-side handler bodies (display fan-out, mic state, transcription,
24
24
  * navigation, etc.) live untouched in `LocalMiniappRuntime.ts`.
25
25
  *
26
- * Cloud-message routing (`phone_stream_status`, `phone_managed_stream_status`)
27
- * goes straight through `LocalMiniappRuntime.handleCloudMessage` nothing
28
- * for the router to do; the responses arrive inside an envelope whose
29
- * `sendMessage` was already registered via the same path here.
26
+ * PhoneStreamCoordinator delivers stream status through LocalMiniappRuntime
27
+ * to the miniapp's registered `sendMessage` callback, using the same local
28
+ * bridge as other responses and events.
30
29
  *
31
30
  * The router also bridges native error / log / unhandled-rejection
32
31
  * events (`iface: "__log"`, `iface: "__error"`) into the standard
@@ -191,11 +190,8 @@ export declare class MentraJSRouter {
191
190
  private tryParseArgs;
192
191
  /**
193
192
  * Push a `kind="bridge"` envelope into the named JSContext's
194
- * `globalThis.__deliver`. Used both by the per-app `sendMessage`
195
- * registered via {@link registerApp} and by ad-hoc callers (e.g.
196
- * cloud-relayed stream-status responses route through
197
- * `LocalMiniappRuntime.handleCloudMessage`, which then calls the
198
- * `app.sendMessage(serialized)` registered above).
193
+ * `globalThis.__deliver`. Used by the per-app `sendMessage` registered via
194
+ * {@link registerApp} to deliver runtime responses and events locally.
199
195
  */
200
196
  private dispatchBridgeRaw;
201
197
  }
@@ -1 +1 @@
1
- {"version":3,"file":"MentraJSRouter.d.ts","sourceRoot":"","sources":["../../src/services/MentraJSRouter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MentraJSRouter.d.ts","sourceRoot":"","sources":["../../src/services/MentraJSRouter.ts"],"names":[],"mappings":"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"}
@@ -23,10 +23,9 @@
23
23
  * Host-side handler bodies (display fan-out, mic state, transcription,
24
24
  * navigation, etc.) live untouched in `LocalMiniappRuntime.ts`.
25
25
  *
26
- * Cloud-message routing (`phone_stream_status`, `phone_managed_stream_status`)
27
- * goes straight through `LocalMiniappRuntime.handleCloudMessage` nothing
28
- * for the router to do; the responses arrive inside an envelope whose
29
- * `sendMessage` was already registered via the same path here.
26
+ * PhoneStreamCoordinator delivers stream status through LocalMiniappRuntime
27
+ * to the miniapp's registered `sendMessage` callback, using the same local
28
+ * bridge as other responses and events.
30
29
  *
31
30
  * The router also bridges native error / log / unhandled-rejection
32
31
  * events (`iface: "__log"`, `iface: "__error"`) into the standard
@@ -474,11 +473,8 @@ export class MentraJSRouter {
474
473
  }
475
474
  /**
476
475
  * Push a `kind="bridge"` envelope into the named JSContext's
477
- * `globalThis.__deliver`. Used both by the per-app `sendMessage`
478
- * registered via {@link registerApp} and by ad-hoc callers (e.g.
479
- * cloud-relayed stream-status responses route through
480
- * `LocalMiniappRuntime.handleCloudMessage`, which then calls the
481
- * `app.sendMessage(serialized)` registered above).
476
+ * `globalThis.__deliver`. Used by the per-app `sendMessage` registered via
477
+ * {@link registerApp} to deliver runtime responses and events locally.
482
478
  */
483
479
  dispatchBridgeRaw(packageName, raw) {
484
480
  void this.crust.mentraJsDispatchToJs(packageName, { kind: "bridge", raw });
@@ -1 +1 @@
1
- {"version":3,"file":"MentraJSRouter.js","sourceRoot":"","sources":["../../src/services/MentraJSRouter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview MentraJSRouter — RN-side host that bridges the per-miniapp\n * JS contexts (iOS-JSC and Android-QuickJS via Zipline) into the existing\n * {@link LocalMiniappRuntime} handler set.\n *\n * Rather than re-implement the 33 dispatch arms inline, the router\n * consumes Crust's `mentrajs_message` Expo event and forwards its\n * `__bridge.send(raw)` payloads to {@link LocalMiniappRuntime.handleRawMessage}.\n * The SDK envelope shape (`{type: \"DISPLAY\", ...}` etc.) is unchanged from\n * the WebView path, so every existing handler runs verbatim. What changes\n * is the *transport*:\n *\n * - **Inbound** (background JS → host): `__dispatch(\"__bridge\", \"send\",\n * [rawJsonString])` → `mentrajs_message` event → router →\n * `LocalMiniappRuntime.handleRawMessage(packageName, raw)`.\n * - **Outbound** (host → background JS): every package registered with\n * the router gets a `sendMessage(raw)` fn that calls\n * `Crust.mentraJsDispatchToJs(packageName, {kind: \"bridge\", raw})`.\n * The polyfill's `__deliver` recognises `kind === \"bridge\"` and calls\n * `__mentraDeliverBridgeRaw(raw)`, which routes into the SDK's\n * {@link DispatchTransport.onMessage} handler.\n *\n * Host-side handler bodies (display fan-out, mic state, transcription,\n * navigation, etc.) live untouched in `LocalMiniappRuntime.ts`.\n *\n * Cloud-message routing (`phone_stream_status`, `phone_managed_stream_status`)\n * goes straight through `LocalMiniappRuntime.handleCloudMessage` — nothing\n * for the router to do; the responses arrive inside an envelope whose\n * `sendMessage` was already registered via the same path here.\n *\n * The router also bridges native error / log / unhandled-rejection\n * events (`iface: \"__log\"`, `iface: \"__error\"`) into the standard\n * `console.*` + Sentry breadcrumb pipeline so miniapp telemetry is\n * visible without bringing up a separate sink.\n */\n\nimport type {EventSubscription} from \"expo-modules-core\"\n\nimport devServerBridge from \"./DevServerBridge\"\nimport type localMiniappRuntime from \"./LocalMiniappRuntime\"\nimport type {InstalledMiniappManifest} from \"./LocalMiniappRuntime\"\nimport type {MentraJSCrashController} from \"./MentraJSCrashController\"\nimport {MentraJSLogRingBuffer, MentraJSLogThrottle, redactSecrets} from \"./MentraJSLogPipeline\"\nimport {islandNotifications} from \"./NotificationsEmitter\"\nimport type {MentraUIRouter} from \"./MentraUIRouter\"\nimport {miniappRunningRegistry} from \"./MiniappRunningRegistry\"\n\n/** The runtime's runtime instance type — the singleton exported from\n * LocalMiniappRuntime.ts (the file's `export default` is the instance,\n * not the class).\n */\ntype LocalMiniappRuntime = typeof localMiniappRuntime\n\n/**\n * Minimal subset of the Crust native module the router uses. Keeping the\n * binding loose lets us mock the module in unit tests without bringing\n * the whole Expo module surface along.\n */\nexport interface MentraJSCrustBinding {\n mentraJsDispatchToJs(packageName: string, envelope: Record<string, unknown>): Promise<void> | void\n mentraJsSetManifest(packageName: string, permissions: string[]): Promise<void> | void\n mentraJsLoadPolyfillBundle?: () => string\n mentraJsSpawn?: (packageName: string, polyfill: string, miniappJs: string) => Promise<boolean> | boolean\n mentraJsKill?: (packageName: string) => Promise<void> | void\n mentraJsAlivePackages?: () => string[]\n addListener: (event: string, handler: (payload: Record<string, unknown>) => void) => EventSubscription\n}\n\nexport interface OutboundMessagePayload {\n packageName: string\n iface: string\n method: string\n argsJson?: string\n args?: unknown[]\n reqId?: string\n // Implementation-internal: any extra fields the dispatcher attached on\n // .forwardToRn (e.g. payload metadata) are passed through verbatim.\n [extra: string]: unknown\n}\n\nexport type RouterLogger = {\n log: (message: string, payload?: unknown) => void\n warn: (message: string, payload?: unknown) => void\n error: (message: string, payload?: unknown) => void\n}\n\nconst defaultLogger: RouterLogger = {\n log: (m, p) => console.log(`[MentraJSRouter] ${m}`, p ?? \"\"),\n\n warn: (m, p) => console.warn(`[MentraJSRouter] ${m}`, p ?? \"\"),\n\n error: (m, p) => console.error(`[MentraJSRouter] ${m}`, p ?? \"\"),\n}\n\ninterface SpawnCache {\n miniappJs: string\n permissions: string[]\n installedManifest?: InstalledMiniappManifest\n}\n\nexport class MentraJSRouter {\n private subscription: EventSubscription | null = null\n private readonly registered: Set<string> = new Set()\n /** Cached spawn arguments so the crash controller can respawn after a backoff. */\n private readonly spawnCache: Map<string, SpawnCache> = new Map()\n /** Active respawn timers (so unregister() can cancel a pending respawn). */\n private readonly respawnTimers: Map<string, ReturnType<typeof setTimeout>> = new Map()\n\n /**\n * Optional crash controller. When wired, every `__error` frame from a\n * JSContext drives the state machine; an Outcome with\n * scheduleRespawnAfterMs queues a setTimeout that re-spawns the\n * miniapp's last-known JS source after the backoff delay.\n */\n crashController: MentraJSCrashController | null = null\n\n /** Hook called when a package transitions to CRASHLOOP_DISABLED. */\n onCrashloop: ((packageName: string, reason: string) => void) | null = null\n /** Hook called on the 2nd-within-window crash (toast UX). */\n onRestartToast: ((packageName: string, reason: string) => void) | null = null\n\n /**\n * Logging plumbing. Every `__log` frame passes through `redactSecrets`\n * (token/password/etc. scrubbed), then the throttle (100/min sustained\n * per pkg, 500 burst), then lands in the ring buffer + the host\n * logger. The ring buffer holds the last 200 lines/pkg so a crash\n * report can attach \"last words\" context.\n *\n * Replace with new instances in tests; production code uses the\n * defaults.\n */\n logThrottle: MentraJSLogThrottle = new MentraJSLogThrottle()\n logRing: MentraJSLogRingBuffer = new MentraJSLogRingBuffer()\n\n /**\n * Optional UI router — when wired, `__bridge.send` envelopes whose\n * inner payload type is `UI_SEND` get routed to the bound WebView\n * instead of through LocalMiniappRuntime. Two-layer miniapps set\n * this; legacy single-bundle WebView miniapps don't and the bridge\n * frames pass through unchanged.\n */\n uiRouter: MentraUIRouter | null = null\n\n constructor(\n private readonly runtime: LocalMiniappRuntime,\n private readonly crust: MentraJSCrustBinding,\n private readonly logger: RouterLogger = defaultLogger,\n ) {}\n\n /**\n * Subscribe to Crust's `mentrajs_message` event. Idempotent — calling\n * start() twice attaches a single listener.\n */\n start(): void {\n if (this.subscription) return\n this.subscription = this.crust.addListener(\"mentrajs_message\", (raw) => {\n try {\n this.handleOutbound(raw as unknown as OutboundMessagePayload)\n } catch (e) {\n this.logger.error(`outbound handler threw`, {error: String(e), raw})\n }\n })\n // A background script unregistered for missing liveness pings is dead\n // weight: its subscriptions are gone (so the mic releases) while the\n // webview keeps rendering stale state. Route it through the same\n // respawn machinery as a crash so it comes back automatically, with\n // the crash controller's backoff + crash-loop protection.\n this.runtime.onLivenessTimeout = (packageName) => {\n this.handleCrash(packageName, \"liveness: missed pings\")\n }\n }\n\n /**\n * Detach the Crust subscription. The router can be restarted later\n * with start(); registrations survive (the runtime's app map is the\n * source of truth).\n */\n stop(): void {\n this.subscription?.remove()\n this.subscription = null\n this.runtime.onLivenessTimeout = null\n }\n\n /**\n * Register a JSContext with the runtime so its handlers can fire\n * `sendMessage(raw)` against the right context. The router builds a\n * `sendMessage` that calls `Crust.mentraJsDispatchToJs(packageName,\n * {kind: \"bridge\", raw})`; the polyfill's `__deliver` then hands the\n * envelope to `DispatchTransport.onMessage` inside the miniapp.\n *\n * Mirrors `MiniappHost.registerRuntime` on the WebView side. Callers\n * (e.g. {@link spawnAndRegister} below, or the host's miniapp launch\n * pipeline) should call this once per spawn.\n */\n registerApp(packageName: string, installedManifest?: InstalledMiniappManifest): void {\n this.runtime.registerApp(\n packageName,\n (raw: string) => {\n this.dispatchBridgeRaw(packageName, raw)\n },\n installedManifest,\n )\n this.registered.add(packageName)\n // JSContext is the source-of-truth for \"miniapp running\". The\n // home tile / tray reads this registry to project the `running`\n // flag — UI WebView open/close is separate.\n miniappRunningRegistry.add(packageName)\n }\n\n /**\n * Convenience: spawn a JSContext via Crust, register the app, and\n * set its declared permissions. Returns true on successful spawn.\n *\n * The host's miniapp launch path\n * (`mobile/src/services/miniapps/launchLocalMiniapp.ts`) calls this\n * once per JSContext mount.\n */\n async spawnAndRegister(\n packageName: string,\n miniappJs: string,\n options?: {permissions?: string[]; installedManifest?: InstalledMiniappManifest},\n ): Promise<boolean> {\n if (!this.crust.mentraJsSpawn) {\n this.logger.warn(\"mentraJsSpawn not available — host binding missing native function\")\n return false\n }\n const polyfill = this.crust.mentraJsLoadPolyfillBundle?.() ?? \"\"\n if (!polyfill) {\n this.logger.warn(`no polyfill bundle loaded for ${packageName}; spawn will likely fail`)\n }\n const ok = await this.crust.mentraJsSpawn(packageName, polyfill, miniappJs)\n if (!ok) {\n this.logger.error(`spawn failed for ${packageName}`)\n return false\n }\n // Two distinct permission gates:\n // 1. Native dispatcher (JSContext → native bridge): `mentraJsSetManifest`\n // checks per-call iface, e.g. __dispatch(\"mic\", \"start\", ...) requires\n // MICROPHONE.\n // 2. LocalMiniappRuntime (SUBSCRIBE envelope): `registerApp(...,\n // installedManifest)` carries the full manifest so SUBSCRIBE's gate\n // can match stream → permission against declared types.\n if (options?.permissions && options.permissions.length > 0) {\n await this.crust.mentraJsSetManifest(packageName, options.permissions)\n }\n this.registerApp(packageName, options?.installedManifest)\n // Cache spawn arguments so the crash controller can respawn the\n // same code after a backoff. permissions + manifest are cached too\n // because the native side resets setManifest on every spawn and\n // LocalMiniappRuntime's installedManifest entry is keyed by\n // connect-time registration.\n this.spawnCache.set(packageName, {\n miniappJs,\n permissions: options?.permissions ?? [],\n installedManifest: options?.installedManifest,\n })\n this.crashController?.onSpawn(packageName)\n\n // Fire the `init` envelope so the polyfill's __deliver handler\n // resolves `__mentraInitCallback(sessionId)`. The SDK's\n // `registerMiniapp(handler)` wires that callback to construct\n // MiniappSession and call the user's handler. Without this\n // dispatch the user's code never runs — `registerMiniapp` just\n // assigns to a global and waits.\n const sessionId = `${packageName}-${Date.now().toString(36)}`\n void this.crust.mentraJsDispatchToJs(packageName, {kind: \"init\", sessionId})\n\n return true\n }\n\n /**\n * Crash-controller integration. Called from the `__error` frame\n * handler. The controller returns an outcome that tells us whether\n * to respawn (with delay) or leave the context dead.\n */\n private handleCrash(packageName: string, reason: string): void {\n // The native context is dead the instant a crash is observed — invalidate\n // its CONNECT handshake NOW so waitForConnect() blocks through the respawn\n // backoff window instead of resolving immediately against the dead context\n // (an action invoked mid-backoff would otherwise be delivered to nothing).\n this.runtime.resetHandshake(packageName)\n const controller = this.crashController\n if (!controller) return\n const cached = this.spawnCache.get(packageName)\n if (!cached) {\n this.logger.warn(`crash for ${packageName} but no cached spawn args — cannot respawn`)\n controller.onCrash(packageName, reason)\n return\n }\n const outcome = controller.onCrash(packageName, reason)\n if (outcome.surfaceCrashloopBanner) {\n this.onCrashloop?.(packageName, reason)\n islandNotifications.emit({kind: \"miniapp_crashloop\", packageName, reason, timestamp: Date.now()})\n return\n }\n if (outcome.showRestartToast) {\n this.onRestartToast?.(packageName, reason)\n }\n if (outcome.scheduleRespawnAfterMs == null) return\n // Cancel any prior pending respawn before scheduling a new one.\n const existing = this.respawnTimers.get(packageName)\n if (existing) clearTimeout(existing)\n const timer = setTimeout(() => {\n this.respawnTimers.delete(packageName)\n void (async () => {\n try {\n await this.crust.mentraJsKill?.(packageName)\n } catch {\n /* native may have already torn down */\n }\n const ok = await this.crust.mentraJsSpawn?.(\n packageName,\n this.crust.mentraJsLoadPolyfillBundle?.() ?? \"\",\n cached.miniappJs,\n )\n if (!ok) {\n this.logger.error(`crash respawn failed for ${packageName}`)\n return\n }\n if (cached.permissions.length > 0) {\n await this.crust.mentraJsSetManifest(packageName, cached.permissions)\n }\n this.registerApp(packageName, cached.installedManifest)\n controller.onSpawn(packageName)\n // Re-fire the init envelope so the respawned context's\n // `registerMiniapp` handler runs again.\n const sessionId = `${packageName}-${Date.now().toString(36)}`\n void this.crust.mentraJsDispatchToJs(packageName, {kind: \"init\", sessionId})\n this.logger.log(`respawned ${packageName} after crash`)\n })()\n }, outcome.scheduleRespawnAfterMs)\n this.respawnTimers.set(packageName, timer)\n }\n\n private summarizeReason(payload: unknown, method: string): string {\n if (payload && typeof payload === \"object\" && \"message\" in (payload as Record<string, unknown>)) {\n return `${method}: ${(payload as {message: string}).message}`\n }\n return method\n }\n\n /**\n * Tear down a JSContext and unregister from the runtime. Synchronous\n * teardown — the spec drops the 50ms WILL_DISCONNECT grace window\n * because there's no transport handshake to flush in the JSC world.\n */\n async unregister(packageName: string): Promise<void> {\n if (!this.registered.has(packageName)) return\n // Cancel any pending crash-respawn before tearing down — we don't\n // want a stale timer to re-spawn a miniapp the user just disabled.\n const pending = this.respawnTimers.get(packageName)\n if (pending) {\n clearTimeout(pending)\n this.respawnTimers.delete(packageName)\n }\n this.spawnCache.delete(packageName)\n this.crashController?.onKill(packageName)\n this.runtime.unregisterApp(packageName)\n this.registered.delete(packageName)\n // JSContext torn down → miniapp is no longer \"running\".\n miniappRunningRegistry.remove(packageName)\n if (this.crust.mentraJsKill) {\n try {\n await this.crust.mentraJsKill(packageName)\n } catch (e) {\n this.logger.warn(`mentraJsKill threw for ${packageName}: ${String(e)}`)\n }\n }\n }\n\n /** List packages the router has registered. */\n registeredPackages(): string[] {\n return Array.from(this.registered)\n }\n\n /**\n * Validate that a reused background JSContext is still responsive when its\n * WebView comes foreground. The runtime owns the ping/timeout mechanics; the\n * router gates this to registered packages and keeps LocalMiniappView from\n * reaching into runtime internals.\n */\n probeForegroundLiveness(packageName: string, reason = \"foreground-open\", timeoutMs?: number): void {\n if (!this.registered.has(packageName)) return\n this.runtime.probeForegroundLiveness(packageName, reason, timeoutMs)\n }\n\n // ----------------------------------------------------------------\n // Outbound message handling\n // ----------------------------------------------------------------\n\n private handleOutbound(msg: OutboundMessagePayload): void {\n const {packageName, iface, method} = msg\n if (!packageName || !iface || !method) {\n this.logger.warn(`bad mentrajs_message — missing fields`, msg)\n return\n }\n\n // 1) Bridge frames: the SDK's DispatchTransport.send(raw) lands here.\n // Forward raw envelope into LocalMiniappRuntime.handleRawMessage\n // so every existing handler arm runs verbatim.\n if (iface === \"__bridge\" && method === \"send\") {\n const raw = this.coerceArgsToBridgeRaw(msg)\n if (raw == null) {\n this.logger.warn(`__bridge.send had no raw payload`, msg)\n return\n }\n // If the payload is a UI_SEND envelope, route it to the bound\n // WebView instead of LocalMiniappRuntime.\n // session.ui.send → DispatchTransport.send → here.\n if (this.uiRouter) {\n const innerPayload = this.peekBridgePayloadType(raw)\n if (innerPayload?.type === \"UI_SEND\") {\n this.uiRouter.routeFromBackground(packageName, innerPayload)\n return\n }\n }\n this.runtime.handleRawMessage(packageName, raw)\n return\n }\n\n // 2) Log frames — console.* rewired through host. We tag with the\n // packageName so Sentry breadcrumbs can be filtered downstream.\n // Pipeline:\n // raw args → redactSecrets → throttle decision → ring buffer\n // → host logger (which surfaces to dev console / Sentry)\n if (iface === \"__log\") {\n const rawArgs = this.tryParseArgs(msg.argsJson)\n const safeArgs = redactSecrets(rawArgs)\n const decision = this.logThrottle.consume(packageName)\n const tag = `[${packageName}]`\n const fn =\n method === \"warn\"\n ? this.logger.warn\n : method === \"error\" || method === \"fatal\"\n ? this.logger.error\n : this.logger.log\n // Emit a synthetic \"[throttled N]\" line in place of the next\n // would-be-allowed log to summarise drops.\n if (!decision.allowed) {\n if (decision.throttledLine) {\n fn(`${tag} ${decision.throttledLine}`)\n this.logRing.push(packageName, `${decision.throttledLine}`)\n }\n return\n }\n const formatted = `${tag} console.${method}`\n fn(formatted, safeArgs)\n // Stringify into the ring buffer for crash-report attachment.\n let line: string\n try {\n line = `${method}: ${JSON.stringify(safeArgs)}`\n } catch {\n line = `${method}: <unserializable>`\n }\n this.logRing.push(packageName, line)\n // Forward to the `mentra-miniapp dev` sidecar (if one is connected\n // for this package). Source=\"background\" so the CLI tags lines as\n // [MentraJS]. The bridge silently drops when no dev server is up,\n // which makes this safe to call unconditionally in prod.\n const argsForBridge = Array.isArray(safeArgs) ? (safeArgs as unknown[]) : [safeArgs]\n devServerBridge.forwardLog(packageName, method, argsForBridge, Date.now(), \"background\")\n return\n }\n\n // 3) Error / unhandled rejection frames — surface as warnings AND\n // drive the crash state machine when one is attached. The\n // controller's outcome may schedule a respawn after a backoff;\n // if it doesn't (CRASHLOOP_DISABLED), we leave the JSContext\n // dead and let the host surface a \"tap to retry\" banner.\n if (iface === \"__error\") {\n const payload = this.tryParseArgs(msg.argsJson)\n // ready_nack is a liveness probe, not a crash. Logging it at error\n // painted WHIP-start queue delay as a Mentra-Call exception.\n if (method === \"ready_nack\") {\n this.logger.warn(`[${packageName}] ${method}`, payload)\n } else {\n this.logger.error(`[${packageName}] ${method}`, payload)\n }\n if (this.crashController) {\n // Only treat \"exception\" + \"unhandledRejection\" + \"uncaught\" as\n // crash signals. `console.error` calls also flow through the\n // log path — those don't end the JSContext.\n const isCrash = method === \"exception\" || method === \"unhandledRejection\" || method === \"uncaught\"\n if (isCrash) {\n this.handleCrash(packageName, this.summarizeReason(payload, method))\n }\n }\n return\n }\n\n // 4) Anything else is a `forwardToRn` from the dispatcher — a\n // handler the native dispatcher didn't know about. We don't have\n // inline handlers for any of these; the runtime's existing path\n // treats them as legacy WebView envelopes by falling through.\n // Log so unknown ifaces surface in dev.\n this.logger.log(`unhandled iface=${iface} method=${method} from ${packageName}`)\n }\n\n /**\n * The wire format for `__bridge.send` is `argsJson = JSON.stringify([raw])`\n * — a single-element array containing the original raw envelope. The\n * dispatcher passes the parsed array through as either:\n * - `msg.args` when the dispatcher unpacked (Android path that turns\n * `argsJson` into a List on the way to RN), or\n * - `msg.argsJson` (iOS path that ships the string verbatim).\n * Cover both shapes here.\n */\n /**\n * Parse a raw bridge envelope just enough to peek at the inner\n * payload's `type` field. Used by the UI_SEND interception path.\n * Returns null if the envelope isn't a valid bridge frame.\n */\n private peekBridgePayloadType(raw: string): {type: string; [k: string]: unknown} | null {\n try {\n const env = JSON.parse(raw) as {payload?: {type?: string}}\n if (env && typeof env.payload === \"object\" && env.payload && typeof env.payload.type === \"string\") {\n return env.payload as {type: string; [k: string]: unknown}\n }\n } catch {\n return null\n }\n return null\n }\n\n private coerceArgsToBridgeRaw(msg: OutboundMessagePayload): string | null {\n if (Array.isArray(msg.args)) {\n const v = msg.args[0]\n return typeof v === \"string\" ? v : null\n }\n if (typeof msg.argsJson === \"string\") {\n try {\n const parsed = JSON.parse(msg.argsJson) as unknown\n if (Array.isArray(parsed) && typeof parsed[0] === \"string\") {\n return parsed[0]\n }\n } catch {\n // fall through\n }\n }\n return null\n }\n\n private tryParseArgs(argsJson: string | undefined): unknown {\n if (!argsJson) return null\n try {\n return JSON.parse(argsJson)\n } catch {\n return argsJson\n }\n }\n\n /**\n * Push a `kind=\"bridge\"` envelope into the named JSContext's\n * `globalThis.__deliver`. Used both by the per-app `sendMessage`\n * registered via {@link registerApp} and by ad-hoc callers (e.g.\n * cloud-relayed stream-status responses route through\n * `LocalMiniappRuntime.handleCloudMessage`, which then calls the\n * `app.sendMessage(serialized)` registered above).\n */\n private dispatchBridgeRaw(packageName: string, raw: string): void {\n void this.crust.mentraJsDispatchToJs(packageName, {kind: \"bridge\", raw})\n }\n}\n"]}
1
+ {"version":3,"file":"MentraJSRouter.js","sourceRoot":"","sources":["../../src/services/MentraJSRouter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview MentraJSRouter — RN-side host that bridges the per-miniapp\n * JS contexts (iOS-JSC and Android-QuickJS via Zipline) into the existing\n * {@link LocalMiniappRuntime} handler set.\n *\n * Rather than re-implement the 33 dispatch arms inline, the router\n * consumes Crust's `mentrajs_message` Expo event and forwards its\n * `__bridge.send(raw)` payloads to {@link LocalMiniappRuntime.handleRawMessage}.\n * The SDK envelope shape (`{type: \"DISPLAY\", ...}` etc.) is unchanged from\n * the WebView path, so every existing handler runs verbatim. What changes\n * is the *transport*:\n *\n * - **Inbound** (background JS → host): `__dispatch(\"__bridge\", \"send\",\n * [rawJsonString])` → `mentrajs_message` event → router →\n * `LocalMiniappRuntime.handleRawMessage(packageName, raw)`.\n * - **Outbound** (host → background JS): every package registered with\n * the router gets a `sendMessage(raw)` fn that calls\n * `Crust.mentraJsDispatchToJs(packageName, {kind: \"bridge\", raw})`.\n * The polyfill's `__deliver` recognises `kind === \"bridge\"` and calls\n * `__mentraDeliverBridgeRaw(raw)`, which routes into the SDK's\n * {@link DispatchTransport.onMessage} handler.\n *\n * Host-side handler bodies (display fan-out, mic state, transcription,\n * navigation, etc.) live untouched in `LocalMiniappRuntime.ts`.\n *\n * PhoneStreamCoordinator delivers stream status through LocalMiniappRuntime\n * to the miniapp's registered `sendMessage` callback, using the same local\n * bridge as other responses and events.\n *\n * The router also bridges native error / log / unhandled-rejection\n * events (`iface: \"__log\"`, `iface: \"__error\"`) into the standard\n * `console.*` + Sentry breadcrumb pipeline so miniapp telemetry is\n * visible without bringing up a separate sink.\n */\n\nimport type {EventSubscription} from \"expo-modules-core\"\n\nimport devServerBridge from \"./DevServerBridge\"\nimport type localMiniappRuntime from \"./LocalMiniappRuntime\"\nimport type {InstalledMiniappManifest} from \"./LocalMiniappRuntime\"\nimport type {MentraJSCrashController} from \"./MentraJSCrashController\"\nimport {MentraJSLogRingBuffer, MentraJSLogThrottle, redactSecrets} from \"./MentraJSLogPipeline\"\nimport {islandNotifications} from \"./NotificationsEmitter\"\nimport type {MentraUIRouter} from \"./MentraUIRouter\"\nimport {miniappRunningRegistry} from \"./MiniappRunningRegistry\"\n\n/** The runtime's runtime instance type — the singleton exported from\n * LocalMiniappRuntime.ts (the file's `export default` is the instance,\n * not the class).\n */\ntype LocalMiniappRuntime = typeof localMiniappRuntime\n\n/**\n * Minimal subset of the Crust native module the router uses. Keeping the\n * binding loose lets us mock the module in unit tests without bringing\n * the whole Expo module surface along.\n */\nexport interface MentraJSCrustBinding {\n mentraJsDispatchToJs(packageName: string, envelope: Record<string, unknown>): Promise<void> | void\n mentraJsSetManifest(packageName: string, permissions: string[]): Promise<void> | void\n mentraJsLoadPolyfillBundle?: () => string\n mentraJsSpawn?: (packageName: string, polyfill: string, miniappJs: string) => Promise<boolean> | boolean\n mentraJsKill?: (packageName: string) => Promise<void> | void\n mentraJsAlivePackages?: () => string[]\n addListener: (event: string, handler: (payload: Record<string, unknown>) => void) => EventSubscription\n}\n\nexport interface OutboundMessagePayload {\n packageName: string\n iface: string\n method: string\n argsJson?: string\n args?: unknown[]\n reqId?: string\n // Implementation-internal: any extra fields the dispatcher attached on\n // .forwardToRn (e.g. payload metadata) are passed through verbatim.\n [extra: string]: unknown\n}\n\nexport type RouterLogger = {\n log: (message: string, payload?: unknown) => void\n warn: (message: string, payload?: unknown) => void\n error: (message: string, payload?: unknown) => void\n}\n\nconst defaultLogger: RouterLogger = {\n log: (m, p) => console.log(`[MentraJSRouter] ${m}`, p ?? \"\"),\n\n warn: (m, p) => console.warn(`[MentraJSRouter] ${m}`, p ?? \"\"),\n\n error: (m, p) => console.error(`[MentraJSRouter] ${m}`, p ?? \"\"),\n}\n\ninterface SpawnCache {\n miniappJs: string\n permissions: string[]\n installedManifest?: InstalledMiniappManifest\n}\n\nexport class MentraJSRouter {\n private subscription: EventSubscription | null = null\n private readonly registered: Set<string> = new Set()\n /** Cached spawn arguments so the crash controller can respawn after a backoff. */\n private readonly spawnCache: Map<string, SpawnCache> = new Map()\n /** Active respawn timers (so unregister() can cancel a pending respawn). */\n private readonly respawnTimers: Map<string, ReturnType<typeof setTimeout>> = new Map()\n\n /**\n * Optional crash controller. When wired, every `__error` frame from a\n * JSContext drives the state machine; an Outcome with\n * scheduleRespawnAfterMs queues a setTimeout that re-spawns the\n * miniapp's last-known JS source after the backoff delay.\n */\n crashController: MentraJSCrashController | null = null\n\n /** Hook called when a package transitions to CRASHLOOP_DISABLED. */\n onCrashloop: ((packageName: string, reason: string) => void) | null = null\n /** Hook called on the 2nd-within-window crash (toast UX). */\n onRestartToast: ((packageName: string, reason: string) => void) | null = null\n\n /**\n * Logging plumbing. Every `__log` frame passes through `redactSecrets`\n * (token/password/etc. scrubbed), then the throttle (100/min sustained\n * per pkg, 500 burst), then lands in the ring buffer + the host\n * logger. The ring buffer holds the last 200 lines/pkg so a crash\n * report can attach \"last words\" context.\n *\n * Replace with new instances in tests; production code uses the\n * defaults.\n */\n logThrottle: MentraJSLogThrottle = new MentraJSLogThrottle()\n logRing: MentraJSLogRingBuffer = new MentraJSLogRingBuffer()\n\n /**\n * Optional UI router — when wired, `__bridge.send` envelopes whose\n * inner payload type is `UI_SEND` get routed to the bound WebView\n * instead of through LocalMiniappRuntime. Two-layer miniapps set\n * this; legacy single-bundle WebView miniapps don't and the bridge\n * frames pass through unchanged.\n */\n uiRouter: MentraUIRouter | null = null\n\n constructor(\n private readonly runtime: LocalMiniappRuntime,\n private readonly crust: MentraJSCrustBinding,\n private readonly logger: RouterLogger = defaultLogger,\n ) {}\n\n /**\n * Subscribe to Crust's `mentrajs_message` event. Idempotent — calling\n * start() twice attaches a single listener.\n */\n start(): void {\n if (this.subscription) return\n this.subscription = this.crust.addListener(\"mentrajs_message\", (raw) => {\n try {\n this.handleOutbound(raw as unknown as OutboundMessagePayload)\n } catch (e) {\n this.logger.error(`outbound handler threw`, {error: String(e), raw})\n }\n })\n // A background script unregistered for missing liveness pings is dead\n // weight: its subscriptions are gone (so the mic releases) while the\n // webview keeps rendering stale state. Route it through the same\n // respawn machinery as a crash so it comes back automatically, with\n // the crash controller's backoff + crash-loop protection.\n this.runtime.onLivenessTimeout = (packageName) => {\n this.handleCrash(packageName, \"liveness: missed pings\")\n }\n }\n\n /**\n * Detach the Crust subscription. The router can be restarted later\n * with start(); registrations survive (the runtime's app map is the\n * source of truth).\n */\n stop(): void {\n this.subscription?.remove()\n this.subscription = null\n this.runtime.onLivenessTimeout = null\n }\n\n /**\n * Register a JSContext with the runtime so its handlers can fire\n * `sendMessage(raw)` against the right context. The router builds a\n * `sendMessage` that calls `Crust.mentraJsDispatchToJs(packageName,\n * {kind: \"bridge\", raw})`; the polyfill's `__deliver` then hands the\n * envelope to `DispatchTransport.onMessage` inside the miniapp.\n *\n * Mirrors `MiniappHost.registerRuntime` on the WebView side. Callers\n * (e.g. {@link spawnAndRegister} below, or the host's miniapp launch\n * pipeline) should call this once per spawn.\n */\n registerApp(packageName: string, installedManifest?: InstalledMiniappManifest): void {\n this.runtime.registerApp(\n packageName,\n (raw: string) => {\n this.dispatchBridgeRaw(packageName, raw)\n },\n installedManifest,\n )\n this.registered.add(packageName)\n // JSContext is the source-of-truth for \"miniapp running\". The\n // home tile / tray reads this registry to project the `running`\n // flag — UI WebView open/close is separate.\n miniappRunningRegistry.add(packageName)\n }\n\n /**\n * Convenience: spawn a JSContext via Crust, register the app, and\n * set its declared permissions. Returns true on successful spawn.\n *\n * The host's miniapp launch path\n * (`mobile/src/services/miniapps/launchLocalMiniapp.ts`) calls this\n * once per JSContext mount.\n */\n async spawnAndRegister(\n packageName: string,\n miniappJs: string,\n options?: {permissions?: string[]; installedManifest?: InstalledMiniappManifest},\n ): Promise<boolean> {\n if (!this.crust.mentraJsSpawn) {\n this.logger.warn(\"mentraJsSpawn not available — host binding missing native function\")\n return false\n }\n const polyfill = this.crust.mentraJsLoadPolyfillBundle?.() ?? \"\"\n if (!polyfill) {\n this.logger.warn(`no polyfill bundle loaded for ${packageName}; spawn will likely fail`)\n }\n const ok = await this.crust.mentraJsSpawn(packageName, polyfill, miniappJs)\n if (!ok) {\n this.logger.error(`spawn failed for ${packageName}`)\n return false\n }\n // Two distinct permission gates:\n // 1. Native dispatcher (JSContext → native bridge): `mentraJsSetManifest`\n // checks per-call iface, e.g. __dispatch(\"mic\", \"start\", ...) requires\n // MICROPHONE.\n // 2. LocalMiniappRuntime (SUBSCRIBE envelope): `registerApp(...,\n // installedManifest)` carries the full manifest so SUBSCRIBE's gate\n // can match stream → permission against declared types.\n if (options?.permissions && options.permissions.length > 0) {\n await this.crust.mentraJsSetManifest(packageName, options.permissions)\n }\n this.registerApp(packageName, options?.installedManifest)\n // Cache spawn arguments so the crash controller can respawn the\n // same code after a backoff. permissions + manifest are cached too\n // because the native side resets setManifest on every spawn and\n // LocalMiniappRuntime's installedManifest entry is keyed by\n // connect-time registration.\n this.spawnCache.set(packageName, {\n miniappJs,\n permissions: options?.permissions ?? [],\n installedManifest: options?.installedManifest,\n })\n this.crashController?.onSpawn(packageName)\n\n // Fire the `init` envelope so the polyfill's __deliver handler\n // resolves `__mentraInitCallback(sessionId)`. The SDK's\n // `registerMiniapp(handler)` wires that callback to construct\n // MiniappSession and call the user's handler. Without this\n // dispatch the user's code never runs — `registerMiniapp` just\n // assigns to a global and waits.\n const sessionId = `${packageName}-${Date.now().toString(36)}`\n void this.crust.mentraJsDispatchToJs(packageName, {kind: \"init\", sessionId})\n\n return true\n }\n\n /**\n * Crash-controller integration. Called from the `__error` frame\n * handler. The controller returns an outcome that tells us whether\n * to respawn (with delay) or leave the context dead.\n */\n private handleCrash(packageName: string, reason: string): void {\n // The native context is dead the instant a crash is observed — invalidate\n // its CONNECT handshake NOW so waitForConnect() blocks through the respawn\n // backoff window instead of resolving immediately against the dead context\n // (an action invoked mid-backoff would otherwise be delivered to nothing).\n this.runtime.resetHandshake(packageName)\n const controller = this.crashController\n if (!controller) return\n const cached = this.spawnCache.get(packageName)\n if (!cached) {\n this.logger.warn(`crash for ${packageName} but no cached spawn args — cannot respawn`)\n controller.onCrash(packageName, reason)\n return\n }\n const outcome = controller.onCrash(packageName, reason)\n if (outcome.surfaceCrashloopBanner) {\n this.onCrashloop?.(packageName, reason)\n islandNotifications.emit({kind: \"miniapp_crashloop\", packageName, reason, timestamp: Date.now()})\n return\n }\n if (outcome.showRestartToast) {\n this.onRestartToast?.(packageName, reason)\n }\n if (outcome.scheduleRespawnAfterMs == null) return\n // Cancel any prior pending respawn before scheduling a new one.\n const existing = this.respawnTimers.get(packageName)\n if (existing) clearTimeout(existing)\n const timer = setTimeout(() => {\n this.respawnTimers.delete(packageName)\n void (async () => {\n try {\n await this.crust.mentraJsKill?.(packageName)\n } catch {\n /* native may have already torn down */\n }\n const ok = await this.crust.mentraJsSpawn?.(\n packageName,\n this.crust.mentraJsLoadPolyfillBundle?.() ?? \"\",\n cached.miniappJs,\n )\n if (!ok) {\n this.logger.error(`crash respawn failed for ${packageName}`)\n return\n }\n if (cached.permissions.length > 0) {\n await this.crust.mentraJsSetManifest(packageName, cached.permissions)\n }\n this.registerApp(packageName, cached.installedManifest)\n controller.onSpawn(packageName)\n // Re-fire the init envelope so the respawned context's\n // `registerMiniapp` handler runs again.\n const sessionId = `${packageName}-${Date.now().toString(36)}`\n void this.crust.mentraJsDispatchToJs(packageName, {kind: \"init\", sessionId})\n this.logger.log(`respawned ${packageName} after crash`)\n })()\n }, outcome.scheduleRespawnAfterMs)\n this.respawnTimers.set(packageName, timer)\n }\n\n private summarizeReason(payload: unknown, method: string): string {\n if (payload && typeof payload === \"object\" && \"message\" in (payload as Record<string, unknown>)) {\n return `${method}: ${(payload as {message: string}).message}`\n }\n return method\n }\n\n /**\n * Tear down a JSContext and unregister from the runtime. Synchronous\n * teardown — the spec drops the 50ms WILL_DISCONNECT grace window\n * because there's no transport handshake to flush in the JSC world.\n */\n async unregister(packageName: string): Promise<void> {\n if (!this.registered.has(packageName)) return\n // Cancel any pending crash-respawn before tearing down — we don't\n // want a stale timer to re-spawn a miniapp the user just disabled.\n const pending = this.respawnTimers.get(packageName)\n if (pending) {\n clearTimeout(pending)\n this.respawnTimers.delete(packageName)\n }\n this.spawnCache.delete(packageName)\n this.crashController?.onKill(packageName)\n this.runtime.unregisterApp(packageName)\n this.registered.delete(packageName)\n // JSContext torn down → miniapp is no longer \"running\".\n miniappRunningRegistry.remove(packageName)\n if (this.crust.mentraJsKill) {\n try {\n await this.crust.mentraJsKill(packageName)\n } catch (e) {\n this.logger.warn(`mentraJsKill threw for ${packageName}: ${String(e)}`)\n }\n }\n }\n\n /** List packages the router has registered. */\n registeredPackages(): string[] {\n return Array.from(this.registered)\n }\n\n /**\n * Validate that a reused background JSContext is still responsive when its\n * WebView comes foreground. The runtime owns the ping/timeout mechanics; the\n * router gates this to registered packages and keeps LocalMiniappView from\n * reaching into runtime internals.\n */\n probeForegroundLiveness(packageName: string, reason = \"foreground-open\", timeoutMs?: number): void {\n if (!this.registered.has(packageName)) return\n this.runtime.probeForegroundLiveness(packageName, reason, timeoutMs)\n }\n\n // ----------------------------------------------------------------\n // Outbound message handling\n // ----------------------------------------------------------------\n\n private handleOutbound(msg: OutboundMessagePayload): void {\n const {packageName, iface, method} = msg\n if (!packageName || !iface || !method) {\n this.logger.warn(`bad mentrajs_message — missing fields`, msg)\n return\n }\n\n // 1) Bridge frames: the SDK's DispatchTransport.send(raw) lands here.\n // Forward raw envelope into LocalMiniappRuntime.handleRawMessage\n // so every existing handler arm runs verbatim.\n if (iface === \"__bridge\" && method === \"send\") {\n const raw = this.coerceArgsToBridgeRaw(msg)\n if (raw == null) {\n this.logger.warn(`__bridge.send had no raw payload`, msg)\n return\n }\n // If the payload is a UI_SEND envelope, route it to the bound\n // WebView instead of LocalMiniappRuntime.\n // session.ui.send → DispatchTransport.send → here.\n if (this.uiRouter) {\n const innerPayload = this.peekBridgePayloadType(raw)\n if (innerPayload?.type === \"UI_SEND\") {\n this.uiRouter.routeFromBackground(packageName, innerPayload)\n return\n }\n }\n this.runtime.handleRawMessage(packageName, raw)\n return\n }\n\n // 2) Log frames — console.* rewired through host. We tag with the\n // packageName so Sentry breadcrumbs can be filtered downstream.\n // Pipeline:\n // raw args → redactSecrets → throttle decision → ring buffer\n // → host logger (which surfaces to dev console / Sentry)\n if (iface === \"__log\") {\n const rawArgs = this.tryParseArgs(msg.argsJson)\n const safeArgs = redactSecrets(rawArgs)\n const decision = this.logThrottle.consume(packageName)\n const tag = `[${packageName}]`\n const fn =\n method === \"warn\"\n ? this.logger.warn\n : method === \"error\" || method === \"fatal\"\n ? this.logger.error\n : this.logger.log\n // Emit a synthetic \"[throttled N]\" line in place of the next\n // would-be-allowed log to summarise drops.\n if (!decision.allowed) {\n if (decision.throttledLine) {\n fn(`${tag} ${decision.throttledLine}`)\n this.logRing.push(packageName, `${decision.throttledLine}`)\n }\n return\n }\n const formatted = `${tag} console.${method}`\n fn(formatted, safeArgs)\n // Stringify into the ring buffer for crash-report attachment.\n let line: string\n try {\n line = `${method}: ${JSON.stringify(safeArgs)}`\n } catch {\n line = `${method}: <unserializable>`\n }\n this.logRing.push(packageName, line)\n // Forward to the `mentra-miniapp dev` sidecar (if one is connected\n // for this package). Source=\"background\" so the CLI tags lines as\n // [MentraJS]. The bridge silently drops when no dev server is up,\n // which makes this safe to call unconditionally in prod.\n const argsForBridge = Array.isArray(safeArgs) ? (safeArgs as unknown[]) : [safeArgs]\n devServerBridge.forwardLog(packageName, method, argsForBridge, Date.now(), \"background\")\n return\n }\n\n // 3) Error / unhandled rejection frames — surface as warnings AND\n // drive the crash state machine when one is attached. The\n // controller's outcome may schedule a respawn after a backoff;\n // if it doesn't (CRASHLOOP_DISABLED), we leave the JSContext\n // dead and let the host surface a \"tap to retry\" banner.\n if (iface === \"__error\") {\n const payload = this.tryParseArgs(msg.argsJson)\n // ready_nack is a liveness probe, not a crash. Logging it at error\n // painted WHIP-start queue delay as a Mentra-Call exception.\n if (method === \"ready_nack\") {\n this.logger.warn(`[${packageName}] ${method}`, payload)\n } else {\n this.logger.error(`[${packageName}] ${method}`, payload)\n }\n if (this.crashController) {\n // Only treat \"exception\" + \"unhandledRejection\" + \"uncaught\" as\n // crash signals. `console.error` calls also flow through the\n // log path — those don't end the JSContext.\n const isCrash = method === \"exception\" || method === \"unhandledRejection\" || method === \"uncaught\"\n if (isCrash) {\n this.handleCrash(packageName, this.summarizeReason(payload, method))\n }\n }\n return\n }\n\n // 4) Anything else is a `forwardToRn` from the dispatcher — a\n // handler the native dispatcher didn't know about. We don't have\n // inline handlers for any of these; the runtime's existing path\n // treats them as legacy WebView envelopes by falling through.\n // Log so unknown ifaces surface in dev.\n this.logger.log(`unhandled iface=${iface} method=${method} from ${packageName}`)\n }\n\n /**\n * The wire format for `__bridge.send` is `argsJson = JSON.stringify([raw])`\n * — a single-element array containing the original raw envelope. The\n * dispatcher passes the parsed array through as either:\n * - `msg.args` when the dispatcher unpacked (Android path that turns\n * `argsJson` into a List on the way to RN), or\n * - `msg.argsJson` (iOS path that ships the string verbatim).\n * Cover both shapes here.\n */\n /**\n * Parse a raw bridge envelope just enough to peek at the inner\n * payload's `type` field. Used by the UI_SEND interception path.\n * Returns null if the envelope isn't a valid bridge frame.\n */\n private peekBridgePayloadType(raw: string): {type: string; [k: string]: unknown} | null {\n try {\n const env = JSON.parse(raw) as {payload?: {type?: string}}\n if (env && typeof env.payload === \"object\" && env.payload && typeof env.payload.type === \"string\") {\n return env.payload as {type: string; [k: string]: unknown}\n }\n } catch {\n return null\n }\n return null\n }\n\n private coerceArgsToBridgeRaw(msg: OutboundMessagePayload): string | null {\n if (Array.isArray(msg.args)) {\n const v = msg.args[0]\n return typeof v === \"string\" ? v : null\n }\n if (typeof msg.argsJson === \"string\") {\n try {\n const parsed = JSON.parse(msg.argsJson) as unknown\n if (Array.isArray(parsed) && typeof parsed[0] === \"string\") {\n return parsed[0]\n }\n } catch {\n // fall through\n }\n }\n return null\n }\n\n private tryParseArgs(argsJson: string | undefined): unknown {\n if (!argsJson) return null\n try {\n return JSON.parse(argsJson)\n } catch {\n return argsJson\n }\n }\n\n /**\n * Push a `kind=\"bridge\"` envelope into the named JSContext's\n * `globalThis.__deliver`. Used by the per-app `sendMessage` registered via\n * {@link registerApp} to deliver runtime responses and events locally.\n */\n private dispatchBridgeRaw(packageName: string, raw: string): void {\n void this.crust.mentraJsDispatchToJs(packageName, {kind: \"bridge\", raw})\n }\n}\n"]}
@@ -43,14 +43,13 @@ export interface MentraUICrustBinding {
43
43
  mentraJsDispatchToJs(packageName: string, envelope: Record<string, unknown>): Promise<void> | void;
44
44
  }
45
45
  /**
46
- * NOTE: the WebView host heartbeat was removed when the lifecycle
47
- * inversion landed. The current model is **at most one WebView at a
48
- * time, foreground UI with an always-on background JSContext** (same
49
- * shape as the cloud-WebView miniapps). User navigation closes it
50
- * explicitly and `onContentProcessDidTerminate` catches OS-level
51
- * crashes, but the host may still re-announce UI_OPEN for an already
52
- * mounted WebView after app resume/dev respawn so the background can
53
- * push a fresh authoritative snapshot.
46
+ * The host mounts at most one miniapp UI WebView at a time. Its background
47
+ * JSContext runs separately on the phone and can remain alive after UI closure.
48
+ * UI closure unbinds the WebView and sends UI_CLOSE; on iOS the host also exits
49
+ * the UI when `onContentProcessDidTerminate` reports a content-process exit.
50
+ * The host may re-announce UI_OPEN after app resume or background dev respawn
51
+ * so the background can push a fresh snapshot. This router has no WebView
52
+ * heartbeat timeout.
54
53
  */
55
54
  export declare class MentraUIRouter {
56
55
  private readonly bindings;
@@ -70,9 +69,8 @@ export declare class MentraUIRouter {
70
69
  */
71
70
  bindWebView(packageName: string, injectFn: MentraUIInjectFn): void;
72
71
  /**
73
- * Called when the WebView unmounts (user navigated away or the host
74
- * tore it down on heartbeat timeout). Pushes UI_CLOSE to background
75
- * so handlers can flush state, then drops the binding.
72
+ * Called when the host tears down the WebView. Drops the binding and
73
+ * sends UI_CLOSE to the background so handlers can flush state.
76
74
  */
77
75
  unbindWebView(packageName: string): void;
78
76
  /** True iff a WebView is currently bound to the named package. */
@@ -96,7 +94,6 @@ export declare class MentraUIRouter {
96
94
  * Recognised envelope types from the WebView shim:
97
95
  * - {type: "ready"} → fire UI_OPEN
98
96
  * - {type: "msg", seq, channel, payload} → fire UI_MESSAGE
99
- * - {type: "heartbeat", seq} → silently ack
100
97
  */
101
98
  routeFromWebView(packageName: string, rawJson: string): void;
102
99
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"MentraUIRouter.d.ts","sourceRoot":"","sources":["../../src/services/MentraUIRouter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,UAAU,gBAAgB;IACxB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;CACnG;AAMD;;;;;;;;;GASG;AAEH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuC;IAChE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsB;gBAEhC,KAAK,EAAE,oBAAoB;IAIvC;;;;;;;;;;;OAWG;IACH,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,GAAG,IAAI;IAIlE;;;;OAIG;IACH,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAMxC,kEAAkE;IAClE,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAIrC;;;;;;;;OAQG;IACH,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAKvC;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IA2C5D;;;;;;;;OAQG;IACH,mBAAmB,CACjB,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE;QACb,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB,GAAG,CAAC,EAAE,MAAM,CAAA;QACZ,SAAS,CAAC,EAAE,MAAM,CAAA;KACnB,GACA,IAAI;IAsBP;;;;OAIG;IACH,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE;QAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAC,GAAG,IAAI;IAQpG;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB;CAa5B"}
1
+ {"version":3,"file":"MentraUIRouter.d.ts","sourceRoot":"","sources":["../../src/services/MentraUIRouter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,UAAU,gBAAgB;IACxB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;CACnG;AAMD;;;;;;;;GAQG;AAEH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuC;IAChE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsB;gBAEhC,KAAK,EAAE,oBAAoB;IAIvC;;;;;;;;;;;OAWG;IACH,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,GAAG,IAAI;IAIlE;;;OAGG;IACH,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAMxC,kEAAkE;IAClE,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAIrC;;;;;;;;OAQG;IACH,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAKvC;;;;;;;;;OASG;IACH,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IA2C5D;;;;;;;;OAQG;IACH,mBAAmB,CACjB,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE;QACb,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB,GAAG,CAAC,EAAE,MAAM,CAAA;QACZ,SAAS,CAAC,EAAE,MAAM,CAAA;KACnB,GACA,IAAI;IAsBP;;;;OAIG;IACH,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE;QAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAC,GAAG,IAAI;IAQpG;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB;CAa5B"}
@@ -33,14 +33,13 @@
33
33
  * forwards them to background via the same EVENT/_ui envelope shape.
34
34
  */
35
35
  /**
36
- * NOTE: the WebView host heartbeat was removed when the lifecycle
37
- * inversion landed. The current model is **at most one WebView at a
38
- * time, foreground UI with an always-on background JSContext** (same
39
- * shape as the cloud-WebView miniapps). User navigation closes it
40
- * explicitly and `onContentProcessDidTerminate` catches OS-level
41
- * crashes, but the host may still re-announce UI_OPEN for an already
42
- * mounted WebView after app resume/dev respawn so the background can
43
- * push a fresh authoritative snapshot.
36
+ * The host mounts at most one miniapp UI WebView at a time. Its background
37
+ * JSContext runs separately on the phone and can remain alive after UI closure.
38
+ * UI closure unbinds the WebView and sends UI_CLOSE; on iOS the host also exits
39
+ * the UI when `onContentProcessDidTerminate` reports a content-process exit.
40
+ * The host may re-announce UI_OPEN after app resume or background dev respawn
41
+ * so the background can push a fresh snapshot. This router has no WebView
42
+ * heartbeat timeout.
44
43
  */
45
44
  export class MentraUIRouter {
46
45
  bindings = new Map();
@@ -64,9 +63,8 @@ export class MentraUIRouter {
64
63
  this.bindings.set(packageName, { inject: injectFn });
65
64
  }
66
65
  /**
67
- * Called when the WebView unmounts (user navigated away or the host
68
- * tore it down on heartbeat timeout). Pushes UI_CLOSE to background
69
- * so handlers can flush state, then drops the binding.
66
+ * Called when the host tears down the WebView. Drops the binding and
67
+ * sends UI_CLOSE to the background so handlers can flush state.
70
68
  */
71
69
  unbindWebView(packageName) {
72
70
  if (!this.bindings.has(packageName))
@@ -101,7 +99,6 @@ export class MentraUIRouter {
101
99
  * Recognised envelope types from the WebView shim:
102
100
  * - {type: "ready"} → fire UI_OPEN
103
101
  * - {type: "msg", seq, channel, payload} → fire UI_MESSAGE
104
- * - {type: "heartbeat", seq} → silently ack
105
102
  */
106
103
  routeFromWebView(packageName, rawJson) {
107
104
  let env;
@@ -1 +1 @@
1
- {"version":3,"file":"MentraUIRouter.js","sourceRoot":"","sources":["../../src/services/MentraUIRouter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * MentraUIRouter — bidirectional bus between a per-miniapp UI WebView\n * and its bound background JSContext.\n *\n * The flow:\n *\n * WebView (mentra.send/on) Background (session.ui.send/on)\n * │ │\n * │ window.ReactNativeWebView │\n * │ .postMessage(jsonEnvelope) │ session.sendOneShot({\n * │ │ type: \"UI_SEND\", channel, payload, seq\n * │ │ })\n * │ │\n * ▼ ▼\n * MiniappHost.onMessage MentraJSRouter (recognises payload.type===\"UI_SEND\")\n * │ │\n * ▼ ▼\n * ──── MentraUIRouter.routeFromWebView ──── MentraUIRouter.routeFromBackground\n * ──► Crust.mentraJsDispatchToJs ──► webView.injectJavaScript(\"window.__mentra.recv(...)\")\n * {kind:\"bridge\", raw: JSON({\n * payload:{\n * type:\"EVENT\", streamType:\"_ui\",\n * data:{type:\"UI_MESSAGE\", channel, payload, seq}\n * }})}\n *\n * The router is a singleton — one instance for the whole host process —\n * because only one WebView is allowed open at a time per spec. The\n * binding map is therefore N entries (one per \"currently has a UI\n * WebView mounted\" miniapp), but in practice it's 0 or 1.\n *\n * UI_OPEN / UI_CLOSE lifecycle envelopes are pushed by the WebView's\n * `mentra.ready()` and the host's WebView teardown handler; the router\n * forwards them to background via the same EVENT/_ui envelope shape.\n */\n\ninterface MentraUIInjectFn {\n (jsSource: string): void\n}\n\n/**\n * Subset of the Crust native module that MentraUIRouter touches.\n * Loose binding keeps tests free of Expo imports.\n */\nexport interface MentraUICrustBinding {\n mentraJsDispatchToJs(packageName: string, envelope: Record<string, unknown>): Promise<void> | void\n}\n\ninterface BoundWebView {\n inject: MentraUIInjectFn\n}\n\n/**\n * NOTE: the WebView ↔ host heartbeat was removed when the lifecycle\n * inversion landed. The current model is **at most one WebView at a\n * time, foreground UI with an always-on background JSContext** (same\n * shape as the cloud-WebView miniapps). User navigation closes it\n * explicitly and `onContentProcessDidTerminate` catches OS-level\n * crashes, but the host may still re-announce UI_OPEN for an already\n * mounted WebView after app resume/dev respawn so the background can\n * push a fresh authoritative snapshot.\n */\n\nexport class MentraUIRouter {\n private readonly bindings: Map<string, BoundWebView> = new Map()\n private readonly crust: MentraUICrustBinding\n\n constructor(crust: MentraUICrustBinding) {\n this.crust = crust\n }\n\n /**\n * Called when a UI WebView mounts. `injectFn` wraps\n * `webView.injectJavaScript` — the router calls it with prebuilt\n * `window.__mentra.recv(...)` strings to deliver background-side\n * frames into the WebView's mentra global.\n *\n * The router also pushes a UI_OPEN envelope to the background side\n * once the WebView signals ready (see {@link routeFromWebView}).\n * Calling bindWebView on a packageName that already has a binding\n * replaces the previous one (defensive — should not happen in\n * practice because only one WebView is open at a time).\n */\n bindWebView(packageName: string, injectFn: MentraUIInjectFn): void {\n this.bindings.set(packageName, {inject: injectFn})\n }\n\n /**\n * Called when the WebView unmounts (user navigated away or the host\n * tore it down on heartbeat timeout). Pushes UI_CLOSE to background\n * so handlers can flush state, then drops the binding.\n */\n unbindWebView(packageName: string): void {\n if (!this.bindings.has(packageName)) return\n this.bindings.delete(packageName)\n this.deliverToBackground(packageName, {type: \"UI_CLOSE\"})\n }\n\n /** True iff a WebView is currently bound to the named package. */\n isBound(packageName: string): boolean {\n return this.bindings.has(packageName)\n }\n\n /**\n * Re-announce the already-mounted WebView to the background JSContext.\n * This covers dev background hot-reload, app resume, and thawed WebViews\n * whose injected UI_SEND frames may have been missed while the host was\n * suspended. Re-emitting UI_OPEN flips `ui.bound` back to true if needed\n * and lets background code push a fresh snapshot via session.ui.onOpen.\n *\n * No-op if no WebView is currently bound for the package.\n */\n notifyReopen(packageName: string): void {\n if (!this.bindings.has(packageName)) return\n this.deliverToBackground(packageName, {type: \"UI_OPEN\"})\n }\n\n /**\n * Forward a WebView-originated postMessage envelope to the JSContext.\n * `rawJson` is the raw string from `event.nativeEvent.data` — the\n * caller hasn't parsed it yet so the router controls the wire format\n * end-to-end.\n *\n * Recognised envelope types from the WebView shim:\n * - {type: \"ready\"} → fire UI_OPEN\n * - {type: \"msg\", seq, channel, payload} → fire UI_MESSAGE\n * - {type: \"heartbeat\", seq} → silently ack\n */\n routeFromWebView(packageName: string, rawJson: string): void {\n let env: {\n type?: string\n seq?: number\n channel?: string\n payload?: unknown\n requestId?: string\n }\n try {\n env = JSON.parse(rawJson)\n } catch {\n return\n }\n if (typeof env.type !== \"string\") return\n\n if (env.type === \"ready\") {\n this.deliverToBackground(packageName, {type: \"UI_OPEN\"})\n return\n }\n if (env.type === \"msg\" && typeof env.channel === \"string\") {\n const out: Record<string, unknown> = {\n type: \"UI_MESSAGE\",\n channel: env.channel,\n payload: env.payload,\n seq: env.seq,\n }\n if (typeof env.requestId === \"string\") out.requestId = env.requestId\n this.deliverToBackground(packageName, out)\n return\n }\n if (env.type === \"cancel\" && typeof env.requestId === \"string\") {\n this.deliverToBackground(packageName, {type: \"UI_CANCEL\", requestId: env.requestId})\n return\n }\n // NOTE: console.* logs do NOT come through this router. The\n // miniappGlobals console-tap shim posts {payload:{type:\"dev_log\"}}\n // envelopes which LocalMiniappRuntime handles and forwards to the\n // dev sidecar tagged source:\"ui\". Keeping that path one-way means\n // we don't have two console-capture pipelines competing.\n //\n // Unknown envelope — drop silently.\n }\n\n /**\n * Called by MentraJSRouter when it sees a `__bridge.send` outbound\n * frame whose parsed payload is a UI_SEND envelope. The router\n * forwards it as a `msg` frame to the bound WebView (or drops if no\n * WebView is currently mounted).\n *\n * `uiSendPayload` is the raw `{type:\"UI_SEND\", channel, payload, seq}`\n * shape produced by `session.ui.send` on the background side.\n */\n routeFromBackground(\n packageName: string,\n uiSendPayload: {\n type: string\n channel?: string\n payload?: unknown\n seq?: number\n requestId?: string\n },\n ): void {\n const binding = this.bindings.get(packageName)\n if (!binding) return\n if (uiSendPayload.type === \"UI_CANCEL\" && typeof uiSendPayload.requestId === \"string\") {\n const cancel = {type: \"cancel\", requestId: uiSendPayload.requestId}\n const literal = JSON.stringify(cancel)\n const escaped = JSON.stringify(literal)\n binding.inject(`if (window.__mentra && window.__mentra.recv) window.__mentra.recv(JSON.parse(${escaped})); true;`)\n return\n }\n const outbound: Record<string, unknown> = {\n type: \"msg\",\n seq: uiSendPayload.seq ?? 0,\n channel: uiSendPayload.channel,\n payload: uiSendPayload.payload,\n }\n if (typeof uiSendPayload.requestId === \"string\") outbound.requestId = uiSendPayload.requestId\n const literal = JSON.stringify(outbound)\n const escaped = JSON.stringify(literal)\n binding.inject(`if (window.__mentra && window.__mentra.recv) window.__mentra.recv(JSON.parse(${escaped})); true;`)\n }\n\n /**\n * Send a synthetic frame to the WebView. Used for host-initiated\n * lifecycle events (`open`, `close`, `ack`). The wire shape is the\n * same as the WebView shim's recv handler expects.\n */\n pushLifecycleFrame(packageName: string, frame: {type: \"open\" | \"close\" | \"ack\"; seq?: number}): void {\n const binding = this.bindings.get(packageName)\n if (!binding) return\n const literal = JSON.stringify(frame)\n const escaped = JSON.stringify(literal)\n binding.inject(`if (window.__mentra && window.__mentra.recv) window.__mentra.recv(JSON.parse(${escaped})); true;`)\n }\n\n /**\n * Wrap an EVENT envelope and push it to background via the bridge.\n * Background's UIModule listens for stream `_ui`. The `type` is the\n * wire value `miniapp_event` — must match `MiniappResponseType.EVENT`\n * exactly, otherwise the SDK's session switch falls through and the\n * `_ui` fan-out never fires (bound stays false; `ui.send` drops).\n */\n private deliverToBackground(packageName: string, data: Record<string, unknown>): void {\n const innerEnvelope = {\n payload: {\n type: \"miniapp_event\",\n streamType: \"_ui\",\n data,\n },\n }\n void this.crust.mentraJsDispatchToJs(packageName, {\n kind: \"bridge\",\n raw: JSON.stringify(innerEnvelope),\n })\n }\n}\n"]}
1
+ {"version":3,"file":"MentraUIRouter.js","sourceRoot":"","sources":["../../src/services/MentraUIRouter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * MentraUIRouter — bidirectional bus between a per-miniapp UI WebView\n * and its bound background JSContext.\n *\n * The flow:\n *\n * WebView (mentra.send/on) Background (session.ui.send/on)\n * │ │\n * │ window.ReactNativeWebView │\n * │ .postMessage(jsonEnvelope) │ session.sendOneShot({\n * │ │ type: \"UI_SEND\", channel, payload, seq\n * │ │ })\n * │ │\n * ▼ ▼\n * MiniappHost.onMessage MentraJSRouter (recognises payload.type===\"UI_SEND\")\n * │ │\n * ▼ ▼\n * ──── MentraUIRouter.routeFromWebView ──── MentraUIRouter.routeFromBackground\n * ──► Crust.mentraJsDispatchToJs ──► webView.injectJavaScript(\"window.__mentra.recv(...)\")\n * {kind:\"bridge\", raw: JSON({\n * payload:{\n * type:\"EVENT\", streamType:\"_ui\",\n * data:{type:\"UI_MESSAGE\", channel, payload, seq}\n * }})}\n *\n * The router is a singleton — one instance for the whole host process —\n * because only one WebView is allowed open at a time per spec. The\n * binding map is therefore N entries (one per \"currently has a UI\n * WebView mounted\" miniapp), but in practice it's 0 or 1.\n *\n * UI_OPEN / UI_CLOSE lifecycle envelopes are pushed by the WebView's\n * `mentra.ready()` and the host's WebView teardown handler; the router\n * forwards them to background via the same EVENT/_ui envelope shape.\n */\n\ninterface MentraUIInjectFn {\n (jsSource: string): void\n}\n\n/**\n * Subset of the Crust native module that MentraUIRouter touches.\n * Loose binding keeps tests free of Expo imports.\n */\nexport interface MentraUICrustBinding {\n mentraJsDispatchToJs(packageName: string, envelope: Record<string, unknown>): Promise<void> | void\n}\n\ninterface BoundWebView {\n inject: MentraUIInjectFn\n}\n\n/**\n * The host mounts at most one miniapp UI WebView at a time. Its background\n * JSContext runs separately on the phone and can remain alive after UI closure.\n * UI closure unbinds the WebView and sends UI_CLOSE; on iOS the host also exits\n * the UI when `onContentProcessDidTerminate` reports a content-process exit.\n * The host may re-announce UI_OPEN after app resume or background dev respawn\n * so the background can push a fresh snapshot. This router has no WebView\n * heartbeat timeout.\n */\n\nexport class MentraUIRouter {\n private readonly bindings: Map<string, BoundWebView> = new Map()\n private readonly crust: MentraUICrustBinding\n\n constructor(crust: MentraUICrustBinding) {\n this.crust = crust\n }\n\n /**\n * Called when a UI WebView mounts. `injectFn` wraps\n * `webView.injectJavaScript` — the router calls it with prebuilt\n * `window.__mentra.recv(...)` strings to deliver background-side\n * frames into the WebView's mentra global.\n *\n * The router also pushes a UI_OPEN envelope to the background side\n * once the WebView signals ready (see {@link routeFromWebView}).\n * Calling bindWebView on a packageName that already has a binding\n * replaces the previous one (defensive — should not happen in\n * practice because only one WebView is open at a time).\n */\n bindWebView(packageName: string, injectFn: MentraUIInjectFn): void {\n this.bindings.set(packageName, {inject: injectFn})\n }\n\n /**\n * Called when the host tears down the WebView. Drops the binding and\n * sends UI_CLOSE to the background so handlers can flush state.\n */\n unbindWebView(packageName: string): void {\n if (!this.bindings.has(packageName)) return\n this.bindings.delete(packageName)\n this.deliverToBackground(packageName, {type: \"UI_CLOSE\"})\n }\n\n /** True iff a WebView is currently bound to the named package. */\n isBound(packageName: string): boolean {\n return this.bindings.has(packageName)\n }\n\n /**\n * Re-announce the already-mounted WebView to the background JSContext.\n * This covers dev background hot-reload, app resume, and thawed WebViews\n * whose injected UI_SEND frames may have been missed while the host was\n * suspended. Re-emitting UI_OPEN flips `ui.bound` back to true if needed\n * and lets background code push a fresh snapshot via session.ui.onOpen.\n *\n * No-op if no WebView is currently bound for the package.\n */\n notifyReopen(packageName: string): void {\n if (!this.bindings.has(packageName)) return\n this.deliverToBackground(packageName, {type: \"UI_OPEN\"})\n }\n\n /**\n * Forward a WebView-originated postMessage envelope to the JSContext.\n * `rawJson` is the raw string from `event.nativeEvent.data` — the\n * caller hasn't parsed it yet so the router controls the wire format\n * end-to-end.\n *\n * Recognised envelope types from the WebView shim:\n * - {type: \"ready\"} → fire UI_OPEN\n * - {type: \"msg\", seq, channel, payload} → fire UI_MESSAGE\n */\n routeFromWebView(packageName: string, rawJson: string): void {\n let env: {\n type?: string\n seq?: number\n channel?: string\n payload?: unknown\n requestId?: string\n }\n try {\n env = JSON.parse(rawJson)\n } catch {\n return\n }\n if (typeof env.type !== \"string\") return\n\n if (env.type === \"ready\") {\n this.deliverToBackground(packageName, {type: \"UI_OPEN\"})\n return\n }\n if (env.type === \"msg\" && typeof env.channel === \"string\") {\n const out: Record<string, unknown> = {\n type: \"UI_MESSAGE\",\n channel: env.channel,\n payload: env.payload,\n seq: env.seq,\n }\n if (typeof env.requestId === \"string\") out.requestId = env.requestId\n this.deliverToBackground(packageName, out)\n return\n }\n if (env.type === \"cancel\" && typeof env.requestId === \"string\") {\n this.deliverToBackground(packageName, {type: \"UI_CANCEL\", requestId: env.requestId})\n return\n }\n // NOTE: console.* logs do NOT come through this router. The\n // miniappGlobals console-tap shim posts {payload:{type:\"dev_log\"}}\n // envelopes which LocalMiniappRuntime handles and forwards to the\n // dev sidecar tagged source:\"ui\". Keeping that path one-way means\n // we don't have two console-capture pipelines competing.\n //\n // Unknown envelope — drop silently.\n }\n\n /**\n * Called by MentraJSRouter when it sees a `__bridge.send` outbound\n * frame whose parsed payload is a UI_SEND envelope. The router\n * forwards it as a `msg` frame to the bound WebView (or drops if no\n * WebView is currently mounted).\n *\n * `uiSendPayload` is the raw `{type:\"UI_SEND\", channel, payload, seq}`\n * shape produced by `session.ui.send` on the background side.\n */\n routeFromBackground(\n packageName: string,\n uiSendPayload: {\n type: string\n channel?: string\n payload?: unknown\n seq?: number\n requestId?: string\n },\n ): void {\n const binding = this.bindings.get(packageName)\n if (!binding) return\n if (uiSendPayload.type === \"UI_CANCEL\" && typeof uiSendPayload.requestId === \"string\") {\n const cancel = {type: \"cancel\", requestId: uiSendPayload.requestId}\n const literal = JSON.stringify(cancel)\n const escaped = JSON.stringify(literal)\n binding.inject(`if (window.__mentra && window.__mentra.recv) window.__mentra.recv(JSON.parse(${escaped})); true;`)\n return\n }\n const outbound: Record<string, unknown> = {\n type: \"msg\",\n seq: uiSendPayload.seq ?? 0,\n channel: uiSendPayload.channel,\n payload: uiSendPayload.payload,\n }\n if (typeof uiSendPayload.requestId === \"string\") outbound.requestId = uiSendPayload.requestId\n const literal = JSON.stringify(outbound)\n const escaped = JSON.stringify(literal)\n binding.inject(`if (window.__mentra && window.__mentra.recv) window.__mentra.recv(JSON.parse(${escaped})); true;`)\n }\n\n /**\n * Send a synthetic frame to the WebView. Used for host-initiated\n * lifecycle events (`open`, `close`, `ack`). The wire shape is the\n * same as the WebView shim's recv handler expects.\n */\n pushLifecycleFrame(packageName: string, frame: {type: \"open\" | \"close\" | \"ack\"; seq?: number}): void {\n const binding = this.bindings.get(packageName)\n if (!binding) return\n const literal = JSON.stringify(frame)\n const escaped = JSON.stringify(literal)\n binding.inject(`if (window.__mentra && window.__mentra.recv) window.__mentra.recv(JSON.parse(${escaped})); true;`)\n }\n\n /**\n * Wrap an EVENT envelope and push it to background via the bridge.\n * Background's UIModule listens for stream `_ui`. The `type` is the\n * wire value `miniapp_event` — must match `MiniappResponseType.EVENT`\n * exactly, otherwise the SDK's session switch falls through and the\n * `_ui` fan-out never fires (bound stays false; `ui.send` drops).\n */\n private deliverToBackground(packageName: string, data: Record<string, unknown>): void {\n const innerEnvelope = {\n payload: {\n type: \"miniapp_event\",\n streamType: \"_ui\",\n data,\n },\n }\n void this.crust.mentraJsDispatchToJs(packageName, {\n kind: \"bridge\",\n raw: JSON.stringify(innerEnvelope),\n })\n }\n}\n"]}
@@ -92,12 +92,9 @@ declare class MiniappLauncher {
92
92
  /**
93
93
  * Re-spawn local miniapps that were running when the app was last killed.
94
94
  *
95
- * Cloud apps run on a remote server: the cloud persists which ones are
96
- * running and resurrects them when the phone reconnects, so a host-app
97
- * restart brings them back on its own. Local (phone-hosted) miniapps run in
98
- * the phone's own JS engine — a host-process kill tears down their JSContext
99
- * and there is no server to resurrect them, so without this they silently
100
- * stay stopped on the next launch even though the user left them running.
95
+ * Every miniapp runs as local JavaScript in the Mentra App on the phone.
96
+ * A host-process kill tears down its JSContext, so without this restoration
97
+ * it stays stopped on the next launch even though the user left it running.
101
98
  *
102
99
  * Each local miniapp persists its running flag to disk on start/stop
103
100
  * (`saveLocalAppRunningState`, via the applet's `onStart`/`onStop`). We read
@@ -106,9 +103,9 @@ declare class MiniappLauncher {
106
103
  * tray/switcher project it as running, exactly as a normal start would. The
107
104
  * WebView, if any, re-attaches lazily when the user opens the app.
108
105
  *
109
- * Idempotent and best-effort: skips already-spawned contexts, and clears the
110
- * persisted flag for any app whose bundle can no longer be resolved
111
- * (uninstalled, or dev server gone) so a dead entry doesn't retry every boot.
106
+ * Idempotent and best-effort: skips already-spawned contexts and clears the
107
+ * persisted running flag if ensureRunning fails (for example, bundle resolution,
108
+ * deployment policy, or context spawning) so it does not retry every boot.
112
109
  * Not compatibility-gated: a previously-running background app shouldn't be
113
110
  * dropped just because glasses are momentarily disconnected at boot — it
114
111
  * resumes when they reconnect, same as mid-session.
@@ -1 +1 @@
1
- {"version":3,"file":"MiniappLauncher.d.ts","sourceRoot":"","sources":["../../src/services/MiniappLauncher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AASH,OAA4B,EAAC,KAAK,wBAAwB,EAAC,MAAM,uBAAuB,CAAA;AACxF,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAEpD,UAAU,YAAY;IACpB,oEAAoE;IACpE,MAAM,EAAE,cAAc,CAAA;CACvB;AAED,6EAA6E;AAC7E,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,6EAA6E;AAC7E,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,mBAAmB,EAAE,MAAM,EAAE,CAAA;IAC7B,iBAAiB,CAAC,EAAE,wBAAwB,CAAA;IAC5C,yEAAyE;IACzE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB;AAED,uDAAuD;AACvD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAED,cAAM,eAAe;IACnB,OAAO,CAAC,IAAI,CAA4B;IAExC;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA2C;IAEpE,uEAAuE;IACvE,SAAS,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI;IAInC,OAAO,CAAC,aAAa;IAOrB,yEAAyE;IACzE,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAIvC;;;;;;OAMG;IACG,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;YA0B/E,eAAe;YAsDf,sBAAsB;IAqDpC;;;;;;;;;;OAUG;IACG,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IA2BpF,iFAAiF;YACnE,KAAK;IA2CnB;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACG,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB7C;;;;OAIG;IACG,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,gBAAgB,SAAS,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAKzG,mDAAmD;IAC7C,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB9C,OAAO,CAAC,YAAY;IAKpB,4EAA4E;IAC5E,OAAO,CAAC,cAAc;CASvB;AAED,eAAO,MAAM,eAAe,iBAAwB,CAAA"}
1
+ {"version":3,"file":"MiniappLauncher.d.ts","sourceRoot":"","sources":["../../src/services/MiniappLauncher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AASH,OAA4B,EAAC,KAAK,wBAAwB,EAAC,MAAM,uBAAuB,CAAA;AACxF,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAEpD,UAAU,YAAY;IACpB,oEAAoE;IACpE,MAAM,EAAE,cAAc,CAAA;CACvB;AAED,6EAA6E;AAC7E,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,6EAA6E;AAC7E,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,mBAAmB,EAAE,MAAM,EAAE,CAAA;IAC7B,iBAAiB,CAAC,EAAE,wBAAwB,CAAA;IAC5C,yEAAyE;IACzE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB;AAED,uDAAuD;AACvD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAED,cAAM,eAAe;IACnB,OAAO,CAAC,IAAI,CAA4B;IAExC;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA2C;IAEpE,uEAAuE;IACvE,SAAS,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI;IAInC,OAAO,CAAC,aAAa;IAOrB,yEAAyE;IACzE,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAIvC;;;;;;OAMG;IACG,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;YA0B/E,eAAe;YAsDf,sBAAsB;IAqDpC;;;;;;;;;;OAUG;IACG,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IA2BpF,iFAAiF;YACnE,KAAK;IA2CnB;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB7C;;;;OAIG;IACG,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,gBAAgB,SAAS,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAKzG,mDAAmD;IAC7C,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB9C,OAAO,CAAC,YAAY;IAKpB,4EAA4E;IAC5E,OAAO,CAAC,cAAc;CASvB;AAED,eAAO,MAAM,eAAe,iBAAwB,CAAA"}
@@ -246,12 +246,9 @@ class MiniappLauncher {
246
246
  /**
247
247
  * Re-spawn local miniapps that were running when the app was last killed.
248
248
  *
249
- * Cloud apps run on a remote server: the cloud persists which ones are
250
- * running and resurrects them when the phone reconnects, so a host-app
251
- * restart brings them back on its own. Local (phone-hosted) miniapps run in
252
- * the phone's own JS engine — a host-process kill tears down their JSContext
253
- * and there is no server to resurrect them, so without this they silently
254
- * stay stopped on the next launch even though the user left them running.
249
+ * Every miniapp runs as local JavaScript in the Mentra App on the phone.
250
+ * A host-process kill tears down its JSContext, so without this restoration
251
+ * it stays stopped on the next launch even though the user left it running.
255
252
  *
256
253
  * Each local miniapp persists its running flag to disk on start/stop
257
254
  * (`saveLocalAppRunningState`, via the applet's `onStart`/`onStop`). We read
@@ -260,9 +257,9 @@ class MiniappLauncher {
260
257
  * tray/switcher project it as running, exactly as a normal start would. The
261
258
  * WebView, if any, re-attaches lazily when the user opens the app.
262
259
  *
263
- * Idempotent and best-effort: skips already-spawned contexts, and clears the
264
- * persisted flag for any app whose bundle can no longer be resolved
265
- * (uninstalled, or dev server gone) so a dead entry doesn't retry every boot.
260
+ * Idempotent and best-effort: skips already-spawned contexts and clears the
261
+ * persisted running flag if ensureRunning fails (for example, bundle resolution,
262
+ * deployment policy, or context spawning) so it does not retry every boot.
266
263
  * Not compatibility-gated: a previously-running background app shouldn't be
267
264
  * dropped just because glasses are momentarily disconnected at boot — it
268
265
  * resumes when they reconnect, same as mid-session.