@burdenoff/website-sdk 2026.1105.1 → 2026.1105.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +94 -1
  2. package/dist/avatar-live/index.d.mts +2 -2
  3. package/dist/avatar-live/index.d.ts +2 -2
  4. package/dist/avatar-live/index.js +11 -1
  5. package/dist/avatar-live/index.js.map +1 -1
  6. package/dist/avatar-live/index.mjs +11 -1
  7. package/dist/avatar-live/index.mjs.map +1 -1
  8. package/dist/avatar-live-view/index.d.mts +2 -2
  9. package/dist/avatar-live-view/index.d.ts +2 -2
  10. package/dist/avatar-live-view/index.js +915 -103
  11. package/dist/avatar-live-view/index.js.map +1 -1
  12. package/dist/avatar-live-view/index.mjs +908 -96
  13. package/dist/avatar-live-view/index.mjs.map +1 -1
  14. package/dist/avatar-mic/index.d.mts +187 -62
  15. package/dist/avatar-mic/index.d.ts +187 -62
  16. package/dist/avatar-mic/index.js +457 -5
  17. package/dist/avatar-mic/index.js.map +1 -1
  18. package/dist/avatar-mic/index.mjs +457 -6
  19. package/dist/avatar-mic/index.mjs.map +1 -1
  20. package/dist/{chunk-XIZE37IB.js → chunk-3AIAJ2L4.js} +2 -2
  21. package/dist/chunk-3AIAJ2L4.js.map +1 -0
  22. package/dist/{chunk-MVNN6LLO.mjs → chunk-JGU6JW4N.mjs} +2 -2
  23. package/dist/chunk-JGU6JW4N.mjs.map +1 -0
  24. package/dist/{explore-avatar-live-config-C-OwXNje.d.ts → explore-avatar-live-config-1zeXdMer.d.ts} +7 -4
  25. package/dist/{explore-avatar-live-config-OO0hvQCK.d.mts → explore-avatar-live-config-BxiE66Im.d.mts} +7 -4
  26. package/dist/index.d.mts +6 -5
  27. package/dist/index.d.ts +6 -5
  28. package/dist/index.js +5 -5
  29. package/dist/index.js.map +1 -1
  30. package/dist/index.mjs +1 -1
  31. package/dist/index.mjs.map +1 -1
  32. package/dist/{types-CXqaLlNB.d.mts → types-CTUJNvQu.d.mts} +10 -0
  33. package/dist/{types-CXqaLlNB.d.ts → types-CTUJNvQu.d.ts} +10 -0
  34. package/package.json +1 -1
  35. package/dist/chunk-MVNN6LLO.mjs.map +0 -1
  36. package/dist/chunk-XIZE37IB.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/avatar-mic/capture-worklet.ts","../../src/avatar-mic/mic-capture.ts","../../src/avatar-mic/stt-stream.ts","../../src/avatar-mic/press.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * BOFF-9797 (Stage C). The AudioWorklet that turns the microphone into 16 kHz PCM, for the Avatar tab's mic.\n *\n * **Ported, not shared.** A copy of `src/shared/assistant/voice/handsfree/captureWorklet.ts` in Algoshred/fe-libs at\n * {@link CAPTURE_WORKLET_PORTED_FROM} (blob `bcf5f754`): the website SDK cannot depend on fe-libs, and this folder\n * imports nothing outside itself. {@link CAPTURE_WORKLET_SOURCE} is that file's string byte for byte (its SHA-256 is\n * pinned by `capture-worklet.test.ts`, which also runs fe-libs' own checks against it), so a fix there is a fix to copy\n * here, and a drift fails the test.\n *\n * A worklet module is loaded from a URL, and this package cannot assume a bundler that emits a second entry file for\n * it, so the processor is a SOURCE STRING that `mic-capture.ts` loads through a Blob URL. It has no imports and no\n * access to this file's scope; everything it needs is inside the string.\n *\n * What it does, per render quantum (128 samples at the device rate):\n * - input 0 is the microphone. (Input 1 is fe-libs' playback reference bus; the website creates none, so the worklet\n * meters it as silence: `refDb` about -90.);\n * - the microphone is decimated to 16 kHz with a windowed-sinc low-pass (cutoff 7.2 kHz). Forcing `sampleRate: 16000`\n * on the context is not reliable across browsers, so the context runs at the device rate;\n * - 320-sample (20 ms) frames are posted as s16le with their RMS (dBFS), zero-crossing rate and the reference RMS.\n *\n * The input buffer is preallocated; nothing is allocated per quantum.\n */\n\n/** Where this file was ported from: Algoshred/fe-libs, at this commit of its `main`. */\nexport const CAPTURE_WORKLET_PORTED_FROM =\n \"fe-libs@5ad67543179abb4d8b8f6151c3d9347584802494\";\n\n/** Samples per frame at 16 kHz: 20 ms. */\nexport const CAPTURE_FRAME_SAMPLES = 320;\nexport const CAPTURE_SAMPLE_RATE = 16000;\nexport const CAPTURE_FRAME_MS = 20;\nexport const CAPTURE_PROCESSOR_NAME = \"boff-handsfree-capture\";\n\n/** What the worklet posts for each frame. */\nexport interface CaptureFrameMessage {\n /** s16le mono 16 kHz, `CAPTURE_FRAME_SAMPLES` samples. */\n pcm: ArrayBuffer;\n /** Microphone level over the frame, dBFS. */\n rmsDb: number;\n /** Reference-bus level over the same samples, dBFS (about -90 when silent, as it always is here). */\n refDb: number;\n /** Zero crossings per sample. */\n zcr: number;\n /** AudioContext time at the end of the frame, seconds. */\n ctxTime: number;\n seq: number;\n}\n\nexport const CAPTURE_WORKLET_SOURCE = `\n\"use strict\";\nconst FRAME = ${CAPTURE_FRAME_SAMPLES};\nclass BoffHandsfreeCapture extends AudioWorkletProcessor {\n constructor() {\n super();\n this.step = sampleRate / ${CAPTURE_SAMPLE_RATE};\n this.half = 6 * this.step;\n this.fc = 7200 / sampleRate;\n this.buf = new Float32Array(Math.ceil(this.half * 2) + 4096);\n this.len = 0;\n this.pos = 0;\n this.frame = new Float32Array(FRAME);\n this.n = 0;\n this.seq = 0;\n this.refEnergy = 0;\n this.refCount = 0;\n this.stopped = false;\n this.port.onmessage = (e) => { if (e.data && e.data.type === \"stop\") this.stopped = true; };\n }\n tap(d) {\n const x = 2 * this.fc * d;\n const s = x === 0 ? 1 : Math.sin(Math.PI * x) / (Math.PI * x);\n return 2 * this.fc * s * 0.5 * (1 + Math.cos(Math.PI * d / this.half));\n }\n emit() {\n const pcm = new Int16Array(FRAME);\n let energy = 0;\n let crossings = 0;\n for (let i = 0; i < FRAME; i++) {\n const v = Math.max(-1, Math.min(1, this.frame[i]));\n pcm[i] = Math.round(v * 32767);\n energy += v * v;\n if (i > 0 && (v >= 0) !== (this.frame[i - 1] >= 0)) crossings++;\n }\n const refMean = this.refCount > 0 ? this.refEnergy / this.refCount : 0;\n this.port.postMessage({\n pcm: pcm.buffer,\n rmsDb: 10 * Math.log10(energy / FRAME + 1e-9),\n refDb: 10 * Math.log10(refMean + 1e-9),\n zcr: crossings / FRAME,\n ctxTime: currentTime,\n seq: this.seq++,\n }, [pcm.buffer]);\n this.n = 0;\n this.refEnergy = 0;\n this.refCount = 0;\n }\n process(inputs) {\n if (this.stopped) return false;\n const mic = inputs[0] && inputs[0][0];\n if (!mic) return true;\n const ref = inputs[1] && inputs[1][0];\n if (ref) { for (let i = 0; i < ref.length; i++) this.refEnergy += ref[i] * ref[i]; }\n this.refCount += mic.length;\n if (this.len + mic.length > this.buf.length) {\n const grown = new Float32Array((this.len + mic.length) * 2);\n grown.set(this.buf.subarray(0, this.len));\n this.buf = grown;\n }\n this.buf.set(mic, this.len);\n this.len += mic.length;\n while (this.pos + this.half < this.len) {\n const from = Math.max(0, Math.ceil(this.pos - this.half));\n const to = Math.floor(this.pos + this.half);\n let acc = 0;\n for (let i = from; i <= to; i++) acc += this.buf[i] * this.tap(i - this.pos);\n this.frame[this.n++] = acc;\n this.pos += this.step;\n if (this.n === FRAME) this.emit();\n }\n const drop = Math.max(0, Math.floor(this.pos - this.half));\n if (drop > 0) {\n this.buf.copyWithin(0, drop, this.len);\n this.len -= drop;\n this.pos -= drop;\n }\n return true;\n }\n}\nregisterProcessor(\"${CAPTURE_PROCESSOR_NAME}\", BoffHandsfreeCapture);\n`;\n","/**\n * BOFF-9797 (Stage C). The Avatar tab's own microphone capture: `getUserMedia`, through the capture worklet\n * (`capture-worklet.ts`), into 16 kHz PCM frames.\n *\n * **Ported, not shared.** From `src/shared/assistant/voice/handsfree/micCapture.ts` in Algoshred/fe-libs at the\n * commit `capture-worklet.ts` names (`CAPTURE_WORKLET_PORTED_FROM`; blob `8486c630`), with one difference: fe-libs\n * routes everything its assistant plays into the worklet's second input (its playback reference, for barge-in), and the\n * website plays nothing through this context (the avatar's voice is the room's own audio element, and the mic is\n * offered only while no session plays), so no reference bus is made and the worklet has the microphone as its only\n * input. `looksLikeHeadset`, which only fe-libs' barge-in reads, is not ported. `capture-worklet.test.ts` holds the\n * parity tests.\n *\n * It opens `getUserMedia` with echo cancellation, noise suppression and auto gain on. Constraints are plain `true`,\n * never `{ exact }`: `exact` throws OverconstrainedError on handsets that cannot honour one. The settings the browser\n * actually applied are read back (`track.getSettings()`), because some Android handsets report `true` and apply nothing.\n *\n * `stop()` stops the track (the browser's recording indicator goes), disconnects the graph and closes the context. The\n * caller does that the moment a press ends, whichever way it ends; `pagehide` does it too, whatever the caller does.\n */\nimport {\n CAPTURE_PROCESSOR_NAME,\n CAPTURE_WORKLET_SOURCE,\n type CaptureFrameMessage,\n} from \"./capture-worklet\";\n\nexport interface MicCaptureHandle {\n context: AudioContext;\n micSource: MediaStreamAudioSourceNode;\n track: MediaStreamTrack;\n /** What the browser reports it applied. */\n settings: MediaTrackSettings;\n /** Stop everything and release the microphone. Safe to call more than once. */\n stop(): void;\n}\n\nexport type MicCaptureFailure = \"unsupported\" | \"not-allowed\" | \"unavailable\";\n\nexport class MicCaptureError extends Error {\n constructor(readonly reason: MicCaptureFailure) {\n super(`mic capture failed: ${reason}`);\n this.name = \"MicCaptureError\";\n }\n}\n\nexport const CAPTURE_CONSTRAINTS: MediaStreamConstraints = {\n audio: {\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true,\n channelCount: 1,\n },\n};\n\nexport function isMicCaptureSupported(): boolean {\n return (\n typeof navigator !== \"undefined\" &&\n typeof navigator.mediaDevices?.getUserMedia === \"function\" &&\n typeof AudioContext !== \"undefined\" &&\n typeof AudioWorkletNode !== \"undefined\"\n );\n}\n\n/**\n * Open the microphone and call `onFrame` with every 20 ms frame until `stop()`. Rejects with a {@link MicCaptureError}:\n * `not-allowed` when the visitor (or the browser, or the page's permissions policy) refuses the microphone,\n * `unsupported` where there is no way to capture, `unavailable` for anything else (no device, a device in use).\n */\nexport async function startMicCapture(\n onFrame: (frame: CaptureFrameMessage) => void,\n): Promise<MicCaptureHandle> {\n if (!isMicCaptureSupported()) throw new MicCaptureError(\"unsupported\");\n let stream: MediaStream;\n try {\n stream = await navigator.mediaDevices.getUserMedia(CAPTURE_CONSTRAINTS);\n } catch (cause) {\n const name = cause instanceof DOMException ? cause.name : \"\";\n throw new MicCaptureError(\n name === \"NotAllowedError\" || name === \"SecurityError\"\n ? \"not-allowed\"\n : \"unavailable\",\n );\n }\n const track = stream.getAudioTracks()[0];\n if (!track) {\n stream.getTracks().forEach((t) => t.stop());\n throw new MicCaptureError(\"unavailable\");\n }\n const context = new AudioContext({ latencyHint: \"interactive\" });\n const release = (): void => {\n stream.getTracks().forEach((t) => t.stop());\n };\n try {\n await context.resume();\n const url = URL.createObjectURL(\n new Blob([CAPTURE_WORKLET_SOURCE], { type: \"text/javascript\" }),\n );\n try {\n await context.audioWorklet.addModule(url);\n } finally {\n URL.revokeObjectURL(url);\n }\n const node = new AudioWorkletNode(context, CAPTURE_PROCESSOR_NAME, {\n numberOfInputs: 1,\n numberOfOutputs: 0,\n });\n node.port.onmessage = (event: MessageEvent<CaptureFrameMessage>) =>\n onFrame(event.data);\n const micSource = context.createMediaStreamSource(stream);\n micSource.connect(node, 0, 0);\n\n let stopped = false;\n const onPageHide = (): void => handle.stop();\n const handle: MicCaptureHandle = {\n context,\n micSource,\n track,\n settings: track.getSettings(),\n stop() {\n if (stopped) return;\n stopped = true;\n window.removeEventListener(\"pagehide\", onPageHide);\n node.port.onmessage = null;\n try {\n node.port.postMessage({ type: \"stop\" });\n micSource.disconnect();\n } catch {\n // already torn down\n }\n release();\n void context.close().catch(() => undefined);\n },\n };\n window.addEventListener(\"pagehide\", onPageHide);\n return handle;\n } catch (cause) {\n release();\n void context.close().catch(() => undefined);\n throw cause instanceof MicCaptureError\n ? cause\n : new MicCaptureError(\"unavailable\");\n }\n}\n","/**\n * BOFF-9797 (Stage C). The wire protocol of the website speech-to-text stream, as the Avatar tab's mic speaks it.\n *\n * The route is the global gateway's `GET /api/web-avatar/v1/stt/stream` (WebSocket, Algoshred/global-public-gateway\n * `src/web-stt-proxy.ts`), on the SDK's gateway, which relays to the existing speech service's website path\n * (Algoshred/global-speech-svc `src/speech/stt/protocol.ts`, `/api/stt/v1/web/stream`):\n *\n * subprotocols `boff.web-stt.v1` and `offer.<token>`: the token an availability answer carried (`stt.token`), never\n * in the URL; the gateway lifts it out before the handshake completes, so it is never echoed back.\n *\n * client -> {t:'config', v:1, utteranceId, epoch, langs:['en-IN'], sampleRate:16000, encoding:'s16le', notice}\n * binary s16le mono 16 kHz frames\n * {t:'end', utteranceId} | {t:'cancel', utteranceId}\n * server -> {t:'ready'} | {t:'pong'} | {t:'eou'|'done', utteranceId, epoch}\n * {t:'partial'|'final', utteranceId, epoch, seq, text, lang}\n * {t:'error', code, retryable, utteranceId?, detail?}\n * close codes: 4400 malformed (the mic notice too: `notice-version`), 4401 auth (any refused upgrade, the offer\n * included), 4403 origin, 4408 idle, 4413 frame too large, 4429 quota or rate, 4500 upstream, 4503 unavailable.\n *\n * **Ported, not shared.** The protocol part of `src/shared/assistant/voice/handsfree/backendStreamTransport.ts` in\n * Algoshred/fe-libs at the commit `capture-worklet.ts` names (`CAPTURE_WORKLET_PORTED_FROM`; blob `461a0706`): how\n * frames are chunked under the gateway's frame cap ({@link chunkFrames}), how a server message is read\n * ({@link readServerMessage} keeps fe-libs' checks), the close-code table ({@link CLOSE_CODE_ERRORS}) and the socket\n * seam ({@link SocketLike}). What differs is the route and its credential (the website offer, not a signed-in token),\n * the `notice` field each press names, `en-IN` only, and one connection a press: the transport's reconnects and\n * keep-alive are not ported, because nothing here holds a connection open between presses (the server's website\n * streams are a few at once, for every visitor together). `stt-stream.test.ts` holds the parity tests.\n */\n\n/** The one subprotocol the website route selects. */\nexport const WEB_STT_SUBPROTOCOL = \"boff.web-stt.v1\";\n/** The offered-subprotocol entry that carries the availability answer's token: `offer.<token>`. */\nconst OFFER_PREFIX = \"offer.\";\n/** Under the web branch's base (`/api/web-avatar/v1`). */\nconst STREAM_PATH = \"/stt/stream\";\n/** The speech service's website path takes `en-IN` only. */\nexport const WEB_STT_LANGUAGES: readonly string[] = [\"en-IN\"];\n/** What a subprotocol entry may hold (and the gateway's own token check): a WebSocket token, nothing else. */\nconst TOKEN_CHARS = /^[A-Za-z0-9._~-]{1,4096}$/;\n/** The speech service's utterance ids and notice versions. */\nconst UTTERANCE_ID = /^[A-Za-z0-9._-]{1,64}$/;\nconst NOTICE_VERSION = /^[A-Za-z0-9._-]{1,32}$/;\nconst LOOPBACK_HOSTS = new Set([\"localhost\", \"127.0.0.1\", \"[::1]\"]);\n\n/** The gateway's frame cap is 8 KB; stay well under it. (fe-libs' value.) */\nexport const MAX_SEND_BYTES = 6400;\n\n/** What the mic needs of a WebSocket; {@link openBrowserSocket} adapts the browser's. (fe-libs' seam.) */\nexport interface SocketLike {\n readonly readyState: number;\n send(data: string | ArrayBufferLike | ArrayBufferView): void;\n close(code?: number): void;\n listen(handlers: SocketHandlers): void;\n}\n\nexport interface SocketHandlers {\n open(): void;\n message(data: unknown): void;\n close(code: number): void;\n error(): void;\n}\n\nexport const SOCKET_OPEN = 1;\n\n/** The error codes the client tells apart. (fe-libs' `SttErrorCode`, less what only its transport selection reads.) */\nexport type WebSttErrorCode = \"auth\" | \"quota\" | \"upstream\" | \"closed\";\n\n/** A close with no error frame before it, read as fe-libs reads it. */\nexport const CLOSE_CODE_ERRORS: Readonly<\n Record<number, { code: WebSttErrorCode; retryable: boolean }>\n> = {\n 4400: { code: \"upstream\", retryable: false },\n 4401: { code: \"auth\", retryable: false },\n 4403: { code: \"auth\", retryable: false },\n 4408: { code: \"closed\", retryable: true },\n 4413: { code: \"upstream\", retryable: false },\n 4429: { code: \"quota\", retryable: false },\n 4500: { code: \"upstream\", retryable: true },\n 4503: { code: \"upstream\", retryable: true },\n};\n\n/** The in-band refusal of an upgrade: the client asks availability again and tries once more. */\nexport const CLOSE_AUTH = 4401;\n\n/**\n * The stream's URL on the web branch's `base` (`avatarApiBase` of the SDK's gateway, `https://…/api/web-avatar/v1`):\n * `wss:` for `https:`, and `ws:` only for `http:` on this machine (local development). Null for anything else.\n */\nexport function webSttUrl(base: string): string | null {\n let url: URL;\n try {\n url = new URL(`${base}${STREAM_PATH}`);\n } catch {\n return null;\n }\n if (url.protocol === \"https:\") url.protocol = \"wss:\";\n else if (\n url.protocol === \"http:\" &&\n LOOPBACK_HOSTS.has(url.hostname.toLowerCase())\n ) {\n url.protocol = \"ws:\";\n } else {\n return null;\n }\n url.search = \"\";\n url.hash = \"\";\n return url.toString();\n}\n\n/** Whether `token` can travel as a subprotocol entry. */\nexport function isOfferToken(token: string): boolean {\n return TOKEN_CHARS.test(token);\n}\n\n/** The subprotocols a connection offers: ours, then the token. */\nexport function webSttSubprotocols(token: string): string[] {\n return [WEB_STT_SUBPROTOCOL, `${OFFER_PREFIX}${token}`];\n}\n\n/** Whether `value` is an utterance id the speech service takes. */\nexport function isUtteranceId(value: string): boolean {\n return UTTERANCE_ID.test(value);\n}\n\n/** Whether `value` is a notice version the speech service takes. */\nexport function isNoticeVersion(value: string): boolean {\n return NOTICE_VERSION.test(value);\n}\n\n/** One press's `config` frame: the speech service's protocol v1, plus the mic notice the visitor saw. */\nexport function configFrame(press: {\n utteranceId: string;\n epoch: number;\n notice: string;\n}): string {\n return JSON.stringify({\n t: \"config\",\n v: 1,\n utteranceId: press.utteranceId,\n epoch: press.epoch,\n langs: [...WEB_STT_LANGUAGES],\n sampleRate: 16000,\n encoding: \"s16le\",\n notice: press.notice,\n });\n}\n\n/** Flush and finalise the press: the visitor tapped to stop, or the limit came. */\nexport function endFrame(utteranceId: string): string {\n return JSON.stringify({ t: \"end\", utteranceId });\n}\n\n/** Drop the press upstream and stop paying for it: superseded, or the visitor left. */\nexport function cancelFrame(utteranceId: string): string {\n return JSON.stringify({ t: \"cancel\", utteranceId });\n}\n\n/** Concatenate frames into chunks of at most `MAX_SEND_BYTES`. (fe-libs' function.) */\nexport function chunkFrames(frames: readonly Int16Array[]): Int16Array[] {\n const perChunk = Math.floor(MAX_SEND_BYTES / 2);\n const out: Int16Array[] = [];\n let current: number[] = [];\n const flush = (): void => {\n if (current.length > 0) out.push(Int16Array.from(current));\n current = [];\n };\n for (const frame of frames) {\n for (const sample of frame) {\n current.push(sample);\n if (current.length === perChunk) flush();\n }\n }\n flush();\n return out;\n}\n\n/** What the server says, read: anything else is not a message the mic acts on. */\nexport type WebSttServerMessage =\n | { t: \"ready\" }\n | {\n t: \"partial\" | \"final\";\n utteranceId: string;\n epoch: number;\n text: string;\n }\n | { t: \"done\"; utteranceId: string; epoch: number }\n | {\n t: \"error\";\n code: string;\n retryable: boolean;\n /** The press it ends; null for the connection as a whole (a refused upgrade, say). */\n utteranceId: string | null;\n detail: string | null;\n };\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\n/**\n * Read one frame from the server: a text frame of JSON, as fe-libs reads it (a partial or final needs its text, its\n * utterance and its epoch; an error's code is kept as said, and only `retryable: true` is retryable). `pong` and `eou`\n * need nothing here (the visitor taps to stop), and neither does anything else: null.\n */\nexport function readServerMessage(data: unknown): WebSttServerMessage | null {\n if (typeof data !== \"string\") return null;\n let parsed: unknown;\n try {\n parsed = JSON.parse(data);\n } catch {\n return null;\n }\n if (!isRecord(parsed)) return null;\n const { t, utteranceId, epoch, text } = parsed;\n if (t === \"ready\") return { t };\n if (t === \"partial\" || t === \"final\") {\n if (\n typeof text !== \"string\" ||\n typeof utteranceId !== \"string\" ||\n typeof epoch !== \"number\"\n ) {\n return null;\n }\n return { t, utteranceId, epoch, text };\n }\n if (t === \"done\") {\n if (typeof utteranceId !== \"string\" || typeof epoch !== \"number\") {\n return null;\n }\n return { t, utteranceId, epoch };\n }\n if (t === \"error\") {\n return {\n t,\n code: typeof parsed.code === \"string\" ? parsed.code : \"upstream\",\n retryable: parsed.retryable === true,\n utteranceId: typeof utteranceId === \"string\" ? utteranceId : null,\n detail: typeof parsed.detail === \"string\" ? parsed.detail : null,\n };\n }\n return null;\n}\n\n/** The browser's WebSocket behind {@link SocketLike}. Throws as `new WebSocket` does (a protocol it cannot offer). */\nexport function openBrowserSocket(\n url: string,\n protocols: string[],\n): SocketLike {\n const socket = new WebSocket(url, protocols);\n socket.binaryType = \"arraybuffer\";\n return {\n get readyState() {\n return socket.readyState;\n },\n send: (data) => socket.send(data),\n close: (code) => socket.close(code),\n listen(handlers) {\n socket.onopen = () => handlers.open();\n socket.onmessage = (event: MessageEvent<unknown>) =>\n handlers.message(event.data);\n socket.onclose = (event: CloseEvent) => handlers.close(event.code);\n socket.onerror = () => handlers.error();\n },\n };\n}\n","/**\n * BOFF-9797 (Stage C). The Avatar tab's mic, one press at a time: tap to start, tap to stop, thirty seconds at most.\n *\n * A press, in order:\n *\n * 1. **The microphone opens** (`startMicCapture`: the browser's permission prompt the first time). Meanwhile the offer\n * is made ready: the token the last availability answer carried while it is fresh, else a new one, asked for now.\n * 2. **The stream connects**, once the microphone is live (never while a permission prompt is up, so no stream is held\n * open for a visitor who has not decided): `boff.web-stt.v1` and `offer.<token>`. A refused upgrade (4401) asks\n * availability again and tries once more, never twice.\n * 3. **The server says it is ready**: the press's `config` (its utterance id, its epoch, `en-IN`, and the mic notice the\n * visitor saw), then up to {@link PRE_ROLL_MS} of what the microphone heard while the stream connected, then every\n * frame as it comes. Listening, from here: what has been heard so far is reported as it is recognised.\n * 4. **The recording stops**: the visitor's tap, or {@link MAX_PRESS_MS} (counted both on the clock and in audio sent),\n * or the speech service's own limit. The microphone is released at once; `end`, and the last of the text.\n * 5. **The text is final** (`done`): reported once, for the view to put in the box. Nothing is ever sent for the\n * visitor: the text goes nowhere else.\n *\n * **Released on every way out.** The microphone's track is stopped the moment the recording stops, and also when the\n * press fails, is cancelled (`cancel()`: the view going, the page hidden, the Chat tab) or superseded (a new press while\n * one is still finishing: `cancel` for the old one, so it stops being paid for, and its text is never reported). A\n * microphone that opens after its press has gone is closed as it opens. The stream is closed whenever no press needs\n * it: one connection serves a press and the press that supersedes it, and no other.\n */\nimport {\n CAPTURE_SAMPLE_RATE,\n type CaptureFrameMessage,\n} from \"./capture-worklet\";\nimport {\n MicCaptureError,\n startMicCapture,\n type MicCaptureHandle,\n} from \"./mic-capture\";\nimport {\n CLOSE_AUTH,\n CLOSE_CODE_ERRORS,\n SOCKET_OPEN,\n cancelFrame,\n chunkFrames,\n configFrame,\n endFrame,\n isNoticeVersion,\n isOfferToken,\n isUtteranceId,\n openBrowserSocket,\n readServerMessage,\n webSttSubprotocols,\n webSttUrl,\n type SocketLike,\n} from \"./stt-stream\";\n\nimport type {\n AvatarMic,\n AvatarMicFailure,\n AvatarMicOffer,\n AvatarMicOptions,\n AvatarMicState,\n} from \"./types\";\n\n/** The longest press: the speech service's ceiling for a website press (`AVATAR_WEB_STT_MAX_SECONDS`, 30 at most). */\nexport const MAX_PRESS_MS = 30_000;\n/** Audio kept while the stream connects, and sent once it is ready: for a visitor who starts speaking a moment early. */\nexport const PRE_ROLL_MS = 1_000;\n/** How long the stream may take, once the microphone is live, to say it is ready. */\nexport const READY_TIMEOUT_MS = 10_000;\n/** After the recording stops, how long the last of the text may take: past the speech service's own final timeout. */\nexport const FINAL_WAIT_MS = 12_000;\n/** How long an offer opens a stream for (the gateway's `WEB_STT_OFFER_TTL_MS`). */\nexport const OFFER_TTL_MS = 120_000;\n/** An offer is used only this far before it expires, so it does not expire on its way. */\nconst OFFER_MARGIN_MS = 5_000;\n/** How far the gateway's clock may sit from this browser's before its `expiresAt` is not used. */\nconst CLOCK_TOLERANCE_MS = 5_000;\n\nconst IDLE: AvatarMicState = { name: \"idle\" };\n\n/**\n * Until when (this browser's clock) an offer is used: its `expiresAt` when this browser's clock agrees with the\n * gateway's, else {@link OFFER_TTL_MS} from when it came; never longer than that, and less a margin either way.\n */\nexport function offerFreshUntil(offer: AvatarMicOffer): number {\n const ahead = offer.expiresAt - offer.receivedAt;\n const life =\n ahead > 0 && ahead <= OFFER_TTL_MS + CLOCK_TOLERANCE_MS\n ? Math.min(ahead, OFFER_TTL_MS)\n : OFFER_TTL_MS;\n return offer.receivedAt + life - OFFER_MARGIN_MS;\n}\n\n/**\n * Why a refusal or an error ends a press, from what the server said: the code, whether it is retryable, its detail.\n * The mic notice of another version, a refused offer and a pause (the website avatar's kill key) are `unavailable`; a\n * spent limit is `limit`; a busy stream, or counters that cannot be read just now, `busy`.\n */\nexport function failureOf(\n code: string,\n retryable: boolean,\n detail: string | null,\n): AvatarMicFailure {\n if (detail === \"notice-version\") return \"unavailable\";\n switch (code) {\n case \"quota\":\n return \"limit\";\n case \"auth\":\n return \"unavailable\";\n case \"busy\":\n return retryable ? \"busy\" : \"unavailable\";\n default:\n return \"failed\";\n }\n}\n\n/** Why a close with no error frame before it ends a press (fe-libs' table, {@link CLOSE_CODE_ERRORS}). */\nfunction failureOfClose(code: number): AvatarMicFailure {\n const known = CLOSE_CODE_ERRORS[code];\n if (known === undefined) return \"failed\";\n return failureOf(known.code, known.retryable, null);\n}\n\n/** A random utterance id, `web-` and 32 hex digits or a UUID; null where the browser has no random source. */\nfunction randomUtteranceId(): string | null {\n const crypto = globalThis.crypto;\n if (typeof crypto?.randomUUID === \"function\") {\n return `web-${crypto.randomUUID()}`;\n }\n if (typeof crypto?.getRandomValues !== \"function\") return null;\n const bytes = crypto.getRandomValues(new Uint8Array(16));\n return `web-${Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\")}`;\n}\n\n/** What a press needs from the browser. The browser's own by default; a test hands in fakes. */\nexport interface AvatarMicSeams {\n createSocket: (url: string, protocols: string[]) => SocketLike;\n startCapture: (\n onFrame: (frame: CaptureFrameMessage) => void,\n ) => Promise<Pick<MicCaptureHandle, \"stop\">>;\n newUtteranceId: () => string | null;\n}\n\nconst BROWSER: AvatarMicSeams = {\n createSocket: openBrowserSocket,\n startCapture: startMicCapture,\n newUtteranceId: randomUtteranceId,\n};\n\ntype Timer = ReturnType<typeof setTimeout>;\n\ninterface Press {\n epoch: number;\n utteranceId: string;\n stage: \"starting\" | \"listening\" | \"finishing\" | \"ended\";\n /** The microphone, once it is live and until it is released. */\n capture: Pick<MicCaptureHandle, \"stop\"> | null;\n /** What the microphone heard while the stream connected, oldest first. */\n preRoll: Int16Array[];\n preRollMs: number;\n /** Audio sent, in milliseconds: the pre-roll and every frame since. */\n sentMs: number;\n startedAt: number;\n finals: string[];\n partial: string;\n limit: boolean;\n /** A connection of its own was opened for it (a superseding press may start on the one it inherited). */\n ownConnection: boolean;\n /** It has asked availability for a new offer after a refused upgrade: the one retry. */\n retried: boolean;\n readyTimer: Timer | null;\n limitTimer: Timer | null;\n finalTimer: Timer | null;\n}\n\ninterface Connection {\n socket: SocketLike;\n /** The server said it is ready: the upgrade was taken. */\n ready: boolean;\n /** The last error frame that named no press: what a refused upgrade said before its close. */\n refusal: { code: string; retryable: boolean; detail: string | null } | null;\n}\n\n/** The mic of one Avatar tab. See the file's comment for what a press does. */\nexport function createAvatarMic(\n options: AvatarMicOptions,\n seams: Partial<AvatarMicSeams> = {},\n): AvatarMic {\n const { createSocket, startCapture, newUtteranceId } = {\n ...BROWSER,\n ...seams,\n };\n let press: Press | null = null;\n let connection: Connection | null = null;\n let epoch = 0;\n let state: AvatarMicState = IDLE;\n\n const report = (next: AvatarMicState): void => {\n state = next;\n options.onState(next);\n };\n\n /** What has been heard: the final text, and the words still being recognised after it. */\n const heard = (p: Press): string =>\n [...p.finals, p.partial].filter((part) => part !== \"\").join(\" \");\n const finalText = (p: Press): string => p.finals.join(\" \");\n\n const show = (p: Press): void => {\n if (p.stage === \"listening\") {\n report({\n name: \"listening\",\n epoch: p.epoch,\n startedAt: p.startedAt,\n text: heard(p),\n });\n } else if (p.stage === \"finishing\") {\n report({\n name: \"finishing\",\n epoch: p.epoch,\n text: heard(p),\n limit: p.limit,\n });\n }\n };\n\n const send = (data: string | ArrayBufferView): void => {\n const socket = connection?.socket;\n if (socket && socket.readyState === SOCKET_OPEN) socket.send(data);\n };\n\n const closeConnection = (): void => {\n const closing = connection;\n connection = null;\n try {\n closing?.socket.close(1000);\n } catch {\n // already closed\n }\n };\n\n const clearTimers = (p: Press): void => {\n for (const timer of [p.readyTimer, p.limitTimer, p.finalTimer]) {\n if (timer !== null) clearTimeout(timer);\n }\n p.readyTimer = null;\n p.limitTimer = null;\n p.finalTimer = null;\n };\n\n /** Stop the microphone's track: the browser's recording indicator goes. */\n const release = (p: Press): void => {\n const capture = p.capture;\n p.capture = null;\n p.preRoll = [];\n p.preRollMs = 0;\n try {\n capture?.stop();\n } catch {\n // already stopped\n }\n };\n\n /** The press is over, one way or another: released, its timers cleared, its connection closed, and `next` said. */\n const settle = (p: Press, next: AvatarMicState): void => {\n if (p.stage === \"ended\") return;\n p.stage = \"ended\";\n release(p);\n clearTimers(p);\n if (press === p) press = null;\n closeConnection();\n report(next);\n };\n\n const fail = (p: Press, reason: AvatarMicFailure): void =>\n settle(p, { name: \"failed\", epoch: p.epoch, reason, text: finalText(p) });\n\n const complete = (p: Press): void =>\n settle(p, {\n name: \"done\",\n epoch: p.epoch,\n text: finalText(p),\n limit: p.limit,\n });\n\n /** The recording stops: the microphone goes now, and the last of the text is waited for. */\n const stopRecording = (p: Press, limit: boolean, withEnd: boolean): void => {\n if (p.stage !== \"listening\") return;\n release(p);\n if (p.limitTimer !== null) clearTimeout(p.limitTimer);\n p.limitTimer = null;\n p.stage = \"finishing\";\n p.limit = limit;\n if (withEnd) send(endFrame(p.utteranceId));\n p.finalTimer = setTimeout(() => {\n p.finalTimer = null;\n if (press !== p || p.stage !== \"finishing\") return;\n if (p.finals.length > 0) complete(p);\n else fail(p, \"failed\");\n }, FINAL_WAIT_MS);\n show(p);\n };\n\n /** The stream is ready and the microphone live: the press's config, its pre-roll, and from here every frame. */\n const begin = (p: Press): void => {\n if (p.stage !== \"starting\" || p.capture === null) return;\n if (p.readyTimer !== null) clearTimeout(p.readyTimer);\n p.readyTimer = null;\n send(\n configFrame({\n utteranceId: p.utteranceId,\n epoch: p.epoch,\n notice: options.notice,\n }),\n );\n for (const chunk of chunkFrames(p.preRoll)) send(chunk);\n p.sentMs += p.preRollMs;\n p.preRoll = [];\n p.preRollMs = 0;\n p.stage = \"listening\";\n p.startedAt = Date.now();\n p.limitTimer = setTimeout(() => {\n p.limitTimer = null;\n if (press === p) stopRecording(p, true, true);\n }, MAX_PRESS_MS);\n show(p);\n };\n\n const onFrame = (p: Press, frame: CaptureFrameMessage): void => {\n if (press !== p) return;\n const pcm = new Int16Array(frame.pcm);\n const ms = (pcm.length * 1000) / CAPTURE_SAMPLE_RATE;\n if (p.stage === \"starting\") {\n p.preRoll.push(pcm);\n p.preRollMs += ms;\n while (p.preRollMs > PRE_ROLL_MS) {\n const oldest = p.preRoll.shift();\n if (oldest === undefined) break;\n p.preRollMs -= (oldest.length * 1000) / CAPTURE_SAMPLE_RATE;\n }\n return;\n }\n if (p.stage !== \"listening\") return;\n if (p.sentMs + ms > MAX_PRESS_MS) {\n stopRecording(p, true, true);\n return;\n }\n send(pcm);\n p.sentMs += ms;\n };\n\n /** An error frame that names the press. */\n const onPressError = (\n p: Press,\n error: { code: string; retryable: boolean; detail: string | null },\n ): void => {\n if (error.code === \"bad-frame\" && error.detail === \"utterance-too-long\") {\n // The speech service's own limit: it finalises what it took, and the text follows.\n stopRecording(p, true, false);\n return;\n }\n if (error.code === \"timeout\") {\n // The speech service ended the press (no audio, a gap, or no final in time): what it finalised stands.\n if (p.finals.length > 0) complete(p);\n else fail(p, \"failed\");\n return;\n }\n fail(p, failureOf(error.code, error.retryable, error.detail));\n };\n\n const onMessage = (data: unknown): void => {\n const message = readServerMessage(data);\n if (message === null || connection === null) return;\n const p = press;\n if (message.t === \"ready\") {\n connection.ready = true;\n if (p !== null) begin(p);\n return;\n }\n if (message.t === \"error\" && message.utteranceId === null) {\n connection.refusal = {\n code: message.code,\n retryable: message.retryable,\n detail: message.detail,\n };\n return;\n }\n // Only the press under way: a superseded one's late words are never shown.\n if (p === null || p.stage === \"ended\") return;\n if (message.utteranceId !== p.utteranceId) return;\n switch (message.t) {\n case \"partial\":\n if (message.epoch !== p.epoch) return;\n p.partial = message.text.trim();\n show(p);\n return;\n case \"final\": {\n if (message.epoch !== p.epoch) return;\n const text = message.text.trim();\n if (text !== \"\") p.finals.push(text);\n p.partial = \"\";\n show(p);\n return;\n }\n case \"done\":\n if (message.epoch !== p.epoch) return;\n complete(p);\n return;\n case \"error\":\n onPressError(p, message);\n return;\n }\n };\n\n const onClose = (closed: Connection, code: number): void => {\n connection = null;\n const p = press;\n if (p === null || p.stage === \"ended\") return;\n if (p.stage === \"starting\") {\n if (closed.ready && !p.ownConnection) {\n // The connection it inherited from the press it superseded went before it began: one of its own, once its\n // microphone is live (until then, the microphone opening connects it).\n if (p.capture !== null) connect(p);\n return;\n }\n if (!closed.ready && !p.retried && code === CLOSE_AUTH) {\n // A refused upgrade (any failed check is 4401: the offer expired, or is for another visitor, site or country\n // by now). Availability again, once. A refused origin (4403) is not one a new offer changes.\n p.retried = true;\n connect(p);\n return;\n }\n }\n if (p.stage === \"finishing\" && p.finals.length > 0) {\n complete(p);\n return;\n }\n const refusal = closed.refusal;\n fail(\n p,\n refusal === null\n ? failureOfClose(code)\n : failureOf(refusal.code, refusal.retryable, refusal.detail),\n );\n };\n\n /**\n * The offer this press connects with: the one held while it is fresh, else (and always for the retry) a new one; null\n * when availability answers without one. Rejects when availability gave no answer.\n */\n const offerFor = async (p: Press): Promise<AvatarMicOffer | null> => {\n const held = options.offer();\n if (!p.retried && held !== null && Date.now() < offerFreshUntil(held)) {\n return held;\n }\n return await options.refreshOffer();\n };\n\n const open = (p: Press, token: string): void => {\n const url = webSttUrl(options.base);\n if (url === null || !isOfferToken(token)) {\n fail(p, \"unavailable\");\n return;\n }\n let socket: SocketLike;\n try {\n socket = createSocket(url, webSttSubprotocols(token));\n } catch {\n fail(p, \"failed\");\n return;\n }\n const opened: Connection = { socket, ready: false, refusal: null };\n connection = opened;\n p.ownConnection = true;\n socket.listen({\n // The server's `ready` is what begins the press; a close always follows an error.\n open: () => undefined,\n error: () => undefined,\n message: (data) => {\n if (connection === opened) onMessage(data);\n },\n close: (code) => {\n if (connection === opened) onClose(opened, code);\n },\n });\n };\n\n /** Connect the press, its microphone being live: on the connection it inherited when that is ready, else its own. */\n function connect(p: Press): void {\n if (connection !== null) {\n if (connection.ready) begin(p);\n return;\n }\n if (p.readyTimer !== null) clearTimeout(p.readyTimer);\n p.readyTimer = setTimeout(() => {\n p.readyTimer = null;\n if (press === p && p.stage === \"starting\") fail(p, \"failed\");\n }, READY_TIMEOUT_MS);\n const waiting = (): boolean =>\n press === p && p.stage === \"starting\" && connection === null;\n void offerFor(p).then(\n (offer) => {\n if (!waiting()) return;\n if (offer === null) {\n fail(p, \"unavailable\");\n return;\n }\n open(p, offer.token);\n },\n () => {\n // No answer (the network, or its deadline) is no refusal: the press fails, and the next one may try again.\n if (waiting()) fail(p, \"failed\");\n },\n );\n }\n\n const cancel = (): void => {\n const p = press;\n press = null;\n if (p !== null && p.stage !== \"ended\") {\n if (p.stage === \"listening\" || p.stage === \"finishing\") {\n send(cancelFrame(p.utteranceId));\n }\n p.stage = \"ended\";\n release(p);\n clearTimers(p);\n }\n closeConnection();\n if (state.name !== \"idle\") report(IDLE);\n };\n\n const start = (): void => {\n const current = press;\n if (\n current !== null &&\n (current.stage === \"starting\" || current.stage === \"listening\")\n ) {\n return;\n }\n if (current !== null && current.stage === \"finishing\") {\n // Superseded: cancelled upstream, so it stops being paid for, and never reported. Its connection carries on.\n send(cancelFrame(current.utteranceId));\n current.stage = \"ended\";\n release(current);\n clearTimers(current);\n press = null;\n }\n epoch += 1;\n const utteranceId = newUtteranceId();\n if (\n utteranceId === null ||\n !isUtteranceId(utteranceId) ||\n !isNoticeVersion(options.notice)\n ) {\n closeConnection();\n report({ name: \"failed\", epoch, reason: \"unsupported\", text: \"\" });\n return;\n }\n const p: Press = {\n epoch,\n utteranceId,\n stage: \"starting\",\n capture: null,\n preRoll: [],\n preRollMs: 0,\n sentMs: 0,\n startedAt: 0,\n finals: [],\n partial: \"\",\n limit: false,\n ownConnection: false,\n retried: false,\n readyTimer: null,\n limitTimer: null,\n finalTimer: null,\n };\n press = p;\n report({ name: \"starting\", epoch });\n let capturing: Promise<Pick<MicCaptureHandle, \"stop\">>;\n try {\n capturing = startCapture((frame) => onFrame(p, frame));\n } catch (error) {\n capturing = Promise.reject(error);\n }\n capturing.then(\n (capture) => {\n if (press !== p || p.stage !== \"starting\") {\n // Its press has gone while the microphone opened: closed as it opens.\n try {\n capture.stop();\n } catch {\n // already stopped\n }\n return;\n }\n p.capture = capture;\n connect(p);\n },\n (error: unknown) => {\n if (press !== p || p.stage !== \"starting\") return;\n fail(\n p,\n error instanceof MicCaptureError && error.reason === \"not-allowed\"\n ? \"denied\"\n : \"unsupported\",\n );\n },\n );\n };\n\n return {\n start,\n stop() {\n const p = press;\n if (p === null) return;\n if (p.stage === \"starting\") cancel();\n else stopRecording(p, false, true);\n },\n cancel,\n state: () => state,\n };\n}\n"]}
1
+ {"version":3,"sources":["../../src/avatar-mic/browser-press.ts","../../src/avatar-mic/capture-worklet.ts","../../src/avatar-mic/mic-capture.ts","../../src/avatar-mic/stt-stream.ts","../../src/avatar-mic/press.ts"],"names":["IDLE","BROWSER"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * BOFF-9797 (Stage C, the browser's own recognizer). The Avatar tab's mic through the browser's speech recognition\n * (`SpeechRecognition`, `webkitSpeechRecognition`), as the product assistant listens: tap to start, tap to stop,\n * thirty seconds at most. The browser turns the voice into text (its own speech service: Google's for Chrome, Apple's\n * for Safari, Microsoft's for Edge); this module never sends anything anywhere, and the text goes only to the view,\n * which puts it in the box for the visitor to check and Send.\n *\n * The phones' quirks are the ones the SDK's Chat dictation (`src/hooks/use-speech-input.ts`, live on the sites) met\n * there, handled the same way: the permission prompt raised by opening the microphone first, a pause before the\n * recognizer opens its own, one quiet retry after a fresh grant, and one utterance per recognizer on a touch device.\n *\n * A press, in order:\n *\n * 1. **The tap** (`start`, called inside the tap where the view can). Where the browser reports the microphone granted\n * (or reports nothing, and a press on this page has had it), the recognizer starts inside the tap. Otherwise the\n * microphone is opened and released at once, inside the tap (`getUserMedia`): that is what raises the browser's\n * permission prompt on phones, where a recognizer's own `start()` is refused (`not-allowed`) without asking anyone.\n * Nothing of that capture is kept, played or sent. Once it is granted, the recognizer starts\n * {@link BROWSER_PRIME_SETTLE_MS} later, so it does not race the released capture for the microphone. The\n * recognizer: interim results, one alternative, the press's language, and `continuous`, except on a touch device,\n * whose recognizer hears one utterance whatever it is asked (and, asked for more, fails sooner). A press still\n * finishing is superseded (aborted, its text never reported; the view lets no tap through meanwhile).\n * 2. **The browser starts listening** (`onstart`, the honest signal: never while a prompt is up): `listening`, and the\n * press's limit counts from here ({@link BrowserAvatarMicOptions.maxPressMs}).\n * 3. **Words as they are recognised**: rebuilt from the whole result list each time (finals, then the words still\n * being recognised), so a result sent again never doubles up, and a final that repeats the one before it with more\n * words replaces it (Android's cumulative finals).\n * 4. **The engine ending by itself** (a pause, a phone's one utterance, a quiet spell's `no-speech`) does NOT end the\n * press: tap to stop holds on every platform. A new recognizer takes over in the same press, its words after the\n * ones before: at once on a computer, after {@link BROWSER_TOUCH_RESTART_MS} on a touch device, and after\n * {@link BROWSER_RESTART_COOLDOWN_MS} when one has just thrown on `start()` or, on a computer, ended as it began.\n * Bounded against a recognizer that never listens: after {@link BROWSER_MAX_QUICK_ENDS} ends in a row as they\n * began, or {@link BROWSER_MAX_RESTARTS} recognizers in all, the press gives what it has. Events of a recognizer that\n * has been replaced are dropped.\n * 5. **The stop** (the visitor's tap, or the limit): `stop()`, not `abort()`, as browsers deliver the last words after\n * it; up to {@link BROWSER_FINAL_WAIT_MS} for its end. A tap while it is still starting (the prompt included) calls\n * the press off.\n * 6. **The text** (`done`): what was heard, final or not (an engine that never marks a result final, iOS Safari, still\n * gives its words: the visitor checks them in the box anyway). Empty when nothing was heard.\n *\n * **Released on every way out.** `cancel()` (the view going, the page hidden, the Chat tab), a failure, a supersede and\n * the end of a press all detach the recognizer's handlers first and then `abort()` it, so the browser's recording\n * indicator goes and nothing it says later is reported. A microphone opened for the prompt is released as soon as it\n * opens, whether or not the press is still there.\n *\n * Errors. Opening the microphone for the prompt: refused (`NotAllowedError`, `SecurityError`) is `denied`; no\n * microphone (`NotFoundError`) is `unsupported`; anything else is `failed`. The recognizer's\n * (`SpeechRecognitionErrorEvent.error`): `not-allowed` or `service-not-allowed` while the microphone is confirmed for\n * the press (the browser reports it granted, or opening it just worked) is tried once more after\n * {@link BROWSER_GRANT_RETRY_MS}, quietly (Android refuses the first start after a fresh grant and takes the next), and\n * after that it is `unsupported`: the speech service refusing, not a permission the visitor can give. Unconfirmed,\n * `not-allowed` is `denied` (and the next tap asks the browser again) and `service-not-allowed` (iOS with Siri and\n * Dictation off, Edge's policy) is `unsupported`; `audio-capture` (no microphone) is `unsupported`;\n * `language-not-supported` tries the fallback language once, then `unsupported`; `network` is `failed`, and\n * `unsupported` the second time running on the page; `no-speech` is a quiet spell (a new recognizer); anything else is\n * `failed`. A failure once words were heard, whatever it is, gives those words instead (`done`).\n */\nimport type {\n AvatarMic,\n AvatarMicFailure,\n AvatarMicState,\n BrowserAvatarMicOptions,\n} from \"./types\";\n\n/** The longest the browser may take to start listening after a tap, its permission prompt (and the retry) included. */\nexport const BROWSER_START_WAIT_MS = 15_000;\n/** After the stop, how long the browser may take to deliver the last words and end. */\nexport const BROWSER_FINAL_WAIT_MS = 3_000;\n/**\n * How long before a new recognizer is started in a press, after one threw on `start()` or ended as it began (fe-libs\n * `START_RETRY_COOLDOWN_MS`): a bound on retrying a recognizer that keeps refusing, short enough that the press goes on.\n */\nexport const BROWSER_RESTART_COOLDOWN_MS = 2_000;\n/**\n * On a touch device, the pause before the next recognizer of a press (as the SDK's Chat dictation waits): its\n * recognizer ends after each utterance, and the next one starting in the same moment can be refused.\n */\nexport const BROWSER_TOUCH_RESTART_MS = 120;\n/** Ends in a row as they began (or starts that threw) after which a press gives what it has: a recognizer not listening. */\nexport const BROWSER_MAX_QUICK_ENDS = 8;\n/**\n * The most recognizers one press starts after its first: a bound on an engine gone wrong that a press which listens never\n * comes near (every end that is not quick has listened a second, or heard words, and a press lasts thirty seconds).\n */\nexport const BROWSER_MAX_RESTARTS = 60;\n/**\n * After the microphone was opened only to raise the browser's prompt (and released), how long before the recognizer\n * opens its own: started while that capture is still being torn down, it is refused on phones.\n */\nexport const BROWSER_PRIME_SETTLE_MS = 250;\n/** After a refusal while the microphone is confirmed, how long before the one retry (Android, after a fresh grant). */\nexport const BROWSER_GRANT_RETRY_MS = 350;\n/** A recognizer that ends this soon after it started, having heard nothing, ended as it began. */\nconst QUICK_END_MS = 1_000;\n/** `network` failures in a row (no words heard between them) after which this browser's recognizer is given up on. */\nconst NETWORK_FAILURES_FOR_GOOD = 2;\n\nconst IDLE: AvatarMicState = { name: \"idle\" };\n\n/** One alternative of a recognition result: what the browser heard. */\nexport interface RecognitionAlternativeLike {\n readonly transcript: string;\n}\n\n/** One recognition result: final, or still being recognised. */\nexport interface RecognitionResultLike {\n readonly isFinal: boolean;\n readonly length: number;\n readonly [index: number]: RecognitionAlternativeLike | undefined;\n}\n\n/** The whole result list of a recognizer, as each `result` event carries it. */\nexport interface RecognitionResultListLike {\n readonly length: number;\n readonly [index: number]: RecognitionResultLike | undefined;\n}\n\n/** What this module uses of a browser's `SpeechRecognition` (declared here: TypeScript's DOM library has none). */\nexport interface RecognitionLike {\n lang: string;\n continuous: boolean;\n interimResults: boolean;\n maxAlternatives: number;\n onstart: (() => void) | null;\n onresult:\n ((event: { readonly results: RecognitionResultListLike }) => void) | null;\n onerror: ((event: { readonly error: string }) => void) | null;\n onend: (() => void) | null;\n start(): void;\n stop(): void;\n abort(): void;\n}\n\n/** A browser's `SpeechRecognition` constructor. */\ntype RecognitionConstructor = new () => RecognitionLike;\n\n/**\n * Whether a global is a constructor to use as {@link RecognitionConstructor}. A browser's `SpeechRecognition` is a\n * function, and nothing else of that name is: the shape behind it is the Web Speech API's, which this module checks\n * by using it (every property it sets and calls is in that API).\n */\nfunction isRecognitionConstructor(\n value: unknown,\n): value is RecognitionConstructor {\n return typeof value === \"function\";\n}\n\n/** The browser's recognizer, new: the standard name first, then WebKit's. Null where the browser has none. */\nexport function newBrowserRecognition(): RecognitionLike | null {\n const found: unknown =\n Reflect.get(globalThis, \"SpeechRecognition\") ??\n Reflect.get(globalThis, \"webkitSpeechRecognition\");\n return isRecognitionConstructor(found) ? new found() : null;\n}\n\n/**\n * Open the microphone and release it at once (`getUserMedia`), which is what raises the browser's permission prompt on\n * phones. Resolves once released; rejects as `getUserMedia` does. Null where the browser has no `getUserMedia`.\n */\nexport function primeBrowserMicrophone(): Promise<void> | null {\n const media =\n typeof navigator === \"undefined\" ? undefined : navigator.mediaDevices;\n if (typeof media?.getUserMedia !== \"function\") return null;\n return media.getUserMedia({ audio: true }).then((stream) => {\n // Only the prompt was wanted: held open, it would show a recording indicator and keep the microphone from the\n // recognizer that is about to ask for it.\n for (const track of stream.getTracks()) track.stop();\n });\n}\n\n/**\n * The microphone permission as the browser reports it (`navigator.permissions`): `onState` with its state now, and\n * again on every change. Nothing where the browser cannot say (no Permissions API, or no `microphone` in it).\n */\nexport function watchBrowserMicPermission(\n onState: (state: PermissionState) => void,\n): void {\n const permissions =\n typeof navigator === \"undefined\" ? undefined : navigator.permissions;\n if (typeof permissions?.query !== \"function\") return;\n try {\n void permissions.query({ name: \"microphone\" }).then(\n (status) => {\n onState(status.state);\n status.addEventListener(\"change\", () => onState(status.state));\n },\n () => undefined,\n );\n } catch {\n // A browser that does not know the name says nothing.\n }\n}\n\n/** A touch device (a coarse pointer, which predicts its recognizer better than a screen size or a user agent). */\nexport function hasCoarsePointer(): boolean {\n if (\n typeof window === \"undefined\" ||\n typeof window.matchMedia !== \"function\"\n ) {\n return false;\n }\n try {\n return window.matchMedia(\"(pointer: coarse)\").matches;\n } catch {\n return false;\n }\n}\n\n/** What a press needs from the browser. The browser's own by default; a test hands in fakes. */\nexport interface BrowserAvatarMicSeams {\n /** A new recognizer, or null where the browser has none. */\n createRecognition: () => RecognitionLike | null;\n /** A monotonic clock, in milliseconds, for the cooldowns. */\n now: () => number;\n /** {@link primeBrowserMicrophone}: called inside the tap, where the microphone is not known to be granted. */\n primeMicrophone: () => Promise<void> | null;\n /** {@link watchBrowserMicPermission}: called once, as the mic is made. */\n watchMicPermission: (onState: (state: PermissionState) => void) => void;\n /** {@link hasCoarsePointer}: read at each tap. */\n touch: () => boolean;\n}\n\nconst BROWSER: BrowserAvatarMicSeams = {\n createRecognition: newBrowserRecognition,\n now: () =>\n typeof performance !== \"undefined\" ? performance.now() : Date.now(),\n primeMicrophone: primeBrowserMicrophone,\n watchMicPermission: watchBrowserMicPermission,\n touch: hasCoarsePointer,\n};\n\n/** What a refusal to open the microphone for the prompt means for the press. */\nfunction primeFailure(error: unknown): AvatarMicFailure {\n const name =\n typeof error === \"object\" && error !== null && \"name\" in error\n ? String(error.name)\n : \"\";\n if (name === \"NotAllowedError\" || name === \"SecurityError\") return \"denied\";\n if (name === \"NotFoundError\" || name === \"DevicesNotFoundError\") {\n return \"unsupported\";\n }\n return \"failed\";\n}\n\n/** Spaces run together and trimmed. */\nfunction tidy(text: string): string {\n return text.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * What a result list says: its finals, in order, and the words still being recognised after them. A final that\n * repeats the one before it with more words (Android Chrome's cumulative finals) replaces it.\n */\nexport function readRecognitionResults(results: RecognitionResultListLike): {\n finals: string[];\n interim: string;\n} {\n const finals: string[] = [];\n const interim: string[] = [];\n for (let index = 0; index < results.length; index += 1) {\n const result = results[index];\n const text = tidy(result?.[0]?.transcript ?? \"\");\n if (result === undefined || text === \"\") continue;\n if (!result.isFinal) {\n interim.push(text);\n continue;\n }\n const last = finals.length > 0 ? finals[finals.length - 1] : undefined;\n const lower = text.toLowerCase();\n if (\n last !== undefined &&\n (lower === last.toLowerCase() ||\n lower.startsWith(`${last.toLowerCase()} `))\n ) {\n finals[finals.length - 1] = text;\n } else {\n finals.push(text);\n }\n }\n return { finals, interim: interim.join(\" \") };\n}\n\ntype Timer = ReturnType<typeof setTimeout>;\n\n/** One recognizer of a press. A press may have several, one after another (see the file's comment, step 4). */\ninterface Instance {\n recognition: RecognitionLike;\n /** Its `onstart` came. */\n started: boolean;\n /** When it started, on the monotonic clock. */\n startedAt: number;\n finals: string[];\n interim: string;\n /** It reported `no-speech`. */\n noSpeech: boolean;\n}\n\ninterface Press {\n epoch: number;\n stage: \"starting\" | \"listening\" | \"finishing\" | \"ended\";\n /** The recognizer listening now; null between two of them. */\n instance: Instance | null;\n /** What the recognizers before it heard, in order. */\n earlier: string[];\n lang: string;\n /** It has tried the fallback language. */\n langRetried: boolean;\n /** Recognizers started after the first. */\n restarts: number;\n /** Ends in a row as they began, or starts that threw: {@link BROWSER_MAX_QUICK_ENDS}. */\n quickEnds: number;\n /** The microphone is confirmed for this press: the browser reported it granted at the tap, or opening it worked. */\n confirmed: boolean;\n /** The one quiet retry after a refusal while confirmed has been used. */\n grantRetried: boolean;\n /** A touch device: one utterance per recognizer. */\n touch: boolean;\n /** When the browser first started listening (this browser's clock): the limit counts from here. */\n startedAt: number;\n limit: boolean;\n startTimer: Timer | null;\n limitTimer: Timer | null;\n finalTimer: Timer | null;\n /** A recognizer to start later: once the primed microphone is released, for the retry, or taking over. */\n launchTimer: Timer | null;\n}\n\n/** The Avatar tab's mic through the browser's own recognizer. See the file's comment for what a press does. */\nexport function createBrowserAvatarMic(\n options: BrowserAvatarMicOptions,\n seams: Partial<BrowserAvatarMicSeams> = {},\n): AvatarMic {\n const { createRecognition, now, primeMicrophone, watchMicPermission, touch } =\n { ...BROWSER, ...seams };\n let press: Press | null = null;\n let epoch = 0;\n let state: AvatarMicState = IDLE;\n /** `network` failures in a row on this page, with no words heard since the first. */\n let networkFailures = 0;\n /** The microphone permission as the browser last reported it; null where it has not said. */\n let permission: PermissionState | null = null;\n /**\n * A press on this page had the microphone (it opened for the prompt, or a recognizer listened). Where the browser\n * reports no permission, a later tap starts the recognizer without opening it first; a refusal forgets it.\n */\n let hadMicrophone = false;\n watchMicPermission((next) => {\n permission = next;\n });\n\n const report = (next: AvatarMicState): void => {\n state = next;\n options.onState(next);\n };\n\n /** Everything heard so far: the recognizers before, then this one's finals and the words still being recognised. */\n const heard = (p: Press): string =>\n [...p.earlier, ...(p.instance?.finals ?? []), p.instance?.interim ?? \"\"]\n .filter((part) => part !== \"\")\n .join(\" \");\n\n const show = (p: Press): void => {\n if (p.stage === \"listening\") {\n report({\n name: \"listening\",\n epoch: p.epoch,\n startedAt: p.startedAt,\n text: heard(p),\n });\n } else if (p.stage === \"finishing\") {\n report({\n name: \"finishing\",\n epoch: p.epoch,\n text: heard(p),\n limit: p.limit,\n });\n }\n };\n\n /** Stop listening to a recognizer, then stop it at once: nothing it says from here is heard. */\n const release = (instance: Instance): void => {\n const { recognition } = instance;\n recognition.onstart = null;\n recognition.onresult = null;\n recognition.onerror = null;\n recognition.onend = null;\n try {\n recognition.abort();\n } catch {\n // already ended\n }\n };\n\n const clearTimers = (p: Press): void => {\n for (const timer of [\n p.startTimer,\n p.limitTimer,\n p.finalTimer,\n p.launchTimer,\n ]) {\n if (timer !== null) clearTimeout(timer);\n }\n p.startTimer = null;\n p.limitTimer = null;\n p.finalTimer = null;\n p.launchTimer = null;\n };\n\n /** The press is over, one way or another: its recognizer released, its timers cleared, and `next` said. */\n const settle = (p: Press, next: AvatarMicState): void => {\n if (p.stage === \"ended\") return;\n p.stage = \"ended\";\n clearTimers(p);\n const instance = p.instance;\n p.instance = null;\n if (instance !== null) release(instance);\n if (press === p) press = null;\n report(next);\n };\n\n /** The press gives what was heard (nothing, when nothing was). */\n const complete = (p: Press): void => {\n const text = heard(p);\n if (text !== \"\") networkFailures = 0;\n settle(p, { name: \"done\", epoch: p.epoch, text, limit: p.limit });\n };\n\n const fail = (p: Press, reason: AvatarMicFailure): void =>\n settle(p, { name: \"failed\", epoch: p.epoch, reason, text: heard(p) });\n\n /** Whether `instance` is the recognizer of the press under way: an older one's events are dropped. */\n const current = (p: Press, instance: Instance): boolean =>\n press === p && p.stage !== \"ended\" && p.instance === instance;\n\n /** The browser listens: the press records from here, and its limit counts from here. */\n const began = (p: Press, instance: Instance): void => {\n instance.started = true;\n instance.startedAt = now();\n hadMicrophone = true;\n if (p.stage !== \"starting\") return;\n if (p.startTimer !== null) clearTimeout(p.startTimer);\n p.startTimer = null;\n p.stage = \"listening\";\n p.startedAt = Date.now();\n p.limitTimer = setTimeout(() => {\n p.limitTimer = null;\n if (press === p) stopRecording(p, true);\n }, options.maxPressMs);\n };\n\n /** A recognizer for the press in `delay` (none: at once), while the press is still where it is now. */\n const launchIn = (p: Press, delay: number): void => {\n if (delay <= 0) {\n launch(p);\n return;\n }\n const stage = p.stage;\n p.launchTimer = setTimeout(() => {\n p.launchTimer = null;\n if (press === p && p.stage === stage) launch(p);\n }, delay);\n };\n\n /**\n * A new recognizer taking over in the press, after one that `listened` (heard words, or listened a while), ended\n * `quick` (as it began), or `threw` on `start()`: the press goes on, its words after the ones before.\n */\n const restart = (p: Press, end: \"listened\" | \"quick\" | \"threw\"): void => {\n p.quickEnds = end === \"listened\" ? 0 : p.quickEnds + 1;\n if (\n p.restarts >= BROWSER_MAX_RESTARTS ||\n p.quickEnds >= BROWSER_MAX_QUICK_ENDS\n ) {\n complete(p);\n return;\n }\n p.restarts += 1;\n launchIn(\n p,\n end === \"threw\" || (end === \"quick\" && !p.touch)\n ? BROWSER_RESTART_COOLDOWN_MS\n : p.touch\n ? BROWSER_TOUCH_RESTART_MS\n : 0,\n );\n };\n\n /** The words a recognizer heard, kept for the press once it has gone. */\n const keep = (p: Press, instance: Instance): void => {\n for (const text of [...instance.finals, instance.interim]) {\n if (text !== \"\") p.earlier.push(text);\n }\n };\n\n const onError = (p: Press, instance: Instance, code: string): void => {\n if (code === \"no-speech\") {\n // A quiet spell: the recognizer ends next, and a new one takes over (or, before any word, the press is done).\n instance.noSpeech = true;\n return;\n }\n // Once the recording has stopped, nothing is started again: the press ends with what it has.\n const going = p.stage === \"starting\" || p.stage === \"listening\";\n if (code === \"language-not-supported\" && going && !p.langRetried) {\n p.langRetried = true;\n if (options.fallbackLang !== p.lang) {\n p.lang = options.fallbackLang;\n keep(p, instance);\n p.instance = null;\n release(instance);\n launch(p);\n return;\n }\n }\n const refused = code === \"not-allowed\" || code === \"service-not-allowed\";\n if (refused && going && p.confirmed && !p.grantRetried) {\n // The microphone is granted: Android often refuses the first start after a fresh grant, and takes the next.\n p.grantRetried = true;\n keep(p, instance);\n p.instance = null;\n release(instance);\n launchIn(p, BROWSER_GRANT_RETRY_MS);\n return;\n }\n // Unconfirmed, a refusal may be the permission: the next tap opens the microphone first, which says.\n if (refused && !p.confirmed) hadMicrophone = false;\n if (heard(p) !== \"\") {\n // Words heard: they are the press's, whatever came after them.\n complete(p);\n return;\n }\n switch (code) {\n case \"not-allowed\":\n // Confirmed (and retried), it is the speech service refusing, not a permission the visitor can give.\n fail(p, p.confirmed ? \"unsupported\" : \"denied\");\n return;\n case \"service-not-allowed\":\n case \"audio-capture\":\n case \"language-not-supported\":\n fail(p, \"unsupported\");\n return;\n case \"network\":\n networkFailures += 1;\n fail(\n p,\n networkFailures >= NETWORK_FAILURES_FOR_GOOD\n ? \"unsupported\"\n : \"failed\",\n );\n return;\n default:\n // `aborted` (we never see our own: a released recognizer has no handlers), and anything else.\n fail(p, \"failed\");\n }\n };\n\n const onEnd = (p: Press, instance: Instance): void => {\n keep(p, instance);\n p.instance = null;\n instance.recognition.onstart = null;\n instance.recognition.onresult = null;\n instance.recognition.onerror = null;\n instance.recognition.onend = null;\n switch (p.stage) {\n case \"starting\":\n // Ended before it ever listened: nothing heard is no words; anything else, the browser gave up.\n if (instance.noSpeech) complete(p);\n else fail(p, \"failed\");\n return;\n case \"listening\": {\n // Ended by itself, the press still on: a new recognizer, at once unless this one ended as it began.\n const quick =\n !instance.started ||\n (now() - instance.startedAt < QUICK_END_MS &&\n instance.finals.length === 0 &&\n instance.interim === \"\");\n restart(p, quick ? \"quick\" : \"listened\");\n return;\n }\n case \"finishing\":\n complete(p);\n return;\n default:\n return;\n }\n };\n\n /** Start a recognizer for the press: the first, or one taking over in it. */\n function launch(p: Press): void {\n let recognition: RecognitionLike | null;\n try {\n recognition = createRecognition();\n } catch {\n recognition = null;\n }\n if (recognition === null) {\n if (p.stage === \"starting\") fail(p, \"unsupported\");\n else complete(p);\n return;\n }\n const instance: Instance = {\n recognition,\n started: false,\n startedAt: 0,\n finals: [],\n interim: \"\",\n noSpeech: false,\n };\n recognition.lang = p.lang;\n // A touch device's recognizer hears one utterance whatever it is asked, and fails sooner asked for more: the press\n // carries on with a new one instead (step 4).\n recognition.continuous = !p.touch;\n recognition.interimResults = true;\n recognition.maxAlternatives = 1;\n recognition.onstart = () => {\n if (!current(p, instance)) return;\n began(p, instance);\n show(p);\n };\n recognition.onresult = (event) => {\n if (!current(p, instance)) return;\n // Words before `onstart` (a browser that never says it started): it is listening all the same.\n if (!instance.started) began(p, instance);\n const read = readRecognitionResults(event.results);\n instance.finals = read.finals;\n instance.interim = read.interim;\n show(p);\n };\n recognition.onerror = (event) => {\n if (current(p, instance)) onError(p, instance, event.error);\n };\n recognition.onend = () => {\n if (current(p, instance)) onEnd(p, instance);\n };\n p.instance = instance;\n try {\n recognition.start();\n } catch {\n // A recognizer the browser will not start (one already running, a busy speech service): the tap is told; a\n // recognizer taking over is tried again after the cooldown, so a refusing one is not retried in a loop.\n p.instance = null;\n release(instance);\n if (p.stage === \"starting\") fail(p, \"failed\");\n else if (p.stage === \"listening\") restart(p, \"threw\");\n else complete(p);\n }\n }\n\n /**\n * Open the microphone and release it, inside the tap, to raise the browser's prompt (step 1); then, granted, the\n * recognizer once the capture is released. A microphone that opens after the press has gone is released all the same.\n */\n function prime(p: Press): void {\n let opening: Promise<void> | null;\n try {\n opening = primeMicrophone();\n } catch (error) {\n fail(p, primeFailure(error));\n return;\n }\n if (opening === null) {\n // No `getUserMedia`: the recognizer tries on its own. It may well work; refusing here would take the mic away.\n launch(p);\n return;\n }\n void opening.then(\n () => {\n hadMicrophone = true;\n if (press !== p || p.stage !== \"starting\") return;\n p.confirmed = true;\n launchIn(p, BROWSER_PRIME_SETTLE_MS);\n },\n (error: unknown) => {\n if (press === p && p.stage === \"starting\") fail(p, primeFailure(error));\n },\n );\n }\n\n /** The recording stops (the visitor's tap, or the limit): the last words are waited for. */\n function stopRecording(p: Press, limit: boolean): void {\n if (p.stage !== \"listening\") return;\n if (p.limitTimer !== null) clearTimeout(p.limitTimer);\n if (p.launchTimer !== null) clearTimeout(p.launchTimer);\n p.limitTimer = null;\n p.launchTimer = null;\n p.stage = \"finishing\";\n p.limit = limit;\n const instance = p.instance;\n if (instance === null || !instance.started) {\n // Between two recognizers, or one not listening yet: nothing more is coming.\n complete(p);\n return;\n }\n try {\n instance.recognition.stop();\n } catch {\n complete(p);\n return;\n }\n p.finalTimer = setTimeout(() => {\n p.finalTimer = null;\n if (press === p && p.stage === \"finishing\") complete(p);\n }, BROWSER_FINAL_WAIT_MS);\n show(p);\n }\n\n const cancel = (): void => {\n const p = press;\n press = null;\n if (p !== null && p.stage !== \"ended\") {\n p.stage = \"ended\";\n clearTimers(p);\n const instance = p.instance;\n p.instance = null;\n if (instance !== null) release(instance);\n }\n if (state.name !== \"idle\") report(IDLE);\n };\n\n const start = (): void => {\n const held = press;\n if (\n held !== null &&\n (held.stage === \"starting\" || held.stage === \"listening\")\n ) {\n return;\n }\n if (held !== null && held.stage === \"finishing\") {\n // Superseded: released, and never reported.\n held.stage = \"ended\";\n clearTimers(held);\n const instance = held.instance;\n held.instance = null;\n if (instance !== null) release(instance);\n press = null;\n }\n epoch += 1;\n const p: Press = {\n epoch,\n stage: \"starting\",\n instance: null,\n earlier: [],\n lang: options.lang,\n langRetried: false,\n restarts: 0,\n quickEnds: 0,\n confirmed: permission === \"granted\",\n grantRetried: false,\n touch: touch(),\n startedAt: 0,\n limit: false,\n startTimer: null,\n limitTimer: null,\n finalTimer: null,\n launchTimer: null,\n };\n press = p;\n report({ name: \"starting\", epoch });\n p.startTimer = setTimeout(() => {\n p.startTimer = null;\n if (press === p && p.stage === \"starting\") fail(p, \"failed\");\n }, BROWSER_START_WAIT_MS);\n // A `denied` reading is not believed (a dismissed prompt reads so): opening the microphone is what says.\n if (p.confirmed || (permission === null && hadMicrophone)) launch(p);\n else prime(p);\n };\n\n return {\n start,\n stop() {\n const p = press;\n if (p === null) return;\n if (p.stage === \"starting\") cancel();\n else stopRecording(p, false);\n },\n cancel,\n state: () => state,\n };\n}\n","/**\n * BOFF-9797 (Stage C). The AudioWorklet that turns the microphone into 16 kHz PCM, for the Avatar tab's mic.\n *\n * **Ported, not shared.** A copy of `src/shared/assistant/voice/handsfree/captureWorklet.ts` in Algoshred/fe-libs at\n * {@link CAPTURE_WORKLET_PORTED_FROM} (blob `bcf5f754`): the website SDK cannot depend on fe-libs, and this folder\n * imports nothing outside itself. {@link CAPTURE_WORKLET_SOURCE} is that file's string byte for byte (its SHA-256 is\n * pinned by `capture-worklet.test.ts`, which also runs fe-libs' own checks against it), so a fix there is a fix to copy\n * here, and a drift fails the test.\n *\n * A worklet module is loaded from a URL, and this package cannot assume a bundler that emits a second entry file for\n * it, so the processor is a SOURCE STRING that `mic-capture.ts` loads through a Blob URL. It has no imports and no\n * access to this file's scope; everything it needs is inside the string.\n *\n * What it does, per render quantum (128 samples at the device rate):\n * - input 0 is the microphone. (Input 1 is fe-libs' playback reference bus; the website creates none, so the worklet\n * meters it as silence: `refDb` about -90.);\n * - the microphone is decimated to 16 kHz with a windowed-sinc low-pass (cutoff 7.2 kHz). Forcing `sampleRate: 16000`\n * on the context is not reliable across browsers, so the context runs at the device rate;\n * - 320-sample (20 ms) frames are posted as s16le with their RMS (dBFS), zero-crossing rate and the reference RMS.\n *\n * The input buffer is preallocated; nothing is allocated per quantum.\n */\n\n/** Where this file was ported from: Algoshred/fe-libs, at this commit of its `main`. */\nexport const CAPTURE_WORKLET_PORTED_FROM =\n \"fe-libs@5ad67543179abb4d8b8f6151c3d9347584802494\";\n\n/** Samples per frame at 16 kHz: 20 ms. */\nexport const CAPTURE_FRAME_SAMPLES = 320;\nexport const CAPTURE_SAMPLE_RATE = 16000;\nexport const CAPTURE_FRAME_MS = 20;\nexport const CAPTURE_PROCESSOR_NAME = \"boff-handsfree-capture\";\n\n/** What the worklet posts for each frame. */\nexport interface CaptureFrameMessage {\n /** s16le mono 16 kHz, `CAPTURE_FRAME_SAMPLES` samples. */\n pcm: ArrayBuffer;\n /** Microphone level over the frame, dBFS. */\n rmsDb: number;\n /** Reference-bus level over the same samples, dBFS (about -90 when silent, as it always is here). */\n refDb: number;\n /** Zero crossings per sample. */\n zcr: number;\n /** AudioContext time at the end of the frame, seconds. */\n ctxTime: number;\n seq: number;\n}\n\nexport const CAPTURE_WORKLET_SOURCE = `\n\"use strict\";\nconst FRAME = ${CAPTURE_FRAME_SAMPLES};\nclass BoffHandsfreeCapture extends AudioWorkletProcessor {\n constructor() {\n super();\n this.step = sampleRate / ${CAPTURE_SAMPLE_RATE};\n this.half = 6 * this.step;\n this.fc = 7200 / sampleRate;\n this.buf = new Float32Array(Math.ceil(this.half * 2) + 4096);\n this.len = 0;\n this.pos = 0;\n this.frame = new Float32Array(FRAME);\n this.n = 0;\n this.seq = 0;\n this.refEnergy = 0;\n this.refCount = 0;\n this.stopped = false;\n this.port.onmessage = (e) => { if (e.data && e.data.type === \"stop\") this.stopped = true; };\n }\n tap(d) {\n const x = 2 * this.fc * d;\n const s = x === 0 ? 1 : Math.sin(Math.PI * x) / (Math.PI * x);\n return 2 * this.fc * s * 0.5 * (1 + Math.cos(Math.PI * d / this.half));\n }\n emit() {\n const pcm = new Int16Array(FRAME);\n let energy = 0;\n let crossings = 0;\n for (let i = 0; i < FRAME; i++) {\n const v = Math.max(-1, Math.min(1, this.frame[i]));\n pcm[i] = Math.round(v * 32767);\n energy += v * v;\n if (i > 0 && (v >= 0) !== (this.frame[i - 1] >= 0)) crossings++;\n }\n const refMean = this.refCount > 0 ? this.refEnergy / this.refCount : 0;\n this.port.postMessage({\n pcm: pcm.buffer,\n rmsDb: 10 * Math.log10(energy / FRAME + 1e-9),\n refDb: 10 * Math.log10(refMean + 1e-9),\n zcr: crossings / FRAME,\n ctxTime: currentTime,\n seq: this.seq++,\n }, [pcm.buffer]);\n this.n = 0;\n this.refEnergy = 0;\n this.refCount = 0;\n }\n process(inputs) {\n if (this.stopped) return false;\n const mic = inputs[0] && inputs[0][0];\n if (!mic) return true;\n const ref = inputs[1] && inputs[1][0];\n if (ref) { for (let i = 0; i < ref.length; i++) this.refEnergy += ref[i] * ref[i]; }\n this.refCount += mic.length;\n if (this.len + mic.length > this.buf.length) {\n const grown = new Float32Array((this.len + mic.length) * 2);\n grown.set(this.buf.subarray(0, this.len));\n this.buf = grown;\n }\n this.buf.set(mic, this.len);\n this.len += mic.length;\n while (this.pos + this.half < this.len) {\n const from = Math.max(0, Math.ceil(this.pos - this.half));\n const to = Math.floor(this.pos + this.half);\n let acc = 0;\n for (let i = from; i <= to; i++) acc += this.buf[i] * this.tap(i - this.pos);\n this.frame[this.n++] = acc;\n this.pos += this.step;\n if (this.n === FRAME) this.emit();\n }\n const drop = Math.max(0, Math.floor(this.pos - this.half));\n if (drop > 0) {\n this.buf.copyWithin(0, drop, this.len);\n this.len -= drop;\n this.pos -= drop;\n }\n return true;\n }\n}\nregisterProcessor(\"${CAPTURE_PROCESSOR_NAME}\", BoffHandsfreeCapture);\n`;\n","/**\n * BOFF-9797 (Stage C). The Avatar tab's own microphone capture: `getUserMedia`, through the capture worklet\n * (`capture-worklet.ts`), into 16 kHz PCM frames.\n *\n * **Ported, not shared.** From `src/shared/assistant/voice/handsfree/micCapture.ts` in Algoshred/fe-libs at the\n * commit `capture-worklet.ts` names (`CAPTURE_WORKLET_PORTED_FROM`; blob `8486c630`), with one difference: fe-libs\n * routes everything its assistant plays into the worklet's second input (its playback reference, for barge-in), and the\n * website plays nothing through this context (the avatar's voice is the room's own audio element, and the mic is\n * offered only while no session plays), so no reference bus is made and the worklet has the microphone as its only\n * input. `looksLikeHeadset`, which only fe-libs' barge-in reads, is not ported. `capture-worklet.test.ts` holds the\n * parity tests.\n *\n * It opens `getUserMedia` with echo cancellation, noise suppression and auto gain on. Constraints are plain `true`,\n * never `{ exact }`: `exact` throws OverconstrainedError on handsets that cannot honour one. The settings the browser\n * actually applied are read back (`track.getSettings()`), because some Android handsets report `true` and apply nothing.\n *\n * `stop()` stops the track (the browser's recording indicator goes), disconnects the graph and closes the context. The\n * caller does that the moment a press ends, whichever way it ends; `pagehide` does it too, whatever the caller does.\n */\nimport {\n CAPTURE_PROCESSOR_NAME,\n CAPTURE_WORKLET_SOURCE,\n type CaptureFrameMessage,\n} from \"./capture-worklet\";\n\nexport interface MicCaptureHandle {\n context: AudioContext;\n micSource: MediaStreamAudioSourceNode;\n track: MediaStreamTrack;\n /** What the browser reports it applied. */\n settings: MediaTrackSettings;\n /** Stop everything and release the microphone. Safe to call more than once. */\n stop(): void;\n}\n\nexport type MicCaptureFailure = \"unsupported\" | \"not-allowed\" | \"unavailable\";\n\nexport class MicCaptureError extends Error {\n constructor(readonly reason: MicCaptureFailure) {\n super(`mic capture failed: ${reason}`);\n this.name = \"MicCaptureError\";\n }\n}\n\nexport const CAPTURE_CONSTRAINTS: MediaStreamConstraints = {\n audio: {\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true,\n channelCount: 1,\n },\n};\n\nexport function isMicCaptureSupported(): boolean {\n return (\n typeof navigator !== \"undefined\" &&\n typeof navigator.mediaDevices?.getUserMedia === \"function\" &&\n typeof AudioContext !== \"undefined\" &&\n typeof AudioWorkletNode !== \"undefined\"\n );\n}\n\n/**\n * Open the microphone and call `onFrame` with every 20 ms frame until `stop()`. Rejects with a {@link MicCaptureError}:\n * `not-allowed` when the visitor (or the browser, or the page's permissions policy) refuses the microphone,\n * `unsupported` where there is no way to capture, `unavailable` for anything else (no device, a device in use).\n */\nexport async function startMicCapture(\n onFrame: (frame: CaptureFrameMessage) => void,\n): Promise<MicCaptureHandle> {\n if (!isMicCaptureSupported()) throw new MicCaptureError(\"unsupported\");\n let stream: MediaStream;\n try {\n stream = await navigator.mediaDevices.getUserMedia(CAPTURE_CONSTRAINTS);\n } catch (cause) {\n const name = cause instanceof DOMException ? cause.name : \"\";\n throw new MicCaptureError(\n name === \"NotAllowedError\" || name === \"SecurityError\"\n ? \"not-allowed\"\n : \"unavailable\",\n );\n }\n const track = stream.getAudioTracks()[0];\n if (!track) {\n stream.getTracks().forEach((t) => t.stop());\n throw new MicCaptureError(\"unavailable\");\n }\n const context = new AudioContext({ latencyHint: \"interactive\" });\n const release = (): void => {\n stream.getTracks().forEach((t) => t.stop());\n };\n try {\n await context.resume();\n const url = URL.createObjectURL(\n new Blob([CAPTURE_WORKLET_SOURCE], { type: \"text/javascript\" }),\n );\n try {\n await context.audioWorklet.addModule(url);\n } finally {\n URL.revokeObjectURL(url);\n }\n const node = new AudioWorkletNode(context, CAPTURE_PROCESSOR_NAME, {\n numberOfInputs: 1,\n numberOfOutputs: 0,\n });\n node.port.onmessage = (event: MessageEvent<CaptureFrameMessage>) =>\n onFrame(event.data);\n const micSource = context.createMediaStreamSource(stream);\n micSource.connect(node, 0, 0);\n\n let stopped = false;\n const onPageHide = (): void => handle.stop();\n const handle: MicCaptureHandle = {\n context,\n micSource,\n track,\n settings: track.getSettings(),\n stop() {\n if (stopped) return;\n stopped = true;\n window.removeEventListener(\"pagehide\", onPageHide);\n node.port.onmessage = null;\n try {\n node.port.postMessage({ type: \"stop\" });\n micSource.disconnect();\n } catch {\n // already torn down\n }\n release();\n void context.close().catch(() => undefined);\n },\n };\n window.addEventListener(\"pagehide\", onPageHide);\n return handle;\n } catch (cause) {\n release();\n void context.close().catch(() => undefined);\n throw cause instanceof MicCaptureError\n ? cause\n : new MicCaptureError(\"unavailable\");\n }\n}\n","/**\n * BOFF-9797 (Stage C). The wire protocol of the website speech-to-text stream, as the Avatar tab's mic speaks it.\n *\n * The route is the global gateway's `GET /api/web-avatar/v1/stt/stream` (WebSocket, Algoshred/global-public-gateway\n * `src/web-stt-proxy.ts`), on the SDK's gateway, which relays to the existing speech service's website path\n * (Algoshred/global-speech-svc `src/speech/stt/protocol.ts`, `/api/stt/v1/web/stream`):\n *\n * subprotocols `boff.web-stt.v1` and `offer.<token>`: the token an availability answer carried (`stt.token`), never\n * in the URL; the gateway lifts it out before the handshake completes, so it is never echoed back.\n *\n * client -> {t:'config', v:1, utteranceId, epoch, langs:['en-IN'], sampleRate:16000, encoding:'s16le', notice}\n * binary s16le mono 16 kHz frames\n * {t:'end', utteranceId} | {t:'cancel', utteranceId}\n * server -> {t:'ready'} | {t:'pong'} | {t:'eou'|'done', utteranceId, epoch}\n * {t:'partial'|'final', utteranceId, epoch, seq, text, lang}\n * {t:'error', code, retryable, utteranceId?, detail?}\n * close codes: 4400 malformed (the mic notice too: `notice-version`), 4401 auth (any refused upgrade, the offer\n * included), 4403 origin, 4408 idle, 4413 frame too large, 4429 quota or rate, 4500 upstream, 4503 unavailable.\n *\n * **Ported, not shared.** The protocol part of `src/shared/assistant/voice/handsfree/backendStreamTransport.ts` in\n * Algoshred/fe-libs at the commit `capture-worklet.ts` names (`CAPTURE_WORKLET_PORTED_FROM`; blob `461a0706`): how\n * frames are chunked under the gateway's frame cap ({@link chunkFrames}), how a server message is read\n * ({@link readServerMessage} keeps fe-libs' checks), the close-code table ({@link CLOSE_CODE_ERRORS}) and the socket\n * seam ({@link SocketLike}). What differs is the route and its credential (the website offer, not a signed-in token),\n * the `notice` field each press names, `en-IN` only, and one connection a press: the transport's reconnects and\n * keep-alive are not ported, because nothing here holds a connection open between presses (the server's website\n * streams are a few at once, for every visitor together). `stt-stream.test.ts` holds the parity tests.\n */\n\n/** The one subprotocol the website route selects. */\nexport const WEB_STT_SUBPROTOCOL = \"boff.web-stt.v1\";\n/** The offered-subprotocol entry that carries the availability answer's token: `offer.<token>`. */\nconst OFFER_PREFIX = \"offer.\";\n/** Under the web branch's base (`/api/web-avatar/v1`). */\nconst STREAM_PATH = \"/stt/stream\";\n/** The speech service's website path takes `en-IN` only. */\nexport const WEB_STT_LANGUAGES: readonly string[] = [\"en-IN\"];\n/** What a subprotocol entry may hold (and the gateway's own token check): a WebSocket token, nothing else. */\nconst TOKEN_CHARS = /^[A-Za-z0-9._~-]{1,4096}$/;\n/** The speech service's utterance ids and notice versions. */\nconst UTTERANCE_ID = /^[A-Za-z0-9._-]{1,64}$/;\nconst NOTICE_VERSION = /^[A-Za-z0-9._-]{1,32}$/;\nconst LOOPBACK_HOSTS = new Set([\"localhost\", \"127.0.0.1\", \"[::1]\"]);\n\n/** The gateway's frame cap is 8 KB; stay well under it. (fe-libs' value.) */\nexport const MAX_SEND_BYTES = 6400;\n\n/** What the mic needs of a WebSocket; {@link openBrowserSocket} adapts the browser's. (fe-libs' seam.) */\nexport interface SocketLike {\n readonly readyState: number;\n send(data: string | ArrayBufferLike | ArrayBufferView): void;\n close(code?: number): void;\n listen(handlers: SocketHandlers): void;\n}\n\nexport interface SocketHandlers {\n open(): void;\n message(data: unknown): void;\n close(code: number): void;\n error(): void;\n}\n\nexport const SOCKET_OPEN = 1;\n\n/** The error codes the client tells apart. (fe-libs' `SttErrorCode`, less what only its transport selection reads.) */\nexport type WebSttErrorCode = \"auth\" | \"quota\" | \"upstream\" | \"closed\";\n\n/** A close with no error frame before it, read as fe-libs reads it. */\nexport const CLOSE_CODE_ERRORS: Readonly<\n Record<number, { code: WebSttErrorCode; retryable: boolean }>\n> = {\n 4400: { code: \"upstream\", retryable: false },\n 4401: { code: \"auth\", retryable: false },\n 4403: { code: \"auth\", retryable: false },\n 4408: { code: \"closed\", retryable: true },\n 4413: { code: \"upstream\", retryable: false },\n 4429: { code: \"quota\", retryable: false },\n 4500: { code: \"upstream\", retryable: true },\n 4503: { code: \"upstream\", retryable: true },\n};\n\n/** The in-band refusal of an upgrade: the client asks availability again and tries once more. */\nexport const CLOSE_AUTH = 4401;\n\n/**\n * The stream's URL on the web branch's `base` (`avatarApiBase` of the SDK's gateway, `https://…/api/web-avatar/v1`):\n * `wss:` for `https:`, and `ws:` only for `http:` on this machine (local development). Null for anything else.\n */\nexport function webSttUrl(base: string): string | null {\n let url: URL;\n try {\n url = new URL(`${base}${STREAM_PATH}`);\n } catch {\n return null;\n }\n if (url.protocol === \"https:\") url.protocol = \"wss:\";\n else if (\n url.protocol === \"http:\" &&\n LOOPBACK_HOSTS.has(url.hostname.toLowerCase())\n ) {\n url.protocol = \"ws:\";\n } else {\n return null;\n }\n url.search = \"\";\n url.hash = \"\";\n return url.toString();\n}\n\n/** Whether `token` can travel as a subprotocol entry. */\nexport function isOfferToken(token: string): boolean {\n return TOKEN_CHARS.test(token);\n}\n\n/** The subprotocols a connection offers: ours, then the token. */\nexport function webSttSubprotocols(token: string): string[] {\n return [WEB_STT_SUBPROTOCOL, `${OFFER_PREFIX}${token}`];\n}\n\n/** Whether `value` is an utterance id the speech service takes. */\nexport function isUtteranceId(value: string): boolean {\n return UTTERANCE_ID.test(value);\n}\n\n/** Whether `value` is a notice version the speech service takes. */\nexport function isNoticeVersion(value: string): boolean {\n return NOTICE_VERSION.test(value);\n}\n\n/** One press's `config` frame: the speech service's protocol v1, plus the mic notice the visitor saw. */\nexport function configFrame(press: {\n utteranceId: string;\n epoch: number;\n notice: string;\n}): string {\n return JSON.stringify({\n t: \"config\",\n v: 1,\n utteranceId: press.utteranceId,\n epoch: press.epoch,\n langs: [...WEB_STT_LANGUAGES],\n sampleRate: 16000,\n encoding: \"s16le\",\n notice: press.notice,\n });\n}\n\n/** Flush and finalise the press: the visitor tapped to stop, or the limit came. */\nexport function endFrame(utteranceId: string): string {\n return JSON.stringify({ t: \"end\", utteranceId });\n}\n\n/** Drop the press upstream and stop paying for it: superseded, or the visitor left. */\nexport function cancelFrame(utteranceId: string): string {\n return JSON.stringify({ t: \"cancel\", utteranceId });\n}\n\n/** Concatenate frames into chunks of at most `MAX_SEND_BYTES`. (fe-libs' function.) */\nexport function chunkFrames(frames: readonly Int16Array[]): Int16Array[] {\n const perChunk = Math.floor(MAX_SEND_BYTES / 2);\n const out: Int16Array[] = [];\n let current: number[] = [];\n const flush = (): void => {\n if (current.length > 0) out.push(Int16Array.from(current));\n current = [];\n };\n for (const frame of frames) {\n for (const sample of frame) {\n current.push(sample);\n if (current.length === perChunk) flush();\n }\n }\n flush();\n return out;\n}\n\n/** What the server says, read: anything else is not a message the mic acts on. */\nexport type WebSttServerMessage =\n | { t: \"ready\" }\n | {\n t: \"partial\" | \"final\";\n utteranceId: string;\n epoch: number;\n text: string;\n }\n | { t: \"done\"; utteranceId: string; epoch: number }\n | {\n t: \"error\";\n code: string;\n retryable: boolean;\n /** The press it ends; null for the connection as a whole (a refused upgrade, say). */\n utteranceId: string | null;\n detail: string | null;\n };\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\n/**\n * Read one frame from the server: a text frame of JSON, as fe-libs reads it (a partial or final needs its text, its\n * utterance and its epoch; an error's code is kept as said, and only `retryable: true` is retryable). `pong` and `eou`\n * need nothing here (the visitor taps to stop), and neither does anything else: null.\n */\nexport function readServerMessage(data: unknown): WebSttServerMessage | null {\n if (typeof data !== \"string\") return null;\n let parsed: unknown;\n try {\n parsed = JSON.parse(data);\n } catch {\n return null;\n }\n if (!isRecord(parsed)) return null;\n const { t, utteranceId, epoch, text } = parsed;\n if (t === \"ready\") return { t };\n if (t === \"partial\" || t === \"final\") {\n if (\n typeof text !== \"string\" ||\n typeof utteranceId !== \"string\" ||\n typeof epoch !== \"number\"\n ) {\n return null;\n }\n return { t, utteranceId, epoch, text };\n }\n if (t === \"done\") {\n if (typeof utteranceId !== \"string\" || typeof epoch !== \"number\") {\n return null;\n }\n return { t, utteranceId, epoch };\n }\n if (t === \"error\") {\n return {\n t,\n code: typeof parsed.code === \"string\" ? parsed.code : \"upstream\",\n retryable: parsed.retryable === true,\n utteranceId: typeof utteranceId === \"string\" ? utteranceId : null,\n detail: typeof parsed.detail === \"string\" ? parsed.detail : null,\n };\n }\n return null;\n}\n\n/** The browser's WebSocket behind {@link SocketLike}. Throws as `new WebSocket` does (a protocol it cannot offer). */\nexport function openBrowserSocket(\n url: string,\n protocols: string[],\n): SocketLike {\n const socket = new WebSocket(url, protocols);\n socket.binaryType = \"arraybuffer\";\n return {\n get readyState() {\n return socket.readyState;\n },\n send: (data) => socket.send(data),\n close: (code) => socket.close(code),\n listen(handlers) {\n socket.onopen = () => handlers.open();\n socket.onmessage = (event: MessageEvent<unknown>) =>\n handlers.message(event.data);\n socket.onclose = (event: CloseEvent) => handlers.close(event.code);\n socket.onerror = () => handlers.error();\n },\n };\n}\n","/**\n * BOFF-9797 (Stage C). The Avatar tab's mic, one press at a time: tap to start, tap to stop, thirty seconds at most.\n *\n * A press, in order:\n *\n * 1. **The microphone opens** (`startMicCapture`: the browser's permission prompt the first time). Meanwhile the offer\n * is made ready: the token the last availability answer carried while it is fresh, else a new one, asked for now.\n * 2. **The stream connects**, once the microphone is live (never while a permission prompt is up, so no stream is held\n * open for a visitor who has not decided): `boff.web-stt.v1` and `offer.<token>`. A refused upgrade (4401) asks\n * availability again and tries once more, never twice.\n * 3. **The server says it is ready**: the press's `config` (its utterance id, its epoch, `en-IN`, and the mic notice the\n * visitor saw), then up to {@link PRE_ROLL_MS} of what the microphone heard while the stream connected, then every\n * frame as it comes. Listening, from here: what has been heard so far is reported as it is recognised.\n * 4. **The recording stops**: the visitor's tap, or {@link MAX_PRESS_MS} (counted both on the clock and in audio sent),\n * or the speech service's own limit. The microphone is released at once; `end`, and the last of the text.\n * 5. **The text is final** (`done`): reported once, for the view to put in the box. Nothing is ever sent for the\n * visitor: the text goes nowhere else.\n *\n * **Released on every way out.** The microphone's track is stopped the moment the recording stops, and also when the\n * press fails, is cancelled (`cancel()`: the view going, the page hidden, the Chat tab) or superseded (a new press while\n * one is still finishing, a tap the view lets through for this stream mic only: `cancel` for the old one, so it stops\n * being paid for, and its text is never reported). A\n * microphone that opens after its press has gone is closed as it opens. The stream is closed whenever no press needs\n * it: one connection serves a press and the press that supersedes it, and no other.\n */\nimport {\n CAPTURE_SAMPLE_RATE,\n type CaptureFrameMessage,\n} from \"./capture-worklet\";\nimport {\n MicCaptureError,\n startMicCapture,\n type MicCaptureHandle,\n} from \"./mic-capture\";\nimport {\n CLOSE_AUTH,\n CLOSE_CODE_ERRORS,\n SOCKET_OPEN,\n cancelFrame,\n chunkFrames,\n configFrame,\n endFrame,\n isNoticeVersion,\n isOfferToken,\n isUtteranceId,\n openBrowserSocket,\n readServerMessage,\n webSttSubprotocols,\n webSttUrl,\n type SocketLike,\n} from \"./stt-stream\";\n\nimport type {\n AvatarMic,\n AvatarMicFailure,\n AvatarMicOffer,\n AvatarMicOptions,\n AvatarMicState,\n} from \"./types\";\n\n/** The longest press: the speech service's ceiling for a website press (`AVATAR_WEB_STT_MAX_SECONDS`, 30 at most). */\nexport const MAX_PRESS_MS = 30_000;\n/** Audio kept while the stream connects, and sent once it is ready: for a visitor who starts speaking a moment early. */\nexport const PRE_ROLL_MS = 1_000;\n/** How long the stream may take, once the microphone is live, to say it is ready. */\nexport const READY_TIMEOUT_MS = 10_000;\n/** After the recording stops, how long the last of the text may take: past the speech service's own final timeout. */\nexport const FINAL_WAIT_MS = 12_000;\n/** How long an offer opens a stream for (the gateway's `WEB_STT_OFFER_TTL_MS`). */\nexport const OFFER_TTL_MS = 120_000;\n/** An offer is used only this far before it expires, so it does not expire on its way. */\nconst OFFER_MARGIN_MS = 5_000;\n/** How far the gateway's clock may sit from this browser's before its `expiresAt` is not used. */\nconst CLOCK_TOLERANCE_MS = 5_000;\n\nconst IDLE: AvatarMicState = { name: \"idle\" };\n\n/**\n * Until when (this browser's clock) an offer is used: its `expiresAt` when this browser's clock agrees with the\n * gateway's, else {@link OFFER_TTL_MS} from when it came; never longer than that, and less a margin either way.\n */\nexport function offerFreshUntil(offer: AvatarMicOffer): number {\n const ahead = offer.expiresAt - offer.receivedAt;\n const life =\n ahead > 0 && ahead <= OFFER_TTL_MS + CLOCK_TOLERANCE_MS\n ? Math.min(ahead, OFFER_TTL_MS)\n : OFFER_TTL_MS;\n return offer.receivedAt + life - OFFER_MARGIN_MS;\n}\n\n/**\n * Why a refusal or an error ends a press, from what the server said: the code, whether it is retryable, its detail.\n * The mic notice of another version, a refused offer and a pause (the website avatar's kill key) are `unavailable`; a\n * spent limit is `limit`; a busy stream, or counters that cannot be read just now, `busy`.\n */\nexport function failureOf(\n code: string,\n retryable: boolean,\n detail: string | null,\n): AvatarMicFailure {\n if (detail === \"notice-version\") return \"unavailable\";\n switch (code) {\n case \"quota\":\n return \"limit\";\n case \"auth\":\n return \"unavailable\";\n case \"busy\":\n return retryable ? \"busy\" : \"unavailable\";\n default:\n return \"failed\";\n }\n}\n\n/** Why a close with no error frame before it ends a press (fe-libs' table, {@link CLOSE_CODE_ERRORS}). */\nfunction failureOfClose(code: number): AvatarMicFailure {\n const known = CLOSE_CODE_ERRORS[code];\n if (known === undefined) return \"failed\";\n return failureOf(known.code, known.retryable, null);\n}\n\n/** A random utterance id, `web-` and 32 hex digits or a UUID; null where the browser has no random source. */\nfunction randomUtteranceId(): string | null {\n const crypto = globalThis.crypto;\n if (typeof crypto?.randomUUID === \"function\") {\n return `web-${crypto.randomUUID()}`;\n }\n if (typeof crypto?.getRandomValues !== \"function\") return null;\n const bytes = crypto.getRandomValues(new Uint8Array(16));\n return `web-${Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\")}`;\n}\n\n/** What a press needs from the browser. The browser's own by default; a test hands in fakes. */\nexport interface AvatarMicSeams {\n createSocket: (url: string, protocols: string[]) => SocketLike;\n startCapture: (\n onFrame: (frame: CaptureFrameMessage) => void,\n ) => Promise<Pick<MicCaptureHandle, \"stop\">>;\n newUtteranceId: () => string | null;\n}\n\nconst BROWSER: AvatarMicSeams = {\n createSocket: openBrowserSocket,\n startCapture: startMicCapture,\n newUtteranceId: randomUtteranceId,\n};\n\ntype Timer = ReturnType<typeof setTimeout>;\n\ninterface Press {\n epoch: number;\n utteranceId: string;\n stage: \"starting\" | \"listening\" | \"finishing\" | \"ended\";\n /** The microphone, once it is live and until it is released. */\n capture: Pick<MicCaptureHandle, \"stop\"> | null;\n /** What the microphone heard while the stream connected, oldest first. */\n preRoll: Int16Array[];\n preRollMs: number;\n /** Audio sent, in milliseconds: the pre-roll and every frame since. */\n sentMs: number;\n startedAt: number;\n finals: string[];\n partial: string;\n limit: boolean;\n /** A connection of its own was opened for it (a superseding press may start on the one it inherited). */\n ownConnection: boolean;\n /** It has asked availability for a new offer after a refused upgrade: the one retry. */\n retried: boolean;\n readyTimer: Timer | null;\n limitTimer: Timer | null;\n finalTimer: Timer | null;\n}\n\ninterface Connection {\n socket: SocketLike;\n /** The server said it is ready: the upgrade was taken. */\n ready: boolean;\n /** The last error frame that named no press: what a refused upgrade said before its close. */\n refusal: { code: string; retryable: boolean; detail: string | null } | null;\n}\n\n/** The mic of one Avatar tab. See the file's comment for what a press does. */\nexport function createAvatarMic(\n options: AvatarMicOptions,\n seams: Partial<AvatarMicSeams> = {},\n): AvatarMic {\n const { createSocket, startCapture, newUtteranceId } = {\n ...BROWSER,\n ...seams,\n };\n let press: Press | null = null;\n let connection: Connection | null = null;\n let epoch = 0;\n let state: AvatarMicState = IDLE;\n\n const report = (next: AvatarMicState): void => {\n state = next;\n options.onState(next);\n };\n\n /** What has been heard: the final text, and the words still being recognised after it. */\n const heard = (p: Press): string =>\n [...p.finals, p.partial].filter((part) => part !== \"\").join(\" \");\n const finalText = (p: Press): string => p.finals.join(\" \");\n\n const show = (p: Press): void => {\n if (p.stage === \"listening\") {\n report({\n name: \"listening\",\n epoch: p.epoch,\n startedAt: p.startedAt,\n text: heard(p),\n });\n } else if (p.stage === \"finishing\") {\n report({\n name: \"finishing\",\n epoch: p.epoch,\n text: heard(p),\n limit: p.limit,\n });\n }\n };\n\n const send = (data: string | ArrayBufferView): void => {\n const socket = connection?.socket;\n if (socket && socket.readyState === SOCKET_OPEN) socket.send(data);\n };\n\n const closeConnection = (): void => {\n const closing = connection;\n connection = null;\n try {\n closing?.socket.close(1000);\n } catch {\n // already closed\n }\n };\n\n const clearTimers = (p: Press): void => {\n for (const timer of [p.readyTimer, p.limitTimer, p.finalTimer]) {\n if (timer !== null) clearTimeout(timer);\n }\n p.readyTimer = null;\n p.limitTimer = null;\n p.finalTimer = null;\n };\n\n /** Stop the microphone's track: the browser's recording indicator goes. */\n const release = (p: Press): void => {\n const capture = p.capture;\n p.capture = null;\n p.preRoll = [];\n p.preRollMs = 0;\n try {\n capture?.stop();\n } catch {\n // already stopped\n }\n };\n\n /** The press is over, one way or another: released, its timers cleared, its connection closed, and `next` said. */\n const settle = (p: Press, next: AvatarMicState): void => {\n if (p.stage === \"ended\") return;\n p.stage = \"ended\";\n release(p);\n clearTimers(p);\n if (press === p) press = null;\n closeConnection();\n report(next);\n };\n\n const fail = (p: Press, reason: AvatarMicFailure): void =>\n settle(p, { name: \"failed\", epoch: p.epoch, reason, text: finalText(p) });\n\n const complete = (p: Press): void =>\n settle(p, {\n name: \"done\",\n epoch: p.epoch,\n text: finalText(p),\n limit: p.limit,\n });\n\n /** The recording stops: the microphone goes now, and the last of the text is waited for. */\n const stopRecording = (p: Press, limit: boolean, withEnd: boolean): void => {\n if (p.stage !== \"listening\") return;\n release(p);\n if (p.limitTimer !== null) clearTimeout(p.limitTimer);\n p.limitTimer = null;\n p.stage = \"finishing\";\n p.limit = limit;\n if (withEnd) send(endFrame(p.utteranceId));\n p.finalTimer = setTimeout(() => {\n p.finalTimer = null;\n if (press !== p || p.stage !== \"finishing\") return;\n if (p.finals.length > 0) complete(p);\n else fail(p, \"failed\");\n }, FINAL_WAIT_MS);\n show(p);\n };\n\n /** The stream is ready and the microphone live: the press's config, its pre-roll, and from here every frame. */\n const begin = (p: Press): void => {\n if (p.stage !== \"starting\" || p.capture === null) return;\n if (p.readyTimer !== null) clearTimeout(p.readyTimer);\n p.readyTimer = null;\n send(\n configFrame({\n utteranceId: p.utteranceId,\n epoch: p.epoch,\n notice: options.notice,\n }),\n );\n for (const chunk of chunkFrames(p.preRoll)) send(chunk);\n p.sentMs += p.preRollMs;\n p.preRoll = [];\n p.preRollMs = 0;\n p.stage = \"listening\";\n p.startedAt = Date.now();\n p.limitTimer = setTimeout(() => {\n p.limitTimer = null;\n if (press === p) stopRecording(p, true, true);\n }, MAX_PRESS_MS);\n show(p);\n };\n\n const onFrame = (p: Press, frame: CaptureFrameMessage): void => {\n if (press !== p) return;\n const pcm = new Int16Array(frame.pcm);\n const ms = (pcm.length * 1000) / CAPTURE_SAMPLE_RATE;\n if (p.stage === \"starting\") {\n p.preRoll.push(pcm);\n p.preRollMs += ms;\n while (p.preRollMs > PRE_ROLL_MS) {\n const oldest = p.preRoll.shift();\n if (oldest === undefined) break;\n p.preRollMs -= (oldest.length * 1000) / CAPTURE_SAMPLE_RATE;\n }\n return;\n }\n if (p.stage !== \"listening\") return;\n if (p.sentMs + ms > MAX_PRESS_MS) {\n stopRecording(p, true, true);\n return;\n }\n send(pcm);\n p.sentMs += ms;\n };\n\n /** An error frame that names the press. */\n const onPressError = (\n p: Press,\n error: { code: string; retryable: boolean; detail: string | null },\n ): void => {\n if (error.code === \"bad-frame\" && error.detail === \"utterance-too-long\") {\n // The speech service's own limit: it finalises what it took, and the text follows.\n stopRecording(p, true, false);\n return;\n }\n if (error.code === \"timeout\") {\n // The speech service ended the press (no audio, a gap, or no final in time): what it finalised stands.\n if (p.finals.length > 0) complete(p);\n else fail(p, \"failed\");\n return;\n }\n fail(p, failureOf(error.code, error.retryable, error.detail));\n };\n\n const onMessage = (data: unknown): void => {\n const message = readServerMessage(data);\n if (message === null || connection === null) return;\n const p = press;\n if (message.t === \"ready\") {\n connection.ready = true;\n if (p !== null) begin(p);\n return;\n }\n if (message.t === \"error\" && message.utteranceId === null) {\n connection.refusal = {\n code: message.code,\n retryable: message.retryable,\n detail: message.detail,\n };\n return;\n }\n // Only the press under way: a superseded one's late words are never shown.\n if (p === null || p.stage === \"ended\") return;\n if (message.utteranceId !== p.utteranceId) return;\n switch (message.t) {\n case \"partial\":\n if (message.epoch !== p.epoch) return;\n p.partial = message.text.trim();\n show(p);\n return;\n case \"final\": {\n if (message.epoch !== p.epoch) return;\n const text = message.text.trim();\n if (text !== \"\") p.finals.push(text);\n p.partial = \"\";\n show(p);\n return;\n }\n case \"done\":\n if (message.epoch !== p.epoch) return;\n complete(p);\n return;\n case \"error\":\n onPressError(p, message);\n return;\n }\n };\n\n const onClose = (closed: Connection, code: number): void => {\n connection = null;\n const p = press;\n if (p === null || p.stage === \"ended\") return;\n if (p.stage === \"starting\") {\n if (closed.ready && !p.ownConnection) {\n // The connection it inherited from the press it superseded went before it began: one of its own, once its\n // microphone is live (until then, the microphone opening connects it).\n if (p.capture !== null) connect(p);\n return;\n }\n if (!closed.ready && !p.retried && code === CLOSE_AUTH) {\n // A refused upgrade (any failed check is 4401: the offer expired, or is for another visitor, site or country\n // by now). Availability again, once. A refused origin (4403) is not one a new offer changes.\n p.retried = true;\n connect(p);\n return;\n }\n }\n if (p.stage === \"finishing\" && p.finals.length > 0) {\n complete(p);\n return;\n }\n const refusal = closed.refusal;\n fail(\n p,\n refusal === null\n ? failureOfClose(code)\n : failureOf(refusal.code, refusal.retryable, refusal.detail),\n );\n };\n\n /**\n * The offer this press connects with: the one held while it is fresh, else (and always for the retry) a new one; null\n * when availability answers without one. Rejects when availability gave no answer.\n */\n const offerFor = async (p: Press): Promise<AvatarMicOffer | null> => {\n const held = options.offer();\n if (!p.retried && held !== null && Date.now() < offerFreshUntil(held)) {\n return held;\n }\n return await options.refreshOffer();\n };\n\n const open = (p: Press, token: string): void => {\n const url = webSttUrl(options.base);\n if (url === null || !isOfferToken(token)) {\n fail(p, \"unavailable\");\n return;\n }\n let socket: SocketLike;\n try {\n socket = createSocket(url, webSttSubprotocols(token));\n } catch {\n fail(p, \"failed\");\n return;\n }\n const opened: Connection = { socket, ready: false, refusal: null };\n connection = opened;\n p.ownConnection = true;\n socket.listen({\n // The server's `ready` is what begins the press; a close always follows an error.\n open: () => undefined,\n error: () => undefined,\n message: (data) => {\n if (connection === opened) onMessage(data);\n },\n close: (code) => {\n if (connection === opened) onClose(opened, code);\n },\n });\n };\n\n /** Connect the press, its microphone being live: on the connection it inherited when that is ready, else its own. */\n function connect(p: Press): void {\n if (connection !== null) {\n if (connection.ready) begin(p);\n return;\n }\n if (p.readyTimer !== null) clearTimeout(p.readyTimer);\n p.readyTimer = setTimeout(() => {\n p.readyTimer = null;\n if (press === p && p.stage === \"starting\") fail(p, \"failed\");\n }, READY_TIMEOUT_MS);\n const waiting = (): boolean =>\n press === p && p.stage === \"starting\" && connection === null;\n void offerFor(p).then(\n (offer) => {\n if (!waiting()) return;\n if (offer === null) {\n fail(p, \"unavailable\");\n return;\n }\n open(p, offer.token);\n },\n () => {\n // No answer (the network, or its deadline) is no refusal: the press fails, and the next one may try again.\n if (waiting()) fail(p, \"failed\");\n },\n );\n }\n\n const cancel = (): void => {\n const p = press;\n press = null;\n if (p !== null && p.stage !== \"ended\") {\n if (p.stage === \"listening\" || p.stage === \"finishing\") {\n send(cancelFrame(p.utteranceId));\n }\n p.stage = \"ended\";\n release(p);\n clearTimers(p);\n }\n closeConnection();\n if (state.name !== \"idle\") report(IDLE);\n };\n\n const start = (): void => {\n const current = press;\n if (\n current !== null &&\n (current.stage === \"starting\" || current.stage === \"listening\")\n ) {\n return;\n }\n if (current !== null && current.stage === \"finishing\") {\n // Superseded: cancelled upstream, so it stops being paid for, and never reported. Its connection carries on.\n send(cancelFrame(current.utteranceId));\n current.stage = \"ended\";\n release(current);\n clearTimers(current);\n press = null;\n }\n epoch += 1;\n const utteranceId = newUtteranceId();\n if (\n utteranceId === null ||\n !isUtteranceId(utteranceId) ||\n !isNoticeVersion(options.notice)\n ) {\n closeConnection();\n report({ name: \"failed\", epoch, reason: \"unsupported\", text: \"\" });\n return;\n }\n const p: Press = {\n epoch,\n utteranceId,\n stage: \"starting\",\n capture: null,\n preRoll: [],\n preRollMs: 0,\n sentMs: 0,\n startedAt: 0,\n finals: [],\n partial: \"\",\n limit: false,\n ownConnection: false,\n retried: false,\n readyTimer: null,\n limitTimer: null,\n finalTimer: null,\n };\n press = p;\n report({ name: \"starting\", epoch });\n let capturing: Promise<Pick<MicCaptureHandle, \"stop\">>;\n try {\n capturing = startCapture((frame) => onFrame(p, frame));\n } catch (error) {\n capturing = Promise.reject(error);\n }\n capturing.then(\n (capture) => {\n if (press !== p || p.stage !== \"starting\") {\n // Its press has gone while the microphone opened: closed as it opens.\n try {\n capture.stop();\n } catch {\n // already stopped\n }\n return;\n }\n p.capture = capture;\n connect(p);\n },\n (error: unknown) => {\n if (press !== p || p.stage !== \"starting\") return;\n fail(\n p,\n error instanceof MicCaptureError && error.reason === \"not-allowed\"\n ? \"denied\"\n : \"unsupported\",\n );\n },\n );\n };\n\n return {\n start,\n stop() {\n const p = press;\n if (p === null) return;\n if (p.stage === \"starting\") cancel();\n else stopRecording(p, false, true);\n },\n cancel,\n state: () => state,\n };\n}\n"]}
@@ -56,5 +56,5 @@ exports.isAvatarVersion = isAvatarVersion;
56
56
  exports.isRealTurnstileSiteKey = isRealTurnstileSiteKey;
57
57
  exports.liveConfigComplete = liveConfigComplete;
58
58
  exports.turnstileSiteKeyOf = turnstileSiteKeyOf;
59
- //# sourceMappingURL=chunk-XIZE37IB.js.map
60
- //# sourceMappingURL=chunk-XIZE37IB.js.map
59
+ //# sourceMappingURL=chunk-3AIAJ2L4.js.map
60
+ //# sourceMappingURL=chunk-3AIAJ2L4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/explore-avatar-live-config.ts"],"names":[],"mappings":";;;AA2FO,IAAM,mBAAA,GAAsB,oBAAA;AAEnC,IAAM,IAAA,GAAO,wBAAA;AACb,IAAM,OAAA,GAAU,wBAAA;AAChB,IAAM,QAAA,GAAW,wBAAA;AAKjB,IAAM,aAAA,GAAgB,wBAAA;AAMtB,IAAM,aAAA,GAAgB,0BAAA;AACtB,IAAM,iCAAiB,IAAI,GAAA,CAAI,CAAC,WAAA,EAAa,WAAA,EAAa,OAAO,CAAC,CAAA;AAG3D,SAAS,aAAa,KAAA,EAAwB;AACnD,EAAA,OAAO,IAAA,CAAK,KAAK,KAAK,CAAA;AACxB;AAGO,SAAS,gBAAgB,KAAA,EAAwB;AACtD,EAAA,OAAO,OAAA,CAAQ,KAAK,KAAK,CAAA;AAC3B;AAOO,SAAS,cAAc,UAAA,EAA+C;AAC3E,EAAA,IAAI,CAAC,YAAY,OAAO,IAAA;AACxB,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,IAAI,IAAI,UAAU,CAAA;AAAA,EAC1B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,KAAA,GACJ,IAAI,QAAA,KAAa,OAAA,IAAW,eAAe,GAAA,CAAI,GAAA,CAAI,QAAA,CAAS,WAAA,EAAa,CAAA;AAC3E,EAAA,IAAI,GAAA,CAAI,QAAA,KAAa,QAAA,IAAY,CAAC,OAAO,OAAO,IAAA;AAChD,EAAA,OAAO,CAAA,EAAG,GAAA,CAAI,MAAM,CAAA,EAAG,mBAAmB,CAAA,CAAA;AAC5C;AAGO,SAAS,uBAAuB,GAAA,EAAsB;AAC3D,EAAA,OAAO,cAAc,IAAA,CAAK,GAAG,KAAK,CAAC,aAAA,CAAc,KAAK,GAAG,CAAA;AAC3D;AAMO,SAAS,mBAAmB,IAAA,EAAuC;AACxE,EAAA,MAAM,MAAe,IAAA,CAAK,gBAAA;AAC1B,EAAA,MAAM,YAAqB,IAAA,CAAK,gBAAA;AAChC,EAAA,MAAM,gBAAyB,IAAA,CAAK,aAAA;AACpC,EAAA,MAAM,MAAe,IAAA,CAAK,GAAA;AAC1B,EAAA,OACE,OAAO,KAAK,IAAA,KAAS,UAAA,IACrB,OAAO,IAAA,CAAK,IAAA,KAAS,YACrB,YAAA,CAAa,IAAA,CAAK,IAAI,CAAA,IACtB,OAAO,KAAK,eAAA,KAAoB,QAAA,IAChC,gBAAgB,IAAA,CAAK,eAAe,MACnC,GAAA,KAAQ,MAAA,IACP,QAAQ,EAAA,IACP,OAAO,QAAQ,QAAA,IAAY,QAAA,CAAS,KAAK,GAAG,CAAA,CAAA,KAC9C,cAAc,MAAA,IAAa,OAAO,cAAc,SAAA,CAAA,KAChD,aAAA,KAAkB,UAAa,OAAO,aAAA,KAAkB,eACxD,GAAA,KAAQ,MAAA,IAAa,OAAO,GAAA,KAAQ,SAAA,CAAA;AAEzC;AAMO,SAAS,mBACd,IAAA,EACe;AACf,EAAA,MAAM,MAAM,IAAA,CAAK,gBAAA;AACjB,EAAA,IAAI,OAAO,QAAQ,QAAA,IAAY,CAAC,SAAS,IAAA,CAAK,GAAG,GAAG,OAAO,IAAA;AAC3D,EAAA,IAAI,KAAK,gBAAA,KAAqB,KAAA,IAAS,CAAC,sBAAA,CAAuB,GAAG,CAAA,EAAG;AACnE,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,GAAA;AACT;AAMA,IAAM,QAAA,mBAAuC,IAAI,GAAA,CAAmB,CAAC,IAAI,CAAC,CAAA;AAGnE,SAAS,2BAA2B,MAAA,EAAgC;AACzE,EAAA,OAAO,QAAA,CAAS,IAAI,MAAM,CAAA;AAC5B","file":"chunk-3AIAJ2L4.js","sourcesContent":["/**\n * BOFF-9797. The small part of the live avatar that the panel itself needs, whether or not it is ever opened: what a\n * host's `avatar.live` is, whether the live avatar can run on this page at all, and where its requests go.\n *\n * Everything else (the view, its state machine, the requests, the words, the bot check) is a separate chunk that a\n * site only downloads when its visitor first opens the Avatar view (see `explore-avatar-live.tsx`). That is why this\n * file is separate and kept to a few lines: it is the only part of the live avatar in the package root for a site that\n * does not pass `avatar.live`, and the part of it that decides, without loading anything, whether the chunk is wanted.\n * Types only, plus plain functions: nothing here imports a component, a context or a string table.\n */\nimport type { ExploreLocale } from \"./explore-i18n\";\nimport type { AvatarLiveModule } from \"../avatar-live/types\";\nimport type { UseExploreChatResult } from \"../hooks/use-explore-chat\";\n\n/**\n * BOFF-9797. A host's opt-in to the live avatar on its panel's Avatar tab. `site`, `load` and `manifestVersion` are\n * required; a config that is incomplete, or has an optional field of the wrong shape, leaves the tab as it was (and a\n * warning in the console).\n */\nexport interface ExplorePanelAvatarLive {\n /** The site, as the live avatar service knows it: `healthybowl`. */\n site: string;\n /**\n * Loads the live avatar's room module: `() => import('@burdenoff/website-sdk/avatar-live')`. Called only after the\n * visitor presses Start on the consent card, never on page load or on opening the tab. That entry needs the\n * package's optional peer dependency for media rooms (see the README).\n */\n load: () => Promise<AvatarLiveModule>;\n /**\n * The site's Cloudflare Turnstile site key, for the bot check that runs when the visitor presses Start. Used only when\n * the server says it checks for bots (its availability's `botCheck`, contract v1.2), or says nothing of it (a server\n * older than v1.2, which always checks): such a server's live avatar then needs a key, and without one the tab stays\n * as it was. A server that runs no bot check needs none, and no Cloudflare script is loaded for it, key or not.\n */\n turnstileSiteKey?: string;\n /**\n * Whether `turnstileSiteKey` may be one of Cloudflare's test keys (`1x00000000000000000000AA` and keys of their\n * shape). `websiteAvatarLive` sets it: true on alpha only, false everywhere else, so a production page never runs a\n * test widget. Unset (a config made by hand): any key of a valid shape, as before.\n */\n allowTestSiteKey?: boolean;\n /** The version of the suggested-question list the panel shows (its `examplePrompts`), such as `hb-en-1`. */\n manifestVersion: string;\n /**\n * End a session nobody is attending to (BOFF-9797 stage A). A session keeps playing behind the Chat tab and on a\n * hidden page, so the answer under way is heard to its end; with this set, out of sight it also ends:\n *\n * - **once its answer has played out**, at once: the idle tail after an answer runs only while the Avatar view is in\n * sight (the shared lifecycle rule; see `AvatarLiveView`'s `attend`);\n * - **when the browser holds its sound back** (autoplay refused, or the audio context suspended), after a short grace:\n * the \"Tap to turn on sound\" button that would let it play is out of sight, so nobody hears it.\n *\n * Both end it with reason `user`. Unset or false: such a session plays on to the end the server planned for it, as\n * before.\n */\n endUnattended?: boolean;\n /**\n * Offer a mic in the Avatar tab's own question box (BOFF-9797 Stage C): tap to start, tap to stop, up to thirty\n * seconds, the text into the box for the visitor to correct and Send (nothing is sent by itself). Offered only where\n * the server's availability answer also offers one, and the server's offer decides how: the browser's own speech\n * recognition under `mic: {mode: \"browser\"}` (contract v1.6, the avatar service's `AVATAR_WEB_MIC`; not in Firefox\n * or Brave, and only under consent words that describe it), or the gateway's speech-to-text stream under `stt` (while\n * the gateway's website speech-to-text is on). Only where the box takes a question, after a mic notice of its own on\n * the first tap. The mic's code is a chunk of its own, loaded the first time it is used. Unset or false: no mic, as\n * before; set, a server that offers no mic still shows none.\n */\n mic?: boolean;\n}\n\n/**\n * What the live avatar reads of the panel's conversation: the transcript, whether it is read-only and the token, and\n * `reset` (the chat's own New chat) for its New chat button where the conversation can never be read. Where the server\n * reads typed questions too (contract v1.3), the Avatar tab's own question box asks through the same conversation:\n * `send` (with `surface: \"AVATAR\"`), and `canSend`, `phase`, `activity` and `catalog` to say when it can and what the\n * answer is doing, and `resent` to follow a question asked there that Chat's Retry sent again.\n */\nexport type AvatarConversation = Pick<\n UseExploreChatResult,\n | \"messages\"\n | \"isSharedView\"\n | \"getConversationToken\"\n | \"reset\"\n | \"send\"\n | \"canSend\"\n | \"phase\"\n | \"activity\"\n | \"catalog\"\n | \"resent\"\n>;\n\n/** The web branch's routes, under the gateway's origin. */\nexport const AVATAR_WEB_API_PATH = \"/api/web-avatar/v1\";\n\nconst SITE = /^[a-z][a-z0-9-]{1,31}$/;\nconst VERSION = /^[A-Za-z0-9._-]{1,32}$/;\nconst SITE_KEY = /^[A-Za-z0-9_-]{1,128}$/;\n/**\n * The shape of Cloudflare's dummy site keys: a digit, `x`, a run of zeros and two letters (`1x00000000000000000000AA`,\n * `2x00000000000000000000AB`, `3x00000000000000000000FF`, …). Also catches an all-zero `0x…` placeholder.\n */\nconst TEST_SITE_KEY = /^\\dx0{16,}[A-Za-z]{2}$/;\n/**\n * A real-looking site key. Cloudflare documents no format for real keys; every key it issues starts `0x` (in practice\n * `0x4AAAAAAA…`, about 24 characters), in letters, digits, `_` and `-`. The length is kept loose (18 to 64 in all) so a\n * longer key Cloudflare might issue later still passes, and the charset matches what the panel accepts.\n */\nconst REAL_SITE_KEY = /^0x[A-Za-z0-9_-]{16,62}$/;\nconst LOOPBACK_HOSTS = new Set([\"localhost\", \"127.0.0.1\", \"[::1]\"]);\n\n/** A site slug the contract accepts (`healthybowl`). */\nexport function isAvatarSite(value: string): boolean {\n return SITE.test(value);\n}\n\n/** A consent or manifest version the contract accepts (`hb-en-1`). */\nexport function isAvatarVersion(value: string): boolean {\n return VERSION.test(value);\n}\n\n/**\n * The web branch's base URL on the SDK's configured gateway: the gateway URL's origin, plus\n * {@link AVATAR_WEB_API_PATH}. Null for anything that is not an `https:` URL (or `http:` on this machine, for local\n * development).\n */\nexport function avatarApiBase(gatewayUrl: string | undefined): string | null {\n if (!gatewayUrl) return null;\n let url: URL;\n try {\n url = new URL(gatewayUrl);\n } catch {\n return null;\n }\n const local =\n url.protocol === \"http:\" && LOOPBACK_HOSTS.has(url.hostname.toLowerCase());\n if (url.protocol !== \"https:\" && !local) return null;\n return `${url.origin}${AVATAR_WEB_API_PATH}`;\n}\n\n/** A real-looking Turnstile site key: `0x…`, and not of the shape of Cloudflare's test keys. */\nexport function isRealTurnstileSiteKey(key: string): boolean {\n return REAL_SITE_KEY.test(key) && !TEST_SITE_KEY.test(key);\n}\n\n/**\n * Whether a host's `avatar.live` has everything the live avatar needs, in the shapes the contract accepts. The site\n * key is optional (an empty one is none), and checked only when it is there.\n */\nexport function liveConfigComplete(live: ExplorePanelAvatarLive): boolean {\n const key: unknown = live.turnstileSiteKey;\n const allowTest: unknown = live.allowTestSiteKey;\n const endUnattended: unknown = live.endUnattended;\n const mic: unknown = live.mic;\n return (\n typeof live.load === \"function\" &&\n typeof live.site === \"string\" &&\n isAvatarSite(live.site) &&\n typeof live.manifestVersion === \"string\" &&\n isAvatarVersion(live.manifestVersion) &&\n (key === undefined ||\n key === \"\" ||\n (typeof key === \"string\" && SITE_KEY.test(key))) &&\n (allowTest === undefined || typeof allowTest === \"boolean\") &&\n (endUnattended === undefined || typeof endUnattended === \"boolean\") &&\n (mic === undefined || typeof mic === \"boolean\")\n );\n}\n\n/**\n * The site key a bot check at Start may use, or null when there is none: no key, one of no valid shape, or one of\n * Cloudflare's test keys where `allowTestSiteKey` is false.\n */\nexport function turnstileSiteKeyOf(\n live: ExplorePanelAvatarLive,\n): string | null {\n const key = live.turnstileSiteKey;\n if (typeof key !== \"string\" || !SITE_KEY.test(key)) return null;\n if (live.allowTestSiteKey === false && !isRealTurnstileSiteKey(key)) {\n return null;\n }\n return key;\n}\n\n/**\n * The locales whose live-avatar strings have been reviewed. The live avatar runs only in these; see\n * `explore-avatar-i18n.ts`. English only, until a named reviewer signs off on another.\n */\nconst REVIEWED: ReadonlySet<ExploreLocale> = new Set<ExploreLocale>([\"en\"]);\n\n/** Whether the live avatar may run in `locale`: its strings have been reviewed. */\nexport function isAvatarLiveLocaleReviewed(locale: ExploreLocale): boolean {\n return REVIEWED.has(locale);\n}\n"]}
@@ -48,5 +48,5 @@ function isAvatarLiveLocaleReviewed(locale) {
48
48
  }
49
49
 
50
50
  export { avatarApiBase, isAvatarLiveLocaleReviewed, isAvatarSite, isAvatarVersion, isRealTurnstileSiteKey, liveConfigComplete, turnstileSiteKeyOf };
51
- //# sourceMappingURL=chunk-MVNN6LLO.mjs.map
52
- //# sourceMappingURL=chunk-MVNN6LLO.mjs.map
51
+ //# sourceMappingURL=chunk-JGU6JW4N.mjs.map
52
+ //# sourceMappingURL=chunk-JGU6JW4N.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/explore-avatar-live-config.ts"],"names":[],"mappings":";AA2FO,IAAM,mBAAA,GAAsB,oBAAA;AAEnC,IAAM,IAAA,GAAO,wBAAA;AACb,IAAM,OAAA,GAAU,wBAAA;AAChB,IAAM,QAAA,GAAW,wBAAA;AAKjB,IAAM,aAAA,GAAgB,wBAAA;AAMtB,IAAM,aAAA,GAAgB,0BAAA;AACtB,IAAM,iCAAiB,IAAI,GAAA,CAAI,CAAC,WAAA,EAAa,WAAA,EAAa,OAAO,CAAC,CAAA;AAG3D,SAAS,aAAa,KAAA,EAAwB;AACnD,EAAA,OAAO,IAAA,CAAK,KAAK,KAAK,CAAA;AACxB;AAGO,SAAS,gBAAgB,KAAA,EAAwB;AACtD,EAAA,OAAO,OAAA,CAAQ,KAAK,KAAK,CAAA;AAC3B;AAOO,SAAS,cAAc,UAAA,EAA+C;AAC3E,EAAA,IAAI,CAAC,YAAY,OAAO,IAAA;AACxB,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,IAAI,IAAI,UAAU,CAAA;AAAA,EAC1B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,KAAA,GACJ,IAAI,QAAA,KAAa,OAAA,IAAW,eAAe,GAAA,CAAI,GAAA,CAAI,QAAA,CAAS,WAAA,EAAa,CAAA;AAC3E,EAAA,IAAI,GAAA,CAAI,QAAA,KAAa,QAAA,IAAY,CAAC,OAAO,OAAO,IAAA;AAChD,EAAA,OAAO,CAAA,EAAG,GAAA,CAAI,MAAM,CAAA,EAAG,mBAAmB,CAAA,CAAA;AAC5C;AAGO,SAAS,uBAAuB,GAAA,EAAsB;AAC3D,EAAA,OAAO,cAAc,IAAA,CAAK,GAAG,KAAK,CAAC,aAAA,CAAc,KAAK,GAAG,CAAA;AAC3D;AAMO,SAAS,mBAAmB,IAAA,EAAuC;AACxE,EAAA,MAAM,MAAe,IAAA,CAAK,gBAAA;AAC1B,EAAA,MAAM,YAAqB,IAAA,CAAK,gBAAA;AAChC,EAAA,MAAM,gBAAyB,IAAA,CAAK,aAAA;AACpC,EAAA,MAAM,MAAe,IAAA,CAAK,GAAA;AAC1B,EAAA,OACE,OAAO,KAAK,IAAA,KAAS,UAAA,IACrB,OAAO,IAAA,CAAK,IAAA,KAAS,YACrB,YAAA,CAAa,IAAA,CAAK,IAAI,CAAA,IACtB,OAAO,KAAK,eAAA,KAAoB,QAAA,IAChC,gBAAgB,IAAA,CAAK,eAAe,MACnC,GAAA,KAAQ,MAAA,IACP,QAAQ,EAAA,IACP,OAAO,QAAQ,QAAA,IAAY,QAAA,CAAS,KAAK,GAAG,CAAA,CAAA,KAC9C,cAAc,MAAA,IAAa,OAAO,cAAc,SAAA,CAAA,KAChD,aAAA,KAAkB,UAAa,OAAO,aAAA,KAAkB,eACxD,GAAA,KAAQ,MAAA,IAAa,OAAO,GAAA,KAAQ,SAAA,CAAA;AAEzC;AAMO,SAAS,mBACd,IAAA,EACe;AACf,EAAA,MAAM,MAAM,IAAA,CAAK,gBAAA;AACjB,EAAA,IAAI,OAAO,QAAQ,QAAA,IAAY,CAAC,SAAS,IAAA,CAAK,GAAG,GAAG,OAAO,IAAA;AAC3D,EAAA,IAAI,KAAK,gBAAA,KAAqB,KAAA,IAAS,CAAC,sBAAA,CAAuB,GAAG,CAAA,EAAG;AACnE,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,GAAA;AACT;AAMA,IAAM,QAAA,mBAAuC,IAAI,GAAA,CAAmB,CAAC,IAAI,CAAC,CAAA;AAGnE,SAAS,2BAA2B,MAAA,EAAgC;AACzE,EAAA,OAAO,QAAA,CAAS,IAAI,MAAM,CAAA;AAC5B","file":"chunk-JGU6JW4N.mjs","sourcesContent":["/**\n * BOFF-9797. The small part of the live avatar that the panel itself needs, whether or not it is ever opened: what a\n * host's `avatar.live` is, whether the live avatar can run on this page at all, and where its requests go.\n *\n * Everything else (the view, its state machine, the requests, the words, the bot check) is a separate chunk that a\n * site only downloads when its visitor first opens the Avatar view (see `explore-avatar-live.tsx`). That is why this\n * file is separate and kept to a few lines: it is the only part of the live avatar in the package root for a site that\n * does not pass `avatar.live`, and the part of it that decides, without loading anything, whether the chunk is wanted.\n * Types only, plus plain functions: nothing here imports a component, a context or a string table.\n */\nimport type { ExploreLocale } from \"./explore-i18n\";\nimport type { AvatarLiveModule } from \"../avatar-live/types\";\nimport type { UseExploreChatResult } from \"../hooks/use-explore-chat\";\n\n/**\n * BOFF-9797. A host's opt-in to the live avatar on its panel's Avatar tab. `site`, `load` and `manifestVersion` are\n * required; a config that is incomplete, or has an optional field of the wrong shape, leaves the tab as it was (and a\n * warning in the console).\n */\nexport interface ExplorePanelAvatarLive {\n /** The site, as the live avatar service knows it: `healthybowl`. */\n site: string;\n /**\n * Loads the live avatar's room module: `() => import('@burdenoff/website-sdk/avatar-live')`. Called only after the\n * visitor presses Start on the consent card, never on page load or on opening the tab. That entry needs the\n * package's optional peer dependency for media rooms (see the README).\n */\n load: () => Promise<AvatarLiveModule>;\n /**\n * The site's Cloudflare Turnstile site key, for the bot check that runs when the visitor presses Start. Used only when\n * the server says it checks for bots (its availability's `botCheck`, contract v1.2), or says nothing of it (a server\n * older than v1.2, which always checks): such a server's live avatar then needs a key, and without one the tab stays\n * as it was. A server that runs no bot check needs none, and no Cloudflare script is loaded for it, key or not.\n */\n turnstileSiteKey?: string;\n /**\n * Whether `turnstileSiteKey` may be one of Cloudflare's test keys (`1x00000000000000000000AA` and keys of their\n * shape). `websiteAvatarLive` sets it: true on alpha only, false everywhere else, so a production page never runs a\n * test widget. Unset (a config made by hand): any key of a valid shape, as before.\n */\n allowTestSiteKey?: boolean;\n /** The version of the suggested-question list the panel shows (its `examplePrompts`), such as `hb-en-1`. */\n manifestVersion: string;\n /**\n * End a session nobody is attending to (BOFF-9797 stage A). A session keeps playing behind the Chat tab and on a\n * hidden page, so the answer under way is heard to its end; with this set, out of sight it also ends:\n *\n * - **once its answer has played out**, at once: the idle tail after an answer runs only while the Avatar view is in\n * sight (the shared lifecycle rule; see `AvatarLiveView`'s `attend`);\n * - **when the browser holds its sound back** (autoplay refused, or the audio context suspended), after a short grace:\n * the \"Tap to turn on sound\" button that would let it play is out of sight, so nobody hears it.\n *\n * Both end it with reason `user`. Unset or false: such a session plays on to the end the server planned for it, as\n * before.\n */\n endUnattended?: boolean;\n /**\n * Offer a mic in the Avatar tab's own question box (BOFF-9797 Stage C): tap to start, tap to stop, up to thirty\n * seconds, the text into the box for the visitor to correct and Send (nothing is sent by itself). Offered only where\n * the server's availability answer also offers one, and the server's offer decides how: the browser's own speech\n * recognition under `mic: {mode: \"browser\"}` (contract v1.6, the avatar service's `AVATAR_WEB_MIC`; not in Firefox\n * or Brave, and only under consent words that describe it), or the gateway's speech-to-text stream under `stt` (while\n * the gateway's website speech-to-text is on). Only where the box takes a question, after a mic notice of its own on\n * the first tap. The mic's code is a chunk of its own, loaded the first time it is used. Unset or false: no mic, as\n * before; set, a server that offers no mic still shows none.\n */\n mic?: boolean;\n}\n\n/**\n * What the live avatar reads of the panel's conversation: the transcript, whether it is read-only and the token, and\n * `reset` (the chat's own New chat) for its New chat button where the conversation can never be read. Where the server\n * reads typed questions too (contract v1.3), the Avatar tab's own question box asks through the same conversation:\n * `send` (with `surface: \"AVATAR\"`), and `canSend`, `phase`, `activity` and `catalog` to say when it can and what the\n * answer is doing, and `resent` to follow a question asked there that Chat's Retry sent again.\n */\nexport type AvatarConversation = Pick<\n UseExploreChatResult,\n | \"messages\"\n | \"isSharedView\"\n | \"getConversationToken\"\n | \"reset\"\n | \"send\"\n | \"canSend\"\n | \"phase\"\n | \"activity\"\n | \"catalog\"\n | \"resent\"\n>;\n\n/** The web branch's routes, under the gateway's origin. */\nexport const AVATAR_WEB_API_PATH = \"/api/web-avatar/v1\";\n\nconst SITE = /^[a-z][a-z0-9-]{1,31}$/;\nconst VERSION = /^[A-Za-z0-9._-]{1,32}$/;\nconst SITE_KEY = /^[A-Za-z0-9_-]{1,128}$/;\n/**\n * The shape of Cloudflare's dummy site keys: a digit, `x`, a run of zeros and two letters (`1x00000000000000000000AA`,\n * `2x00000000000000000000AB`, `3x00000000000000000000FF`, …). Also catches an all-zero `0x…` placeholder.\n */\nconst TEST_SITE_KEY = /^\\dx0{16,}[A-Za-z]{2}$/;\n/**\n * A real-looking site key. Cloudflare documents no format for real keys; every key it issues starts `0x` (in practice\n * `0x4AAAAAAA…`, about 24 characters), in letters, digits, `_` and `-`. The length is kept loose (18 to 64 in all) so a\n * longer key Cloudflare might issue later still passes, and the charset matches what the panel accepts.\n */\nconst REAL_SITE_KEY = /^0x[A-Za-z0-9_-]{16,62}$/;\nconst LOOPBACK_HOSTS = new Set([\"localhost\", \"127.0.0.1\", \"[::1]\"]);\n\n/** A site slug the contract accepts (`healthybowl`). */\nexport function isAvatarSite(value: string): boolean {\n return SITE.test(value);\n}\n\n/** A consent or manifest version the contract accepts (`hb-en-1`). */\nexport function isAvatarVersion(value: string): boolean {\n return VERSION.test(value);\n}\n\n/**\n * The web branch's base URL on the SDK's configured gateway: the gateway URL's origin, plus\n * {@link AVATAR_WEB_API_PATH}. Null for anything that is not an `https:` URL (or `http:` on this machine, for local\n * development).\n */\nexport function avatarApiBase(gatewayUrl: string | undefined): string | null {\n if (!gatewayUrl) return null;\n let url: URL;\n try {\n url = new URL(gatewayUrl);\n } catch {\n return null;\n }\n const local =\n url.protocol === \"http:\" && LOOPBACK_HOSTS.has(url.hostname.toLowerCase());\n if (url.protocol !== \"https:\" && !local) return null;\n return `${url.origin}${AVATAR_WEB_API_PATH}`;\n}\n\n/** A real-looking Turnstile site key: `0x…`, and not of the shape of Cloudflare's test keys. */\nexport function isRealTurnstileSiteKey(key: string): boolean {\n return REAL_SITE_KEY.test(key) && !TEST_SITE_KEY.test(key);\n}\n\n/**\n * Whether a host's `avatar.live` has everything the live avatar needs, in the shapes the contract accepts. The site\n * key is optional (an empty one is none), and checked only when it is there.\n */\nexport function liveConfigComplete(live: ExplorePanelAvatarLive): boolean {\n const key: unknown = live.turnstileSiteKey;\n const allowTest: unknown = live.allowTestSiteKey;\n const endUnattended: unknown = live.endUnattended;\n const mic: unknown = live.mic;\n return (\n typeof live.load === \"function\" &&\n typeof live.site === \"string\" &&\n isAvatarSite(live.site) &&\n typeof live.manifestVersion === \"string\" &&\n isAvatarVersion(live.manifestVersion) &&\n (key === undefined ||\n key === \"\" ||\n (typeof key === \"string\" && SITE_KEY.test(key))) &&\n (allowTest === undefined || typeof allowTest === \"boolean\") &&\n (endUnattended === undefined || typeof endUnattended === \"boolean\") &&\n (mic === undefined || typeof mic === \"boolean\")\n );\n}\n\n/**\n * The site key a bot check at Start may use, or null when there is none: no key, one of no valid shape, or one of\n * Cloudflare's test keys where `allowTestSiteKey` is false.\n */\nexport function turnstileSiteKeyOf(\n live: ExplorePanelAvatarLive,\n): string | null {\n const key = live.turnstileSiteKey;\n if (typeof key !== \"string\" || !SITE_KEY.test(key)) return null;\n if (live.allowTestSiteKey === false && !isRealTurnstileSiteKey(key)) {\n return null;\n }\n return key;\n}\n\n/**\n * The locales whose live-avatar strings have been reviewed. The live avatar runs only in these; see\n * `explore-avatar-i18n.ts`. English only, until a named reviewer signs off on another.\n */\nconst REVIEWED: ReadonlySet<ExploreLocale> = new Set<ExploreLocale>([\"en\"]);\n\n/** Whether the live avatar may run in `locale`: its strings have been reviewed. */\nexport function isAvatarLiveLocaleReviewed(locale: ExploreLocale): boolean {\n return REVIEWED.has(locale);\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { A as AvatarLiveModule } from './types-CXqaLlNB.js';
1
+ import { A as AvatarLiveModule } from './types-CTUJNvQu.js';
2
2
  import { h as UseExploreChatResult } from './use-explore-chat-B3dOOvJN.js';
3
3
 
4
4
  /**
@@ -304,9 +304,12 @@ interface ExplorePanelAvatarLive {
304
304
  /**
305
305
  * Offer a mic in the Avatar tab's own question box (BOFF-9797 Stage C): tap to start, tap to stop, up to thirty
306
306
  * seconds, the text into the box for the visitor to correct and Send (nothing is sent by itself). Offered only where
307
- * the server's availability answer also carries a mic offer (`stt`, while the gateway's website speech-to-text is on)
308
- * and the box takes a question, after a mic notice of its own on the first tap. The mic's code is a chunk of its own,
309
- * loaded the first time it is used. Unset or false: no mic, as before.
307
+ * the server's availability answer also offers one, and the server's offer decides how: the browser's own speech
308
+ * recognition under `mic: {mode: "browser"}` (contract v1.6, the avatar service's `AVATAR_WEB_MIC`; not in Firefox
309
+ * or Brave, and only under consent words that describe it), or the gateway's speech-to-text stream under `stt` (while
310
+ * the gateway's website speech-to-text is on). Only where the box takes a question, after a mic notice of its own on
311
+ * the first tap. The mic's code is a chunk of its own, loaded the first time it is used. Unset or false: no mic, as
312
+ * before; set, a server that offers no mic still shows none.
310
313
  */
311
314
  mic?: boolean;
312
315
  }
@@ -1,4 +1,4 @@
1
- import { A as AvatarLiveModule } from './types-CXqaLlNB.mjs';
1
+ import { A as AvatarLiveModule } from './types-CTUJNvQu.mjs';
2
2
  import { h as UseExploreChatResult } from './use-explore-chat-CbfohA9O.mjs';
3
3
 
4
4
  /**
@@ -304,9 +304,12 @@ interface ExplorePanelAvatarLive {
304
304
  /**
305
305
  * Offer a mic in the Avatar tab's own question box (BOFF-9797 Stage C): tap to start, tap to stop, up to thirty
306
306
  * seconds, the text into the box for the visitor to correct and Send (nothing is sent by itself). Offered only where
307
- * the server's availability answer also carries a mic offer (`stt`, while the gateway's website speech-to-text is on)
308
- * and the box takes a question, after a mic notice of its own on the first tap. The mic's code is a chunk of its own,
309
- * loaded the first time it is used. Unset or false: no mic, as before.
307
+ * the server's availability answer also offers one, and the server's offer decides how: the browser's own speech
308
+ * recognition under `mic: {mode: "browser"}` (contract v1.6, the avatar service's `AVATAR_WEB_MIC`; not in Firefox
309
+ * or Brave, and only under consent words that describe it), or the gateway's speech-to-text stream under `stt` (while
310
+ * the gateway's website speech-to-text is on). Only where the box takes a question, after a mic notice of its own on
311
+ * the first tap. The mic's code is a chunk of its own, loaded the first time it is used. Unset or false: no mic, as
312
+ * before; set, a server that offers no mic still shows none.
310
313
  */
311
314
  mic?: boolean;
312
315
  }