@burdenoff/website-sdk 2026.1104.4 → 2026.1105.1

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.
@@ -0,0 +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"]}
@@ -31,7 +31,8 @@ function liveConfigComplete(live) {
31
31
  const key = live.turnstileSiteKey;
32
32
  const allowTest = live.allowTestSiteKey;
33
33
  const endUnattended = live.endUnattended;
34
- return typeof live.load === "function" && typeof live.site === "string" && isAvatarSite(live.site) && typeof live.manifestVersion === "string" && isAvatarVersion(live.manifestVersion) && (key === void 0 || key === "" || typeof key === "string" && SITE_KEY.test(key)) && (allowTest === void 0 || typeof allowTest === "boolean") && (endUnattended === void 0 || typeof endUnattended === "boolean");
34
+ const mic = live.mic;
35
+ return typeof live.load === "function" && typeof live.site === "string" && isAvatarSite(live.site) && typeof live.manifestVersion === "string" && isAvatarVersion(live.manifestVersion) && (key === void 0 || key === "" || typeof key === "string" && SITE_KEY.test(key)) && (allowTest === void 0 || typeof allowTest === "boolean") && (endUnattended === void 0 || typeof endUnattended === "boolean") && (mic === void 0 || typeof mic === "boolean");
35
36
  }
36
37
  function turnstileSiteKeyOf(live) {
37
38
  const key = live.turnstileSiteKey;
@@ -47,5 +48,5 @@ function isAvatarLiveLocaleReviewed(locale) {
47
48
  }
48
49
 
49
50
  export { avatarApiBase, isAvatarLiveLocaleReviewed, isAvatarSite, isAvatarVersion, isRealTurnstileSiteKey, liveConfigComplete, turnstileSiteKeyOf };
50
- //# sourceMappingURL=chunk-7MSB3EUI.mjs.map
51
- //# sourceMappingURL=chunk-7MSB3EUI.mjs.map
51
+ //# sourceMappingURL=chunk-MVNN6LLO.mjs.map
52
+ //# sourceMappingURL=chunk-MVNN6LLO.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/explore-avatar-live-config.ts"],"names":[],"mappings":";AAwFO,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-MVNN6LLO.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 carries a mic offer (`stt`, while the gateway's website speech-to-text is on)\n * 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,\n * loaded the first time it is used. Unset or false: no mic, as before.\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"]}
@@ -33,7 +33,8 @@ function liveConfigComplete(live) {
33
33
  const key = live.turnstileSiteKey;
34
34
  const allowTest = live.allowTestSiteKey;
35
35
  const endUnattended = live.endUnattended;
36
- return typeof live.load === "function" && typeof live.site === "string" && isAvatarSite(live.site) && typeof live.manifestVersion === "string" && isAvatarVersion(live.manifestVersion) && (key === void 0 || key === "" || typeof key === "string" && SITE_KEY.test(key)) && (allowTest === void 0 || typeof allowTest === "boolean") && (endUnattended === void 0 || typeof endUnattended === "boolean");
36
+ const mic = live.mic;
37
+ return typeof live.load === "function" && typeof live.site === "string" && isAvatarSite(live.site) && typeof live.manifestVersion === "string" && isAvatarVersion(live.manifestVersion) && (key === void 0 || key === "" || typeof key === "string" && SITE_KEY.test(key)) && (allowTest === void 0 || typeof allowTest === "boolean") && (endUnattended === void 0 || typeof endUnattended === "boolean") && (mic === void 0 || typeof mic === "boolean");
37
38
  }
38
39
  function turnstileSiteKeyOf(live) {
39
40
  const key = live.turnstileSiteKey;
@@ -55,5 +56,5 @@ exports.isAvatarVersion = isAvatarVersion;
55
56
  exports.isRealTurnstileSiteKey = isRealTurnstileSiteKey;
56
57
  exports.liveConfigComplete = liveConfigComplete;
57
58
  exports.turnstileSiteKeyOf = turnstileSiteKeyOf;
58
- //# sourceMappingURL=chunk-WSEQ2I6I.js.map
59
- //# sourceMappingURL=chunk-WSEQ2I6I.js.map
59
+ //# sourceMappingURL=chunk-XIZE37IB.js.map
60
+ //# sourceMappingURL=chunk-XIZE37IB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/explore-avatar-live-config.ts"],"names":[],"mappings":";;;AAwFO,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-XIZE37IB.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 carries a mic offer (`stt`, while the gateway's website speech-to-text is on)\n * 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,\n * loaded the first time it is used. Unset or false: no mic, as before.\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"]}
@@ -301,6 +301,14 @@ interface ExplorePanelAvatarLive {
301
301
  * before.
302
302
  */
303
303
  endUnattended?: boolean;
304
+ /**
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
+ * 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.
310
+ */
311
+ mic?: boolean;
304
312
  }
305
313
  /**
306
314
  * What the live avatar reads of the panel's conversation: the transcript, whether it is read-only and the token, and
@@ -301,6 +301,14 @@ interface ExplorePanelAvatarLive {
301
301
  * before.
302
302
  */
303
303
  endUnattended?: boolean;
304
+ /**
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
+ * 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.
310
+ */
311
+ mic?: boolean;
304
312
  }
305
313
  /**
306
314
  * What the live avatar reads of the panel's conversation: the transcript, whether it is read-only and the token, and
package/dist/index.d.mts CHANGED
@@ -18,8 +18,8 @@ export { LaunchCountdown, LaunchCountdownProps } from './components/launch-count
18
18
  export { ProblemSolved, ProblemsSolvedSection, ProblemsSolvedSectionProps } from './components/problems-solved.mjs';
19
19
  export { DetectedPlatform, ElectronDownloadLink, ElectronDownloadLinkProps, detectElectronPlatform } from './components/electron-download.mjs';
20
20
  import { Components } from 'react-markdown';
21
- import { a as ExploreLocale, E as ExplorePanelAvatarLive } from './explore-avatar-live-config-B6_p0q1c.mjs';
22
- export { b as EXPLORE_LOCALES, c as ExploreStrings, s as speechLocaleOf } from './explore-avatar-live-config-B6_p0q1c.mjs';
21
+ import { a as ExploreLocale, E as ExplorePanelAvatarLive } from './explore-avatar-live-config-OO0hvQCK.mjs';
22
+ export { b as EXPLORE_LOCALES, c as ExploreStrings, s as speechLocaleOf } from './explore-avatar-live-config-OO0hvQCK.mjs';
23
23
  import { A as AnswerRendererStrings, E as ExploreScope } from './explore-ei8uoko9.mjs';
24
24
  export { a as EXPLORE_PREFILL_MAX_LENGTH, b as ExploreAnswerBody, c as ExploreAnswerBodyProps, d as ExploreAnswerStyles, e as ExplorePage, f as ExplorePageProps, g as answerPlainText, h as answerSpeechText, i as exploreQuestionHref, j as inlineImageOrigins, k as isInlineImageAllowed, l as isInlineVideoAllowed, p as productSlugsByOrigin } from './explore-ei8uoko9.mjs';
25
25
  export { ExploreCta, ExploreCtaProps } from './components/explore-cta.mjs';
@@ -854,13 +854,18 @@ interface WebsiteAvatarLiveOptions {
854
854
  * plays on to the end the server planned for it.
855
855
  */
856
856
  endUnattended?: boolean;
857
+ /**
858
+ * `mic` on the live config (Stage C): a mic in the Avatar tab's own question box, where the server offers one too.
859
+ * Default unset: no mic.
860
+ */
861
+ mic?: boolean;
857
862
  }
858
863
  /** The `avatar.live` prop for this build, or `undefined` for the still picture only. */
859
- declare function websiteAvatarLive({ deployEnv, siteKey, site, manifestVersion, load, enabled, endUnattended, }: WebsiteAvatarLiveOptions): ExplorePanelAvatarLive | undefined;
864
+ declare function websiteAvatarLive({ deployEnv, siteKey, site, manifestVersion, load, enabled, endUnattended, mic, }: WebsiteAvatarLiveOptions): ExplorePanelAvatarLive | undefined;
860
865
 
861
866
  declare const buttonVariants: (props?: ({
862
867
  variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
863
- size?: "icon" | "default" | "sm" | "lg" | null | undefined;
868
+ size?: "default" | "sm" | "lg" | "icon" | null | undefined;
864
869
  } & class_variance_authority_types.ClassProp) | undefined) => string;
865
870
  interface ButtonProps extends react.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
866
871
  asChild?: boolean;
package/dist/index.d.ts CHANGED
@@ -18,8 +18,8 @@ export { LaunchCountdown, LaunchCountdownProps } from './components/launch-count
18
18
  export { ProblemSolved, ProblemsSolvedSection, ProblemsSolvedSectionProps } from './components/problems-solved.js';
19
19
  export { DetectedPlatform, ElectronDownloadLink, ElectronDownloadLinkProps, detectElectronPlatform } from './components/electron-download.js';
20
20
  import { Components } from 'react-markdown';
21
- import { a as ExploreLocale, E as ExplorePanelAvatarLive } from './explore-avatar-live-config-DRpS-mqQ.js';
22
- export { b as EXPLORE_LOCALES, c as ExploreStrings, s as speechLocaleOf } from './explore-avatar-live-config-DRpS-mqQ.js';
21
+ import { a as ExploreLocale, E as ExplorePanelAvatarLive } from './explore-avatar-live-config-C-OwXNje.js';
22
+ export { b as EXPLORE_LOCALES, c as ExploreStrings, s as speechLocaleOf } from './explore-avatar-live-config-C-OwXNje.js';
23
23
  import { A as AnswerRendererStrings, E as ExploreScope } from './explore-Dfru4j4m.js';
24
24
  export { a as EXPLORE_PREFILL_MAX_LENGTH, b as ExploreAnswerBody, c as ExploreAnswerBodyProps, d as ExploreAnswerStyles, e as ExplorePage, f as ExplorePageProps, g as answerPlainText, h as answerSpeechText, i as exploreQuestionHref, j as inlineImageOrigins, k as isInlineImageAllowed, l as isInlineVideoAllowed, p as productSlugsByOrigin } from './explore-Dfru4j4m.js';
25
25
  export { ExploreCta, ExploreCtaProps } from './components/explore-cta.js';
@@ -854,13 +854,18 @@ interface WebsiteAvatarLiveOptions {
854
854
  * plays on to the end the server planned for it.
855
855
  */
856
856
  endUnattended?: boolean;
857
+ /**
858
+ * `mic` on the live config (Stage C): a mic in the Avatar tab's own question box, where the server offers one too.
859
+ * Default unset: no mic.
860
+ */
861
+ mic?: boolean;
857
862
  }
858
863
  /** The `avatar.live` prop for this build, or `undefined` for the still picture only. */
859
- declare function websiteAvatarLive({ deployEnv, siteKey, site, manifestVersion, load, enabled, endUnattended, }: WebsiteAvatarLiveOptions): ExplorePanelAvatarLive | undefined;
864
+ declare function websiteAvatarLive({ deployEnv, siteKey, site, manifestVersion, load, enabled, endUnattended, mic, }: WebsiteAvatarLiveOptions): ExplorePanelAvatarLive | undefined;
860
865
 
861
866
  declare const buttonVariants: (props?: ({
862
867
  variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
863
- size?: "icon" | "default" | "sm" | "lg" | null | undefined;
868
+ size?: "default" | "sm" | "lg" | "icon" | null | undefined;
864
869
  } & class_variance_authority_types.ClassProp) | undefined) => string;
865
870
  interface ButtonProps extends react.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
866
871
  asChild?: boolean;
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkWSEQ2I6I_js = require('./chunk-WSEQ2I6I.js');
3
+ var chunkXIZE37IB_js = require('./chunk-XIZE37IB.js');
4
4
  var chunk6KY2ZRVI_js = require('./chunk-6KY2ZRVI.js');
5
5
  require('./chunk-VRWZLGR7.js');
6
6
  var chunkQMA6U6AU_js = require('./chunk-QMA6U6AU.js');
@@ -3365,13 +3365,13 @@ function ExploreAvatarLive({
3365
3365
  () => suggestedQuestions(catalog, examplePrompts, pinnedSlug),
3366
3366
  [catalog, examplePrompts, pinnedSlug]
3367
3367
  );
3368
- const base = chunkWSEQ2I6I_js.avatarApiBase(config.gatewayUrl);
3368
+ const base = chunkXIZE37IB_js.avatarApiBase(config.gatewayUrl);
3369
3369
  const headers = react.useMemo(
3370
3370
  () => chunkJXLSTVBK_js.cfAccessHeaders(config.gatewayUrl, config.cfAccess),
3371
3371
  [config.gatewayUrl, config.cfAccess]
3372
3372
  );
3373
- const complete = chunkWSEQ2I6I_js.liveConfigComplete(live);
3374
- const off = !complete || base === null || conversation === null || conversation.isSharedView || !chunkWSEQ2I6I_js.isAvatarLiveLocaleReviewed(locale);
3373
+ const complete = chunkXIZE37IB_js.liveConfigComplete(live);
3374
+ const off = !complete || base === null || conversation === null || conversation.isSharedView || !chunkXIZE37IB_js.isAvatarLiveLocaleReviewed(locale);
3375
3375
  react.useEffect(() => {
3376
3376
  if (!complete) {
3377
3377
  console.warn(
@@ -4344,7 +4344,8 @@ function websiteAvatarLive({
4344
4344
  manifestVersion,
4345
4345
  load,
4346
4346
  enabled,
4347
- endUnattended
4347
+ endUnattended,
4348
+ mic
4348
4349
  }) {
4349
4350
  if (enabled === false) return void 0;
4350
4351
  const alpha = typeof deployEnv === "string" && deployEnv.trim().toLowerCase() === "alpha";
@@ -4354,11 +4355,12 @@ function websiteAvatarLive({
4354
4355
  manifestVersion,
4355
4356
  allowTestSiteKey: alpha,
4356
4357
  // Only when the site sets it: a site that does not gets the very config it got before.
4357
- ...endUnattended === void 0 ? {} : { endUnattended }
4358
+ ...endUnattended === void 0 ? {} : { endUnattended },
4359
+ ...mic === void 0 ? {} : { mic }
4358
4360
  };
4359
4361
  const key = typeof siteKey === "string" ? siteKey.trim() : "";
4360
4362
  if (key === "") return live;
4361
- const accepted = alpha ? key === ALPHA_TEST_SITE_KEY || chunkWSEQ2I6I_js.isRealTurnstileSiteKey(key) : chunkWSEQ2I6I_js.isRealTurnstileSiteKey(key);
4363
+ const accepted = alpha ? key === ALPHA_TEST_SITE_KEY || chunkXIZE37IB_js.isRealTurnstileSiteKey(key) : chunkXIZE37IB_js.isRealTurnstileSiteKey(key);
4362
4364
  if (!accepted) return void 0;
4363
4365
  return { ...live, turnstileSiteKey: key };
4364
4366
  }