@mentra/engine 3.2.0-dev.233 → 3.2.0-dev.245
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/generated/releaseMetadata.js +5 -5
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/react/MentraLiveOtaFlow.d.ts +5 -1
- package/build/react/MentraLiveOtaFlow.d.ts.map +1 -1
- package/build/react/MentraLiveOtaFlow.js +31 -3
- package/build/react/MentraLiveOtaFlow.js.map +1 -1
- package/build/react/index.d.ts +1 -1
- package/build/react/index.d.ts.map +1 -1
- package/build/react/index.js +1 -1
- package/build/react/index.js.map +1 -1
- package/build/services/AcsMeetingService.d.ts +70 -0
- package/build/services/AcsMeetingService.d.ts.map +1 -1
- package/build/services/AcsMeetingService.js +97 -0
- package/build/services/AcsMeetingService.js.map +1 -1
- package/build/services/AppRegistry.d.ts +2 -12
- package/build/services/AppRegistry.d.ts.map +1 -1
- package/build/services/AppRegistry.js +2 -37
- package/build/services/AppRegistry.js.map +1 -1
- package/build/services/CloudClientService.d.ts +1 -1
- package/build/services/CloudClientService.d.ts.map +1 -1
- package/build/services/CloudClientService.js +2 -2
- package/build/services/CloudClientService.js.map +1 -1
- package/build/services/LocalMiniappRuntime.d.ts +51 -0
- package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
- package/build/services/LocalMiniappRuntime.js +228 -6
- package/build/services/LocalMiniappRuntime.js.map +1 -1
- package/build/services/PhoneNotificationsSync.d.ts +1 -1
- package/build/services/PhonePhotoCoordinator.d.ts +3 -2
- package/build/services/PhonePhotoCoordinator.d.ts.map +1 -1
- package/build/services/PhonePhotoCoordinator.js +19 -14
- package/build/services/PhonePhotoCoordinator.js.map +1 -1
- package/build/services/SoftapCallTransport.d.ts +64 -0
- package/build/services/SoftapCallTransport.d.ts.map +1 -1
- package/build/services/SoftapCallTransport.js +103 -3
- package/build/services/SoftapCallTransport.js.map +1 -1
- package/build/services/manifestPermissions.d.ts +13 -0
- package/build/services/manifestPermissions.d.ts.map +1 -0
- package/build/services/manifestPermissions.js +42 -0
- package/build/services/manifestPermissions.js.map +1 -0
- package/build/types/applet.d.ts +13 -1
- package/build/types/applet.d.ts.map +1 -1
- package/build/types/applet.js.map +1 -1
- package/package.json +8 -8
- package/src/generated/releaseMetadata.ts +5 -5
- package/src/react/MentraLiveOtaFlow.tsx +73 -6
- package/src/react/index.ts +1 -0
- package/src/react/lucide-LICENSE.txt +39 -0
- package/src/services/AcsMeetingService.ts +138 -0
- package/src/services/AppRegistry.ts +3 -40
- package/src/services/CloudClientService.ts +2 -2
- package/src/services/LocalMiniappRuntime.ts +268 -7
- package/src/services/PhonePhotoCoordinator.ts +18 -14
- package/src/services/SoftapCallTransport.ts +151 -16
- package/src/services/manifestPermissions.ts +44 -0
- package/src/types/applet.ts +11 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SoftapCallTransport.js","sourceRoot":"","sources":["../../src/services/SoftapCallTransport.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Sequences a SoftAP call. Sequencing only — no sockets, no peers, no BLE.\n *\n * The glasses open a hotspot, the phone joins it without giving up its cellular route, and the\n * glasses publish WebRTC straight to a listener on the phone. Cloudflare is not involved at all.\n *\n * The order below is the whole point of this file, and one step in it is load-bearing:\n *\n * hotspot on -> scoped join -> ACS join (binds the listener and arms the raw outputs)\n * -> glasses publish -> WHIP negotiation -> first frame -> LIVE\n *\n * Publishing must come after the ACS join, not before. `LIVE` means a frame reached ACS, so if the\n * glasses start publishing first, decoded video and audio can arrive before the raw outgoing\n * streams exist and the first frames are dropped by whatever happens to be null at the time. That\n * is not a lifecycle anyone designed; making the order explicit is what removes it.\n *\n * Ownership is deliberately narrow. This object owns the *sequence* and nothing else: the meeting\n * session owns the WHIP listener and the peer, `PhoneStreamCoordinator` owns the publisher, and\n * `localNetworkTransport` owns the scoped network. Every step therefore has exactly one owner that\n * can tear it down, which is what makes leaving mid-join safe.\n */\n\nimport {softapTrace, softapTraceFailure, beginSoftapTrace, resetSoftapTrace} from \"../utils/softapTrace\"\n\n/** Steps in order. Also the teardown order, reversed. */\nexport const SOFTAP_STEPS = [\"hotspot\", \"scopedJoin\", \"acsJoin\", \"publish\", \"live\"] as const\n\nexport type SoftapStep = (typeof SOFTAP_STEPS)[number]\n\n/**\n * Where the sequence is.\n *\n * `starting` covers every step up to `live` because the caller's only useful distinction is\n * \"not yet usable\" versus \"carrying media\"; the step names are for diagnostics, not for branching.\n */\nexport type SoftapPhase = \"idle\" | \"starting\" | \"live\" | \"stopping\" | \"failed\"\n\n/** A failure, named by the step that produced it so the UI and the logs agree on the cause. */\nexport class SoftapCallError extends Error {\n constructor(\n readonly step: SoftapStep,\n readonly code: string,\n message: string,\n readonly cause?: unknown,\n ) {\n super(message)\n this.name = \"SoftapCallError\"\n }\n}\n\n/** Gallery sync already learned this: glasses report enabled before the SSID is in the phone scan. */\nexport const HOTSPOT_BROADCAST_WAIT_MS = 3_000\n\n/**\n * Android's WifiNetworkSpecifier called onUnavailable. The native message lists three causes\n * because the callback does not say which one happened; on the 18:02 Samsung path the SSID was\n * in scan and the join sheet was bypassed — assoc rejected after leaving another AP.\n */\nfunction isScopedJoinUnavailable(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error)\n return /SOFTAP_UNAVAILABLE|ScopedNetworkError\\$Unavailable|SSID not in scan, Wi-Fi off, or the system join prompt/i.test(\n message,\n )\n}\n\nexport type SoftapStepStatus = \"pending\" | \"running\" | \"done\" | \"failed\"\n\n/**\n * One step as the UI should show it. `detail` is the fact the step produced (SSID, phone address,\n * ingest URL, what the glasses last reported); `error` is set only on `failed`.\n */\nexport interface SoftapStepState {\n step: SoftapStep\n status: SoftapStepStatus\n detail?: string\n error?: string\n /** Wall-clock ms the step took; present once it is done or failed. */\n durationMs?: number\n}\n\n/**\n * Whole-sequence snapshot, re-sent on every transition so a consumer that missed one still holds\n * the truth. This is what the miniapp renders as its join checklist.\n */\nexport interface SoftapProgress {\n traceId: string\n phase: SoftapPhase\n steps: SoftapStepState[]\n /** ms since `start()` was called. */\n elapsedMs: number\n}\n\n/** Sub-status callback a step can use to narrate what it is doing while it runs. */\nexport type SoftapStepReporter = (detail: string) => void\n\nexport interface SoftapCallDeps {\n /** Enable the glasses hotspot and return its credentials. */\n startHotspot(report?: SoftapStepReporter): Promise<{ssid: string; passphrase: string}>\n /**\n * Wait until the phone can actually see the AP. `setHotspotState` resolves when the glasses\n * accept the command, not when `ap0` is beaconing. A WifiNetworkSpecifier issued too early\n * comes back `Unavailable` in well under a second — it does not keep scanning for the timeout.\n */\n waitUntilHotspotJoinable?(report?: SoftapStepReporter): Promise<void>\n /** Disable it. Must tolerate being called when it was never enabled. */\n stopHotspot(): Promise<void>\n /** Join the hotspot without taking the phone's default route. Resolves to the phone's own IPv4. */\n joinScopedNetwork(ssid: string, passphrase: string, report?: SoftapStepReporter): Promise<string | undefined>\n leaveScopedNetwork(): Promise<void>\n /** Interrupt a pending native join while retaining its cleanup barrier. Unsupported hosts wait. */\n cancelScopedNetworkJoin?(): Promise<void>\n /**\n * Join the meeting. This is what binds the local WHIP listener and arms the ACS raw outputs, so\n * it must resolve before the glasses are told to publish.\n *\n * @returns the URL the glasses must POST their offer to\n */\n joinMeeting(\n args: {ssid: string; passphrase: string; bindAddress?: string},\n report?: SoftapStepReporter,\n ): Promise<{ingestUrl: string}>\n leaveMeeting(): Promise<void>\n /**\n * End the meeting for everyone instead of leaving it. Optional: a host that cannot do this still\n * tears down correctly, it just cannot honour `stop({mode: \"end\"})`.\n */\n endMeeting?(): Promise<void>\n /** Tell the glasses to publish to [ingestUrl] in host-only ICE mode. */\n startPublishing(args: {ingestUrl: string; traceId: string}, report?: SoftapStepReporter): Promise<void>\n stopPublishing(): Promise<void>\n /**\n * Resolves when a frame has reached ACS, rejects if the feed failed or the deadline passed.\n * Separate from [joinMeeting] because an answered negotiation is not a working call: a session\n * that never delivers a frame reads as healthy behind a frozen tile.\n */\n awaitFirstFrame(report?: SoftapStepReporter): Promise<void>\n}\n\nexport interface SoftapCallOptions {\n /** Override the minted trace id, so a caller can correlate with logs it already started. */\n traceId?: string\n /**\n * Receives a fresh snapshot on every transition: step begins, step narrates, step ends, sequence\n * ends. Exceptions thrown here are swallowed — a broken listener must not fail the call.\n */\n onProgress?: (progress: SoftapProgress) => void\n /**\n * Narration the caller already showed before the sequence existed — signing in to Teams, asking\n * for a permission. Without it the first `emitProgress` would blank the checklist the wearer is\n * already reading. Only `detail` is taken: the caller reports what it did, it does not get to\n * claim a step ran.\n */\n initialSteps?: SoftapStepState[]\n}\n\nfunction freshSteps(): SoftapStepState[] {\n return SOFTAP_STEPS.map((step) => ({step, status: \"pending\"}))\n}\n\n/** See {@link SoftapCallOptions.initialSteps}. */\nfunction seededSteps(initial: SoftapStepState[] | undefined): SoftapStepState[] {\n if (!initial?.length) return freshSteps()\n return freshSteps().map((step) => {\n const seed = initial.find((entry) => entry.step === step.step)\n return seed?.detail ? {...step, detail: seed.detail} : step\n })\n}\n\n/** A promise plus the function that settles it. */\nfunction deferred(): {promise: Promise<void>; resolve: () => void} {\n let resolve!: () => void\n const promise = new Promise<void>((settle) => {\n resolve = settle\n })\n return {promise, resolve}\n}\n\n/**\n * How a call is being taken down.\n *\n * `leave` takes this device out; `end` terminates the group call for everyone first. Everything\n * after that step is identical, which is the point: End is not a second teardown path, it is one\n * different verb at one step of the same one.\n */\nexport type SoftapTeardownMode = \"leave\" | \"end\"\n\nexport interface SoftapStopOptions {\n mode?: SoftapTeardownMode\n keepProgress?: boolean\n}\n\nexport class SoftapEndNotSupportedError extends Error {\n constructor() {\n super(\"This host cannot end a meeting for everyone\")\n this.name = \"SoftapEndNotSupportedError\"\n }\n}\n\nexport class SoftapCallTransport {\n private phase: SoftapPhase = \"idle\"\n /**\n * Steps completed and not yet undone, in the order they succeeded. Teardown walks this\n * backwards, so a failure halfway through unwinds exactly what was built and nothing else.\n */\n private completed: SoftapStep[] = []\n /**\n * Bumped by every start and stop. A step that resolves after the caller has moved on must not\n * write to the new attempt's state, which is the leave-during-join race.\n */\n private generation = 0\n private stopping: Promise<void> | null = null\n /**\n * The step currently in flight, and a promise that settles only after its body *and* the undo it\n * runs when it finds itself cancelled are both finished.\n *\n * This is what [stop] waits on. A step that resolves late still owns a resource — a hotspot that\n * came up after the wearer left — and its release happens inside the step, out of the teardown's\n * sight. Without this wait, `stop()` resolves while that release is still pending and the next\n * call brings a hotspot up straight into it.\n */\n private running: {step: SoftapStep; settled: Promise<void>} | null = null\n /** True once [start] has been called at least once, so [stop] can tell \"cancelled\" from \"reusable\". */\n private startedEver = false\n /**\n * A [stop] that landed before the sequence ever began.\n *\n * There is nothing to unwind in that case, so the flag is the only thing that can carry the\n * cancellation forward: a `start()` arriving afterwards belongs to the attempt that was just\n * cancelled and must refuse rather than build a call nobody is waiting for.\n */\n private cancelledBeforeStart = false\n /** Failed undos for this attempt, retained across repeated stops. See [lastTeardownFailures]. */\n private teardownFailures: SoftapStep[] = []\n /**\n * Raised the instant a teardown is decided, before any resource is touched.\n *\n * Everything that watches the call for failure — a lost hotspot above all — has to be able to ask\n * \"was this supposed to happen?\". Without the flag, releasing the scoped network during a\n * successful Leave looks exactly like the glasses walking out of range, and the wearer gets an\n * error screen for a call that ended the way they asked.\n */\n private terminating = false\n /** How this teardown ends the meeting. Read by the `acsJoin` undo. */\n private teardownMode: SoftapTeardownMode = \"leave\"\n /** Set when `stop({mode: \"end\"})` could not end for everyone. The caller must not claim it did. */\n private endFailure: unknown = null\n private hotspot: {ssid: string; passphrase: string} | null = null\n private ingestUrl: string | null = null\n private steps: SoftapStepState[] = freshSteps()\n private stepStartedAt = new Map<SoftapStep, number>()\n private startedAt = 0\n private traceId = \"\"\n private onProgress: ((progress: SoftapProgress) => void) | undefined\n\n constructor(private readonly deps: SoftapCallDeps) {}\n\n currentPhase(): SoftapPhase {\n return this.phase\n }\n\n /**\n * True once a teardown has been decided. Anything that would otherwise report a failure — a lost\n * hotspot, a dropped ACS call — must check this first: after the wearer asks to leave, those are\n * the sound of it working.\n */\n isTerminating(): boolean {\n return this.terminating\n }\n\n /** What the UI should show right now. Safe to call in any phase. */\n progress(): SoftapProgress {\n return {\n traceId: this.traceId,\n phase: this.phase,\n steps: this.steps.map((step) => ({...step})),\n elapsedMs: this.startedAt ? Date.now() - this.startedAt : 0,\n }\n }\n\n private emitProgress(): void {\n const listener = this.onProgress\n if (!listener) return\n try {\n listener(this.progress())\n } catch (error) {\n softapTraceFailure(\"softap_progress_listener_threw\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n }\n }\n\n private setStep(step: SoftapStep, patch: Partial<SoftapStepState>): void {\n this.steps = this.steps.map((entry) => (entry.step === step ? {...entry, ...patch} : entry))\n this.emitProgress()\n }\n\n /** Narration for a running step: what the phone or the glasses just reported. */\n private note(generation: number, step: SoftapStep, detail: string): void {\n if (generation !== this.generation) {\n // A step that is still narrating after the sequence moved on. The detail is dropped rather\n // than written onto the new attempt's checklist, and the drop is said out loud because a\n // step that goes quiet here is usually one that is still holding a native call open.\n softapTrace(\"softap_step_note_dropped\", {step, generation, current: this.generation, detail})\n return\n }\n softapTrace(\"softap_step_note\", {step, detail})\n this.setStep(step, {detail})\n }\n\n /** Steps currently built up, oldest first. Empty when nothing needs tearing down. */\n activeSteps(): SoftapStep[] {\n return [...this.completed]\n }\n\n /** The URL handed to the glasses, for diagnostics. Null outside a live attempt. */\n currentIngestUrl(): string | null {\n return this.ingestUrl\n }\n\n /**\n * Steps whose undo threw during the last teardown, so the caller can refuse the next call.\n *\n * Teardown deliberately swallows these to keep unwinding — but a hotspot that would not turn off\n * is exactly the state the next call cannot be built on, and starting anyway is what produced\n * \"Cannot start glasses hotspot\" followed by a scoped join that never found the SSID.\n */\n lastTeardownFailures(): SoftapStep[] {\n // Logged on read rather than only on write, because this is the moment the list turns into a\n // refusal for the next call: a wearer told to power-cycle the hotspot needs the reason to be\n // findable, and the write happened somewhere in the middle of a noisy teardown.\n if (this.teardownFailures.length > 0) {\n softapTraceFailure(\"softap_teardown_failures_read\", {steps: this.teardownFailures.join(\",\")})\n }\n return [...this.teardownFailures]\n }\n\n /**\n * Runs the sequence. On any failure the partial sequence is torn down before the error is\n * rethrown, so a failed start never leaves a hotspot up or a publisher running.\n */\n async start(options: SoftapCallOptions = {}): Promise<void> {\n if (this.cancelledBeforeStart) {\n // The wearer's Cancel landed before the sequence began, so there is no step to name and no\n // trace id yet. This line is the only evidence that the flag did its job rather than the\n // join having silently never been asked for.\n softapTraceFailure(\"softap_call_refused\", {reason: \"cancelled before start\"})\n throw new SoftapCallError(\"hotspot\", \"CANCELLED\", \"SoftAP call was cancelled before it started\")\n }\n if (this.phase !== \"idle\" && this.phase !== \"failed\") {\n softapTraceFailure(\"softap_call_refused\", {reason: \"already active\", phase: this.phase})\n throw new SoftapCallError(\"hotspot\", \"ALREADY_ACTIVE\", `A SoftAP call is already ${this.phase}`)\n }\n this.startedEver = true\n const generation = ++this.generation\n this.phase = \"starting\"\n this.terminating = false\n this.teardownMode = \"leave\"\n this.endFailure = null\n this.completed = []\n this.ingestUrl = null\n this.hotspot = null\n this.teardownFailures = []\n this.steps = seededSteps(options.initialSteps)\n this.stepStartedAt.clear()\n this.startedAt = Date.now()\n this.onProgress = options.onProgress\n const traceId = beginSoftapTrace(options.traceId)\n this.traceId = traceId\n softapTrace(\"softap_call_start\", {traceId})\n this.emitProgress()\n\n try {\n await this.step(generation, \"hotspot\", \"HOTSPOT_FAILED\", async (report) => {\n report(\"Asking the glasses to turn on their hotspot\")\n const hotspot = await this.deps.startHotspot(report)\n if (!hotspot.ssid) {\n throw new Error(\"the glasses reported no hotspot SSID\")\n }\n this.hotspot = hotspot\n // The passphrase never reaches the log; softapTrace redacts it by key, and only the SSID\n // is useful for matching against the phone's Wi-Fi state anyway.\n softapTrace(\"hotspot_enabled\", {ssid: hotspot.ssid})\n report(`Hotspot ${hotspot.ssid} is on; waiting for it to broadcast`)\n await this.deps.waitUntilHotspotJoinable?.(report)\n softapTrace(\"hotspot_broadcast_wait_done\", {ssid: hotspot.ssid})\n report(`Hotspot ${hotspot.ssid}`)\n })\n\n const hotspot = this.requireHotspot()\n let bindAddress: string | undefined\n await this.step(generation, \"scopedJoin\", \"SCOPED_JOIN_FAILED\", async (report) => {\n report(\n `Phone joining ${hotspot.ssid}. Turn Wi-Fi on if a panel opens — Teams stays on cellular.`,\n )\n bindAddress = await this.deps.joinScopedNetwork(hotspot.ssid, hotspot.passphrase, report)\n softapTrace(\"scoped_network_joined\", {bindAddress: bindAddress ?? \"unknown\"})\n if (bindAddress) report(`Phone is ${bindAddress} on ${hotspot.ssid}`)\n })\n\n await this.step(generation, \"acsJoin\", \"ACS_JOIN_FAILED\", async (report) => {\n report(bindAddress ? `Opening video receiver on ${bindAddress}, then joining Teams` : \"Joining Teams\")\n const {ingestUrl} = await this.deps.joinMeeting(\n {\n ssid: hotspot.ssid,\n passphrase: hotspot.passphrase,\n bindAddress,\n },\n report,\n )\n if (!ingestUrl) {\n // Without a bound listener there is nowhere for the glasses to publish, and telling them\n // to publish anyway produces a failure several seconds later on the wrong device.\n throw new Error(\"the meeting reported no ingest URL\")\n }\n this.ingestUrl = ingestUrl\n softapTrace(\"acs_receiver_ready\", {ingestUrl})\n report(`Receiver ready at ${ingestUrl}`)\n })\n\n const ingestUrl = this.requireIngestUrl()\n await this.step(generation, \"publish\", \"PUBLISH_FAILED\", async (report) => {\n report(\"Telling the glasses to start the camera and publish to the phone\")\n await this.deps.startPublishing({ingestUrl, traceId}, report)\n softapTrace(\"glasses_publishing\", {ingestUrl})\n report(\"Glasses camera is streaming to the phone\")\n })\n\n await this.step(generation, \"live\", \"NO_FIRST_FRAME\", async (report) => {\n report(\"Waiting for the first glasses video frame on this phone\")\n await this.deps.awaitFirstFrame(report)\n softapTrace(\"first_glasses_frame_received\")\n report(\"Glasses video is reaching this phone\")\n })\n\n if (generation !== this.generation) {\n // Every step succeeded and the call is nevertheless not this transport's any more. The\n // steps released themselves on the way past, so there is nothing to undo — but a join\n // that got all the way to a frame and then vanished is otherwise a log that simply stops.\n softapTraceFailure(\"softap_call_abandoned_at_live\", {generation, current: this.generation})\n return\n }\n this.phase = \"live\"\n softapTrace(\"softap_call_live\")\n this.emitProgress()\n } catch (error) {\n // Unwind before rethrowing. A caller that sees a rejection is entitled to assume nothing was\n // left running, and a hotspot left up is both a battery cost and a second call's failure.\n await this.stop({keepProgress: true})\n this.phase = \"failed\"\n this.emitProgress()\n throw error\n }\n }\n\n /**\n * Tears down in exact reverse order, and only what was built.\n *\n * Every step is attempted even if an earlier one throws: a failure to stop the publisher must\n * not leave the hotspot on. Concurrent calls share one teardown rather than racing each other\n * through the same resources, and a second `stop()` after one finished is a no-op — this is the\n * only SoftAP exit, so every terminal path can call it without checking whether another already\n * did.\n *\n * `mode: \"end\"` swaps the meeting verb and nothing else. If ending for everyone fails, the rest of\n * the teardown still runs and the failure is rethrown at the end, so the caller can tell the\n * wearer they left a meeting that may still be live rather than inventing a clean end.\n */\n async stop(options: SoftapStopOptions = {}): Promise<void> {\n // Intent before action, always: a watcher must be able to tell a deliberate teardown from a\n // failure even during the very first await below.\n this.terminating = true\n if (options.mode) this.teardownMode = options.mode\n if (this.stopping) {\n softapTrace(\"softap_stop_joined_in_flight\", {mode: this.teardownMode})\n return this.stopping\n }\n const running = this.running\n if (this.completed.length === 0 && this.phase === \"idle\" && !running) {\n // Nothing was built, so there is nothing to unwind — but a start() that has not run yet\n // still has to be refused, and a generation bump still has to invalidate anything holding\n // the old one.\n this.generation++\n if (!this.startedEver) this.cancelledBeforeStart = true\n softapTrace(\"softap_stop_nothing_built\", {\n // The distinction the next `start()` turns on: a transport that was never started refuses\n // outright, one that has already run is reusable.\n cancelledBeforeStart: this.cancelledBeforeStart,\n generation: this.generation,\n })\n return\n }\n\n this.generation++\n this.phase = \"stopping\"\n this.endFailure = null\n softapTrace(\"softap_call_stop\", {steps: this.completed.join(\",\"), mode: this.teardownMode})\n this.emitProgress()\n\n this.stopping = (async () => {\n // The generation bump above has already told the in-flight step to release whatever it\n // produced. Waiting for that release is what makes a resolved `stop()` mean \"nothing from\n // this call is still coming\". Deliberately unbounded: a native call that never returns must\n // hold the next call back, never let it race this one's cleanup.\n if (running) {\n const cancellation =\n running.step === \"scopedJoin\" && this.deps.cancelScopedNetworkJoin\n ? Promise.resolve()\n .then(() => this.deps.cancelScopedNetworkJoin!())\n .catch((error) => {\n if (!this.teardownFailures.includes(\"scopedJoin\")) this.teardownFailures.push(\"scopedJoin\")\n softapTraceFailure(\"softap_join_cancel_failed\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n })\n : undefined\n softapTrace(\"softap_stop_waiting_for_step\", {step: running.step})\n const waitStartedAt = Date.now()\n await running.settled\n await cancellation\n // This wait is unbounded by design, so its duration is the difference between \"the leave\n // was slow\" and \"the leave was held by a native call that had not returned\".\n softapTrace(\"softap_stop_step_settled\", {step: running.step, waitedMs: Date.now() - waitStartedAt})\n }\n // The late step may have recorded a failed self-undo while we waited. Preserve it,\n // and any earlier teardown result, until start() explicitly begins a new attempt.\n const failures: SoftapStep[] = [...this.teardownFailures]\n for (const step of [...this.completed].reverse()) {\n const undoStartedAt = Date.now()\n try {\n await this.undo(step)\n softapTrace(\"softap_step_undone\", {step, durationMs: Date.now() - undoStartedAt})\n } catch (error) {\n // Recorded, not rethrown: the remaining steps still have to be undone. The caller reads\n // them back through [lastTeardownFailures] and refuses the next call, because a hotspot\n // that would not turn off is exactly the state the next call cannot build on.\n failures.push(step)\n softapTraceFailure(\"softap_step_undo_failed\", {\n step,\n durationMs: Date.now() - undoStartedAt,\n reason: error instanceof Error ? error.message : String(error),\n })\n }\n }\n this.completed = []\n this.hotspot = null\n this.ingestUrl = null\n this.phase = \"idle\"\n this.teardownFailures = failures\n softapTrace(\"softap_call_stopped\", {undoFailures: failures.join(\",\")})\n resetSoftapTrace()\n // A failed start keeps its checklist so the UI can show which step broke; a deliberate\n // leave wipes it, because there is nothing left to explain.\n if (!options.keepProgress) {\n this.steps = freshSteps()\n this.emitProgress()\n }\n })()\n\n try {\n await this.stopping\n } finally {\n this.stopping = null\n }\n // Rethrown last, after every resource is released. An End that could not terminate the meeting\n // has still taken this device out; only the claim about the others is wrong.\n const endFailure = this.endFailure\n this.endFailure = null\n if (endFailure) throw endFailure\n }\n\n private async undo(step: SoftapStep): Promise<void> {\n switch (step) {\n // `live` is an observation, not a resource — there is nothing to release.\n case \"live\":\n return\n case \"publish\":\n return this.deps.stopPublishing()\n case \"acsJoin\":\n return this.leaveOrEndMeeting()\n case \"scopedJoin\":\n return this.deps.leaveScopedNetwork()\n case \"hotspot\":\n return this.deps.stopHotspot()\n }\n }\n\n /**\n * The one step End changes.\n *\n * A failed End falls back to leaving, so the wearer is out either way, and the original failure is\n * kept for [stop] to rethrow. Recording it rather than throwing here is what keeps the hotspot\n * teardown — the steps after this one — unconditional.\n */\n private async leaveOrEndMeeting(): Promise<void> {\n if (this.teardownMode !== \"end\") return this.deps.leaveMeeting()\n const endMeeting = this.deps.endMeeting\n if (!endMeeting) {\n this.endFailure = new SoftapEndNotSupportedError()\n return this.deps.leaveMeeting()\n }\n try {\n await endMeeting()\n softapTrace(\"softap_meeting_ended_for_everyone\")\n } catch (error) {\n this.endFailure = error\n softapTraceFailure(\"softap_end_for_everyone_failed\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n // Native ends the local call even when the hang-up is refused, so this is a belt-and-braces\n // leave rather than a second teardown: it must not resurrect the failure it is covering for.\n await this.deps.leaveMeeting().catch(() => undefined)\n }\n }\n\n /**\n * Runs one step, records it as undoable, and maps any throw to a [SoftapCallError] naming the\n * step. The generation check is what makes leaving mid-step safe: a step that resolves after the\n * caller gave up is not recorded, so teardown does not try to undo it twice.\n */\n private async step(\n generation: number,\n step: SoftapStep,\n code: string,\n run: (report: SoftapStepReporter) => Promise<void>,\n ): Promise<void> {\n if (generation !== this.generation) {\n // The sequence stopped between two steps. Named here because the caller only ever sees one\n // CANCELLED error, and which step it never reached is the thing worth knowing.\n softapTraceFailure(\"softap_step_skipped_after_cancel\", {step, generation, current: this.generation})\n throw new SoftapCallError(step, \"CANCELLED\", `SoftAP call was cancelled before ${step}`)\n }\n // Published before the first await so a `stop()` on the very next tick can see it. Settled in\n // the `finally`, after any self-undo, so waiting on it means the step owns nothing any more.\n const settle = deferred()\n this.running = {step, settled: settle.promise}\n try {\n await this.runStep(generation, step, code, run)\n } finally {\n if (this.running?.settled === settle.promise) this.running = null\n settle.resolve()\n }\n }\n\n /** The step body itself. Split out so [step] can publish and settle {@link running} around it. */\n private async runStep(\n generation: number,\n step: SoftapStep,\n code: string,\n run: (report: SoftapStepReporter) => Promise<void>,\n ): Promise<void> {\n softapTrace(\"softap_step_begin\", {step})\n const startedAt = Date.now()\n this.stepStartedAt.set(step, startedAt)\n this.setStep(step, {status: \"running\", error: undefined})\n const report: SoftapStepReporter = (detail) => this.note(generation, step, detail)\n try {\n await run(report)\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error)\n softapTraceFailure(\"softap_step_failed\", {step, code, reason})\n if (generation === this.generation) {\n this.setStep(step, {status: \"failed\", error: reason, durationMs: Date.now() - startedAt})\n }\n throw new SoftapCallError(step, code, error instanceof Error ? error.message : `${step} failed`, error)\n }\n if (generation !== this.generation) {\n // The step succeeded after the caller gave up. Release it here rather than recording it for\n // the teardown to find: that teardown may already have walked past this step, or finished\n // altogether, in which case nothing else ever would. This is the leak the generation guard\n // exists to close — a meeting joined a few milliseconds after the user left.\n softapTrace(\"softap_step_completed_after_cancel\", {step})\n await this.undoSafely(step)\n throw new SoftapCallError(step, \"CANCELLED\", `SoftAP call was cancelled during ${step}`)\n }\n this.completed.push(step)\n softapTrace(\"softap_step_done\", {step, durationMs: Date.now() - startedAt})\n this.setStep(step, {status: \"done\", durationMs: Date.now() - startedAt})\n }\n\n /** Undo that reports rather than throws, for the cancellation path where there is no caller. */\n private async undoSafely(step: SoftapStep): Promise<void> {\n try {\n await this.undo(step)\n } catch (error) {\n if (!this.teardownFailures.includes(step)) this.teardownFailures.push(step)\n softapTraceFailure(\"softap_step_undo_failed\", {\n step,\n reason: error instanceof Error ? error.message : String(error),\n })\n }\n }\n\n private requireHotspot(): {ssid: string; passphrase: string} {\n const hotspot = this.hotspot\n if (!hotspot) throw new SoftapCallError(\"hotspot\", \"HOTSPOT_FAILED\", \"no hotspot credentials\")\n return hotspot\n }\n\n private requireIngestUrl(): string {\n const url = this.ingestUrl\n if (!url) throw new SoftapCallError(\"acsJoin\", \"ACS_JOIN_FAILED\", \"no ingest URL\")\n return url\n }\n}\n\n/**\n * Binds the sequence to the real subsystems.\n *\n * Kept separate from the class so the ordering above is tested against fakes rather than against\n * BLE and ACS. The only logic here is adapting shapes; anything that needs a decision belongs in\n * the class.\n *\n * @param packageName the miniapp that owns the call\n * @param meeting the meeting to join, and how to observe its media health\n */\nexport function createSoftapCallDeps(args: {\n packageName: string\n meetingUrl: string\n token: string\n displayName?: string\n /** Resolves when the meeting reports a frame reached ACS; rejects on a failed feed. */\n awaitFirstFrame: () => Promise<void>\n subsystems: {\n setHotspotState: (enabled: boolean) => Promise<{state: string; ssid?: string; password?: string; localIp?: string}>\n joinScopedNetwork: (ssid: string, passphrase: string, gateway?: string) => Promise<string | undefined>\n leaveScopedNetwork: () => Promise<void>\n cancelScopedNetworkJoin?: () => Promise<void>\n joinMeeting: (\n packageName: string,\n options: {\n meetingUrl: string\n token: string\n videoSource: {type: \"softap\"; ssid?: string; passphrase?: string; bindAddress?: string}\n displayName?: string\n },\n ) => Promise<unknown>\n leaveMeeting: (packageName: string) => Promise<void>\n /** Terminate the group call for everyone. Absent on hosts that cannot. */\n endMeeting?: (packageName: string) => Promise<void>\n ingestUrl: () => string | null\n startPublishing: (\n packageName: string,\n options: {streamUrl: string; ice: {stun: string}; traceId: string; captureAudio?: boolean},\n ) => Promise<unknown>\n stopPublishing: (packageName: string) => Promise<void>\n /**\n * Whether the host is taking the wearer's voice off the glasses over BLE LC3 for this call.\n *\n * Asked after the meeting join and before the publish, because that is the only moment the\n * answer is both known (the host has seen the native's capabilities) and still actionable (the\n * glasses have not been told what to capture). True means the WHIP publish is video-only;\n * false means the glasses put their microphone on the WHIP track as they always have. Absent\n * on hosts that only have the WHIP audio path.\n */\n glassesLc3Uplink?: () => boolean\n /**\n * Prove the phone can reach the glasses over the hotspot it just joined. Optional because\n * only Android hosts have the scoped network handle; when present its verdict is narrated\n * into the scoped-join step and a failure is reported, not thrown — the glasses-to-phone\n * direction is what the call actually needs, and that is tested by the publish step.\n */\n probeGateway?: () => Promise<{reachable: boolean; detail: string}>\n /**\n * Wait for the phone's default network to be validated again after the hotspot join took Wi-Fi\n * away. Optional because only Android hosts can answer it.\n *\n * Not fatal when it reports an unusable network: the wearer is told, and the join is attempted\n * anyway. Aborting here would fail calls that recover a second later, and the ACS join has its\n * own bounded timeout for the case that does not.\n */\n awaitValidatedDefaultNetwork?: () => Promise<{usable: boolean; detail: string} | null>\n /**\n * Glasses `stream_status` events, so the publish step can say \"camera starting\" and \"offer\n * posted\" instead of going quiet for the whole BLE round trip. Returns an unsubscribe.\n */\n onGlassesStreamStatus?: (\n listener: (event: {status: string; streamId?: string; reason?: string; error?: string}) => void,\n ) => () => void\n }\n /** Override only in tests. Production waits the gallery-proven broadcast window. */\n hotspotBroadcastWaitMs?: number\n}): SoftapCallDeps {\n const {packageName, subsystems} = args\n const hotspotBroadcastWaitMs = args.hotspotBroadcastWaitMs ?? HOTSPOT_BROADCAST_WAIT_MS\n let gatewayAddress: string | undefined\n return {\n startHotspot: async (report) => {\n const enable = async () => {\n const status = await subsystems.setHotspotState(true)\n if (status.state !== \"enabled\" || !status.ssid) {\n throw new Error(`the glasses hotspot did not start (state=${status.state})`)\n }\n if (!status.password) {\n throw new Error(\"the glasses hotspot reported no password\")\n }\n report?.(`Glasses report hotspot ${status.ssid} enabled`)\n gatewayAddress = status.localIp\n return {ssid: status.ssid, passphrase: status.password}\n }\n try {\n return await enable()\n } catch (error) {\n if (error instanceof Error && /no password/.test(error.message)) throw error\n // Cancel-then-start races the previous disable: the glasses report disabled (or no SSID)\n // and the UI said \"Couldn't start glasses hotspot\" before step 2 ran on a leftover AP.\n softapTraceFailure(\"hotspot_enable_retry\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n report?.(\"Glasses hotspot did not start; turning it off and trying again\")\n await subsystems.setHotspotState(false)\n if (hotspotBroadcastWaitMs > 0) {\n await new Promise<void>(resolve => setTimeout(resolve, Math.min(1_000, hotspotBroadcastWaitMs)))\n }\n return await enable()\n }\n },\n waitUntilHotspotJoinable: async (report) => {\n if (hotspotBroadcastWaitMs <= 0) return\n softapTrace(\"hotspot_broadcast_wait\", {ms: hotspotBroadcastWaitMs})\n report?.(`Giving the hotspot ${Math.round(hotspotBroadcastWaitMs / 1000)}s to start broadcasting`)\n await new Promise<void>(resolve => setTimeout(resolve, hotspotBroadcastWaitMs))\n },\n stopHotspot: async () => {\n await subsystems.setHotspotState(false)\n },\n joinScopedNetwork: async (ssid, passphrase, report) => {\n const joinOnce = (nextSsid: string, nextPassphrase: string) =>\n gatewayAddress\n ? subsystems.joinScopedNetwork(nextSsid, nextPassphrase, gatewayAddress)\n : subsystems.joinScopedNetwork(nextSsid, nextPassphrase)\n let address: string | undefined\n try {\n address = await joinOnce(ssid, passphrase)\n } catch (error) {\n if (!isScopedJoinUnavailable(error)) throw error\n // First specifier left the phone's previous Wi-Fi and assoc-rejected the glasses AP.\n // Cycle the AP and join again from an idle STA — the radio is free now.\n softapTraceFailure(\"scoped_join_unavailable_retry\", {ssid})\n report?.(\"Phone couldn't join; cycling the glasses hotspot and trying again\")\n await subsystems.setHotspotState(false)\n const status = await subsystems.setHotspotState(true)\n if (status.state !== \"enabled\" || !status.ssid || !status.password) throw error\n gatewayAddress = status.localIp\n if (hotspotBroadcastWaitMs > 0) {\n report?.(\n `Giving the hotspot ${Math.round(hotspotBroadcastWaitMs / 1000)}s to start broadcasting`,\n )\n await new Promise<void>(resolve => setTimeout(resolve, hotspotBroadcastWaitMs))\n }\n address = await joinOnce(status.ssid, status.password)\n }\n if (subsystems.probeGateway) {\n report?.(`Phone is ${address ?? \"on the hotspot\"}; checking it can reach the glasses`)\n try {\n const probe = await subsystems.probeGateway()\n softapTrace(probe.reachable ? \"gateway_probe_ok\" : \"gateway_probe_failed\", {detail: probe.detail})\n report?.(\n probe.reachable\n ? `Phone ${address ?? \"\"} ↔ glasses OK (${probe.detail})`\n : `Phone ${address ?? \"\"} joined, but cannot reach the glasses: ${probe.detail}`,\n )\n } catch (error) {\n softapTraceFailure(\"gateway_probe_threw\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n }\n }\n return address\n },\n leaveScopedNetwork: () => subsystems.leaveScopedNetwork(),\n cancelScopedNetworkJoin: subsystems.cancelScopedNetworkJoin,\n joinMeeting: async ({ssid, passphrase, bindAddress}, report) => {\n // The hotspot join just took this phone off Wi-Fi, so the route Teams needs is whatever\n // Android promoted in its place. Waiting for it to validate is what stopped the ACS join\n // from burning its whole timeout on DNS that could not resolve yet.\n if (subsystems.awaitValidatedDefaultNetwork) {\n report?.(\"Waiting for this phone's mobile data to take over so Teams can connect\")\n try {\n const network = await subsystems.awaitValidatedDefaultNetwork()\n if (network) {\n softapTrace(network.usable ? \"default_network_ok\" : \"default_network_unvalidated\", {\n detail: network.detail,\n })\n report?.(\n network.usable\n ? `Internet is on ${network.detail}`\n : `Internet is not confirmed yet (${network.detail}); joining Teams anyway`,\n )\n }\n } catch (error) {\n softapTraceFailure(\"default_network_check_threw\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n }\n }\n report?.(\"Binding the video receiver and joining Teams over cellular\")\n await subsystems.joinMeeting(packageName, {\n meetingUrl: args.meetingUrl,\n token: args.token,\n videoSource: {type: \"softap\", ssid, passphrase, bindAddress},\n displayName: args.displayName,\n })\n // The listener binds during the join, so the URL only exists now.\n return {ingestUrl: subsystems.ingestUrl() ?? \"\"}\n },\n leaveMeeting: () => subsystems.leaveMeeting(packageName),\n ...(subsystems.endMeeting ? {endMeeting: () => subsystems.endMeeting!(packageName)} : {}),\n startPublishing: async ({ingestUrl, traceId}, report) => {\n // Narrate the glasses side while the BLE start command is in flight. `initializing` means\n // the glasses accepted the command and are opening the camera; `streaming` means the WHIP\n // offer was answered and ICE connected; anything else is the reason it did not.\n const unsubscribe = subsystems.onGlassesStreamStatus?.((event) => {\n if (event.status === \"initializing\") {\n report?.(\"Glasses accepted the command: camera starting, gathering ICE, posting offer to the phone\")\n } else if (event.status === \"streaming\") {\n report?.(\"Glasses are streaming to the phone\")\n } else if (event.status === \"error\") {\n report?.(`Glasses reported: ${event.error ?? event.reason ?? \"stream error\"}`)\n } else if (event.status === \"reconnecting\") {\n report?.(`Glasses reconnecting: ${event.reason ?? \"\"}`)\n }\n })\n // Decided before the command goes out, never after: the glasses cannot drop an audio track\n // they already negotiated, and two live copies of the wearer's voice in one call is worse\n // than either one alone.\n const lc3Uplink = subsystems.glassesLc3Uplink?.() ?? false\n softapTrace(\"publish_audio_decision\", {captureAudio: !lc3Uplink, micTransport: lc3Uplink ? \"ble-lc3\" : \"whip\"})\n report?.(\n lc3Uplink\n ? \"Publishing video only; the wearer's voice comes over Bluetooth LC3\"\n : \"Publishing video and the glasses microphone\",\n )\n try {\n await subsystems.startPublishing(packageName, {\n streamUrl: ingestUrl,\n // Empty STUN server means host-only: there is no route from the hotspot to a STUN server,\n // so a configured one would add doomed gathering to every call.\n ice: {stun: \"\"},\n traceId,\n captureAudio: !lc3Uplink,\n })\n } finally {\n unsubscribe?.()\n }\n },\n stopPublishing: () => subsystems.stopPublishing(packageName),\n awaitFirstFrame: args.awaitFirstFrame,\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"SoftapCallTransport.js","sourceRoot":"","sources":["../../src/services/SoftapCallTransport.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Sequences a SoftAP call. Sequencing only — no sockets, no peers, no BLE.\n *\n * The glasses open a hotspot, the phone joins it without giving up its cellular route, and the\n * glasses publish WebRTC straight to a listener on the phone. Cloudflare is not involved at all.\n *\n * The order below is the whole point of this file, and one step in it is load-bearing:\n *\n * hotspot on -> scoped join -> ACS join (binds the listener and arms the raw outputs)\n * -> glasses publish -> WHIP negotiation -> first frame -> LIVE\n *\n * Publishing must come after the ACS join, not before. `LIVE` means a frame reached ACS, so if the\n * glasses start publishing first, decoded video and audio can arrive before the raw outgoing\n * streams exist and the first frames are dropped by whatever happens to be null at the time. That\n * is not a lifecycle anyone designed; making the order explicit is what removes it.\n *\n * Ownership is deliberately narrow. This object owns the *sequence* and nothing else: the meeting\n * session owns the WHIP listener and the peer, `PhoneStreamCoordinator` owns the publisher, and\n * `localNetworkTransport` owns the scoped network. Every step therefore has exactly one owner that\n * can tear it down, which is what makes leaving mid-join safe.\n */\n\nimport {softapTrace, softapTraceFailure, beginSoftapTrace, resetSoftapTrace} from \"../utils/softapTrace\"\n\n/** Steps in order. Also the teardown order, reversed. */\nexport const SOFTAP_STEPS = [\"hotspot\", \"scopedJoin\", \"acsJoin\", \"publish\", \"live\"] as const\n\nexport type SoftapStep = (typeof SOFTAP_STEPS)[number]\n\n/**\n * Where the sequence is.\n *\n * `starting` covers every step up to `live` because the caller's only useful distinction is\n * \"not yet usable\" versus \"carrying media\"; the step names are for diagnostics, not for branching.\n */\nexport type SoftapPhase = \"idle\" | \"starting\" | \"live\" | \"stopping\" | \"failed\"\n\n/** A failure, named by the step that produced it so the UI and the logs agree on the cause. */\nexport class SoftapCallError extends Error {\n constructor(readonly step: SoftapStep, readonly code: string, message: string, readonly cause?: unknown) {\n super(message)\n this.name = \"SoftapCallError\"\n }\n}\n\n/** Gallery sync already learned this: glasses report enabled before the SSID is in the phone scan. */\nexport const HOTSPOT_BROADCAST_WAIT_MS = 3_000\n\n/**\n * What the glasses→phone hop is worth at 540p over a hotspot with one client and no contention.\n *\n * Not the ACS ceiling: this link is a metre of air between two devices that are already paired,\n * and the profile's `maxBitrateBps` describes the phone→Teams hop, which crosses the internet.\n * Sharing one number between them makes the easy hop obey the hard hop's limits.\n */\nexport const GLASSES_PHONE_BITRATE_BPS = 2_500_000\n\n/** Where the encoder starts. High, because the link is good from the first frame. */\nconst SOFTAP_START_BITRATE_BPS = 2_000_000\n\n/**\n * The floor. This is the whole point of the policy.\n *\n * WHIP's default has none, so after an ICE interruption WebRTC restarts at its own minimum and\n * climbs by probing — which is the \"potato for a while\" the wearer reports. The link did not get\n * worse; the estimator merely forgot what it knew. A floor says: this hop is a hotspot, not a\n * congested uplink, and it is never worth less than this.\n *\n * That trade is the opposite of Mentra-Call#27's cloud-WHIP review: a 1 Mbps floor on Auto over\n * LTE turns a weak WAN into freezes. This function is SoftAP-only. Cloud WHIP must not call it.\n */\nconst SOFTAP_MIN_BITRATE_BPS = 1_200_000\n\n/** Field names are the glasses' `WhipStreamConfig` parser's, where `bitrate` means the maximum. */\nexport interface SoftapVideoPolicy {\n width: number\n height: number\n fps: number\n bitrate: number\n initialBitrateBps: number\n minBitrateBps: number\n}\n\n/**\n * The bitrate the glasses are told to hold on the hop to the phone.\n *\n * The hotspot has its own bitrate budget, independent of the phone-to-Teams cap. Above 540p,\n * allow a higher requested ceiling while retaining the hotspot budget for low WAN caps.\n */\nexport function softapVideoPolicy(video: {\n width: number\n height: number\n fps: number\n maxBitrateBps: number\n}): SoftapVideoPolicy {\n const isSmall = video.width * video.height <= 960 * 540\n if (!Number.isFinite(video.maxBitrateBps) || video.maxBitrateBps <= 0) {\n throw new Error(`invalid SoftAP video bitrate: ${video.maxBitrateBps}`)\n }\n const max = isSmall ? GLASSES_PHONE_BITRATE_BPS : Math.max(GLASSES_PHONE_BITRATE_BPS, video.maxBitrateBps)\n const initialBitrateBps = Math.min(SOFTAP_START_BITRATE_BPS, max)\n const minBitrateBps = Math.min(SOFTAP_MIN_BITRATE_BPS, initialBitrateBps)\n if (!(minBitrateBps <= initialBitrateBps && initialBitrateBps <= max)) {\n throw new Error(`incoherent SoftAP video policy: min=${minBitrateBps} start=${initialBitrateBps} max=${max}`)\n }\n return {\n width: video.width,\n height: video.height,\n fps: video.fps,\n bitrate: max,\n initialBitrateBps,\n minBitrateBps,\n }\n}\n\n/**\n * Android's WifiNetworkSpecifier called onUnavailable. The native message lists three causes\n * because the callback does not say which one happened; on the 18:02 Samsung path the SSID was\n * in scan and the join sheet was bypassed — assoc rejected after leaving another AP.\n */\nfunction isScopedJoinUnavailable(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error)\n return /SOFTAP_UNAVAILABLE|ScopedNetworkError\\$Unavailable|SSID not in scan, Wi-Fi off, or the system join prompt/i.test(\n message,\n )\n}\n\nexport type SoftapStepStatus = \"pending\" | \"running\" | \"done\" | \"failed\"\n\n/**\n * One step as the UI should show it. `detail` is the fact the step produced (SSID, phone address,\n * ingest URL, what the glasses last reported); `error` is set only on `failed`.\n */\nexport interface SoftapStepState {\n step: SoftapStep\n status: SoftapStepStatus\n detail?: string\n error?: string\n /** Wall-clock ms the step took; present once it is done or failed. */\n durationMs?: number\n}\n\n/**\n * Whole-sequence snapshot, re-sent on every transition so a consumer that missed one still holds\n * the truth. This is what the miniapp renders as its join checklist.\n */\nexport interface SoftapProgress {\n traceId: string\n phase: SoftapPhase\n steps: SoftapStepState[]\n /** ms since `start()` was called. */\n elapsedMs: number\n}\n\n/** Sub-status callback a step can use to narrate what it is doing while it runs. */\nexport type SoftapStepReporter = (detail: string) => void\n\nexport interface SoftapCallDeps {\n /**\n * Is this phone's Wi-Fi radio on? Asked before anything is built.\n *\n * The station radio is what reaches the glasses, and no app can turn it on since Android 10.\n * Finding out at `scopedJoin` means the glasses already raised a hotspot for a join that cannot\n * happen, so the wearer pays a teardown for a condition that was knowable up front. Optional:\n * a host that cannot answer skips the preflight and relies on the native throw at `scopedJoin`.\n */\n isWifiEnabled?(): Promise<boolean>\n /** Enable the glasses hotspot and return its credentials. */\n startHotspot(report?: SoftapStepReporter): Promise<{ssid: string; passphrase: string}>\n /**\n * Wait until the phone can actually see the AP. `setHotspotState` resolves when the glasses\n * accept the command, not when `ap0` is beaconing. A WifiNetworkSpecifier issued too early\n * comes back `Unavailable` in well under a second — it does not keep scanning for the timeout.\n */\n waitUntilHotspotJoinable?(report?: SoftapStepReporter): Promise<void>\n /** Disable it. Must tolerate being called when it was never enabled. */\n stopHotspot(): Promise<void>\n /** Join the hotspot without taking the phone's default route. Resolves to the phone's own IPv4. */\n joinScopedNetwork(ssid: string, passphrase: string, report?: SoftapStepReporter): Promise<string | undefined>\n leaveScopedNetwork(): Promise<void>\n /** Interrupt a pending native join while retaining its cleanup barrier. Unsupported hosts wait. */\n cancelScopedNetworkJoin?(): Promise<void>\n /**\n * Join the meeting. This is what binds the local WHIP listener and arms the ACS raw outputs, so\n * it must resolve before the glasses are told to publish.\n *\n * @returns the URL the glasses must POST their offer to\n */\n joinMeeting(\n args: {ssid: string; passphrase: string; bindAddress?: string},\n report?: SoftapStepReporter,\n ): Promise<{ingestUrl: string}>\n leaveMeeting(): Promise<void>\n /**\n * End the meeting for everyone instead of leaving it. Optional: a host that cannot do this still\n * tears down correctly, it just cannot honour `stop({mode: \"end\"})`.\n */\n endMeeting?(): Promise<void>\n /** Tell the glasses to publish to [ingestUrl] in host-only ICE mode. */\n startPublishing(args: {ingestUrl: string; traceId: string}, report?: SoftapStepReporter): Promise<void>\n stopPublishing(): Promise<void>\n /**\n * Resolves when a frame has reached ACS, rejects if the feed failed or the deadline passed.\n * Separate from [joinMeeting] because an answered negotiation is not a working call: a session\n * that never delivers a frame reads as healthy behind a frozen tile.\n */\n awaitFirstFrame(report?: SoftapStepReporter): Promise<void>\n}\n\nexport interface SoftapCallOptions {\n /** Override the minted trace id, so a caller can correlate with logs it already started. */\n traceId?: string\n /**\n * Receives a fresh snapshot on every transition: step begins, step narrates, step ends, sequence\n * ends. Exceptions thrown here are swallowed — a broken listener must not fail the call.\n */\n onProgress?: (progress: SoftapProgress) => void\n /**\n * Narration the caller already showed before the sequence existed — signing in to Teams, asking\n * for a permission. Without it the first `emitProgress` would blank the checklist the wearer is\n * already reading. Only `detail` is taken: the caller reports what it did, it does not get to\n * claim a step ran.\n */\n initialSteps?: SoftapStepState[]\n}\n\nfunction freshSteps(): SoftapStepState[] {\n return SOFTAP_STEPS.map((step) => ({step, status: \"pending\"}))\n}\n\n/** See {@link SoftapCallOptions.initialSteps}. */\nfunction seededSteps(initial: SoftapStepState[] | undefined): SoftapStepState[] {\n if (!initial?.length) return freshSteps()\n return freshSteps().map((step) => {\n const seed = initial.find((entry) => entry.step === step.step)\n return seed?.detail ? {...step, detail: seed.detail} : step\n })\n}\n\n/** A promise plus the function that settles it. */\nfunction deferred(): {promise: Promise<void>; resolve: () => void} {\n let resolve!: () => void\n const promise = new Promise<void>((settle) => {\n resolve = settle\n })\n return {promise, resolve}\n}\n\n/**\n * How a call is being taken down.\n *\n * `leave` takes this device out; `end` terminates the group call for everyone first. Everything\n * after that step is identical, which is the point: End is not a second teardown path, it is one\n * different verb at one step of the same one.\n */\nexport type SoftapTeardownMode = \"leave\" | \"end\"\n\nexport interface SoftapStopOptions {\n mode?: SoftapTeardownMode\n keepProgress?: boolean\n}\n\nexport class SoftapEndNotSupportedError extends Error {\n constructor() {\n super(\"This host cannot end a meeting for everyone\")\n this.name = \"SoftapEndNotSupportedError\"\n }\n}\n\nexport class SoftapCallTransport {\n private phase: SoftapPhase = \"idle\"\n /**\n * Steps completed and not yet undone, in the order they succeeded. Teardown walks this\n * backwards, so a failure halfway through unwinds exactly what was built and nothing else.\n */\n private completed: SoftapStep[] = []\n /**\n * Bumped by every start and stop. A step that resolves after the caller has moved on must not\n * write to the new attempt's state, which is the leave-during-join race.\n */\n private generation = 0\n private stopping: Promise<void> | null = null\n /**\n * The step currently in flight, and a promise that settles only after its body *and* the undo it\n * runs when it finds itself cancelled are both finished.\n *\n * This is what [stop] waits on. A step that resolves late still owns a resource — a hotspot that\n * came up after the wearer left — and its release happens inside the step, out of the teardown's\n * sight. Without this wait, `stop()` resolves while that release is still pending and the next\n * call brings a hotspot up straight into it.\n */\n private running: {step: SoftapStep; settled: Promise<void>} | null = null\n /** True once [start] has been called at least once, so [stop] can tell \"cancelled\" from \"reusable\". */\n private startedEver = false\n /**\n * A [stop] that landed before the sequence ever began.\n *\n * There is nothing to unwind in that case, so the flag is the only thing that can carry the\n * cancellation forward: a `start()` arriving afterwards belongs to the attempt that was just\n * cancelled and must refuse rather than build a call nobody is waiting for.\n */\n private cancelledBeforeStart = false\n /** Failed undos for this attempt, retained across repeated stops. See [lastTeardownFailures]. */\n private teardownFailures: SoftapStep[] = []\n /**\n * Raised the instant a teardown is decided, before any resource is touched.\n *\n * Everything that watches the call for failure — a lost hotspot above all — has to be able to ask\n * \"was this supposed to happen?\". Without the flag, releasing the scoped network during a\n * successful Leave looks exactly like the glasses walking out of range, and the wearer gets an\n * error screen for a call that ended the way they asked.\n */\n private terminating = false\n /** How this teardown ends the meeting. Read by the `acsJoin` undo. */\n private teardownMode: SoftapTeardownMode = \"leave\"\n /** Set when `stop({mode: \"end\"})` could not end for everyone. The caller must not claim it did. */\n private endFailure: unknown = null\n private hotspot: {ssid: string; passphrase: string} | null = null\n private ingestUrl: string | null = null\n private steps: SoftapStepState[] = freshSteps()\n private stepStartedAt = new Map<SoftapStep, number>()\n private startedAt = 0\n private traceId = \"\"\n private onProgress: ((progress: SoftapProgress) => void) | undefined\n\n constructor(private readonly deps: SoftapCallDeps) {}\n\n currentPhase(): SoftapPhase {\n return this.phase\n }\n\n /**\n * True once a teardown has been decided. Anything that would otherwise report a failure — a lost\n * hotspot, a dropped ACS call — must check this first: after the wearer asks to leave, those are\n * the sound of it working.\n */\n isTerminating(): boolean {\n return this.terminating\n }\n\n /** What the UI should show right now. Safe to call in any phase. */\n progress(): SoftapProgress {\n return {\n traceId: this.traceId,\n phase: this.phase,\n steps: this.steps.map((step) => ({...step})),\n elapsedMs: this.startedAt ? Date.now() - this.startedAt : 0,\n }\n }\n\n private emitProgress(): void {\n const listener = this.onProgress\n if (!listener) return\n try {\n listener(this.progress())\n } catch (error) {\n softapTraceFailure(\"softap_progress_listener_threw\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n }\n }\n\n private setStep(step: SoftapStep, patch: Partial<SoftapStepState>): void {\n this.steps = this.steps.map((entry) => (entry.step === step ? {...entry, ...patch} : entry))\n this.emitProgress()\n }\n\n /** Narration for a running step: what the phone or the glasses just reported. */\n private note(generation: number, step: SoftapStep, detail: string): void {\n if (generation !== this.generation) {\n // A step that is still narrating after the sequence moved on. The detail is dropped rather\n // than written onto the new attempt's checklist, and the drop is said out loud because a\n // step that goes quiet here is usually one that is still holding a native call open.\n softapTrace(\"softap_step_note_dropped\", {step, generation, current: this.generation, detail})\n return\n }\n softapTrace(\"softap_step_note\", {step, detail})\n this.setStep(step, {detail})\n }\n\n /** Steps currently built up, oldest first. Empty when nothing needs tearing down. */\n activeSteps(): SoftapStep[] {\n return [...this.completed]\n }\n\n /** The URL handed to the glasses, for diagnostics. Null outside a live attempt. */\n currentIngestUrl(): string | null {\n return this.ingestUrl\n }\n\n /**\n * Steps whose undo threw during the last teardown, so the caller can refuse the next call.\n *\n * Teardown deliberately swallows these to keep unwinding — but a hotspot that would not turn off\n * is exactly the state the next call cannot be built on, and starting anyway is what produced\n * \"Cannot start glasses hotspot\" followed by a scoped join that never found the SSID.\n */\n lastTeardownFailures(): SoftapStep[] {\n // Logged on read rather than only on write, because this is the moment the list turns into a\n // refusal for the next call: a wearer told to power-cycle the hotspot needs the reason to be\n // findable, and the write happened somewhere in the middle of a noisy teardown.\n if (this.teardownFailures.length > 0) {\n softapTraceFailure(\"softap_teardown_failures_read\", {steps: this.teardownFailures.join(\",\")})\n }\n return [...this.teardownFailures]\n }\n\n /**\n * Refuse the call while the Wi-Fi radio is off, before the glasses are asked for anything.\n *\n * Ordered ahead of the hotspot step rather than folded into `scopedJoin` because the cost of\n * learning late is paid by the glasses: a hotspot raised, a teardown, and a wearer watching a\n * checklist fail at step 2 for a toggle on their own phone. The native join keeps its own throw\n * for the radio that goes off in between — this is the explainable path, that one is the racy\n * backstop.\n *\n * A probe that throws is treated as \"unknown, carry on\": an unanswerable question about the\n * radio must not be the thing that stops a call the radio would have carried.\n */\n private async preflightWifi(): Promise<void> {\n if (!this.deps.isWifiEnabled) return\n let enabled: boolean\n try {\n enabled = await this.deps.isWifiEnabled()\n } catch (error) {\n softapTraceFailure(\"softap_wifi_preflight_unknown\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n return\n }\n softapTrace(\"softap_wifi_preflight\", {enabled})\n if (enabled) return\n this.setStep(\"hotspot\", {status: \"failed\", error: \"This phone's Wi-Fi is off\"})\n this.emitProgress()\n // Code in the message as well as on the error: the miniapp classifies on the message today\n // (the structured code only arrives on the join rejection), and every other SoftAP failure\n // carries its code the same way.\n throw new SoftapCallError(\n \"hotspot\",\n \"SOFTAP_WIFI_DISABLED\",\n \"SOFTAP_WIFI_DISABLED: this phone's Wi-Fi is off, so it cannot reach the glasses.\",\n )\n }\n\n /**\n * Runs the sequence. On any failure the partial sequence is torn down before the error is\n * rethrown, so a failed start never leaves a hotspot up or a publisher running.\n */\n async start(options: SoftapCallOptions = {}): Promise<void> {\n if (this.cancelledBeforeStart) {\n // The wearer's Cancel landed before the sequence began, so there is no step to name and no\n // trace id yet. This line is the only evidence that the flag did its job rather than the\n // join having silently never been asked for.\n softapTraceFailure(\"softap_call_refused\", {reason: \"cancelled before start\"})\n throw new SoftapCallError(\"hotspot\", \"CANCELLED\", \"SoftAP call was cancelled before it started\")\n }\n if (this.phase !== \"idle\" && this.phase !== \"failed\") {\n softapTraceFailure(\"softap_call_refused\", {reason: \"already active\", phase: this.phase})\n throw new SoftapCallError(\"hotspot\", \"ALREADY_ACTIVE\", `A SoftAP call is already ${this.phase}`)\n }\n this.startedEver = true\n const generation = ++this.generation\n this.phase = \"starting\"\n this.terminating = false\n this.teardownMode = \"leave\"\n this.endFailure = null\n this.completed = []\n this.ingestUrl = null\n this.hotspot = null\n this.teardownFailures = []\n this.steps = seededSteps(options.initialSteps)\n this.stepStartedAt.clear()\n this.startedAt = Date.now()\n this.onProgress = options.onProgress\n const traceId = beginSoftapTrace(options.traceId)\n this.traceId = traceId\n softapTrace(\"softap_call_start\", {traceId})\n this.emitProgress()\n\n try {\n await this.preflightWifi()\n\n await this.step(generation, \"hotspot\", \"HOTSPOT_FAILED\", async (report) => {\n report(\"Asking the glasses to turn on their hotspot\")\n const hotspot = await this.deps.startHotspot(report)\n if (!hotspot.ssid) {\n throw new Error(\"the glasses reported no hotspot SSID\")\n }\n this.hotspot = hotspot\n // The passphrase never reaches the log; softapTrace redacts it by key, and only the SSID\n // is useful for matching against the phone's Wi-Fi state anyway.\n softapTrace(\"hotspot_enabled\", {ssid: hotspot.ssid})\n report(`Hotspot ${hotspot.ssid} is on; waiting for it to broadcast`)\n await this.deps.waitUntilHotspotJoinable?.(report)\n softapTrace(\"hotspot_broadcast_wait_done\", {ssid: hotspot.ssid})\n report(`Hotspot ${hotspot.ssid}`)\n })\n\n const hotspot = this.requireHotspot()\n let bindAddress: string | undefined\n await this.step(generation, \"scopedJoin\", \"SCOPED_JOIN_FAILED\", async (report) => {\n report(`Phone joining ${hotspot.ssid}. Turn Wi-Fi on if a panel opens — Teams stays on cellular.`)\n bindAddress = await this.deps.joinScopedNetwork(hotspot.ssid, hotspot.passphrase, report)\n softapTrace(\"scoped_network_joined\", {bindAddress: bindAddress ?? \"unknown\"})\n if (bindAddress) report(`Phone is ${bindAddress} on ${hotspot.ssid}`)\n })\n\n await this.step(generation, \"acsJoin\", \"ACS_JOIN_FAILED\", async (report) => {\n report(bindAddress ? `Opening video receiver on ${bindAddress}, then joining Teams` : \"Joining Teams\")\n const {ingestUrl} = await this.deps.joinMeeting(\n {\n ssid: hotspot.ssid,\n passphrase: hotspot.passphrase,\n bindAddress,\n },\n report,\n )\n if (!ingestUrl) {\n // Without a bound listener there is nowhere for the glasses to publish, and telling them\n // to publish anyway produces a failure several seconds later on the wrong device.\n throw new Error(\"the meeting reported no ingest URL\")\n }\n this.ingestUrl = ingestUrl\n softapTrace(\"acs_receiver_ready\", {ingestUrl})\n report(`Receiver ready at ${ingestUrl}`)\n })\n\n const ingestUrl = this.requireIngestUrl()\n await this.step(generation, \"publish\", \"PUBLISH_FAILED\", async (report) => {\n report(\"Telling the glasses to start the camera and publish to the phone\")\n await this.deps.startPublishing({ingestUrl, traceId}, report)\n softapTrace(\"glasses_publishing\", {ingestUrl})\n report(\"Glasses camera is streaming to the phone\")\n })\n\n await this.step(generation, \"live\", \"NO_FIRST_FRAME\", async (report) => {\n report(\"Waiting for the first glasses video frame on this phone\")\n await this.deps.awaitFirstFrame(report)\n softapTrace(\"first_glasses_frame_received\")\n report(\"Glasses video is reaching this phone\")\n })\n\n if (generation !== this.generation) {\n // Every step succeeded and the call is nevertheless not this transport's any more. The\n // steps released themselves on the way past, so there is nothing to undo — but a join\n // that got all the way to a frame and then vanished is otherwise a log that simply stops.\n softapTraceFailure(\"softap_call_abandoned_at_live\", {generation, current: this.generation})\n return\n }\n this.phase = \"live\"\n softapTrace(\"softap_call_live\")\n this.emitProgress()\n } catch (error) {\n // Unwind before rethrowing. A caller that sees a rejection is entitled to assume nothing was\n // left running, and a hotspot left up is both a battery cost and a second call's failure.\n await this.stop({keepProgress: true})\n this.phase = \"failed\"\n this.emitProgress()\n throw error\n }\n }\n\n /**\n * Tears down in exact reverse order, and only what was built.\n *\n * Every step is attempted even if an earlier one throws: a failure to stop the publisher must\n * not leave the hotspot on. Concurrent calls share one teardown rather than racing each other\n * through the same resources, and a second `stop()` after one finished is a no-op — this is the\n * only SoftAP exit, so every terminal path can call it without checking whether another already\n * did.\n *\n * `mode: \"end\"` swaps the meeting verb and nothing else. If ending for everyone fails, the rest of\n * the teardown still runs and the failure is rethrown at the end, so the caller can tell the\n * wearer they left a meeting that may still be live rather than inventing a clean end.\n */\n async stop(options: SoftapStopOptions = {}): Promise<void> {\n // Intent before action, always: a watcher must be able to tell a deliberate teardown from a\n // failure even during the very first await below.\n this.terminating = true\n if (options.mode) this.teardownMode = options.mode\n if (this.stopping) {\n softapTrace(\"softap_stop_joined_in_flight\", {mode: this.teardownMode})\n return this.stopping\n }\n const running = this.running\n if (this.completed.length === 0 && this.phase === \"idle\" && !running) {\n // Nothing was built, so there is nothing to unwind — but a start() that has not run yet\n // still has to be refused, and a generation bump still has to invalidate anything holding\n // the old one.\n this.generation++\n if (!this.startedEver) this.cancelledBeforeStart = true\n softapTrace(\"softap_stop_nothing_built\", {\n // The distinction the next `start()` turns on: a transport that was never started refuses\n // outright, one that has already run is reusable.\n cancelledBeforeStart: this.cancelledBeforeStart,\n generation: this.generation,\n })\n return\n }\n\n this.generation++\n this.phase = \"stopping\"\n this.endFailure = null\n softapTrace(\"softap_call_stop\", {steps: this.completed.join(\",\"), mode: this.teardownMode})\n this.emitProgress()\n\n this.stopping = (async () => {\n // The generation bump above has already told the in-flight step to release whatever it\n // produced. Waiting for that release is what makes a resolved `stop()` mean \"nothing from\n // this call is still coming\". Deliberately unbounded: a native call that never returns must\n // hold the next call back, never let it race this one's cleanup.\n if (running) {\n const cancellation =\n running.step === \"scopedJoin\" && this.deps.cancelScopedNetworkJoin\n ? Promise.resolve()\n .then(() => this.deps.cancelScopedNetworkJoin!())\n .catch((error) => {\n if (!this.teardownFailures.includes(\"scopedJoin\")) this.teardownFailures.push(\"scopedJoin\")\n softapTraceFailure(\"softap_join_cancel_failed\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n })\n : undefined\n softapTrace(\"softap_stop_waiting_for_step\", {step: running.step})\n const waitStartedAt = Date.now()\n await running.settled\n await cancellation\n // This wait is unbounded by design, so its duration is the difference between \"the leave\n // was slow\" and \"the leave was held by a native call that had not returned\".\n softapTrace(\"softap_stop_step_settled\", {step: running.step, waitedMs: Date.now() - waitStartedAt})\n }\n // The late step may have recorded a failed self-undo while we waited. Preserve it,\n // and any earlier teardown result, until start() explicitly begins a new attempt.\n const failures: SoftapStep[] = [...this.teardownFailures]\n for (const step of [...this.completed].reverse()) {\n const undoStartedAt = Date.now()\n try {\n await this.undo(step)\n softapTrace(\"softap_step_undone\", {step, durationMs: Date.now() - undoStartedAt})\n } catch (error) {\n // Recorded, not rethrown: the remaining steps still have to be undone. The caller reads\n // them back through [lastTeardownFailures] and refuses the next call, because a hotspot\n // that would not turn off is exactly the state the next call cannot build on.\n failures.push(step)\n softapTraceFailure(\"softap_step_undo_failed\", {\n step,\n durationMs: Date.now() - undoStartedAt,\n reason: error instanceof Error ? error.message : String(error),\n })\n }\n }\n this.completed = []\n this.hotspot = null\n this.ingestUrl = null\n this.phase = \"idle\"\n this.teardownFailures = failures\n softapTrace(\"softap_call_stopped\", {undoFailures: failures.join(\",\")})\n resetSoftapTrace()\n // A failed start keeps its checklist so the UI can show which step broke; a deliberate\n // leave wipes it, because there is nothing left to explain.\n if (!options.keepProgress) {\n this.steps = freshSteps()\n this.emitProgress()\n }\n })()\n\n try {\n await this.stopping\n } finally {\n this.stopping = null\n }\n // Rethrown last, after every resource is released. An End that could not terminate the meeting\n // has still taken this device out; only the claim about the others is wrong.\n const endFailure = this.endFailure\n this.endFailure = null\n if (endFailure) throw endFailure\n }\n\n private async undo(step: SoftapStep): Promise<void> {\n switch (step) {\n // `live` is an observation, not a resource — there is nothing to release.\n case \"live\":\n return\n case \"publish\":\n return this.deps.stopPublishing()\n case \"acsJoin\":\n return this.leaveOrEndMeeting()\n case \"scopedJoin\":\n return this.deps.leaveScopedNetwork()\n case \"hotspot\":\n return this.deps.stopHotspot()\n }\n }\n\n /**\n * The one step End changes.\n *\n * A failed End falls back to leaving, so the wearer is out either way, and the original failure is\n * kept for [stop] to rethrow. Recording it rather than throwing here is what keeps the hotspot\n * teardown — the steps after this one — unconditional.\n */\n private async leaveOrEndMeeting(): Promise<void> {\n if (this.teardownMode !== \"end\") return this.deps.leaveMeeting()\n const endMeeting = this.deps.endMeeting\n if (!endMeeting) {\n this.endFailure = new SoftapEndNotSupportedError()\n return this.deps.leaveMeeting()\n }\n try {\n await endMeeting()\n softapTrace(\"softap_meeting_ended_for_everyone\")\n } catch (error) {\n this.endFailure = error\n softapTraceFailure(\"softap_end_for_everyone_failed\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n // Native ends the local call even when the hang-up is refused, so this is a belt-and-braces\n // leave rather than a second teardown: it must not resurrect the failure it is covering for.\n await this.deps.leaveMeeting().catch(() => undefined)\n }\n }\n\n /**\n * Runs one step, records it as undoable, and maps any throw to a [SoftapCallError] naming the\n * step. The generation check is what makes leaving mid-step safe: a step that resolves after the\n * caller gave up is not recorded, so teardown does not try to undo it twice.\n */\n private async step(\n generation: number,\n step: SoftapStep,\n code: string,\n run: (report: SoftapStepReporter) => Promise<void>,\n ): Promise<void> {\n if (generation !== this.generation) {\n // The sequence stopped between two steps. Named here because the caller only ever sees one\n // CANCELLED error, and which step it never reached is the thing worth knowing.\n softapTraceFailure(\"softap_step_skipped_after_cancel\", {step, generation, current: this.generation})\n throw new SoftapCallError(step, \"CANCELLED\", `SoftAP call was cancelled before ${step}`)\n }\n // Published before the first await so a `stop()` on the very next tick can see it. Settled in\n // the `finally`, after any self-undo, so waiting on it means the step owns nothing any more.\n const settle = deferred()\n this.running = {step, settled: settle.promise}\n try {\n await this.runStep(generation, step, code, run)\n } finally {\n if (this.running?.settled === settle.promise) this.running = null\n settle.resolve()\n }\n }\n\n /** The step body itself. Split out so [step] can publish and settle {@link running} around it. */\n private async runStep(\n generation: number,\n step: SoftapStep,\n code: string,\n run: (report: SoftapStepReporter) => Promise<void>,\n ): Promise<void> {\n softapTrace(\"softap_step_begin\", {step})\n const startedAt = Date.now()\n this.stepStartedAt.set(step, startedAt)\n this.setStep(step, {status: \"running\", error: undefined})\n const report: SoftapStepReporter = (detail) => this.note(generation, step, detail)\n try {\n await run(report)\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error)\n softapTraceFailure(\"softap_step_failed\", {step, code, reason})\n if (generation === this.generation) {\n this.setStep(step, {status: \"failed\", error: reason, durationMs: Date.now() - startedAt})\n }\n throw new SoftapCallError(step, code, error instanceof Error ? error.message : `${step} failed`, error)\n }\n if (generation !== this.generation) {\n // The step succeeded after the caller gave up. Release it here rather than recording it for\n // the teardown to find: that teardown may already have walked past this step, or finished\n // altogether, in which case nothing else ever would. This is the leak the generation guard\n // exists to close — a meeting joined a few milliseconds after the user left.\n softapTrace(\"softap_step_completed_after_cancel\", {step})\n await this.undoSafely(step)\n throw new SoftapCallError(step, \"CANCELLED\", `SoftAP call was cancelled during ${step}`)\n }\n this.completed.push(step)\n softapTrace(\"softap_step_done\", {step, durationMs: Date.now() - startedAt})\n this.setStep(step, {status: \"done\", durationMs: Date.now() - startedAt})\n }\n\n /** Undo that reports rather than throws, for the cancellation path where there is no caller. */\n private async undoSafely(step: SoftapStep): Promise<void> {\n try {\n await this.undo(step)\n } catch (error) {\n if (!this.teardownFailures.includes(step)) this.teardownFailures.push(step)\n softapTraceFailure(\"softap_step_undo_failed\", {\n step,\n reason: error instanceof Error ? error.message : String(error),\n })\n }\n }\n\n private requireHotspot(): {ssid: string; passphrase: string} {\n const hotspot = this.hotspot\n if (!hotspot) throw new SoftapCallError(\"hotspot\", \"HOTSPOT_FAILED\", \"no hotspot credentials\")\n return hotspot\n }\n\n private requireIngestUrl(): string {\n const url = this.ingestUrl\n if (!url) throw new SoftapCallError(\"acsJoin\", \"ACS_JOIN_FAILED\", \"no ingest URL\")\n return url\n }\n}\n\n/**\n * Binds the sequence to the real subsystems.\n *\n * Kept separate from the class so the ordering above is tested against fakes rather than against\n * BLE and ACS. The only logic here is adapting shapes; anything that needs a decision belongs in\n * the class.\n *\n * @param packageName the miniapp that owns the call\n * @param meeting the meeting to join, and how to observe its media health\n */\nexport function createSoftapCallDeps(args: {\n packageName: string\n meetingUrl: string\n token: string\n displayName?: string\n /**\n * The ACS outgoing profile. Used here only to size the glasses→phone hop; when absent the\n * glasses keep their WHIP defaults, which is what every pre-policy build did.\n */\n video?: {width: number; height: number; fps: number; maxBitrateBps: number}\n /** Resolves when the meeting reports a frame reached ACS; rejects on a failed feed. */\n awaitFirstFrame: () => Promise<void>\n subsystems: {\n setHotspotState: (enabled: boolean) => Promise<{state: string; ssid?: string; password?: string; localIp?: string}>\n /** Whether this phone's Wi-Fi radio is on. Optional: only Android hosts can answer it. */\n isWifiEnabled?: () => Promise<boolean>\n joinScopedNetwork: (ssid: string, passphrase: string, gateway?: string) => Promise<string | undefined>\n leaveScopedNetwork: () => Promise<void>\n cancelScopedNetworkJoin?: () => Promise<void>\n joinMeeting: (\n packageName: string,\n options: {\n meetingUrl: string\n token: string\n videoSource: {type: \"softap\"; ssid?: string; passphrase?: string; bindAddress?: string}\n displayName?: string\n },\n ) => Promise<unknown>\n leaveMeeting: (packageName: string) => Promise<void>\n /** Terminate the group call for everyone. Absent on hosts that cannot. */\n endMeeting?: (packageName: string) => Promise<void>\n ingestUrl: () => string | null\n startPublishing: (\n packageName: string,\n options: {\n streamUrl: string\n ice: {stun: string}\n traceId: string\n captureAudio?: boolean\n video?: SoftapVideoPolicy\n },\n ) => Promise<unknown>\n stopPublishing: (packageName: string) => Promise<void>\n /**\n * Whether the host is taking the wearer's voice off the glasses over BLE LC3 for this call.\n *\n * Asked after the meeting join and before the publish, because that is the only moment the\n * answer is both known (the host has seen the native's capabilities) and still actionable (the\n * glasses have not been told what to capture). True means the WHIP publish is video-only;\n * false means the glasses put their microphone on the WHIP track as they always have. Absent\n * on hosts that only have the WHIP audio path.\n */\n glassesLc3Uplink?: () => boolean\n /**\n * Prove the phone can reach the glasses over the hotspot it just joined. Optional because\n * only Android hosts have the scoped network handle; when present its verdict is narrated\n * into the scoped-join step and a failure is reported, not thrown — the glasses-to-phone\n * direction is what the call actually needs, and that is tested by the publish step.\n */\n probeGateway?: () => Promise<{reachable: boolean; detail: string}>\n /**\n * Wait for the phone's default network to be validated again after the hotspot join took Wi-Fi\n * away. Optional because only Android hosts can answer it.\n *\n * Not fatal when it reports an unusable network: the wearer is told, and the join is attempted\n * anyway. Aborting here would fail calls that recover a second later, and the ACS join has its\n * own bounded timeout for the case that does not.\n */\n awaitValidatedDefaultNetwork?: () => Promise<{usable: boolean; detail: string} | null>\n /**\n * Glasses `stream_status` events, so the publish step can say \"camera starting\" and \"offer\n * posted\" instead of going quiet for the whole BLE round trip. Returns an unsubscribe.\n */\n onGlassesStreamStatus?: (\n listener: (event: {status: string; streamId?: string; reason?: string; error?: string}) => void,\n ) => () => void\n }\n /** Override only in tests. Production waits the gallery-proven broadcast window. */\n hotspotBroadcastWaitMs?: number\n}): SoftapCallDeps {\n const {packageName, subsystems} = args\n const hotspotBroadcastWaitMs = args.hotspotBroadcastWaitMs ?? HOTSPOT_BROADCAST_WAIT_MS\n let gatewayAddress: string | undefined\n return {\n isWifiEnabled: subsystems.isWifiEnabled ? () => subsystems.isWifiEnabled!() : undefined,\n startHotspot: async (report) => {\n const enable = async () => {\n const status = await subsystems.setHotspotState(true)\n if (status.state !== \"enabled\" || !status.ssid) {\n throw new Error(`the glasses hotspot did not start (state=${status.state})`)\n }\n if (!status.password) {\n throw new Error(\"the glasses hotspot reported no password\")\n }\n report?.(`Glasses report hotspot ${status.ssid} enabled`)\n gatewayAddress = status.localIp\n return {ssid: status.ssid, passphrase: status.password}\n }\n try {\n return await enable()\n } catch (error) {\n if (error instanceof Error && /no password/.test(error.message)) throw error\n // Cancel-then-start races the previous disable: the glasses report disabled (or no SSID)\n // and the UI said \"Couldn't start glasses hotspot\" before step 2 ran on a leftover AP.\n softapTraceFailure(\"hotspot_enable_retry\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n report?.(\"Glasses hotspot did not start; turning it off and trying again\")\n await subsystems.setHotspotState(false)\n if (hotspotBroadcastWaitMs > 0) {\n await new Promise<void>((resolve) => setTimeout(resolve, Math.min(1_000, hotspotBroadcastWaitMs)))\n }\n return await enable()\n }\n },\n waitUntilHotspotJoinable: async (report) => {\n if (hotspotBroadcastWaitMs <= 0) return\n softapTrace(\"hotspot_broadcast_wait\", {ms: hotspotBroadcastWaitMs})\n report?.(`Giving the hotspot ${Math.round(hotspotBroadcastWaitMs / 1000)}s to start broadcasting`)\n await new Promise<void>((resolve) => setTimeout(resolve, hotspotBroadcastWaitMs))\n },\n stopHotspot: async () => {\n await subsystems.setHotspotState(false)\n },\n joinScopedNetwork: async (ssid, passphrase, report) => {\n const joinOnce = (nextSsid: string, nextPassphrase: string) =>\n gatewayAddress\n ? subsystems.joinScopedNetwork(nextSsid, nextPassphrase, gatewayAddress)\n : subsystems.joinScopedNetwork(nextSsid, nextPassphrase)\n let address: string | undefined\n try {\n address = await joinOnce(ssid, passphrase)\n } catch (error) {\n if (!isScopedJoinUnavailable(error)) throw error\n // First specifier left the phone's previous Wi-Fi and assoc-rejected the glasses AP.\n // Cycle the AP and join again from an idle STA — the radio is free now.\n softapTraceFailure(\"scoped_join_unavailable_retry\", {ssid})\n report?.(\"Phone couldn't join; cycling the glasses hotspot and trying again\")\n await subsystems.setHotspotState(false)\n const status = await subsystems.setHotspotState(true)\n if (status.state !== \"enabled\" || !status.ssid || !status.password) throw error\n gatewayAddress = status.localIp\n if (hotspotBroadcastWaitMs > 0) {\n report?.(`Giving the hotspot ${Math.round(hotspotBroadcastWaitMs / 1000)}s to start broadcasting`)\n await new Promise<void>((resolve) => setTimeout(resolve, hotspotBroadcastWaitMs))\n }\n address = await joinOnce(status.ssid, status.password)\n }\n if (subsystems.probeGateway) {\n report?.(`Phone is ${address ?? \"on the hotspot\"}; checking it can reach the glasses`)\n try {\n const probe = await subsystems.probeGateway()\n softapTrace(probe.reachable ? \"gateway_probe_ok\" : \"gateway_probe_failed\", {detail: probe.detail})\n report?.(\n probe.reachable\n ? `Phone ${address ?? \"\"} ↔ glasses OK (${probe.detail})`\n : `Phone ${address ?? \"\"} joined, but cannot reach the glasses: ${probe.detail}`,\n )\n } catch (error) {\n softapTraceFailure(\"gateway_probe_threw\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n }\n }\n return address\n },\n leaveScopedNetwork: () => subsystems.leaveScopedNetwork(),\n cancelScopedNetworkJoin: subsystems.cancelScopedNetworkJoin,\n joinMeeting: async ({ssid, passphrase, bindAddress}, report) => {\n // The hotspot join just took this phone off Wi-Fi, so the route Teams needs is whatever\n // Android promoted in its place. Waiting for it to validate is what stopped the ACS join\n // from burning its whole timeout on DNS that could not resolve yet.\n if (subsystems.awaitValidatedDefaultNetwork) {\n report?.(\"Waiting for this phone's mobile data to take over so Teams can connect\")\n try {\n const network = await subsystems.awaitValidatedDefaultNetwork()\n if (network) {\n softapTrace(network.usable ? \"default_network_ok\" : \"default_network_unvalidated\", {\n detail: network.detail,\n })\n report?.(\n network.usable\n ? `Internet is on ${network.detail}`\n : `Internet is not confirmed yet (${network.detail}); joining Teams anyway`,\n )\n }\n } catch (error) {\n softapTraceFailure(\"default_network_check_threw\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n }\n }\n report?.(\"Binding the video receiver and joining Teams over cellular\")\n await subsystems.joinMeeting(packageName, {\n meetingUrl: args.meetingUrl,\n token: args.token,\n videoSource: {type: \"softap\", ssid, passphrase, bindAddress},\n displayName: args.displayName,\n })\n // The listener binds during the join, so the URL only exists now.\n return {ingestUrl: subsystems.ingestUrl() ?? \"\"}\n },\n leaveMeeting: () => subsystems.leaveMeeting(packageName),\n ...(subsystems.endMeeting ? {endMeeting: () => subsystems.endMeeting!(packageName)} : {}),\n startPublishing: async ({ingestUrl, traceId}, report) => {\n // Narrate the glasses side while the BLE start command is in flight. `initializing` means\n // the glasses accepted the command and are opening the camera; `streaming` means the WHIP\n // offer was answered and ICE connected; anything else is the reason it did not.\n const unsubscribe = subsystems.onGlassesStreamStatus?.((event) => {\n if (event.status === \"initializing\") {\n report?.(\"Glasses accepted the command: camera starting, gathering ICE, posting offer to the phone\")\n } else if (event.status === \"streaming\") {\n report?.(\"Glasses are streaming to the phone\")\n } else if (event.status === \"error\") {\n report?.(`Glasses reported: ${event.error ?? event.reason ?? \"stream error\"}`)\n } else if (event.status === \"reconnecting\") {\n report?.(`Glasses reconnecting: ${event.reason ?? \"\"}`)\n }\n })\n // Decided before the command goes out, never after: the glasses cannot drop an audio track\n // they already negotiated, and two live copies of the wearer's voice in one call is worse\n // than either one alone.\n const lc3Uplink = subsystems.glassesLc3Uplink?.() ?? false\n softapTrace(\"publish_audio_decision\", {captureAudio: !lc3Uplink, micTransport: lc3Uplink ? \"ble-lc3\" : \"whip\"})\n report?.(\n lc3Uplink\n ? \"Publishing video only; the wearer's voice comes over Bluetooth LC3\"\n : \"Publishing video and the glasses microphone\",\n )\n const policy = args.video ? softapVideoPolicy(args.video) : undefined\n if (policy) {\n // Traced at send time rather than read back: the glasses log what they applied in\n // `applyBitrateConstraints`, and the pair of lines is what shows a clamp we did not\n // intend. One line alone can only ever show agreement with itself.\n softapTrace(\"softap_video_policy\", {\n width: policy.width,\n height: policy.height,\n fps: policy.fps,\n min: policy.minBitrateBps,\n start: policy.initialBitrateBps,\n max: policy.bitrate,\n })\n }\n try {\n await subsystems.startPublishing(packageName, {\n streamUrl: ingestUrl,\n // Empty STUN server means host-only: there is no route from the hotspot to a STUN server,\n // so a configured one would add doomed gathering to every call.\n ice: {stun: \"\"},\n traceId,\n captureAudio: !lc3Uplink,\n ...(policy ? {video: policy} : {}),\n })\n } finally {\n unsubscribe?.()\n }\n },\n stopPublishing: () => subsystems.stopPublishing(packageName),\n awaitFirstFrame: args.awaitFirstFrame,\n }\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AppletPermission } from "../types/applet";
|
|
2
|
+
/**
|
|
3
|
+
* Normalize the `permissions` field from a miniapp.json manifest.
|
|
4
|
+
*
|
|
5
|
+
* New miniapps ship `[{type, required?, description?}]` objects. A few older
|
|
6
|
+
* installed bundles may have `["MICROPHONE", ...]` plain strings. Accept both.
|
|
7
|
+
*/
|
|
8
|
+
export declare function normalizeManifestPermissions(raw: Array<string | {
|
|
9
|
+
type: string;
|
|
10
|
+
required?: boolean;
|
|
11
|
+
description?: string;
|
|
12
|
+
}> | undefined): AppletPermission[];
|
|
13
|
+
//# sourceMappingURL=manifestPermissions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifestPermissions.d.ts","sourceRoot":"","sources":["../../src/services/manifestPermissions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,gBAAgB,EAAoB,MAAM,iBAAiB,CAAA;AAgBxE;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,GAAG,EAAE,KAAK,CAAC,MAAM,GAAG;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAC,CAAC,GAAG,SAAS,GACxF,gBAAgB,EAAE,CAmBpB"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const ALLOWED_PERMISSION_TYPES = new Set([
|
|
2
|
+
"MICROPHONE",
|
|
3
|
+
"CAMERA",
|
|
4
|
+
// Phone camera, not glasses camera. Mentra Call needs this on the home-screen
|
|
5
|
+
// permission list so opening the miniapp prompts for Android CAMERA; without
|
|
6
|
+
// it the join later fails because ACS publishes video from this phone.
|
|
7
|
+
"PHONE_CAMERA",
|
|
8
|
+
"CALENDAR",
|
|
9
|
+
"LOCATION",
|
|
10
|
+
"BACKGROUND_LOCATION",
|
|
11
|
+
"READ_NOTIFICATIONS",
|
|
12
|
+
"POST_NOTIFICATIONS",
|
|
13
|
+
]);
|
|
14
|
+
/**
|
|
15
|
+
* Normalize the `permissions` field from a miniapp.json manifest.
|
|
16
|
+
*
|
|
17
|
+
* New miniapps ship `[{type, required?, description?}]` objects. A few older
|
|
18
|
+
* installed bundles may have `["MICROPHONE", ...]` plain strings. Accept both.
|
|
19
|
+
*/
|
|
20
|
+
export function normalizeManifestPermissions(raw) {
|
|
21
|
+
if (!Array.isArray(raw))
|
|
22
|
+
return [];
|
|
23
|
+
const out = [];
|
|
24
|
+
for (const p of raw) {
|
|
25
|
+
if (typeof p === "string") {
|
|
26
|
+
if (ALLOWED_PERMISSION_TYPES.has(p)) {
|
|
27
|
+
out.push({ type: p, required: true });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
else if (p && typeof p === "object" && typeof p.type === "string") {
|
|
31
|
+
if (ALLOWED_PERMISSION_TYPES.has(p.type)) {
|
|
32
|
+
out.push({
|
|
33
|
+
type: p.type,
|
|
34
|
+
...(typeof p.required === "boolean" ? { required: p.required } : {}),
|
|
35
|
+
...(typeof p.description === "string" ? { description: p.description } : {}),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=manifestPermissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifestPermissions.js","sourceRoot":"","sources":["../../src/services/manifestPermissions.ts"],"names":[],"mappings":"AAEA,MAAM,wBAAwB,GAAmC,IAAI,GAAG,CAAoB;IAC1F,YAAY;IACZ,QAAQ;IACR,8EAA8E;IAC9E,6EAA6E;IAC7E,uEAAuE;IACvE,cAAc;IACd,UAAU;IACV,UAAU;IACV,qBAAqB;IACrB,oBAAoB;IACpB,oBAAoB;CACrB,CAAC,CAAA;AAEF;;;;;GAKG;AACH,MAAM,UAAU,4BAA4B,CAC1C,GAAyF;IAEzF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAA;IAClC,MAAM,GAAG,GAAuB,EAAE,CAAA;IAClC,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;QACpB,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC1B,IAAI,wBAAwB,CAAC,GAAG,CAAC,CAAsB,CAAC,EAAE,CAAC;gBACzD,GAAG,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,CAAsB,EAAE,QAAQ,EAAE,IAAI,EAAC,CAAC,CAAA;YAC1D,CAAC;QACH,CAAC;aAAM,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACpE,IAAI,wBAAwB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAyB,CAAC,EAAE,CAAC;gBAC9D,GAAG,CAAC,IAAI,CAAC;oBACP,IAAI,EAAE,CAAC,CAAC,IAAyB;oBACjC,GAAG,CAAC,OAAO,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAC,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;oBAClE,GAAG,CAAC,OAAO,CAAC,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAC,WAAW,EAAE,CAAC,CAAC,WAAW,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;iBAC3E,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC","sourcesContent":["import type {AppletPermission, AppPermissionType} from \"../types/applet\"\n\nconst ALLOWED_PERMISSION_TYPES: ReadonlySet<AppPermissionType> = new Set<AppPermissionType>([\n \"MICROPHONE\",\n \"CAMERA\",\n // Phone camera, not glasses camera. Mentra Call needs this on the home-screen\n // permission list so opening the miniapp prompts for Android CAMERA; without\n // it the join later fails because ACS publishes video from this phone.\n \"PHONE_CAMERA\",\n \"CALENDAR\",\n \"LOCATION\",\n \"BACKGROUND_LOCATION\",\n \"READ_NOTIFICATIONS\",\n \"POST_NOTIFICATIONS\",\n])\n\n/**\n * Normalize the `permissions` field from a miniapp.json manifest.\n *\n * New miniapps ship `[{type, required?, description?}]` objects. A few older\n * installed bundles may have `[\"MICROPHONE\", ...]` plain strings. Accept both.\n */\nexport function normalizeManifestPermissions(\n raw: Array<string | {type: string; required?: boolean; description?: string}> | undefined,\n): AppletPermission[] {\n if (!Array.isArray(raw)) return []\n const out: AppletPermission[] = []\n for (const p of raw) {\n if (typeof p === \"string\") {\n if (ALLOWED_PERMISSION_TYPES.has(p as AppPermissionType)) {\n out.push({type: p as AppPermissionType, required: true})\n }\n } else if (p && typeof p === \"object\" && typeof p.type === \"string\") {\n if (ALLOWED_PERMISSION_TYPES.has(p.type as AppPermissionType)) {\n out.push({\n type: p.type as AppPermissionType,\n ...(typeof p.required === \"boolean\" ? {required: p.required} : {}),\n ...(typeof p.description === \"string\" ? {description: p.description} : {}),\n })\n }\n }\n }\n return out\n}\n"]}
|
package/build/types/applet.d.ts
CHANGED
|
@@ -11,7 +11,19 @@ export type AppletType = "standard" | "background" | "system_dashboard";
|
|
|
11
11
|
/**
|
|
12
12
|
* Permission types that apps can request
|
|
13
13
|
*/
|
|
14
|
-
export type AppPermissionType = "ALL" | "MICROPHONE"
|
|
14
|
+
export type AppPermissionType = "ALL" | "MICROPHONE"
|
|
15
|
+
/** The glasses camera. */
|
|
16
|
+
| "CAMERA"
|
|
17
|
+
/**
|
|
18
|
+
* This phone's own camera.
|
|
19
|
+
*
|
|
20
|
+
* Separate from `CAMERA` because that one has always meant the glasses, for every miniapp, and
|
|
21
|
+
* is never prompted for as an OS permission. A miniapp that publishes video *from the phone*
|
|
22
|
+
* (an ACS Teams call does, even though the frames originate on the glasses) needs the Android
|
|
23
|
+
* `CAMERA` runtime permission, and asking for it under the existing type would start prompting
|
|
24
|
+
* every miniapp on the platform for a camera it does not use.
|
|
25
|
+
*/
|
|
26
|
+
| "PHONE_CAMERA" | "CALENDAR" | "LOCATION" | "BACKGROUND_LOCATION" | "READ_NOTIFICATIONS" | "POST_NOTIFICATIONS";
|
|
15
27
|
/**
|
|
16
28
|
* Permission object with type and description
|
|
17
29
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"applet.d.ts","sourceRoot":"","sources":["../../src/types/applet.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAA;AAEpC,OAAO,EAAC,mBAAmB,EAAC,MAAM,YAAY,CAAA;AAE9C,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,4BAA4B,CAAA;AAEnE;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,YAAY,GAAG,kBAAkB,CAAA;AAEvE;;GAEG;AACH,MAAM,MAAM,iBAAiB,GACzB,KAAK,GACL,YAAY,
|
|
1
|
+
{"version":3,"file":"applet.d.ts","sourceRoot":"","sources":["../../src/types/applet.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAA;AAEpC,OAAO,EAAC,mBAAmB,EAAC,MAAM,YAAY,CAAA;AAE9C,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,4BAA4B,CAAA;AAEnE;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,YAAY,GAAG,kBAAkB,CAAA;AAEvE;;GAEG;AACH,MAAM,MAAM,iBAAiB,GACzB,KAAK,GACL,YAAY;AACd,0BAA0B;GACxB,QAAQ;AACV;;;;;;;;GAQG;GACD,cAAc,GACd,UAAU,GACV,UAAU,GACV,qBAAqB,GACrB,oBAAoB,GACpB,oBAAoB,CAAA;AAExB;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,iBAAiB,CAAA;IACvB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,aAAa,CAAC,EAAE,SAAS,CAAA;IACzB,IAAI,EAAE,UAAU,CAAA;IAChB,WAAW,EAAE,gBAAgB,EAAE,CAAA;IAC/B,OAAO,EAAE,OAAO,CAAA;IAChB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,OAAO,EAAE,OAAO,CAAA;IAChB,oBAAoB,EAAE,mBAAmB,EAAE,CAAA;IAC3C,iDAAiD;IACjD,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,uFAAuF;IACvF,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;;GAQG;AACH;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,WAAW,EAAE,MAAM,CAAA;IACnB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACpC,iEAAiE;IACjE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACvC;AAED,MAAM,WAAW,SAAU,SAAQ,eAAe;IAChD,OAAO,EAAE,OAAO,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,CAAC,EAAE,mBAAmB,CAAA;IACnC,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,OAAO,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC7B,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,cAAc,EAAE,CAAA;CAC3B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"applet.js","sourceRoot":"","sources":["../../src/types/applet.ts"],"names":[],"mappings":"AAAA;;GAEG","sourcesContent":["/**\n * App and miniapp types owned by @mentra/engine.\n */\n\nimport type {ReactNode} from \"react\"\n\nimport {HardwareRequirement} from \"./hardware\"\n\nimport type {CompatibilityResult} from \"../utils/hardware/hardware\"\n\n/**\n * App execution model types\n */\nexport type AppletType = \"standard\" | \"background\" | \"system_dashboard\"\n\n/**\n * Permission types that apps can request\n */\nexport type AppPermissionType =\n | \"ALL\"\n | \"MICROPHONE\"\n | \"CAMERA\"\n | \"CALENDAR\"\n | \"LOCATION\"\n | \"BACKGROUND_LOCATION\"\n | \"READ_NOTIFICATIONS\"\n | \"POST_NOTIFICATIONS\"\n\n/**\n * Permission object with type and description\n */\nexport interface AppletPermission {\n type: AppPermissionType\n description?: string\n required?: boolean\n}\n\n/**\n * Minimal app interface for client home screen display\n * Optimized for fast rendering - only essential fields\n *\n * This is the client-facing interface used by mobile apps.\n * Internal cloud services use AppI from models (more fields).\n */\nexport interface AppletInterface {\n packageName: string\n name: string\n webviewUrl: string\n logoUrl: string\n iconComponent?: ReactNode\n type: AppletType\n permissions: AppletPermission[]\n running: boolean\n /**\n * True while this app's UI WebView is mounted in the Compositor overlay.\n * At most one app is foregrounded at a time. Distinct from `running`:\n * a foregrounded app is always running, but a running app may be\n * backgrounded (JSContext alive, WebView torn down). Normalized to a\n * concrete boolean by the apps store's projectApps; literal call sites\n * may omit it.\n */\n foregrounded?: boolean\n healthy: boolean\n hardwareRequirements: HardwareRequirement[]\n /** ISO date string when the app was installed */\n installedDate?: string\n /** ISO date string when the app was last run. Undefined if never run (app is \"new\") */\n lastActiveAt?: string\n}\n\n/**\n * Runtime applet shape used by the engine apps store and OEM hosts.\n *\n * Extends AppletInterface with the host-side fields the manager / OEM tracks\n * outside the manifest: offline routing, hardware compatibility result,\n * loading/hidden/local flags, lifecycle hooks, screenshot, and the\n * dev-miniapp escape hatches (`devUrl` / `isMiniappDev`) that surface a\n * `mentra-miniapp dev` snapshot.\n */\n/**\n * A manifest-declared action a miniapp exposes for other (system) miniapps to\n * invoke via `session.actions`. Populated from `miniapp.json`'s `actions` field.\n * Shape maps 1:1 onto an MCP tool (id→name, description, parameters→inputSchema).\n */\nexport interface DeclaredAction {\n id: string\n description: string\n /** JSON-Schema input descriptor (MCP-compatible subset). */\n parameters?: Record<string, unknown>\n /** JSON-Schema descriptor for the action's structured result. */\n outputSchema?: Record<string, unknown>\n}\n\nexport interface ClientApp extends AppletInterface {\n offline: boolean\n offlineRoute: string\n compatibility?: CompatibilityResult\n loading: boolean\n local: boolean\n hidden: boolean\n onStart?: () => void\n onStop?: () => void\n screenshot?: string\n runtimePermissions?: string[]\n declaredPermissions?: string[]\n version?: string\n needsPcm?: boolean\n needsTranscript?: boolean\n devUrl?: string\n devPort?: number\n isMiniappDev?: boolean\n /** Manifest-declared actions (for session.miniapps.list + invoke gating). */\n actions?: DeclaredAction[]\n}\n"]}
|
|
1
|
+
{"version":3,"file":"applet.js","sourceRoot":"","sources":["../../src/types/applet.ts"],"names":[],"mappings":"AAAA;;GAEG","sourcesContent":["/**\n * App and miniapp types owned by @mentra/engine.\n */\n\nimport type {ReactNode} from \"react\"\n\nimport {HardwareRequirement} from \"./hardware\"\n\nimport type {CompatibilityResult} from \"../utils/hardware/hardware\"\n\n/**\n * App execution model types\n */\nexport type AppletType = \"standard\" | \"background\" | \"system_dashboard\"\n\n/**\n * Permission types that apps can request\n */\nexport type AppPermissionType =\n | \"ALL\"\n | \"MICROPHONE\"\n /** The glasses camera. */\n | \"CAMERA\"\n /**\n * This phone's own camera.\n *\n * Separate from `CAMERA` because that one has always meant the glasses, for every miniapp, and\n * is never prompted for as an OS permission. A miniapp that publishes video *from the phone*\n * (an ACS Teams call does, even though the frames originate on the glasses) needs the Android\n * `CAMERA` runtime permission, and asking for it under the existing type would start prompting\n * every miniapp on the platform for a camera it does not use.\n */\n | \"PHONE_CAMERA\"\n | \"CALENDAR\"\n | \"LOCATION\"\n | \"BACKGROUND_LOCATION\"\n | \"READ_NOTIFICATIONS\"\n | \"POST_NOTIFICATIONS\"\n\n/**\n * Permission object with type and description\n */\nexport interface AppletPermission {\n type: AppPermissionType\n description?: string\n required?: boolean\n}\n\n/**\n * Minimal app interface for client home screen display\n * Optimized for fast rendering - only essential fields\n *\n * This is the client-facing interface used by mobile apps.\n * Internal cloud services use AppI from models (more fields).\n */\nexport interface AppletInterface {\n packageName: string\n name: string\n webviewUrl: string\n logoUrl: string\n iconComponent?: ReactNode\n type: AppletType\n permissions: AppletPermission[]\n running: boolean\n /**\n * True while this app's UI WebView is mounted in the Compositor overlay.\n * At most one app is foregrounded at a time. Distinct from `running`:\n * a foregrounded app is always running, but a running app may be\n * backgrounded (JSContext alive, WebView torn down). Normalized to a\n * concrete boolean by the apps store's projectApps; literal call sites\n * may omit it.\n */\n foregrounded?: boolean\n healthy: boolean\n hardwareRequirements: HardwareRequirement[]\n /** ISO date string when the app was installed */\n installedDate?: string\n /** ISO date string when the app was last run. Undefined if never run (app is \"new\") */\n lastActiveAt?: string\n}\n\n/**\n * Runtime applet shape used by the engine apps store and OEM hosts.\n *\n * Extends AppletInterface with the host-side fields the manager / OEM tracks\n * outside the manifest: offline routing, hardware compatibility result,\n * loading/hidden/local flags, lifecycle hooks, screenshot, and the\n * dev-miniapp escape hatches (`devUrl` / `isMiniappDev`) that surface a\n * `mentra-miniapp dev` snapshot.\n */\n/**\n * A manifest-declared action a miniapp exposes for other (system) miniapps to\n * invoke via `session.actions`. Populated from `miniapp.json`'s `actions` field.\n * Shape maps 1:1 onto an MCP tool (id→name, description, parameters→inputSchema).\n */\nexport interface DeclaredAction {\n id: string\n description: string\n /** JSON-Schema input descriptor (MCP-compatible subset). */\n parameters?: Record<string, unknown>\n /** JSON-Schema descriptor for the action's structured result. */\n outputSchema?: Record<string, unknown>\n}\n\nexport interface ClientApp extends AppletInterface {\n offline: boolean\n offlineRoute: string\n compatibility?: CompatibilityResult\n loading: boolean\n local: boolean\n hidden: boolean\n onStart?: () => void\n onStop?: () => void\n screenshot?: string\n runtimePermissions?: string[]\n declaredPermissions?: string[]\n version?: string\n needsPcm?: boolean\n needsTranscript?: boolean\n devUrl?: string\n devPort?: number\n isMiniappDev?: boolean\n /** Manifest-declared actions (for session.miniapps.list + invoke gating). */\n actions?: DeclaredAction[]\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mentra/engine",
|
|
3
|
-
"version": "3.2.0-dev.
|
|
3
|
+
"version": "3.2.0-dev.245",
|
|
4
4
|
"description": "Mentra Engine — miniapp registry, WebView bridge, and miniapp store",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"react-native": "src/index.ts",
|
|
@@ -97,13 +97,13 @@
|
|
|
97
97
|
"registry": "https://registry.npmjs.org/"
|
|
98
98
|
},
|
|
99
99
|
"dependencies": {
|
|
100
|
-
"@mentra/acs-meeting": "3.2.0-dev.
|
|
101
|
-
"@mentra/glasses-media": "3.2.0-dev.
|
|
102
|
-
"@mentra/bluetooth-sdk": "3.2.0-dev.
|
|
103
|
-
"@mentra/cloud-client": "3.2.0-dev.
|
|
104
|
-
"@mentra/cloud-protocol": "3.2.0-dev.
|
|
105
|
-
"@mentra/crust": "3.2.0-dev.
|
|
106
|
-
"@mentra/miniapp": "3.2.0-dev.
|
|
100
|
+
"@mentra/acs-meeting": "3.2.0-dev.245",
|
|
101
|
+
"@mentra/glasses-media": "3.2.0-dev.245",
|
|
102
|
+
"@mentra/bluetooth-sdk": "3.2.0-dev.245",
|
|
103
|
+
"@mentra/cloud-client": "3.2.0-dev.245",
|
|
104
|
+
"@mentra/cloud-protocol": "3.2.0-dev.245",
|
|
105
|
+
"@mentra/crust": "3.2.0-dev.245",
|
|
106
|
+
"@mentra/miniapp": "3.2.0-dev.245",
|
|
107
107
|
"buffer": "^6.0.3",
|
|
108
108
|
"events": "^3.3.0",
|
|
109
109
|
"react-native-marked": "8.1.1",
|
|
@@ -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": "3.2.0",
|
|
15
|
-
"releaseIdentity": "3.2.0-dev.
|
|
16
|
-
"releaseSetId": "mentra-3.2.0-dev.
|
|
17
|
-
"sourceCommit": "
|
|
18
|
-
"otaManifestUrl": "https://github.com/Mentra-Community/MentraOS/releases/download/mentra-builds-v3.2.0/mentra-live-ota-3.2.0-dev.
|
|
19
|
-
"otaManifestSha256": "
|
|
15
|
+
"releaseIdentity": "3.2.0-dev.245",
|
|
16
|
+
"releaseSetId": "mentra-3.2.0-dev.245",
|
|
17
|
+
"sourceCommit": "979b6f01635a92d0061160e9007ccb8be313b06e",
|
|
18
|
+
"otaManifestUrl": "https://github.com/Mentra-Community/MentraOS/releases/download/mentra-builds-v3.2.0/mentra-live-ota-3.2.0-dev.245.json",
|
|
19
|
+
"otaManifestSha256": "b9e030e64254b2d39e89a4e446032ec2d996702a5f248d71a5bad390f99ef914"
|
|
20
20
|
})
|