@liforma/client 0.4.8 → 0.4.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/dist/next/index.js +516 -185
- package/dist/next/index.js.map +1 -1
- package/dist/next/next/createLiformaSessionRouteHandler.d.ts +4 -0
- package/dist/next/next/createLiformaSessionRouteHandler.d.ts.map +1 -1
- package/dist/next/v2/api/mintPublicSession.d.ts +1 -0
- package/dist/next/v2/api/mintPublicSession.d.ts.map +1 -1
- package/dist/next/v2/api/sessionEndpointRequest.d.ts +4 -0
- package/dist/next/v2/api/sessionEndpointRequest.d.ts.map +1 -1
- package/dist/next/v2/embed/iframeHost.d.ts +13 -1
- package/dist/next/v2/embed/iframeHost.d.ts.map +1 -1
- package/dist/next/v2/embed/protocol.d.ts +35 -1
- package/dist/next/v2/embed/protocol.d.ts.map +1 -1
- package/dist/next/v2/experience.d.ts +17 -2
- package/dist/next/v2/experience.d.ts.map +1 -1
- package/dist/next/v2/experienceEvents.d.ts +3 -1
- package/dist/next/v2/experienceEvents.d.ts.map +1 -1
- package/dist/next/v2/sdkRelease.d.ts +3 -0
- package/dist/next/v2/sdkRelease.d.ts.map +1 -0
- package/dist/next/v2/types/sessionInteraction.d.ts +29 -0
- package/dist/next/v2/types/sessionInteraction.d.ts.map +1 -1
- package/dist/next/v2/types/sessionManifest.d.ts +1 -0
- package/dist/next/v2/types/sessionManifest.d.ts.map +1 -1
- package/dist/next/widget/mountExperienceWidget.d.ts.map +1 -1
- package/dist/next/widget/types.d.ts +5 -0
- package/dist/next/widget/types.d.ts.map +1 -1
- package/dist/npm/index.js +542 -225
- package/dist/npm/index.js.map +1 -1
- package/dist/npm/svelte/experienceLoadError.d.ts.map +1 -1
- package/dist/npm/svelte/experienceLoadErrorStyles.d.ts +1 -1
- package/dist/npm/svelte/experienceLoadErrorStyles.d.ts.map +1 -1
- package/dist/npm/v2/api/mintPublicSession.d.ts +1 -0
- package/dist/npm/v2/api/mintPublicSession.d.ts.map +1 -1
- package/dist/npm/v2/api/sessionEndpointRequest.d.ts +4 -0
- package/dist/npm/v2/api/sessionEndpointRequest.d.ts.map +1 -1
- package/dist/npm/v2/embed/iframeHost.d.ts +13 -1
- package/dist/npm/v2/embed/iframeHost.d.ts.map +1 -1
- package/dist/npm/v2/embed/protocol.d.ts +35 -1
- package/dist/npm/v2/embed/protocol.d.ts.map +1 -1
- package/dist/npm/v2/experience.d.ts +17 -2
- package/dist/npm/v2/experience.d.ts.map +1 -1
- package/dist/npm/v2/experienceEvents.d.ts +3 -1
- package/dist/npm/v2/experienceEvents.d.ts.map +1 -1
- package/dist/npm/v2/index.d.ts +1 -1
- package/dist/npm/v2/index.d.ts.map +1 -1
- package/dist/npm/v2/liforma-experience.d.ts +2 -0
- package/dist/npm/v2/liforma-experience.d.ts.map +1 -1
- package/dist/npm/v2/npm.d.ts +1 -1
- package/dist/npm/v2/npm.d.ts.map +1 -1
- package/dist/npm/v2/sdkRelease.d.ts +3 -0
- package/dist/npm/v2/sdkRelease.d.ts.map +1 -0
- package/dist/npm/v2/types/sessionInteraction.d.ts +29 -0
- package/dist/npm/v2/types/sessionInteraction.d.ts.map +1 -1
- package/dist/npm/v2/types/sessionManifest.d.ts +1 -0
- package/dist/npm/v2/types/sessionManifest.d.ts.map +1 -1
- package/dist/npm/v2/types/sessionManifestSchema.d.ts +17 -0
- package/dist/npm/v2/types/sessionManifestSchema.d.ts.map +1 -1
- package/dist/npm/widget/mountExperienceWidget.d.ts.map +1 -1
- package/dist/npm/widget/types.d.ts +5 -0
- package/dist/npm/widget/types.d.ts.map +1 -1
- package/dist/react/component/experienceComponentLaunch.d.ts.map +1 -1
- package/dist/react/component/experienceComponentRuntime.d.ts +1 -0
- package/dist/react/component/experienceComponentRuntime.d.ts.map +1 -1
- package/dist/react/component/experienceComponentTypes.d.ts +7 -0
- package/dist/react/component/experienceComponentTypes.d.ts.map +1 -1
- package/dist/react/index.js +977 -642
- package/dist/react/index.js.map +1 -1
- package/dist/react/react/Experience.d.ts.map +1 -1
- package/dist/react/svelte/experienceLoadError.d.ts.map +1 -1
- package/dist/react/svelte/experienceLoadErrorStyles.d.ts +1 -1
- package/dist/react/svelte/experienceLoadErrorStyles.d.ts.map +1 -1
- package/dist/react/v2/api/mintPublicSession.d.ts +1 -0
- package/dist/react/v2/api/mintPublicSession.d.ts.map +1 -1
- package/dist/react/v2/api/sessionEndpointRequest.d.ts +4 -0
- package/dist/react/v2/api/sessionEndpointRequest.d.ts.map +1 -1
- package/dist/react/v2/embed/iframeHost.d.ts +13 -1
- package/dist/react/v2/embed/iframeHost.d.ts.map +1 -1
- package/dist/react/v2/embed/protocol.d.ts +35 -1
- package/dist/react/v2/embed/protocol.d.ts.map +1 -1
- package/dist/react/v2/experience.d.ts +17 -2
- package/dist/react/v2/experience.d.ts.map +1 -1
- package/dist/react/v2/experienceEvents.d.ts +3 -1
- package/dist/react/v2/experienceEvents.d.ts.map +1 -1
- package/dist/react/v2/sdkRelease.d.ts +3 -0
- package/dist/react/v2/sdkRelease.d.ts.map +1 -0
- package/dist/react/v2/types/sessionInteraction.d.ts +29 -0
- package/dist/react/v2/types/sessionInteraction.d.ts.map +1 -1
- package/dist/react/v2/types/sessionManifest.d.ts +1 -0
- package/dist/react/v2/types/sessionManifest.d.ts.map +1 -1
- package/dist/react/widget/mountExperienceWidget.d.ts.map +1 -1
- package/dist/react/widget/types.d.ts +5 -0
- package/dist/react/widget/types.d.ts.map +1 -1
- package/dist/sdk/v2/client.js +2 -2
- package/dist/sdk/v2/client.js.map +1 -1
- package/dist/svelte/Experience.svelte +6 -0
- package/dist/svelte/experienceLoadError.js +37 -15
- package/dist/svelte/experienceLoadError.test.js +8 -0
- package/dist/svelte/experienceLoadErrorOverlay.js +1 -1
- package/dist/svelte/experienceLoadErrorStyles.d.ts +1 -1
- package/dist/svelte/experienceLoadErrorStyles.js +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":[],"sources":["../../../src/shims/localStack.ts","../../../src/shims/apiBaseUrl.ts","../../../src/v2/errors/LiformaError.ts","../../../src/v2/api/captureAttribution.ts","../../../src/v2/api/sessionEndpointRequest.ts","../../../src/v2/types/sessionLaunch.ts","../../../src/v2/api/mintPublicSession.ts","../../../src/v2/conversationProcessor.ts","../../../src/v2/embed/playerReachability.ts","../../../src/v2/embed/protocol.ts","../../../src/v2/embed/fullWindowHost.ts","../../../src/v2/embed/iframeHost.ts","../../../src/v2/embed/readyGate.ts","../../../src/v2/shims/embedBaseUrl.ts","../../../src/v2/experienceEvents.ts","../../../src/v2/speech/types.ts","../../../src/byo/pcm.ts","../../../src/byo/resample.ts","../../../src/byo/audioCapture.ts","../../../src/v2/speech/captureMediaStreamTrack.ts","../../../src/v2/speech/speechController.ts","../../../src/v2/types/sessionInteraction.ts","../../../src/v2/experience.ts","../../../src/v2/index.ts"],"sourcesContent":["/**\n * Opt-in local monorepo stack (api :3001, player :3002).\n * Never inferred from hostname alone — third-party demos run on localhost against production.\n */\nexport function useExplicitLocalStack(): boolean {\n\tif ((globalThis as { __LIFORMA_STACK?: string }).__LIFORMA_STACK === 'local') {\n\t\treturn true;\n\t}\n\n\tif (typeof location === 'undefined') {\n\t\treturn false;\n\t}\n\n\ttry {\n\t\treturn new URLSearchParams(location.search).get('stack') === 'local';\n\t} catch {\n\t\treturn false;\n\t}\n}\n","import { useExplicitLocalStack } from './localStack';\n\nconst PRODUCTION_API_BASE_URL = 'https://api.liforma.ai';\nconst LOCAL_API_BASE_URL = 'http://localhost:3001';\n\nfunction readConfiguredApiBaseUrl(): string | null {\n\tconst globalValue = (globalThis as { __LIFORMA_API_BASE_URL?: string }).__LIFORMA_API_BASE_URL;\n\tif (globalValue?.trim()) {\n\t\treturn globalValue.trim().replace(/\\/$/, '');\n\t}\n\n\tif (typeof document === 'undefined') {\n\t\treturn null;\n\t}\n\n\tconst script =\n\t\tdocument.querySelector('script[data-liforma-sdk][src*=\"client.js\"]') ??\n\t\tdocument.querySelector('script[src*=\"/sdk/v2/client.js\"]');\n\tconst fromScript = script?.getAttribute('data-api-base-url')?.trim();\n\tif (fromScript) {\n\t\treturn fromScript.replace(/\\/$/, '');\n\t}\n\n\treturn null;\n}\n\n/**\n * Browser-visible API origin for Liforma HTTP calls from the CDN SDK.\n *\n * Defaults to production. Local stack is opt-in only — never inferred from\n * `localhost` hostname (third-party demos run on localhost against production).\n *\n * Override order:\n * 1. `window.__LIFORMA_API_BASE_URL`\n * 2. `data-api-base-url` on the SDK script tag\n * 3. `window.__LIFORMA_STACK === 'local'` or host `?stack=local` → http://localhost:3001\n * 4. production default → https://api.liforma.ai\n */\nexport function resolvePublicApiBaseUrl(): string {\n\tconst configured = readConfiguredApiBaseUrl();\n\tif (configured) {\n\t\treturn configured;\n\t}\n\n\tif (useExplicitLocalStack()) {\n\t\treturn LOCAL_API_BASE_URL;\n\t}\n\n\treturn PRODUCTION_API_BASE_URL;\n}\n","/**\n * Structured API / mint error from Liforma.\n * Prefer `.code` and `.requestId` over parsing `.message`.\n */\nexport class LiformaError extends Error {\n\treadonly code: string;\n\treadonly requestId: string | undefined;\n\treadonly status: number | undefined;\n\treadonly details: Record<string, unknown> | undefined;\n\n\tconstructor(\n\t\tmessage: string,\n\t\toptions?: {\n\t\t\treadonly code?: string;\n\t\t\treadonly requestId?: string;\n\t\t\treadonly status?: number;\n\t\t\treadonly details?: Record<string, unknown>;\n\t\t\treadonly cause?: unknown;\n\t\t}\n\t) {\n\t\tsuper(message, options?.cause !== undefined ? { cause: options.cause } : undefined);\n\t\tthis.name = 'LiformaError';\n\t\tthis.code = options?.code?.trim() || 'UNKNOWN';\n\t\tthis.requestId = options?.requestId?.trim() || undefined;\n\t\tthis.status = options?.status;\n\t\tthis.details = options?.details;\n\t}\n}\n\ntype NestedErrorShape = {\n\treadonly error?: {\n\t\treadonly code?: unknown;\n\t\treadonly message?: unknown;\n\t\treadonly requestId?: unknown;\n\t\treadonly [key: string]: unknown;\n\t};\n\treadonly code?: unknown;\n\treadonly message?: unknown;\n\treadonly requestId?: unknown;\n};\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n\tif (!value || typeof value !== 'object' || Array.isArray(value)) return undefined;\n\treturn value as Record<string, unknown>;\n}\n\n/**\n * Parse a mint/API error response body + optional `Liforma-Request-Id` header\n * into a {@link LiformaError}. Falls back to flat `{ code, message }` shapes.\n */\nexport function liformaErrorFromResponse(\n\tstatus: number,\n\ttext: string,\n\theaders?: Headers\n): LiformaError {\n\tconst headerRequestId = headers?.get('Liforma-Request-Id')?.trim() || undefined;\n\tlet parsed: NestedErrorShape | undefined;\n\ttry {\n\t\tparsed = JSON.parse(text) as NestedErrorShape;\n\t} catch {\n\t\t/* keep */\n\t}\n\n\tconst nested = parsed?.error && typeof parsed.error === 'object' ? parsed.error : undefined;\n\tconst codeRaw = nested?.code ?? parsed?.code;\n\tconst messageRaw = nested?.message ?? parsed?.message;\n\tconst requestIdRaw = nested?.requestId ?? parsed?.requestId ?? headerRequestId;\n\n\tconst code = typeof codeRaw === 'string' && codeRaw.trim() ? codeRaw.trim() : 'HTTP_ERROR';\n\tconst message =\n\t\ttypeof messageRaw === 'string' && messageRaw.trim()\n\t\t\t? messageRaw.trim()\n\t\t\t: text.trim().slice(0, 500) || `Request failed (${status})`;\n\tconst requestId =\n\t\ttypeof requestIdRaw === 'string' && requestIdRaw.trim() ? requestIdRaw.trim() : headerRequestId;\n\n\tconst details = asRecord(nested) ?? asRecord(parsed);\n\tconst { code: _c, message: _m, requestId: _r, ...rest } = details ?? {};\n\tvoid _c;\n\tvoid _m;\n\tvoid _r;\n\n\treturn new LiformaError(message, {\n\t\tcode,\n\t\trequestId,\n\t\tstatus,\n\t\tdetails: Object.keys(rest).length > 0 ? rest : undefined\n\t});\n}\n","export type ExperienceAttribution = {\n\treadonly utmSource?: string;\n\treadonly utmMedium?: string;\n\treadonly utmCampaign?: string;\n\treadonly utmContent?: string;\n\treadonly utmTerm?: string;\n\treadonly referrer?: string;\n};\n\nconst ATTR_MAX = 128;\nconst CONTROL = /[\\u0000-\\u001f\\u007f]/g;\n\nfunction bound(value: string | null | undefined): string | undefined {\n\tif (!value) return undefined;\n\tconst trimmed = value.replace(CONTROL, '').trim();\n\tif (!trimmed) return undefined;\n\treturn trimmed.slice(0, ATTR_MAX);\n}\n\nfunction utmFromSearch(search: string | null | undefined): ExperienceAttribution {\n\tconst params = new URLSearchParams((search ?? '').startsWith('?') ? (search ?? '').slice(1) : (search ?? ''));\n\treturn {\n\t\t...(bound(params.get('utm_source')) ? { utmSource: bound(params.get('utm_source')) } : {}),\n\t\t...(bound(params.get('utm_medium')) ? { utmMedium: bound(params.get('utm_medium')) } : {}),\n\t\t...(bound(params.get('utm_campaign')) ? { utmCampaign: bound(params.get('utm_campaign')) } : {}),\n\t\t...(bound(params.get('utm_content')) ? { utmContent: bound(params.get('utm_content')) } : {}),\n\t\t...(bound(params.get('utm_term')) ? { utmTerm: bound(params.get('utm_term')) } : {})\n\t};\n}\n\nexport function resolveMintAttribution(\n\tattribution: ExperienceAttribution | false | undefined\n): ExperienceAttribution | undefined {\n\tif (attribution === false) return undefined;\n\tif (attribution && typeof attribution === 'object') {\n\t\tconst explicit: ExperienceAttribution = {\n\t\t\t...(bound(attribution.utmSource) ? { utmSource: bound(attribution.utmSource) } : {}),\n\t\t\t...(bound(attribution.utmMedium) ? { utmMedium: bound(attribution.utmMedium) } : {}),\n\t\t\t...(bound(attribution.utmCampaign) ? { utmCampaign: bound(attribution.utmCampaign) } : {}),\n\t\t\t...(bound(attribution.utmContent) ? { utmContent: bound(attribution.utmContent) } : {}),\n\t\t\t...(bound(attribution.utmTerm) ? { utmTerm: bound(attribution.utmTerm) } : {}),\n\t\t\t...(bound(attribution.referrer) ? { referrer: bound(attribution.referrer) } : {})\n\t\t};\n\t\treturn Object.keys(explicit).length ? explicit : undefined;\n\t}\n\tif (typeof window === 'undefined') return undefined;\n\tconst fromPage = utmFromSearch(window.location?.search);\n\tconst referrer = bound(document.referrer || undefined);\n\tconst auto: ExperienceAttribution = {\n\t\t...fromPage,\n\t\t...(referrer ? { referrer } : {})\n\t};\n\treturn Object.keys(auto).length ? auto : undefined;\n}\n","import { resolveMintAttribution } from './captureAttribution';\n\nexport type SessionEndpointRequestOptions = {\n\treadonly experienceId: string;\n\t/** BCP 47 locale (preferred). When omitted in the browser, defaults to `navigator.language`. */\n\treadonly locale?: string;\n\t/** Paired / learning language for dual experiences (BCP 47). */\n\treadonly secondaryLocale?: string;\n\t/** Alias of `secondaryLocale` — language-learning apps (tutors + roleplay). */\n\treadonly learningLocale?: string;\n\t/** @deprecated Prefer `locale`. */\n\treadonly language?: 'en' | 'es' | string;\n\treadonly mode?: 'conversation' | 'presenter';\n\treadonly speechInputMode?: 'auto' | 'manual' | 'off';\n\treadonly speechOnly?: boolean;\n\t/** Optional Idempotency-Key header value (max 256 chars). */\n\treadonly idempotencyKey?: string;\n\treadonly attribution?: import('./captureAttribution').ExperienceAttribution | false;\n};\n\nfunction resolveLocale(options: SessionEndpointRequestOptions): string | undefined {\n\tconst locale = options.locale?.trim();\n\tif (locale) return locale;\n\tconst language = options.language?.trim();\n\tif (language) return language;\n\tif (typeof navigator !== 'undefined' && navigator.language?.trim()) {\n\t\treturn navigator.language.trim();\n\t}\n\treturn undefined;\n}\n\nfunction resolveSecondaryLocale(options: SessionEndpointRequestOptions): string | undefined {\n\tconst secondary = options.secondaryLocale?.trim();\n\tconst learning = options.learningLocale?.trim();\n\tif (secondary && learning && secondary !== learning) {\n\t\tthrow new Error(\n\t\t\t'secondaryLocale and learningLocale disagree; pass only one or make them equal.'\n\t\t);\n\t}\n\treturn secondary || learning || undefined;\n}\n\nexport function createSessionEndpointRequest(\n\tsessionEndpoint: string,\n\toptions: SessionEndpointRequestOptions\n): { readonly url: string; readonly init: RequestInit } {\n\tconst endpoint = sessionEndpoint.trim();\n\tif (!endpoint) {\n\t\tthrow new Error('sessionEndpoint must not be empty.');\n\t}\n\tif (typeof location === 'undefined') {\n\t\tthrow new Error('sessionEndpoint is only available in a browser.');\n\t}\n\n\tconst url = new URL(endpoint, location.href);\n\tif (url.origin !== location.origin) {\n\t\tthrow new Error('sessionEndpoint must be same-origin.');\n\t}\n\n\tconst experienceId = options.experienceId.trim();\n\tif (!experienceId) {\n\t\tthrow new Error('sessionEndpoint requires experienceId.');\n\t}\n\n\tconst locale = resolveLocale(options);\n\tconst secondaryLocale = resolveSecondaryLocale(options);\n\tconst idempotencyKey = options.idempotencyKey?.trim();\n\n\treturn {\n\t\turl: url.toString(),\n\t\tinit: {\n\t\t\tmethod: 'POST',\n\t\t\tcredentials: 'same-origin',\n\t\t\theaders: {\n\t\t\t\tAccept: 'application/json',\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t...(idempotencyKey ? { 'Idempotency-Key': idempotencyKey } : {})\n\t\t\t},\n\t\t\tbody: JSON.stringify({\n\t\t\t\texperienceId,\n\t\t\t\t...(locale ? { locale } : {}),\n\t\t\t\t...(secondaryLocale ? { secondaryLocale } : {}),\n\t\t\t\t...(options.mode ? { mode: options.mode } : {}),\n\t\t\t\t...(options.speechInputMode ? { speechInputMode: options.speechInputMode } : {}),\n\t\t\t\t...(options.speechOnly !== undefined ? { speechOnly: options.speechOnly } : {}),\n\t\t\t\t...(() => {\n\t\t\t\t\tconst attribution = resolveMintAttribution(options.attribution);\n\t\t\t\t\treturn attribution ? { attribution } : {};\n\t\t\t\t})()\n\t\t\t})\n\t\t}\n\t};\n}\n","/**\n * Public Session Launch contract (integrator-facing).\n * Runtime internals live inside the opaque `launch` string — do not parse it.\n */\n\nexport type SessionCapabilities = {\n\treadonly speech: { readonly input: boolean; readonly output: boolean; readonly externalAudio: boolean };\n\treadonly conversation: { readonly managed: boolean };\n\treadonly avatar: { readonly enabled: boolean };\n\treadonly tools: { readonly enabled: boolean };\n};\n\nexport type SessionMode = 'conversation' | 'presenter';\n\nexport type SessionStatus = 'active' | 'ended';\n\n/** Mint collapsed a non-English locale onto English because TTS cannot synthesize it. */\nexport type LocaleVoiceFallback = {\n\treadonly axis: 'locale' | 'secondaryLocale';\n\treadonly requested: string;\n\treadonly resolved: string;\n\treadonly reason: 'voice_unsupported';\n};\n\nexport type Session = {\n\treadonly id: string;\n\treadonly experienceId: string;\n\treadonly experienceRevisionId: string;\n\treadonly expiresAt: string;\n\treadonly locale: string;\n\t/** Paired / learning language when dual; omitted for plain sessions. */\n\treadonly secondaryLocale?: string;\n\treadonly mode: SessionMode;\n\treadonly capabilities: SessionCapabilities;\n\treadonly localeVoiceFallbacks?: readonly LocaleVoiceFallback[];\n\t/** Present on mint when RuntimeSession was persisted. */\n\treadonly status?: SessionStatus;\n\treadonly createdAt?: string;\n};\n\nexport type SessionLaunchResponse = {\n\treadonly session: Session;\n\t/**\n\t * Asymmetrically signed opaque runtime bootstrap for the player.\n\t * Contract-opaque (unsupported to parse), not confidentiality-opaque.\n\t */\n\treadonly launch: string;\n};\n\nexport type PlayerStatus = 'loading' | 'scene' | 'ready' | 'error';\n\n/** Listening / speaking activity (replaces overloaded modeChange). */\nexport type SessionActivity = 'idle' | 'listening' | 'thinking' | 'speaking';\n\nexport type CloseButtonOptions = {\n\treadonly visible?: boolean;\n\treadonly style?: 'icon' | 'text';\n\treadonly label?: string | null;\n\treadonly position?: string;\n};\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isBoolean(value: unknown): value is boolean {\n\treturn typeof value === 'boolean';\n}\n\nfunction parseNestedCapabilities(raw: unknown): SessionCapabilities | null {\n\tif (!isRecord(raw)) return null;\n\tconst speech = raw.speech;\n\tconst conversation = raw.conversation;\n\tconst avatar = raw.avatar;\n\tconst tools = raw.tools;\n\tif (\n\t\t!isRecord(speech) ||\n\t\t!isRecord(conversation) ||\n\t\t!isRecord(avatar) ||\n\t\t!isRecord(tools) ||\n\t\t!isBoolean(speech.input) ||\n\t\t!isBoolean(speech.output) ||\n\t\t!isBoolean(speech.externalAudio) ||\n\t\t!isBoolean(conversation.managed) ||\n\t\t!isBoolean(avatar.enabled) ||\n\t\t!isBoolean(tools.enabled)\n\t) {\n\t\treturn null;\n\t}\n\treturn {\n\t\tspeech: {\n\t\t\tinput: speech.input,\n\t\t\toutput: speech.output,\n\t\t\texternalAudio: speech.externalAudio\n\t\t},\n\t\tconversation: { managed: conversation.managed },\n\t\tavatar: { enabled: avatar.enabled },\n\t\ttools: { enabled: tools.enabled }\n\t};\n}\n\n/** @deprecated Flat capabilities from pre-v1 mint responses. */\nfunction parseLegacyFlatCapabilities(raw: unknown): SessionCapabilities | null {\n\tif (!isRecord(raw)) return null;\n\tif (\n\t\t!isBoolean(raw.avatar) ||\n\t\t!isBoolean(raw.speechInput) ||\n\t\t!isBoolean(raw.speechOutput) ||\n\t\t!isBoolean(raw.tools) ||\n\t\t!isBoolean(raw.externalAudio)\n\t) {\n\t\treturn null;\n\t}\n\treturn {\n\t\tspeech: {\n\t\t\tinput: raw.speechInput,\n\t\t\toutput: raw.speechOutput,\n\t\t\texternalAudio: raw.externalAudio\n\t\t},\n\t\tconversation: { managed: true },\n\t\tavatar: { enabled: raw.avatar },\n\t\ttools: { enabled: raw.tools }\n\t};\n}\n\nfunction parseCapabilities(raw: unknown): SessionCapabilities | null {\n\treturn parseNestedCapabilities(raw) ?? parseLegacyFlatCapabilities(raw);\n}\n\nexport function parseSession(raw: unknown): Session {\n\tif (!isRecord(raw)) {\n\t\tthrow new Error('Session Launch response is missing session.');\n\t}\n\tconst id = typeof raw.id === 'string' ? raw.id.trim() : '';\n\tconst experienceId = typeof raw.experienceId === 'string' ? raw.experienceId.trim() : '';\n\tconst experienceRevisionId =\n\t\ttypeof raw.experienceRevisionId === 'string' ? raw.experienceRevisionId.trim() : '';\n\tconst expiresAt = typeof raw.expiresAt === 'string' ? raw.expiresAt.trim() : '';\n\tconst locale = typeof raw.locale === 'string' ? raw.locale.trim() : '';\n\tconst secondaryLocale =\n\t\ttypeof raw.secondaryLocale === 'string' && raw.secondaryLocale.trim()\n\t\t\t? raw.secondaryLocale.trim()\n\t\t\t: undefined;\n\tconst mode = raw.mode === 'conversation' || raw.mode === 'presenter' ? raw.mode : null;\n\tconst capabilities = parseCapabilities(raw.capabilities);\n\tconst localeVoiceFallbacks = parseLocaleVoiceFallbacks(raw.localeVoiceFallbacks);\n\tconst status =\n\t\traw.status === 'active' || raw.status === 'ended' ? raw.status : undefined;\n\tconst createdAt =\n\t\ttypeof raw.createdAt === 'string' && raw.createdAt.trim() ? raw.createdAt.trim() : undefined;\n\n\tif (!id || !experienceId || !experienceRevisionId || !expiresAt || !locale || !mode || !capabilities) {\n\t\tthrow new Error('Session Launch response has an invalid session object.');\n\t}\n\n\treturn {\n\t\tid,\n\t\texperienceId,\n\t\texperienceRevisionId,\n\t\texpiresAt,\n\t\tlocale,\n\t\t...(secondaryLocale ? { secondaryLocale } : {}),\n\t\tmode,\n\t\tcapabilities,\n\t\t...(localeVoiceFallbacks ? { localeVoiceFallbacks } : {}),\n\t\t...(status ? { status } : {}),\n\t\t...(createdAt ? { createdAt } : {})\n\t};\n}\n\nfunction parseLocaleVoiceFallbacks(raw: unknown): readonly LocaleVoiceFallback[] | undefined {\n\tif (!Array.isArray(raw) || raw.length === 0) return undefined;\n\tconst out: LocaleVoiceFallback[] = [];\n\tfor (const item of raw) {\n\t\tif (!isRecord(item)) continue;\n\t\tconst axis = item.axis === 'locale' || item.axis === 'secondaryLocale' ? item.axis : null;\n\t\tconst requested = typeof item.requested === 'string' ? item.requested.trim() : '';\n\t\tconst resolved = typeof item.resolved === 'string' ? item.resolved.trim() : '';\n\t\tif (!axis || !requested || !resolved || item.reason !== 'voice_unsupported') continue;\n\t\tout.push({ axis, requested, resolved, reason: 'voice_unsupported' });\n\t}\n\treturn out.length > 0 ? out : undefined;\n}\n\n/** Browser console warnings when mint fell back to English for voice support. */\nexport function warnLocaleVoiceFallbacks(session: Session): void {\n\tconst fallbacks = session.localeVoiceFallbacks;\n\tif (!fallbacks?.length) return;\n\tfor (const fb of fallbacks) {\n\t\tconst label = fb.axis === 'secondaryLocale' ? 'secondaryLocale' : 'locale';\n\t\tconsole.warn(\n\t\t\t`[liforma] Session ${label} fell back to ${fb.resolved} because the voice does not support ${fb.requested}.`\n\t\t);\n\t}\n}\n\nexport function parseSessionLaunchResponse(raw: unknown): SessionLaunchResponse {\n\tif (!isRecord(raw)) {\n\t\tthrow new Error('Session Launch response must be a JSON object.');\n\t}\n\tconst launch = typeof raw.launch === 'string' ? raw.launch.trim() : '';\n\tif (!launch) {\n\t\tthrow new Error('Session Launch response is missing launch.');\n\t}\n\tconst session = parseSession(raw.session);\n\twarnLocaleVoiceFallbacks(session);\n\treturn {\n\t\tsession,\n\t\tlaunch\n\t};\n}\n","import { resolvePublicApiBaseUrl } from '../../shims/apiBaseUrl';\nimport { LiformaError, liformaErrorFromResponse } from '../errors/LiformaError';\nimport { createSessionEndpointRequest } from './sessionEndpointRequest';\nimport { resolveMintAttribution } from './captureAttribution';\nimport {\n\tparseSessionLaunchResponse,\n\ttype SessionLaunchResponse\n} from '../types/sessionLaunch';\n\nexport type MintBrowserSessionOptions = {\n\t/** BCP 47 locale (preferred). When omitted in the browser, defaults to `navigator.language`. */\n\treadonly locale?: string;\n\t/** Paired / learning language for dual experiences (BCP 47). */\n\treadonly secondaryLocale?: string;\n\t/** Alias of `secondaryLocale` — language-learning apps (tutors + roleplay). */\n\treadonly learningLocale?: string;\n\t/** @deprecated Prefer `locale`. */\n\treadonly language?: 'en' | 'es' | string;\n\treadonly mode?: 'conversation' | 'presenter';\n\treadonly speechInputMode?: 'auto' | 'manual' | 'off';\n\treadonly speechOnly?: boolean;\n\t/** Optional Idempotency-Key header value (max 256 chars). */\n\treadonly idempotencyKey?: string;\n\treadonly attribution?: import('./captureAttribution').ExperienceAttribution | false;\n};\n\nfunction currentPageOrigin(): string | undefined {\n\ttry {\n\t\tif (typeof globalThis.location?.origin === 'string' && globalThis.location.origin) {\n\t\t\treturn globalThis.location.origin;\n\t\t}\n\t} catch {\n\t\t/* ignore */\n\t}\n\treturn undefined;\n}\n\nfunction normalizeMintErrorCode(code: string | undefined): string {\n\tif (!code) return '';\n\treturn code.trim().toUpperCase().replace(/-/g, '_');\n}\n\nfunction enrichPublicMintError(experienceId: string, err: LiformaError): LiformaError {\n\tconst pageOrigin = currentPageOrigin();\n\tconst code = normalizeMintErrorCode(err.code);\n\tconst apiMessage = err.message.trim();\n\tconst details = err.details ?? {};\n\n\tif (\n\t\tcode === 'ORIGIN_NOT_ALLOWED' ||\n\t\t(/^Origin not allowed/i.test(apiMessage) && pageOrigin)\n\t) {\n\t\tif (apiMessage.includes(experienceId) && apiMessage.includes('allowed origin')) {\n\t\t\treturn err;\n\t\t}\n\t\tconst origin =\n\t\t\t(typeof details.origin === 'string' && details.origin) ||\n\t\t\tpageOrigin ||\n\t\t\t'(unknown origin)';\n\t\treturn new LiformaError(\n\t\t\t`Your origin ${origin} is not an allowed origin for experience ${experienceId}. ` +\n\t\t\t\t`If you own this experience, sign in to the Liforma developer portal (app.liforma.ai), ` +\n\t\t\t\t`open Workspace → Settings → Origins, add ${origin} to the list of allowed origins, ` +\n\t\t\t\t`and ensure “Allow public client-only embeds” is enabled.`,\n\t\t\t{ code: 'ORIGIN_NOT_ALLOWED', requestId: err.requestId, status: err.status, details }\n\t\t);\n\t}\n\n\tif (code === 'BROWSER_EMBEDS_DISABLED' || /^Browser embeds are not enabled/i.test(apiMessage)) {\n\t\tif (apiMessage.includes('Allow public client-only embeds')) {\n\t\t\treturn err;\n\t\t}\n\t\treturn new LiformaError(\n\t\t\t`Browser embeds are not enabled for experience ${experienceId}. ` +\n\t\t\t\t`If you own this experience, sign in to the Liforma developer portal (app.liforma.ai), ` +\n\t\t\t\t`open Workspace → Settings → Origins, and enable “Allow public client-only embeds”.`,\n\t\t\t{\n\t\t\t\tcode: 'BROWSER_EMBEDS_DISABLED',\n\t\t\t\trequestId: err.requestId,\n\t\t\t\tstatus: err.status,\n\t\t\t\tdetails\n\t\t\t}\n\t\t);\n\t}\n\n\tif (\n\t\tcode === 'EXPERIENCE_UNAVAILABLE' ||\n\t\t/^Experience is not available\\.?$/i.test(apiMessage) ||\n\t\t/^Unknown experience\\.?$/i.test(apiMessage)\n\t) {\n\t\tif (apiMessage.includes('No playable experience found')) {\n\t\t\treturn err;\n\t\t}\n\t\treturn new LiformaError(\n\t\t\t`No playable experience found for “${experienceId}”. ` +\n\t\t\t\t`Check that the experience id is correct (it should look like exp_…), ` +\n\t\t\t\t`and that the experience exists and is published in the Liforma developer portal (app.liforma.ai). ` +\n\t\t\t\t`Deleted, archived, and unpublished experiences cannot be started from a browser embed.`,\n\t\t\t{\n\t\t\t\tcode: 'EXPERIENCE_UNAVAILABLE',\n\t\t\t\trequestId: err.requestId,\n\t\t\t\tstatus: err.status,\n\t\t\t\tdetails\n\t\t\t}\n\t\t);\n\t}\n\n\treturn err;\n}\n\nfunction resolveLocale(options?: MintBrowserSessionOptions): string | undefined {\n\tconst locale = options?.locale?.trim();\n\tif (locale) return locale;\n\tconst language = options?.language?.trim();\n\tif (language) return language;\n\tif (typeof navigator !== 'undefined' && navigator.language?.trim()) {\n\t\treturn navigator.language.trim();\n\t}\n\treturn undefined;\n}\n\nfunction resolveSecondaryLocale(options?: MintBrowserSessionOptions): string | undefined {\n\tconst secondary = options?.secondaryLocale?.trim();\n\tconst learning = options?.learningLocale?.trim();\n\tif (secondary && learning && secondary !== learning) {\n\t\tthrow new LiformaError(\n\t\t\t'secondaryLocale and learningLocale disagree; pass only one or make them equal.',\n\t\t\t{ code: 'INVALID_BODY' }\n\t\t);\n\t}\n\treturn secondary || learning || undefined;\n}\n\nfunction buildMintBody(\n\texperienceId: string,\n\toptions?: MintBrowserSessionOptions\n): Record<string, unknown> {\n\tconst body: Record<string, unknown> = { experienceId };\n\tconst locale = resolveLocale(options);\n\tif (locale) body.locale = locale;\n\tconst secondaryLocale = resolveSecondaryLocale(options);\n\tif (secondaryLocale) body.secondaryLocale = secondaryLocale;\n\tif (options?.mode) body.mode = options.mode;\n\tif (options?.speechInputMode) body.speechInputMode = options.speechInputMode;\n\tif (options?.speechOnly !== undefined) body.speechOnly = options.speechOnly;\n\tconst attribution = resolveMintAttribution(options?.attribution);\n\tif (attribution) body.attribution = attribution;\n\treturn body;\n}\n\n/** Mint a browser session via `POST /v1/browser-sessions`. */\nexport async function mintBrowserSession(\n\texperienceId: string,\n\toptions?: MintBrowserSessionOptions\n): Promise<SessionLaunchResponse> {\n\tconst apiBaseUrl = resolvePublicApiBaseUrl();\n\tconst idempotencyKey = options?.idempotencyKey?.trim();\n\tconst res = await fetch(`${apiBaseUrl}/v1/browser-sessions`, {\n\t\tmethod: 'POST',\n\t\theaders: {\n\t\t\t'Content-Type': 'application/json',\n\t\t\t...(idempotencyKey ? { 'Idempotency-Key': idempotencyKey } : {})\n\t\t},\n\t\tbody: JSON.stringify(buildMintBody(experienceId, options))\n\t});\n\n\tif (!res.ok) {\n\t\tconst text = await res.text();\n\t\tthrow enrichPublicMintError(experienceId, liformaErrorFromResponse(res.status, text, res.headers));\n\t}\n\tlet raw: unknown;\n\ttry {\n\t\traw = await res.json();\n\t} catch {\n\t\tthrow new LiformaError('Browser session mint returned invalid JSON.', {\n\t\t\tcode: 'INVALID_RESPONSE',\n\t\t\tstatus: res.status,\n\t\t\trequestId: res.headers.get('Liforma-Request-Id') ?? undefined\n\t\t});\n\t}\n\n\treturn parseSessionLaunchResponse(raw);\n}\n\n/** @deprecated Prefer {@link mintBrowserSession}. */\nexport const mintPublicSession = mintBrowserSession;\n\nexport type FetchSessionLaunchOptions = MintBrowserSessionOptions & {\n\treadonly experienceId: string;\n\treadonly signal?: AbortSignal;\n\treadonly timeoutMs?: number;\n};\n\n/** @deprecated Prefer {@link FetchSessionLaunchOptions}. */\nexport type FetchSessionManifestOptions = FetchSessionLaunchOptions;\n\nexport async function fetchSessionLaunch(\n\tsessionEndpoint: string,\n\toptions: FetchSessionLaunchOptions\n): Promise<SessionLaunchResponse> {\n\tconst request = createSessionEndpointRequest(sessionEndpoint, options);\n\n\tconst controller = new AbortController();\n\tconst abortFromCaller = () => controller.abort(options.signal?.reason);\n\tif (options.signal?.aborted) {\n\t\tabortFromCaller();\n\t} else {\n\t\toptions.signal?.addEventListener('abort', abortFromCaller, { once: true });\n\t}\n\tconst timeoutId = globalThis.setTimeout(\n\t\t() => controller.abort(new DOMException('Session endpoint timed out.', 'TimeoutError')),\n\t\toptions.timeoutMs ?? 30_000\n\t);\n\n\tlet res: Response;\n\ttry {\n\t\tres = await fetch(request.url, {\n\t\t\t...request.init,\n\t\t\tsignal: controller.signal\n\t\t});\n\t} finally {\n\t\tglobalThis.clearTimeout(timeoutId);\n\t\toptions.signal?.removeEventListener('abort', abortFromCaller);\n\t}\n\n\tif (!res.ok) {\n\t\tconst text = await res.text();\n\t\tthrow liformaErrorFromResponse(res.status, text, res.headers);\n\t}\n\tif (!res.headers.get('content-type')?.toLowerCase().includes('application/json')) {\n\t\tthrow new LiformaError('Session endpoint must return a JSON Session Launch response.', {\n\t\t\tcode: 'INVALID_RESPONSE',\n\t\t\tstatus: res.status,\n\t\t\trequestId: res.headers.get('Liforma-Request-Id') ?? undefined\n\t\t});\n\t}\n\n\tlet raw: unknown;\n\ttry {\n\t\traw = await res.json();\n\t} catch {\n\t\tthrow new LiformaError('Session endpoint returned invalid JSON.', {\n\t\t\tcode: 'INVALID_RESPONSE',\n\t\t\tstatus: res.status,\n\t\t\trequestId: res.headers.get('Liforma-Request-Id') ?? undefined\n\t\t});\n\t}\n\n\treturn parseSessionLaunchResponse(raw);\n}\n\n/** @deprecated Prefer {@link fetchSessionLaunch}. */\nexport const fetchSessionManifest = fetchSessionLaunch;\n","import type {\n\tConversationProcessorContext,\n\tConversationProcessorFn,\n\tConversationProcessorResult,\n\tNormalizedProcessorSpeech,\n\tProcessorDispatchResult,\n\tSpeakBehavior\n} from './types/sessionInteraction';\n\nexport function isAsyncIterableString(value: unknown): value is AsyncIterable<string> {\n\tif (value == null || typeof value !== 'object') return false;\n\treturn typeof (value as AsyncIterable<string>)[Symbol.asyncIterator] === 'function';\n}\n\nexport function normalizeConversationProcessorResult(\n\tresult: ConversationProcessorResult\n): NormalizedProcessorSpeech {\n\tif (typeof result === 'string') {\n\t\tconst text = result.trim();\n\t\tif (!text) {\n\t\t\tthrow new Error('conversationProcessor returned empty text.');\n\t\t}\n\t\treturn { text };\n\t}\n\n\tconst text = result.text.trim();\n\tif (!text) {\n\t\tthrow new Error('conversationProcessor returned empty text.');\n\t}\n\n\treturn {\n\t\ttext,\n\t\t...(result.characterId ? { characterId: result.characterId } : {}),\n\t\t...(result.behavior ? { behavior: result.behavior } : {})\n\t};\n}\n\nexport async function runConversationProcessor(\n\tprocessor: ConversationProcessorFn,\n\tcontext: ConversationProcessorContext\n): Promise<NormalizedProcessorSpeech> {\n\tconst dispatch = await dispatchConversationProcessor(processor, context);\n\tif (dispatch.kind !== 'complete') {\n\t\tthrow new Error('conversationProcessor returned a stream; use dispatchConversationProcessor.');\n\t}\n\treturn dispatch.speech;\n}\n\nexport async function dispatchConversationProcessor(\n\tprocessor: ConversationProcessorFn,\n\tcontext: ConversationProcessorContext\n): Promise<ProcessorDispatchResult> {\n\tconst result = await processor(context);\n\tif (isAsyncIterableString(result)) {\n\t\treturn { kind: 'stream', stream: result };\n\t}\n\treturn {\n\t\tkind: 'complete',\n\t\tspeech: normalizeConversationProcessorResult(result)\n\t};\n}\n","const LOCAL_PLAYER_DEV_PORT = '3002';\n\nexport function formatPlayerUnreachableMessage(playerOrigin: string): string {\n\tconst url = new URL(playerOrigin);\n\tconst isLocalHost = url.hostname === 'localhost' || url.hostname === '127.0.0.1';\n\n\tif (isLocalHost) {\n\t\tconst devPort = url.port || LOCAL_PLAYER_DEV_PORT;\n\t\treturn (\n\t\t\t`Cannot connect to the Liforma player at ${playerOrigin} — nothing is listening on port ${devPort}. ` +\n\t\t\t`Start the player dev server in player.liforma.ai (npm run dev).`\n\t\t);\n\t}\n\n\treturn (\n\t\t`Cannot connect to the Liforma player at ${playerOrigin}. ` +\n\t\t`The embed did not load; check your network connection and player URL configuration.`\n\t);\n}\n\nexport async function assertPlayerReachable(\n\tembedUrl: string,\n\tplayerOrigin: string\n): Promise<void> {\n\ttry {\n\t\tawait fetch(embedUrl, {\n\t\t\tmethod: 'GET',\n\t\t\tmode: 'no-cors',\n\t\t\tsignal: AbortSignal.timeout(8_000)\n\t\t});\n\t} catch {\n\t\tthrow new Error(formatPlayerUnreachableMessage(playerOrigin));\n\t}\n}\n\nexport function postMessageToPlayer(\n\ttarget: Window,\n\tmessage: unknown,\n\tplayerOrigin: string,\n\ttransfer?: Transferable[]\n): void {\n\ttry {\n\t\tif (transfer && transfer.length > 0) {\n\t\t\ttarget.postMessage(message, playerOrigin, transfer);\n\t\t} else {\n\t\t\ttarget.postMessage(message, playerOrigin);\n\t\t}\n\t} catch (error) {\n\t\tif (error instanceof DOMException && error.name === 'SecurityError') {\n\t\t\tthrow new Error(formatPlayerUnreachableMessage(playerOrigin), { cause: error });\n\t\t}\n\t\tthrow error;\n\t}\n}\n","import type {\n\tCharacterSpeechEvent,\n\tConversationMessage,\n\tSpeakBehavior,\n\tSessionModeChange,\n\tUserSpeechBoundaryEvent,\n\tUserTranscriptUpdate,\n\tUtteranceResult\n} from '../types/sessionInteraction';\nimport type { Session, SessionActivity } from '../types/sessionLaunch';\nimport type { StartButtonOptions, PlayerTheme } from '../types/sessionInteraction';\nimport type {\n\tCompleteSpeechQueuePolicy,\n\tSpeechAudioFormat,\n\tSpeechInterruptOptions,\n\tSpeechPlayEmbedSource,\n\tStreamingSpeechQueuePolicy\n} from '../speech/types';\n\nexport const EMBED_MESSAGE_SCHEMA_VERSION = 2 as const;\n\n/** Outbound postMessage versions accepted from the player embed. */\nexport const SUPPORTED_EMBED_MESSAGE_SCHEMA_VERSIONS: ReadonlySet<number> = new Set([1, 2]);\n\nexport function isSupportedEmbedMessageSchemaVersion(version: unknown): boolean {\n\treturn typeof version === 'number' && SUPPORTED_EMBED_MESSAGE_SCHEMA_VERSIONS.has(version);\n}\n\nexport type CloseEvent = {\n\treadonly sessionId?: string;\n\treadonly reason: 'user' | 'destroy';\n\treadonly returnUrl?: string;\n};\n\nexport type EmbedOutboundMessage =\n\t| {\n\t\t\treadonly type: 'close';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: CloseEvent;\n\t }\n\t| {\n\t\t\treadonly type: 'stateUpdate';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly state: 'loading' | 'scene' | 'ready' | 'error' };\n\t }\n\t| {\n\t\t\treadonly type: 'commandResult';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly ok: boolean;\n\t\t\t\treadonly error?: string;\n\t\t\t\treadonly result?: unknown;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'userTranscript';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: UserTranscriptUpdate;\n\t }\n\t| {\n\t\t\treadonly type: 'characterSpeechStarted';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: CharacterSpeechEvent;\n\t }\n\t| {\n\t\t\treadonly type: 'characterSpeechEnded';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: CharacterSpeechEvent;\n\t }\n\t| {\n\t\t\treadonly type: 'characterFocusChanged';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly characterId: string;\n\t\t\t\treadonly reason: 'speech' | 'api' | 'node_enter';\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'conversationUpdate';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly conversation: readonly ConversationMessage[] };\n\t }\n\t| {\n\t\t\treadonly type: 'listeningState';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly listening: boolean };\n\t }\n\t| {\n\t\t\treadonly type: 'userSpeechStarted';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: UserSpeechBoundaryEvent;\n\t }\n\t| {\n\t\t\treadonly type: 'userSpeechEnded';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: UserSpeechBoundaryEvent;\n\t }\n\t| {\n\t\t\treadonly type: 'modeChange';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly mode: SessionModeChange };\n\t }\n\t| {\n\t\t\treadonly type: 'activityChange';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly activity: SessionActivity };\n\t }\n\t| {\n\t\t\treadonly type: 'feedback';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly contractVersion: 'feedback.v1';\n\t\t\t\treadonly types: readonly {\n\t\t\t\t\treadonly feedbackId: string;\n\t\t\t\t\treadonly name: string;\n\t\t\t\t\treadonly criteria: readonly {\n\t\t\t\t\t\treadonly criterionId: string;\n\t\t\t\t\t\treadonly label: string;\n\t\t\t\t\t\treadonly score: number | string;\n\t\t\t\t\t\treadonly rationale: string;\n\t\t\t\t\t}[];\n\t\t\t\t}[];\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'feedbackFailed';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly error: string; readonly model?: string };\n\t }\n\t| {\n\t\t\treadonly type: 'message';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: ConversationMessage;\n\t }\n\t| {\n\t\t\treadonly type: 'started';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly mode: 'conversation' | 'presenter' };\n\t }\n\t| {\n\t\t\t/**\n\t\t\t * Player document is ready to receive `launch` (iframe HMR / Vite reload).\n\t\t\t * Parent re-posts the last launch token so bootstrap does not hang.\n\t\t\t */\n\t\t\treadonly type: 'embedReady';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t }\n\t| {\n\t\t\treadonly type: 'widgetReady';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: Record<string, never>;\n\t }\n\t| {\n\t\t\treadonly type: 'widgetExpand';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: Record<string, never>;\n\t }\n\t| {\n\t\t\treadonly type: 'widgetCollapse';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: Record<string, never>;\n\t }\n\t| {\n\t\t\treadonly type: 'widgetAudioSettings';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly open: boolean };\n\t }\n\t| {\n\t\t\treadonly type: 'widgetDragStart';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly pointerId: number;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'widgetDragMove';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly pointerId: number;\n\t\t\t\t/** Pointer deltas in CSS pixels (not iframe-local coordinates). */\n\t\t\t\treadonly dx: number;\n\t\t\t\treadonly dy: number;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'widgetDragEnd';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly pointerId: number;\n\t\t\t};\n\t }\n\t| {\n\t\t\t/** Expand / collapse the parent embed host to fill the browser window. */\n\t\t\treadonly type: 'fullWindow';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly active: boolean };\n\t };\n\nexport type WidgetChromeMode = 'collapsed' | 'loading' | 'expanded' | 'docked';\n\nexport type WidgetDragStartEvent = {\n\treadonly pointerId: number;\n};\n\nexport type WidgetDragMoveEvent = {\n\treadonly pointerId: number;\n\treadonly dx: number;\n\treadonly dy: number;\n};\n\n/** @deprecated Prefer WidgetDragStartEvent / WidgetDragMoveEvent */\nexport type WidgetDragPointerEvent = WidgetDragMoveEvent;\n\nexport type EmbedInboundMessage =\n\t| {\n\t\t\treadonly type: 'launch';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly launch: string;\n\t\t\t\treadonly session?: Session | object;\n\t\t\t\t/** Player chrome from attach — not part of the signed launch string. */\n\t\t\t\treadonly startButton?: StartButtonOptions;\n\t\t\t\t/** Global player chrome theme from attach. */\n\t\t\t\treadonly theme?: PlayerTheme;\n\t\t\t\t/**\n\t\t\t\t * When false, player skips Feedback step-through UI (host renders scores).\n\t\t\t\t * Default when omitted: true (player shows Feedback).\n\t\t\t\t */\n\t\t\t\treadonly showFeedback?: boolean;\n\t\t\t};\n\t }\n\t| {\n\t\t\t/** @deprecated Prefer `launch`. Kept briefly for older players. */\n\t\t\treadonly type: 'manifest';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly manifest: unknown };\n\t }\n\t| {\n\t\t\treadonly type: 'parentHello';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t }\n\t| {\n\t\t\treadonly type: 'speak';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly text: string;\n\t\t\t\treadonly characterId?: string;\n\t\t\t\treadonly behavior?: SpeakBehavior;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'startListening';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly correlationId: string };\n\t }\n\t| {\n\t\t\treadonly type: 'stopListening';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly correlationId: string };\n\t }\n\t| {\n\t\t\treadonly type: 'getConversation';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly correlationId: string };\n\t }\n\t| {\n\t\t\treadonly type: 'listenOnce';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly timeoutMs?: number;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'speakStreamStart';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly characterId?: string;\n\t\t\t\treadonly behavior?: SpeakBehavior;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'speakStreamChunk';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly streamId: string;\n\t\t\t\treadonly text: string;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'speakStreamEnd';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly streamId: string;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'widgetSetChrome';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly mode: WidgetChromeMode };\n\t }\n\t| {\n\t\t\treadonly type: 'widgetToggleAudioSettings';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: Record<string, never>;\n\t }\n\t| {\n\t\t\treadonly type: 'speechPlay';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly source: SpeechPlayEmbedSource;\n\t\t\t\treadonly characterId?: string;\n\t\t\t\treadonly transcript?: string;\n\t\t\t\treadonly history?: 'none' | 'commit';\n\t\t\t\treadonly queue?: CompleteSpeechQueuePolicy;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'speechUtteranceBegin';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly utteranceId: string;\n\t\t\t\treadonly format: SpeechAudioFormat;\n\t\t\t\treadonly characterId?: string;\n\t\t\t\treadonly queue: StreamingSpeechQueuePolicy;\n\t\t\t\treadonly transcript?: string;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'speechUtteranceWrite';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly utteranceId: string;\n\t\t\t\treadonly audio: ArrayBuffer;\n\t\t\t\treadonly byteLength: number;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'speechUtteranceSetTranscript';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly utteranceId: string;\n\t\t\t\treadonly transcript: string;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'speechUtteranceClose';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly utteranceId: string;\n\t\t\t\treadonly transcript?: string;\n\t\t\t\treadonly history?: 'none' | 'commit';\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'speechUtteranceCancel';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly utteranceId: string;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'speechInterrupt';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t} & SpeechInterruptOptions;\n\t }\n\t| {\n\t\t\treadonly type: 'focusCharacter';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly characterId: string;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'setFit';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly fit: 'full' | 'face' | 'medium';\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'conversion';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly key: string;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'engage';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t};\n\t };\n\nexport type EmbedState = 'loading' | 'scene' | 'ready' | 'error';\n\nconst OUTBOUND_TYPES = new Set([\n\t'close',\n\t'stateUpdate',\n\t'commandResult',\n\t'userTranscript',\n\t'characterSpeechStarted',\n\t'characterSpeechEnded',\n\t'characterFocusChanged',\n\t'conversationUpdate',\n\t'listeningState',\n\t'userSpeechStarted',\n\t'userSpeechEnded',\n\t'modeChange',\n\t'activityChange',\n\t'feedback',\n\t'feedbackFailed',\n\t'message',\n\t'started',\n\t'embedReady',\n\t'widgetReady',\n\t'widgetExpand',\n\t'widgetCollapse',\n\t'widgetAudioSettings',\n\t'widgetDragStart',\n\t'widgetDragMove',\n\t'widgetDragEnd',\n\t'fullWindow'\n]);\n\nfunction isWidgetChromeMode(value: unknown): value is WidgetChromeMode {\n\treturn (\n\t\tvalue === 'collapsed' ||\n\t\tvalue === 'loading' ||\n\t\tvalue === 'expanded' ||\n\t\tvalue === 'docked'\n\t);\n}\n\nexport function parseOutboundMessage(data: unknown): EmbedOutboundMessage | null {\n\tif (!data || typeof data !== 'object') return null;\n\tconst msg = data as Partial<EmbedOutboundMessage>;\n\tif (!isSupportedEmbedMessageSchemaVersion(msg.schemaVersion)) return null;\n\tif (!msg.type || !OUTBOUND_TYPES.has(msg.type)) return null;\n\tif (\n\t\tmsg.type === 'embedReady' ||\n\t\tmsg.type === 'widgetReady' ||\n\t\tmsg.type === 'widgetExpand' ||\n\t\tmsg.type === 'widgetCollapse'\n\t) {\n\t\treturn msg as EmbedOutboundMessage;\n\t}\n\tif (msg.type === 'fullWindow') {\n\t\tconst payload = (msg as { payload?: unknown }).payload;\n\t\tif (!payload || typeof payload !== 'object') return null;\n\t\tif (typeof (payload as { active?: unknown }).active !== 'boolean') return null;\n\t\treturn msg as EmbedOutboundMessage;\n\t}\n\tif (msg.type === 'widgetAudioSettings') {\n\t\tconst payload = (msg as { payload?: unknown }).payload;\n\t\tif (!payload || typeof payload !== 'object') return null;\n\t\tif (typeof (payload as { open?: unknown }).open !== 'boolean') return null;\n\t\treturn msg as EmbedOutboundMessage;\n\t}\n\tif (msg.type === 'widgetDragStart' || msg.type === 'widgetDragEnd') {\n\t\tconst payload = (msg as { payload?: unknown }).payload;\n\t\tif (!payload || typeof payload !== 'object') return null;\n\t\tif (typeof (payload as { pointerId?: unknown }).pointerId !== 'number') return null;\n\t\tif (!Number.isFinite((payload as { pointerId: number }).pointerId)) return null;\n\t\treturn msg as EmbedOutboundMessage;\n\t}\n\tif (msg.type === 'widgetDragMove') {\n\t\tconst payload = (msg as { payload?: unknown }).payload;\n\t\tif (!payload || typeof payload !== 'object') return null;\n\t\tconst { pointerId, dx, dy } = payload as {\n\t\t\tpointerId?: unknown;\n\t\t\tdx?: unknown;\n\t\t\tdy?: unknown;\n\t\t};\n\t\tif (typeof pointerId !== 'number' || !Number.isFinite(pointerId)) return null;\n\t\tif (typeof dx !== 'number' || !Number.isFinite(dx)) return null;\n\t\tif (typeof dy !== 'number' || !Number.isFinite(dy)) return null;\n\t\treturn msg as EmbedOutboundMessage;\n\t}\n\tconst payload = (msg as { payload?: unknown }).payload;\n\tif (!payload || typeof payload !== 'object') return null;\n\treturn msg as EmbedOutboundMessage;\n}\n\nconst INBOUND_TYPES = new Set([\n\t'launch',\n\t'manifest',\n\t'parentHello',\n\t'speak',\n\t'startListening',\n\t'stopListening',\n\t'getConversation',\n\t'listenOnce',\n\t'speakStreamStart',\n\t'speakStreamChunk',\n\t'speakStreamEnd',\n\t'widgetSetChrome',\n\t'widgetToggleAudioSettings',\n\t'speechPlay',\n\t'speechUtteranceBegin',\n\t'speechUtteranceWrite',\n\t'speechUtteranceSetTranscript',\n\t'speechUtteranceClose',\n\t'speechUtteranceCancel',\n\t'speechInterrupt',\n\t'focusCharacter',\n\t'setFit',\n\t'conversion',\n\t'engage'\n]);\n\nexport function parseInboundMessage(data: unknown): EmbedInboundMessage | null {\n\tif (!data || typeof data !== 'object') return null;\n\tconst msg = data as Partial<EmbedInboundMessage>;\n\tif (!isSupportedEmbedMessageSchemaVersion(msg.schemaVersion)) return null;\n\tif (!msg.type || !INBOUND_TYPES.has(msg.type)) return null;\n\tif (msg.type === 'parentHello') return msg as EmbedInboundMessage;\n\tif (msg.type === 'widgetToggleAudioSettings') return msg as EmbedInboundMessage;\n\tif (msg.type === 'widgetSetChrome') {\n\t\tconst payload = (msg as { payload?: unknown }).payload;\n\t\tif (!payload || typeof payload !== 'object') return null;\n\t\tconst mode = (payload as { mode?: unknown }).mode;\n\t\tif (!isWidgetChromeMode(mode)) return null;\n\t\treturn msg as EmbedInboundMessage;\n\t}\n\tif (msg.type === 'setFit') {\n\t\tconst payload = (msg as { payload?: unknown }).payload;\n\t\tif (!payload || typeof payload !== 'object') return null;\n\t\tconst fit = (payload as { fit?: unknown }).fit;\n\t\tconst correlationId = (payload as { correlationId?: unknown }).correlationId;\n\t\tif (fit !== 'full' && fit !== 'medium' && fit !== 'face') return null;\n\t\tif (typeof correlationId !== 'string' || !correlationId.trim()) return null;\n\t\treturn msg as EmbedInboundMessage;\n\t}\n\tif (msg.type === 'speakStreamChunk') {\n\t\tconst payload = (msg as { payload?: unknown }).payload;\n\t\tif (!payload || typeof payload !== 'object') return null;\n\t\tconst streamId = (payload as { streamId?: unknown }).streamId;\n\t\tconst text = (payload as { text?: unknown }).text;\n\t\tif (typeof streamId !== 'string' || !streamId.trim()) return null;\n\t\tif (typeof text !== 'string') return null;\n\t\treturn msg as EmbedInboundMessage;\n\t}\n\tif (msg.type === 'launch') {\n\t\tconst payload = (msg as { payload?: unknown }).payload;\n\t\tif (!payload || typeof payload !== 'object') return null;\n\t\tconst launch = (payload as { launch?: unknown }).launch;\n\t\tif (typeof launch !== 'string' || !launch.trim()) return null;\n\t\treturn msg as EmbedInboundMessage;\n\t}\n\tconst payload = (msg as { payload?: unknown }).payload;\n\tif (!payload || typeof payload !== 'object') return null;\n\treturn msg as EmbedInboundMessage;\n}\n\nexport function createLaunchMessage(\n\tlaunch: string,\n\tsession?: Session | object,\n\tchrome?: {\n\t\treadonly startButton?: StartButtonOptions;\n\t\treadonly theme?: PlayerTheme;\n\t\treadonly showFeedback?: boolean;\n\t}\n): EmbedInboundMessage {\n\tconst trimmed = launch.trim();\n\tif (!trimmed) {\n\t\tthrow new Error('createLaunchMessage requires a non-empty launch string.');\n\t}\n\tconst startButton = chrome?.startButton;\n\tconst theme = chrome?.theme;\n\tconst showFeedback = chrome?.showFeedback;\n\treturn {\n\t\ttype: 'launch',\n\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\tpayload: {\n\t\t\tlaunch: trimmed,\n\t\t\t...(session !== undefined ? { session } : {}),\n\t\t\t...(startButton ? { startButton } : {}),\n\t\t\t...(theme ? { theme } : {}),\n\t\t\t...(showFeedback !== undefined ? { showFeedback } : {})\n\t\t}\n\t};\n}\n\n/** @deprecated Prefer {@link createLaunchMessage}. */\nexport function createManifestMessage(manifest: unknown): EmbedInboundMessage {\n\treturn {\n\t\ttype: 'manifest',\n\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\tpayload: { manifest }\n\t};\n}\n\nexport function createParentHelloMessage(): EmbedInboundMessage {\n\treturn {\n\t\ttype: 'parentHello',\n\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION\n\t};\n}\n\nexport function createEmbedReadyMessage(): EmbedOutboundMessage {\n\treturn {\n\t\ttype: 'embedReady',\n\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION\n\t};\n}\n\nexport function createWidgetSetChromeMessage(mode: WidgetChromeMode): EmbedInboundMessage {\n\treturn {\n\t\ttype: 'widgetSetChrome',\n\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\tpayload: { mode }\n\t};\n}\n\nexport function createWidgetToggleAudioSettingsMessage(): EmbedInboundMessage {\n\treturn {\n\t\ttype: 'widgetToggleAudioSettings',\n\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\tpayload: {}\n\t};\n}\n","/** Saved inline styles so full-window can be restored cleanly. */\nexport type FullWindowStyleSnapshot = {\n\treadonly position: string;\n\treadonly top: string;\n\treadonly right: string;\n\treadonly bottom: string;\n\treadonly left: string;\n\treadonly inset: string;\n\treadonly width: string;\n\treadonly height: string;\n\treadonly zIndex: string;\n\treadonly margin: string;\n\treadonly borderRadius: string;\n\treadonly maxWidth: string;\n\treadonly maxHeight: string;\n};\n\nconst FULL_WINDOW_Z_INDEX = '2147483000';\n\nexport function snapshotFullWindowStyles(el: HTMLElement): FullWindowStyleSnapshot {\n\tconst { style } = el;\n\treturn {\n\t\tposition: style.position,\n\t\ttop: style.top,\n\t\tright: style.right,\n\t\tbottom: style.bottom,\n\t\tleft: style.left,\n\t\tinset: style.inset,\n\t\twidth: style.width,\n\t\theight: style.height,\n\t\tzIndex: style.zIndex,\n\t\tmargin: style.margin,\n\t\tborderRadius: style.borderRadius,\n\t\tmaxWidth: style.maxWidth,\n\t\tmaxHeight: style.maxHeight\n\t};\n}\n\nexport function applyFullWindowStyles(el: HTMLElement): void {\n\tconst { style } = el;\n\tstyle.position = 'fixed';\n\tstyle.top = '0';\n\tstyle.right = '0';\n\tstyle.bottom = '0';\n\tstyle.left = '0';\n\tstyle.inset = '0';\n\tstyle.width = '100vw';\n\tstyle.width = '100dvw';\n\tstyle.height = '100vh';\n\tstyle.height = '100dvh';\n\tstyle.zIndex = FULL_WINDOW_Z_INDEX;\n\tstyle.margin = '0';\n\tstyle.borderRadius = '0';\n\tstyle.maxWidth = 'none';\n\tstyle.maxHeight = 'none';\n\tel.dataset.liformaFullWindow = '1';\n}\n\nexport function restoreFullWindowStyles(\n\tel: HTMLElement,\n\tsnapshot: FullWindowStyleSnapshot | null\n): void {\n\tdelete el.dataset.liformaFullWindow;\n\tif (!snapshot) {\n\t\tel.style.position = '';\n\t\tel.style.top = '';\n\t\tel.style.right = '';\n\t\tel.style.bottom = '';\n\t\tel.style.left = '';\n\t\tel.style.inset = '';\n\t\tel.style.width = '';\n\t\tel.style.height = '';\n\t\tel.style.zIndex = '';\n\t\tel.style.margin = '';\n\t\tel.style.borderRadius = '';\n\t\tel.style.maxWidth = '';\n\t\tel.style.maxHeight = '';\n\t\treturn;\n\t}\n\tconst { style } = el;\n\tstyle.position = snapshot.position;\n\tstyle.top = snapshot.top;\n\tstyle.right = snapshot.right;\n\tstyle.bottom = snapshot.bottom;\n\tstyle.left = snapshot.left;\n\tstyle.inset = snapshot.inset;\n\tstyle.width = snapshot.width;\n\tstyle.height = snapshot.height;\n\tstyle.zIndex = snapshot.zIndex;\n\tstyle.margin = snapshot.margin;\n\tstyle.borderRadius = snapshot.borderRadius;\n\tstyle.maxWidth = snapshot.maxWidth;\n\tstyle.maxHeight = snapshot.maxHeight;\n}\n","import {\n\tassertPlayerReachable,\n\tformatPlayerUnreachableMessage,\n\tpostMessageToPlayer\n} from './playerReachability';\nimport type { CloseEvent, EmbedInboundMessage, EmbedOutboundMessage, EmbedState } from './protocol';\nimport {\n\tcreateLaunchMessage,\n\tcreateManifestMessage,\n\tcreateParentHelloMessage,\n\tcreateWidgetSetChromeMessage,\n\tcreateWidgetToggleAudioSettingsMessage,\n\tEMBED_MESSAGE_SCHEMA_VERSION,\n\tparseOutboundMessage,\n\ttype WidgetChromeMode,\n\ttype WidgetDragMoveEvent,\n\ttype WidgetDragStartEvent\n} from './protocol';\nimport {\n\tapplyFullWindowStyles,\n\trestoreFullWindowStyles,\n\tsnapshotFullWindowStyles,\n\ttype FullWindowStyleSnapshot\n} from './fullWindowHost';\nimport type {\n\tCharacterSpeechEvent,\n\tConversationMessage,\n\tSpeakBehavior,\n\tSpeechResult as LegacySpeakResult,\n\tUserSpeechBoundaryEvent,\n\tUserTranscriptUpdate,\n\tUtteranceResult\n} from '../types/sessionInteraction';\nimport type { PlayerStatus, Session, SessionActivity } from '../types/sessionLaunch';\nimport type { StartButtonOptions, PlayerTheme } from '../types/sessionInteraction';\nimport type {\n\tCompleteSpeechQueuePolicy,\n\tSpeechAudioFormat,\n\tSpeechInterruptOptions,\n\tSpeechPlayEmbedSource,\n\tSpeechResult,\n\tStreamingSpeechQueuePolicy\n} from '../speech/types';\n\nexport type IframeHostEventMap = {\n\tclose: CloseEvent;\n\tstateUpdate: EmbedState;\n\tuserTranscript: UserTranscriptUpdate;\n\tcharacterSpeechStarted: CharacterSpeechEvent;\n\tcharacterSpeechEnded: CharacterSpeechEvent;\n\tconversationUpdate: readonly ConversationMessage[];\n\tlisteningState: boolean;\n\tstarted: { readonly mode: 'conversation' | 'presenter' };\n\twidgetReady: void;\n\twidgetExpand: void;\n\twidgetCollapse: void;\n\twidgetAudioSettings: boolean;\n\twidgetDragStart: WidgetDragStartEvent;\n\twidgetDragMove: WidgetDragMoveEvent;\n\twidgetDragEnd: { readonly pointerId: number };\n};\n\nexport type IframeHostOptions = {\n\treadonly container: HTMLElement;\n\treadonly src: string;\n\treadonly playerOrigin: string;\n\t/** Transparent iframe for ExperienceWidget warm overlay over a thumb. */\n\treadonly transparent?: boolean;\n\treadonly onClose?: (event: CloseEvent) => void;\n\t/** @deprecated Prefer {@link IframeHostOptions.onPlayerStatusChange}. */\n\treadonly onStateUpdate?: (state: EmbedState) => void;\n\treadonly onPlayerStatusChange?: (status: PlayerStatus) => void;\n\treadonly onUserTranscript?: (update: UserTranscriptUpdate) => void;\n\treadonly onUserSpeechStarted?: (event: UserSpeechBoundaryEvent) => void;\n\treadonly onUserSpeechEnded?: (event: UserSpeechBoundaryEvent) => void;\n\treadonly onCharacterSpeechStarted?: (event: CharacterSpeechEvent) => void;\n\treadonly onCharacterSpeechEnded?: (event: CharacterSpeechEvent) => void;\n\treadonly onCharacterFocusChanged?: (event: {\n\t\treadonly characterId: string;\n\t\treadonly reason: 'speech' | 'api' | 'node_enter';\n\t}) => void;\n\treadonly onConversationUpdate?: (conversation: readonly ConversationMessage[]) => void;\n\treadonly onMessage?: (message: ConversationMessage) => void;\n\treadonly onListeningState?: (listening: boolean) => void;\n\treadonly onActivityChange?: (activity: SessionActivity) => void;\n\treadonly onFeedback?: (result: {\n\t\treadonly contractVersion: 'feedback.v1';\n\t\treadonly types: readonly {\n\t\t\treadonly feedbackId: string;\n\t\t\treadonly name: string;\n\t\t\treadonly criteria: readonly {\n\t\t\t\treadonly criterionId: string;\n\t\t\t\treadonly label: string;\n\t\t\t\treadonly score: number | string;\n\t\t\t\treadonly rationale: string;\n\t\t\t}[];\n\t\t}[];\n\t}) => void;\n\treadonly onFeedbackFailed?: (event: {\n\t\treadonly error: string;\n\t\treadonly model?: string;\n\t}) => void;\n\treadonly onStarted?: (event: { readonly mode: 'conversation' | 'presenter' }) => void;\n\treadonly onWidgetReady?: () => void;\n\treadonly onWidgetExpand?: () => void;\n\treadonly onWidgetCollapse?: () => void;\n\treadonly onWidgetAudioSettings?: (open: boolean) => void;\n\treadonly onWidgetDragStart?: (event: WidgetDragStartEvent) => void;\n\treadonly onWidgetDragMove?: (event: WidgetDragMoveEvent) => void;\n\treadonly onWidgetDragEnd?: (event: { readonly pointerId: number }) => void;\n\treadonly onFullWindowChange?: (active: boolean) => void;\n};\n\nfunction legacyModeToActivity(mode: 'speaking' | 'listening' | 'thinking'): SessionActivity {\n\treturn mode;\n}\n\nexport type IframeHost = {\n\twaitForLoad(): Promise<void>;\n\tpostParentHello(): void;\n\tpostLaunch(\n\t\tlaunch: string,\n\t\tsession?: Session | object,\n\t\tchrome?: {\n\t\t\treadonly startButton?: StartButtonOptions;\n\t\t\treadonly theme?: PlayerTheme;\n\t\t\treadonly showFeedback?: boolean;\n\t\t}\n\t): void;\n\t/** @deprecated Prefer {@link IframeHost.postLaunch}. */\n\tpostManifest(manifest: unknown): void;\n\tpostWidgetSetChrome(mode: WidgetChromeMode): void;\n\tpostWidgetToggleAudioSettings(): void;\n\tspeak(options: {\n\t\ttext: string;\n\t\tcharacterId?: string;\n\t\tbehavior?: SpeakBehavior;\n\t}): Promise<LegacySpeakResult>;\n\tstartListening(): Promise<void>;\n\tstopListening(): Promise<UtteranceResult>;\n\tlistenOnce(options?: { readonly timeoutMs?: number }): Promise<UtteranceResult>;\n\tspeakProcessorStream(\n\t\tstream: AsyncIterable<string>,\n\t\toptions?: {\n\t\t\treadonly characterId?: string;\n\t\t\treadonly behavior?: SpeakBehavior;\n\t\t\treadonly signal?: AbortSignal;\n\t\t}\n\t): Promise<LegacySpeakResult>;\n\tspeechPlay(options: {\n\t\tsource: SpeechPlayEmbedSource;\n\t\tcharacterId?: string;\n\t\ttranscript?: string;\n\t\thistory?: 'none' | 'commit';\n\t\tqueue?: CompleteSpeechQueuePolicy;\n\t\tsignal?: AbortSignal;\n\t}): Promise<SpeechResult>;\n\tspeechUtteranceBegin(options: {\n\t\tutteranceId: string;\n\t\tformat: SpeechAudioFormat;\n\t\tcharacterId?: string;\n\t\tqueue: StreamingSpeechQueuePolicy;\n\t\ttranscript?: string;\n\t}): Promise<void>;\n\tspeechUtteranceWrite(options: {\n\t\tutteranceId: string;\n\t\taudio: ArrayBuffer;\n\t\tbyteLength: number;\n\t}): Promise<{ readonly bufferedMs: number }>;\n\tspeechUtteranceSetTranscript(options: {\n\t\tutteranceId: string;\n\t\ttranscript: string;\n\t}): Promise<void>;\n\tspeechUtteranceClose(options: {\n\t\tutteranceId: string;\n\t\ttranscript?: string;\n\t\thistory?: 'none' | 'commit';\n\t}): Promise<SpeechResult>;\n\tspeechUtteranceCancel(options: { utteranceId: string }): Promise<SpeechResult>;\n\tspeechInterrupt(options: SpeechInterruptOptions): Promise<readonly SpeechResult[]>;\n\tgetConversation(): Promise<readonly ConversationMessage[]>;\n\tfocusCharacter(characterId: string): Promise<void>;\n\tsetFit(fit: 'full' | 'face' | 'medium'): Promise<void>;\n\tconversion(key: string): Promise<void>;\n\tengage(): Promise<void>;\n\tdestroy(): void;\n};\n\nfunction newCorrelationId(): string {\n\tif (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n\t\treturn `cmd_${crypto.randomUUID().replace(/-/g, '').slice(0, 12)}`;\n\t}\n\treturn `cmd_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;\n}\n\nconst SPEECH_WRITE_COMMAND_TIMEOUT_MS = 30_000;\n\nexport function createIframeHost(options: IframeHostOptions): IframeHost {\n\tconst container = options.container;\n\tconst containerPosition = getComputedStyle(container).position;\n\tif (containerPosition === 'static') {\n\t\tcontainer.style.position = 'relative';\n\t}\n\n\tconst iframe = document.createElement('iframe');\n\tiframe.src = options.src;\n\tiframe.title = 'Liforma experience';\n\tiframe.setAttribute(\n\t\t'allow',\n\t\t'microphone; autoplay; clipboard-read; clipboard-write'\n\t);\n\t// Absolute fill so the player viewport matches the host box even when the host\n\t// height comes from flex or min-height (percentage height:100% often collapses).\n\tiframe.style.cssText = options.transparent\n\t\t? 'display:block;position:absolute;inset:0;width:100%;height:100%;border:0;background:transparent;'\n\t\t: 'display:block;position:absolute;inset:0;width:100%;height:100%;border:0;background:#030508;';\n\tif (options.transparent) {\n\t\tiframe.setAttribute('allowtransparency', 'true');\n\t}\n\n\tlet destroyed = false;\n\tlet fullWindowActive = false;\n\tlet fullWindowSnapshot: FullWindowStyleSnapshot | null = null;\n\tconst fullWindowTarget =\n\t\tcontainer.closest('.liforma-experience-shell') instanceof HTMLElement\n\t\t\t? (container.closest('.liforma-experience-shell') as HTMLElement)\n\t\t\t: container;\n\n\tconst setFullWindowActive = (active: boolean) => {\n\t\tif (fullWindowActive === active) return;\n\t\tfullWindowActive = active;\n\t\tif (active) {\n\t\t\tfullWindowSnapshot = snapshotFullWindowStyles(fullWindowTarget);\n\t\t\tapplyFullWindowStyles(fullWindowTarget);\n\t\t} else {\n\t\t\trestoreFullWindowStyles(fullWindowTarget, fullWindowSnapshot);\n\t\t\tfullWindowSnapshot = null;\n\t\t}\n\t\toptions.onFullWindowChange?.(active);\n\t};\n\tconst pendingCommands = new Map<\n\t\tstring,\n\t\t{\n\t\t\tresolve: (value: unknown) => void;\n\t\t\treject: (error: Error) => void;\n\t\t}\n\t>();\n\n\ttype StoredLaunch = {\n\t\treadonly launch: string;\n\t\treadonly session?: Session | object;\n\t\treadonly chrome?: {\n\t\t\treadonly startButton?: StartButtonOptions;\n\t\t\treadonly theme?: PlayerTheme;\n\t\t\treadonly showFeedback?: boolean;\n\t\t};\n\t};\n\n\tlet storedLaunch: StoredLaunch | null = null;\n\tlet loadGeneration = 0;\n\tlet lastLaunchBurstAt = 0;\n\tconst LAUNCH_BURST_COOLDOWN_MS = 250;\n\tconst launchBurstTimers: number[] = [];\n\n\tlet firstLoadResolve: (() => void) | null = null;\n\tlet firstLoadReject: ((error: Error) => void) | null = null;\n\tconst loadPromise = new Promise<void>((resolve, reject) => {\n\t\tfirstLoadResolve = resolve;\n\t\tfirstLoadReject = reject;\n\t});\n\n\tconst clearLaunchBurstTimers = () => {\n\t\tfor (const id of launchBurstTimers) window.clearTimeout(id);\n\t\tlaunchBurstTimers.length = 0;\n\t};\n\n\tconst postLaunchBurst = (stored: StoredLaunch): void => {\n\t\tif (destroyed) return;\n\t\tconst now = Date.now();\n\t\tif (lastLaunchBurstAt > 0 && now - lastLaunchBurstAt < LAUNCH_BURST_COOLDOWN_MS) {\n\t\t\treturn;\n\t\t}\n\t\tlastLaunchBurstAt = now;\n\t\tclearLaunchBurstTimers();\n\t\tconst message = createLaunchMessage(stored.launch, stored.session, stored.chrome);\n\t\tconst postOnce = () => {\n\t\t\tif (destroyed) return;\n\t\t\tconst target = iframe.contentWindow;\n\t\t\tif (!target) return;\n\t\t\tpostMessageToPlayer(target, message, options.playerOrigin);\n\t\t};\n\t\tpostOnce();\n\t\tfor (let attempt = 1; attempt <= 12; attempt += 1) {\n\t\t\tlaunchBurstTimers.push(window.setTimeout(postOnce, attempt * 75));\n\t\t}\n\t};\n\n\tconst replayStoredLaunch = (): void => {\n\t\tif (destroyed || !storedLaunch) return;\n\t\tpostLaunchBurst(storedLaunch);\n\t};\n\n\tconst onIframeLoad = () => {\n\t\tloadGeneration += 1;\n\t\tif (loadGeneration === 1) {\n\t\t\tvoid assertPlayerReachable(options.src, options.playerOrigin).then(\n\t\t\t\t() => firstLoadResolve?.(),\n\t\t\t\t(error) =>\n\t\t\t\t\tfirstLoadReject?.(error instanceof Error ? error : new Error(String(error)))\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\t// Vite / HMR reloads the player document in-place. The first-load handshake\n\t\t// already completed, so re-post launch to the new contentWindow.\n\t\tlastLaunchBurstAt = 0;\n\t\treplayStoredLaunch();\n\t};\n\tconst onIframeError = () => {\n\t\tif (loadGeneration > 0) return;\n\t\tfirstLoadReject?.(new Error(formatPlayerUnreachableMessage(options.playerOrigin)));\n\t};\n\tiframe.addEventListener('load', onIframeLoad);\n\tiframe.addEventListener('error', onIframeError);\n\n\tconst onMessage = (event: MessageEvent) => {\n\t\tif (destroyed) return;\n\t\tif (event.source !== iframe.contentWindow) return;\n\t\tif (event.origin !== options.playerOrigin) return;\n\n\t\tconst message = parseOutboundMessage(event.data);\n\t\tif (!message) return;\n\n\t\tswitch (message.type) {\n\t\t\tcase 'close':\n\t\t\t\toptions.onClose?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'stateUpdate':\n\t\t\t\toptions.onPlayerStatusChange?.(message.payload.state);\n\t\t\t\toptions.onStateUpdate?.(message.payload.state);\n\t\t\t\tbreak;\n\t\t\tcase 'commandResult': {\n\t\t\t\tconst pending = pendingCommands.get(message.payload.correlationId);\n\t\t\t\tif (!pending) return;\n\t\t\t\tpendingCommands.delete(message.payload.correlationId);\n\t\t\t\tif (message.payload.ok) {\n\t\t\t\t\tpending.resolve(message.payload.result);\n\t\t\t\t} else {\n\t\t\t\t\tpending.reject(new Error(message.payload.error ?? 'Command failed.'));\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'userTranscript':\n\t\t\t\toptions.onUserTranscript?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'characterSpeechStarted':\n\t\t\t\toptions.onCharacterSpeechStarted?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'characterSpeechEnded':\n\t\t\t\toptions.onCharacterSpeechEnded?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'characterFocusChanged':\n\t\t\t\toptions.onCharacterFocusChanged?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'conversationUpdate':\n\t\t\t\toptions.onConversationUpdate?.(message.payload.conversation);\n\t\t\t\tbreak;\n\t\t\tcase 'listeningState':\n\t\t\t\toptions.onListeningState?.(message.payload.listening);\n\t\t\t\tbreak;\n\t\t\tcase 'userSpeechStarted':\n\t\t\t\toptions.onUserSpeechStarted?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'userSpeechEnded':\n\t\t\t\toptions.onUserSpeechEnded?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'modeChange':\n\t\t\t\toptions.onActivityChange?.(legacyModeToActivity(message.payload.mode));\n\t\t\t\tbreak;\n\t\t\tcase 'activityChange':\n\t\t\t\toptions.onActivityChange?.(message.payload.activity);\n\t\t\t\tbreak;\n\t\t\tcase 'feedback':\n\t\t\t\toptions.onFeedback?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'feedbackFailed':\n\t\t\t\toptions.onFeedbackFailed?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'message':\n\t\t\t\toptions.onMessage?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'started':\n\t\t\t\toptions.onStarted?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'embedReady':\n\t\t\t\t// Soft HMR remounts the player without an iframe `load` event.\n\t\t\t\treplayStoredLaunch();\n\t\t\t\tbreak;\n\t\t\tcase 'widgetReady':\n\t\t\t\toptions.onWidgetReady?.();\n\t\t\t\tbreak;\n\t\t\tcase 'widgetExpand':\n\t\t\t\toptions.onWidgetExpand?.();\n\t\t\t\tbreak;\n\t\t\tcase 'widgetCollapse':\n\t\t\t\toptions.onWidgetCollapse?.();\n\t\t\t\tbreak;\n\t\t\tcase 'widgetAudioSettings':\n\t\t\t\toptions.onWidgetAudioSettings?.(message.payload.open);\n\t\t\t\tbreak;\n\t\t\tcase 'widgetDragStart':\n\t\t\t\toptions.onWidgetDragStart?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'widgetDragMove':\n\t\t\t\toptions.onWidgetDragMove?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'widgetDragEnd':\n\t\t\t\toptions.onWidgetDragEnd?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'fullWindow':\n\t\t\t\tsetFullWindowActive(message.payload.active);\n\t\t\t\tbreak;\n\t\t}\n\t};\n\n\twindow.addEventListener('message', onMessage);\n\tcontainer.replaceChildren(iframe);\n\t// Absolute iframe does not contribute to parent height — keep a usable floor when\n\t// the host only sized itself from previous in-flow content.\n\tif (container.clientHeight < 2 && !container.style.minHeight) {\n\t\tconst computedMin = getComputedStyle(container).minHeight;\n\t\tif (computedMin === '0px' || computedMin === 'auto') {\n\t\t\tcontainer.style.minHeight = '480px';\n\t\t}\n\t}\n\n\tconst postToIframe = (message: EmbedInboundMessage, transfer?: Transferable[]) => {\n\t\tif (destroyed) return;\n\t\tconst target = iframe.contentWindow;\n\t\tif (!target) {\n\t\t\tthrow new Error(formatPlayerUnreachableMessage(options.playerOrigin));\n\t\t}\n\t\tpostMessageToPlayer(target, message, options.playerOrigin, transfer);\n\t};\n\n\tconst postCommand = <T>(\n\t\tmessage: EmbedInboundMessage,\n\t\ttimeoutMs = 120_000,\n\t\ttransfer?: Transferable[]\n\t): Promise<T> => {\n\t\tconst correlationId =\n\t\t\tmessage.type !== 'parentHello' && message.payload && 'correlationId' in message.payload\n\t\t\t\t? (message.payload.correlationId as string)\n\t\t\t\t: newCorrelationId();\n\n\t\tif (message.type !== 'parentHello' && message.payload && 'correlationId' in message.payload) {\n\t\t\t// correlationId already set\n\t\t} else if (message.type !== 'parentHello' && message.payload) {\n\t\t\t(message.payload as { correlationId: string }).correlationId = correlationId;\n\t\t}\n\n\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\tpendingCommands.set(correlationId, {\n\t\t\t\tresolve: (value) => resolve(value as T),\n\t\t\t\treject\n\t\t\t});\n\t\t\tpostToIframe(message, transfer);\n\t\t\tsetTimeout(() => {\n\t\t\t\tif (!pendingCommands.has(correlationId)) return;\n\t\t\t\tpendingCommands.delete(correlationId);\n\t\t\t\treject(new Error('Timed out waiting for player command result.'));\n\t\t\t}, timeoutMs);\n\t\t});\n\t};\n\n\treturn {\n\t\twaitForLoad() {\n\t\t\treturn loadPromise;\n\t\t},\n\t\tpostParentHello() {\n\t\t\tpostToIframe(createParentHelloMessage());\n\t\t},\n\t\tpostLaunch(launch, session, chrome) {\n\t\t\tif (destroyed) return;\n\t\t\tstoredLaunch = { launch, session, chrome };\n\t\t\tlastLaunchBurstAt = 0;\n\t\t\tpostLaunchBurst(storedLaunch);\n\t\t},\n\t\tpostManifest(manifest) {\n\t\t\tif (typeof manifest === 'string') {\n\t\t\t\tthis.postLaunch(manifest);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (\n\t\t\t\tmanifest &&\n\t\t\t\ttypeof manifest === 'object' &&\n\t\t\t\ttypeof (manifest as { launch?: unknown }).launch === 'string'\n\t\t\t) {\n\t\t\t\tconst launch = String((manifest as { launch: string }).launch);\n\t\t\t\tconst session = (manifest as { session?: object }).session;\n\t\t\t\tthis.postLaunch(launch, session);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow new Error(\n\t\t\t\t'postManifest is deprecated; use postLaunch with an opaque launch string from SessionLaunchResponse.'\n\t\t\t);\n\t\t},\n\t\tpostWidgetSetChrome(mode) {\n\t\t\tpostToIframe(createWidgetSetChromeMessage(mode));\n\t\t},\n\t\tpostWidgetToggleAudioSettings() {\n\t\t\tpostToIframe(createWidgetToggleAudioSettingsMessage());\n\t\t},\n\t\tspeak(options) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<LegacySpeakResult>({\n\t\t\t\ttype: 'speak',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: {\n\t\t\t\t\tcorrelationId,\n\t\t\t\t\ttext: options.text,\n\t\t\t\t\t...(options.characterId ? { characterId: options.characterId } : {}),\n\t\t\t\t\t...(options.behavior ? { behavior: options.behavior } : {})\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\tstartListening() {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<void>({\n\t\t\t\ttype: 'startListening',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: { correlationId }\n\t\t\t});\n\t\t},\n\t\tstopListening() {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<UtteranceResult>({\n\t\t\t\ttype: 'stopListening',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: { correlationId }\n\t\t\t});\n\t\t},\n\t\tlistenOnce(options) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<UtteranceResult>({\n\t\t\t\ttype: 'listenOnce',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: {\n\t\t\t\t\tcorrelationId,\n\t\t\t\t\t...(options?.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {})\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\tasync speakProcessorStream(stream, options) {\n\t\t\tconst startCorrelationId = newCorrelationId();\n\t\t\tconst endCorrelationId = newCorrelationId();\n\t\t\tconst started = await postCommand<{ streamId: string }>({\n\t\t\t\ttype: 'speakStreamStart',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: {\n\t\t\t\t\tcorrelationId: startCorrelationId,\n\t\t\t\t\t...(options?.characterId ? { characterId: options.characterId } : {}),\n\t\t\t\t\t...(options?.behavior ? { behavior: options.behavior } : {})\n\t\t\t\t}\n\t\t\t});\n\t\t\tconst streamId = started.streamId;\n\t\t\ttry {\n\t\t\t\tfor await (const chunk of stream) {\n\t\t\t\t\tif (options?.signal?.aborted) {\n\t\t\t\t\t\tthrow new DOMException('Processor stream aborted.', 'AbortError');\n\t\t\t\t\t}\n\t\t\t\t\tif (!chunk) continue;\n\t\t\t\t\tpostToIframe({\n\t\t\t\t\t\ttype: 'speakStreamChunk',\n\t\t\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\t\t\tpayload: { streamId, text: chunk }\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (options?.signal?.aborted) {\n\t\t\t\t\tthrow new DOMException('Processor stream aborted.', 'AbortError');\n\t\t\t\t}\n\t\t\t\treturn await postCommand<LegacySpeakResult>({\n\t\t\t\t\ttype: 'speakStreamEnd',\n\t\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\t\tpayload: { correlationId: endCorrelationId, streamId }\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\ttry {\n\t\t\t\t\tawait postCommand<LegacySpeakResult>({\n\t\t\t\t\t\ttype: 'speakStreamEnd',\n\t\t\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\t\t\tpayload: { correlationId: endCorrelationId, streamId }\n\t\t\t\t\t});\n\t\t\t\t} catch {\n\t\t\t\t\t/* stream may already be torn down */\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t\tspeechPlay(options) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\tconst transfer: Transferable[] = [];\n\t\t\tif (options.source.kind === 'pcm' || options.source.kind === 'encoded') {\n\t\t\t\ttransfer.push(options.source.data);\n\t\t\t}\n\t\t\treturn postCommand<SpeechResult>(\n\t\t\t\t{\n\t\t\t\t\ttype: 'speechPlay',\n\t\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\t\tpayload: {\n\t\t\t\t\t\tcorrelationId,\n\t\t\t\t\t\tsource: options.source,\n\t\t\t\t\t\t...(options.characterId ? { characterId: options.characterId } : {}),\n\t\t\t\t\t\t...(options.transcript !== undefined ? { transcript: options.transcript } : {}),\n\t\t\t\t\t\t...(options.history ? { history: options.history } : {}),\n\t\t\t\t\t\t...(options.queue ? { queue: options.queue } : {})\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t120_000,\n\t\t\t\ttransfer\n\t\t\t);\n\t\t},\n\t\tspeechUtteranceBegin(options) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<void>({\n\t\t\t\ttype: 'speechUtteranceBegin',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: {\n\t\t\t\t\tcorrelationId,\n\t\t\t\t\tutteranceId: options.utteranceId,\n\t\t\t\t\tformat: options.format,\n\t\t\t\t\tqueue: options.queue,\n\t\t\t\t\t...(options.characterId ? { characterId: options.characterId } : {}),\n\t\t\t\t\t...(options.transcript !== undefined ? { transcript: options.transcript } : {})\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\tspeechUtteranceWrite(options) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<{ bufferedMs: number }>(\n\t\t\t\t{\n\t\t\t\t\ttype: 'speechUtteranceWrite',\n\t\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\t\tpayload: {\n\t\t\t\t\t\tcorrelationId,\n\t\t\t\t\t\tutteranceId: options.utteranceId,\n\t\t\t\t\t\taudio: options.audio,\n\t\t\t\t\t\tbyteLength: options.byteLength\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tSPEECH_WRITE_COMMAND_TIMEOUT_MS,\n\t\t\t\t[options.audio]\n\t\t\t);\n\t\t},\n\t\tspeechUtteranceSetTranscript(options) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<void>({\n\t\t\t\ttype: 'speechUtteranceSetTranscript',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: {\n\t\t\t\t\tcorrelationId,\n\t\t\t\t\tutteranceId: options.utteranceId,\n\t\t\t\t\ttranscript: options.transcript\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\tspeechUtteranceClose(options) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<SpeechResult>({\n\t\t\t\ttype: 'speechUtteranceClose',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: {\n\t\t\t\t\tcorrelationId,\n\t\t\t\t\tutteranceId: options.utteranceId,\n\t\t\t\t\t...(options.transcript !== undefined ? { transcript: options.transcript } : {}),\n\t\t\t\t\t...(options.history ? { history: options.history } : {})\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\tspeechUtteranceCancel(options) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<SpeechResult>({\n\t\t\t\ttype: 'speechUtteranceCancel',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: {\n\t\t\t\t\tcorrelationId,\n\t\t\t\t\tutteranceId: options.utteranceId\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\tspeechInterrupt(options) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<readonly SpeechResult[]>({\n\t\t\t\ttype: 'speechInterrupt',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: {\n\t\t\t\t\tcorrelationId,\n\t\t\t\t\t...options\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\tgetConversation() {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<readonly ConversationMessage[]>({\n\t\t\t\ttype: 'getConversation',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: { correlationId }\n\t\t\t});\n\t\t},\n\t\tfocusCharacter(characterId) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<void>({\n\t\t\t\ttype: 'focusCharacter',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: { correlationId, characterId }\n\t\t\t});\n\t\t},\n\t\tsetFit(fit) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<void>({\n\t\t\t\ttype: 'setFit',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: { correlationId, fit }\n\t\t\t});\n\t\t},\n\t\tconversion(key) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<void>({\n\t\t\t\ttype: 'conversion',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: { correlationId, key }\n\t\t\t});\n\t\t},\n\t\tengage() {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<void>({\n\t\t\t\ttype: 'engage',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: { correlationId }\n\t\t\t});\n\t\t},\n\t\tdestroy() {\n\t\t\tif (destroyed) return;\n\t\t\tdestroyed = true;\n\t\t\tif (fullWindowActive) {\n\t\t\t\tsetFullWindowActive(false);\n\t\t\t}\n\t\t\tfor (const pending of pendingCommands.values()) {\n\t\t\t\tpending.reject(new Error('Iframe host destroyed.'));\n\t\t\t}\n\t\t\tpendingCommands.clear();\n\t\t\tclearLaunchBurstTimers();\n\t\t\tstoredLaunch = null;\n\t\t\tiframe.removeEventListener('load', onIframeLoad);\n\t\t\tiframe.removeEventListener('error', onIframeError);\n\t\t\twindow.removeEventListener('message', onMessage);\n\t\t\tiframe.remove();\n\t\t}\n\t};\n}\n\n","export type ReadyGate<T> = {\n\tsetValue(value: T): void;\n\tmarkReady(): void;\n};\n\n/** Emits once after both an asynchronous value and readiness signal are available. */\nexport function createReadyGate<T>(onReady: (value: T) => void): ReadyGate<T> {\n\tlet value: T | undefined;\n\tlet ready = false;\n\tlet emitted = false;\n\n\tconst emitIfPossible = (): void => {\n\t\tif (emitted || !ready || value === undefined) return;\n\t\temitted = true;\n\t\tonReady(value);\n\t};\n\n\treturn {\n\t\tsetValue(nextValue) {\n\t\t\tvalue = nextValue;\n\t\t\temitIfPossible();\n\t\t},\n\t\tmarkReady() {\n\t\t\tready = true;\n\t\t\temitIfPossible();\n\t\t}\n\t};\n}\n","import { useExplicitLocalStack } from '../../shims/localStack';\n\nconst PRODUCTION_PLAYER_EMBED_URL = 'https://player.liforma.ai/embed';\nconst LOCAL_PLAYER_EMBED_URL = 'http://localhost:3002/embed';\n\nfunction readConfiguredEmbedUrl(): string | null {\n\tconst globalValue = (globalThis as { __LIFORMA_PLAYER_EMBED_URL?: string })\n\t\t.__LIFORMA_PLAYER_EMBED_URL;\n\tif (globalValue?.trim()) {\n\t\treturn globalValue.trim().replace(/\\/$/, '');\n\t}\n\n\tif (typeof document === 'undefined') {\n\t\treturn null;\n\t}\n\n\tconst script =\n\t\tdocument.querySelector('script[data-liforma-sdk][src*=\"client.js\"]') ??\n\t\tdocument.querySelector('script[src*=\"/sdk/v2/client.js\"]');\n\tconst fromScript = script?.getAttribute('data-player-embed-url')?.trim();\n\tif (fromScript) {\n\t\treturn fromScript.replace(/\\/$/, '');\n\t}\n\n\treturn null;\n}\n\n/**\n * Hosted player embed document URL (iframe `src` base).\n *\n * Defaults to production. Local stack is opt-in only — never inferred from\n * `localhost` hostname (third-party demos run on localhost against production).\n *\n * Override order:\n * 1. `window.__LIFORMA_PLAYER_EMBED_URL`\n * 2. `data-player-embed-url` on the SDK script tag\n * 3. `window.__LIFORMA_STACK === 'local'` or host `?stack=local` → http://localhost:3002/embed\n * 4. production → https://player.liforma.ai/embed\n */\nexport function resolvePublicPlayerEmbedUrl(): string {\n\tconst configured = readConfiguredEmbedUrl();\n\tif (configured) {\n\t\treturn configured.endsWith('/embed') ? configured : `${configured}/embed`;\n\t}\n\n\tif (useExplicitLocalStack()) {\n\t\treturn LOCAL_PLAYER_EMBED_URL;\n\t}\n\n\treturn PRODUCTION_PLAYER_EMBED_URL;\n}\n\nexport function resolveSceneHintId(backdropId?: string, locationId?: string): string | undefined {\n\tconst id = backdropId?.trim() || locationId?.trim();\n\treturn id || undefined;\n}\n\nexport function buildManifestEmbedUrl(\n\tembedBaseUrl?: string,\n\tdebug?: boolean,\n\tbackdropId?: string,\n\tavatarId?: string,\n\tfit?: 'full' | 'face' | 'medium',\n\tui?: 'widget',\n\tshowClose?: boolean,\n\tcastSize?: 2 | 3 | 4\n): string {\n\tconst base = (embedBaseUrl ?? resolvePublicPlayerEmbedUrl()).replace(/\\/$/, '');\n\tconst embedRoot = base.endsWith('/embed') ? base : `${base}/embed`;\n\tconst url = new URL(embedRoot);\n\tconst loc = backdropId?.trim();\n\tif (loc) {\n\t\turl.searchParams.set('backdropId', loc);\n\t\turl.searchParams.set('locationId', loc);\n\t}\n\tconst avatar = avatarId?.trim();\n\tif (avatar) {\n\t\turl.searchParams.set('avatarId', avatar);\n\t}\n\tif (fit === 'face' || fit === 'medium') {\n\t\turl.searchParams.set('fit', fit);\n\t}\n\tif (ui === 'widget') {\n\t\turl.searchParams.set('ui', 'widget');\n\t}\n\tif (showClose) {\n\t\turl.searchParams.set('close', '1');\n\t}\n\tif (debug) {\n\t\turl.searchParams.set('debug', 'true');\n\t}\n\tif (castSize === 2 || castSize === 3 || castSize === 4) {\n\t\turl.searchParams.set('cast', String(castSize));\n\t}\n\treturn withEmbedParentOrigin(url.toString());\n}\n\nexport function buildPublicEmbedUrl(\n\texperienceId: string,\n\tembedBaseUrl?: string,\n\tlanguage?: 'en' | 'es',\n\tbackdropId?: string,\n\tavatarId?: string,\n\tdebug?: boolean\n): string {\n\tconst base = (embedBaseUrl ?? resolvePublicPlayerEmbedUrl()).replace(/\\/$/, '');\n\tconst embedRoot = base.endsWith('/embed') ? base : `${base}/embed`;\n\tconst url = new URL(embedRoot);\n\turl.searchParams.set('experienceId', experienceId);\n\tif (language && language !== 'en') {\n\t\turl.searchParams.set('language', language);\n\t}\n\tconst loc = backdropId?.trim();\n\tif (loc) {\n\t\turl.searchParams.set('backdropId', loc);\n\t\turl.searchParams.set('locationId', loc);\n\t}\n\tconst avatar = avatarId?.trim();\n\tif (avatar) {\n\t\turl.searchParams.set('avatarId', avatar);\n\t}\n\tif (debug) {\n\t\turl.searchParams.set('debug', 'true');\n\t}\n\treturn withEmbedParentOrigin(url.toString());\n}\n\n/** Tell the player embed which origin may receive postMessage events (SDK parent page). */\nexport function withEmbedParentOrigin(embedUrl: string): string {\n\tif (typeof location === 'undefined') return embedUrl;\n\tconst url = new URL(embedUrl);\n\turl.searchParams.set('parentOrigin', location.origin);\n\treturn url.toString();\n}\n\nexport function resolvePlayerOrigin(embedUrl: string): string {\n\treturn new URL(embedUrl).origin;\n}\n","import type { ReadyEvent } from './experience';\nimport type {\n\tCharacterSpeechEvent,\n\tConversationMessage,\n\tConversationProcessorErrorEvent,\n\tStartedEvent,\n\tUserSpeechBoundaryEvent,\n\tUserTranscriptUpdate\n} from './types/sessionInteraction';\nimport type { SessionActivity } from './types/sessionLaunch';\n\nexport type FeedbackResult = {\n\treadonly contractVersion: 'feedback.v1';\n\treadonly types: readonly {\n\t\treadonly feedbackId: string;\n\t\treadonly name: string;\n\t\treadonly criteria: readonly {\n\t\t\treadonly criterionId: string;\n\t\t\treadonly label: string;\n\t\t\treadonly score: number | string;\n\t\t\treadonly rationale: string;\n\t\t}[];\n\t}[];\n};\n\nexport type FeedbackFailedEvent = {\n\treadonly error: string;\n\treadonly model?: string;\n};\n\nexport type ExperienceEventEnvelope<T = unknown> = {\n\treadonly id: string;\n\treadonly type: string;\n\treadonly sessionId: string;\n\treadonly timestamp: string;\n\treadonly data: T;\n};\n\nfunction newEventId(): string {\n\tif (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n\t\treturn `evt_${crypto.randomUUID().replace(/-/g, '').slice(0, 12)}`;\n\t}\n\treturn `evt_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;\n}\n\nexport function createExperienceEventEnvelope<T>(\n\ttype: string,\n\tsessionId: string,\n\tdata: T\n): ExperienceEventEnvelope<T> {\n\treturn {\n\t\tid: newEventId(),\n\t\ttype,\n\t\tsessionId,\n\t\ttimestamp: new Date().toISOString(),\n\t\tdata\n\t};\n}\n\nexport type ExperienceEvents = {\n\treadonly ready: ExperienceEventEnvelope<ReadyEvent>;\n\treadonly started: ExperienceEventEnvelope<StartedEvent>;\n\t/** Fired once after a successful Session Launch mint (before player ready). */\n\treadonly sessionMinted: ExperienceEventEnvelope<ReadyEvent>;\n\treadonly userTranscript: ExperienceEventEnvelope<UserTranscriptUpdate>;\n\treadonly userSpeechStarted: ExperienceEventEnvelope<UserSpeechBoundaryEvent>;\n\treadonly userSpeechEnded: ExperienceEventEnvelope<UserSpeechBoundaryEvent>;\n\treadonly characterSpeechStarted: ExperienceEventEnvelope<CharacterSpeechEvent>;\n\treadonly characterSpeechEnded: ExperienceEventEnvelope<CharacterSpeechEvent>;\n\treadonly characterFocusChanged: ExperienceEventEnvelope<{\n\t\treadonly characterId: string;\n\t\treadonly reason: 'speech' | 'api' | 'node_enter';\n\t}>;\n\treadonly conversationUpdate: ExperienceEventEnvelope<readonly ConversationMessage[]>;\n\treadonly message: ExperienceEventEnvelope<ConversationMessage>;\n\treadonly listeningState: ExperienceEventEnvelope<boolean>;\n\treadonly activityChange: ExperienceEventEnvelope<SessionActivity>;\n\t/** End-of-session Feedback scores (`feedback.v1`). Emitted when scoring succeeds. */\n\treadonly feedback: ExperienceEventEnvelope<FeedbackResult>;\n\t/** End-of-session Feedback scoring failed. */\n\treadonly feedbackFailed: ExperienceEventEnvelope<FeedbackFailedEvent>;\n\treadonly conversationProcessorError: ExperienceEventEnvelope<ConversationProcessorErrorEvent>;\n};\n\n/**\n * Reserved integrator event name: `backdropChange`.\n * The hosted player does not emit `locationChange` or `backdropChange` today.\n * Do not invent a client-side fake until the runtime actually changes scene mid-session.\n */\n\nexport type ExperienceEventName = keyof ExperienceEvents;\n\ntype HandlerSet<K extends ExperienceEventName> = Set<(event: ExperienceEvents[K]) => void>;\n\nexport type ExperienceEventRegistry = {\n\treadonly [K in ExperienceEventName]: HandlerSet<K>;\n};\n\nexport function createExperienceEventRegistry(): ExperienceEventRegistry {\n\treturn {\n\t\tready: new Set(),\n\t\tstarted: new Set(),\n\t\tsessionMinted: new Set(),\n\t\tuserTranscript: new Set(),\n\t\tuserSpeechStarted: new Set(),\n\t\tuserSpeechEnded: new Set(),\n\t\tcharacterSpeechStarted: new Set(),\n\t\tcharacterSpeechEnded: new Set(),\n\t\tcharacterFocusChanged: new Set(),\n\t\tconversationUpdate: new Set(),\n\t\tmessage: new Set(),\n\t\tlisteningState: new Set(),\n\t\tactivityChange: new Set(),\n\t\tfeedback: new Set(),\n\t\tfeedbackFailed: new Set(),\n\t\tconversationProcessorError: new Set()\n\t};\n}\n\nexport function subscribeExperienceEvent<K extends ExperienceEventName>(\n\tregistry: ExperienceEventRegistry,\n\tevent: K,\n\thandler: (payload: ExperienceEvents[K]) => void\n): () => void {\n\tregistry[event].add(handler);\n\treturn () => registry[event].delete(handler);\n}\n\nexport function emitExperienceEvent<K extends ExperienceEventName>(\n\tregistry: ExperienceEventRegistry,\n\tevent: K,\n\tpayload: ExperienceEvents[K]\n): void {\n\tfor (const handler of registry[event]) {\n\t\thandler(payload);\n\t}\n}\n\nexport function clearExperienceEventRegistry(registry: ExperienceEventRegistry): void {\n\tfor (const key of Object.keys(registry) as ExperienceEventName[]) {\n\t\tregistry[key].clear();\n\t}\n}\n","/**\n * Phase A public speech contract for Experience.speech\n * (docs/plans/2026/08/experience-play-audio-api.plan.md).\n */\n\nexport type SpeechAudioFormat = {\n\treadonly encoding: 'pcm_s16le';\n\treadonly sampleRate: number;\n\treadonly channels: 1;\n};\n\n/** Complete one-shot ops only (`speak` / `play`). */\nexport type CompleteSpeechQueuePolicy = 'append' | 'replace-active' | 'replace-all';\n\n/** Live streams only — `append` is forbidden. */\nexport type StreamingSpeechQueuePolicy = 'replace-active' | 'replace-all';\n\nexport type SpeechTerminalStatus = 'completed' | 'interrupted' | 'cancelled' | 'destroyed';\n\nexport type SpeechAnimationMode = 'tracked' | 'partially-tracked' | 'energy-fallback' | 'none';\n\nexport type SpeechResult = {\n\treadonly utteranceId: string;\n\treadonly characterId: string;\n\treadonly status: SpeechTerminalStatus;\n\treadonly durationMs: number;\n\treadonly transcript?: string;\n\treadonly animation: {\n\t\treadonly mode: SpeechAnimationMode;\n\t\treadonly trackedDurationMs: number;\n\t\treadonly fallbackDurationMs: number;\n\t\treadonly warningCodes?: readonly string[];\n\t};\n};\n\nexport type SpeechInterruptOptions =\n\t| { readonly utteranceId: string }\n\t| { readonly characterId: string }\n\t| { readonly scope?: 'active' | 'all' };\n\nexport type SpeechSpeakOptions = {\n\treadonly text: string;\n\treadonly characterId?: string;\n\treadonly queue?: CompleteSpeechQueuePolicy;\n\treadonly signal?: AbortSignal;\n};\n\n/** Raw PCM one-shot (Phase A). */\nexport type SpeechPlayPcmAudio = {\n\treadonly data: ArrayBuffer | Uint8Array;\n\treadonly format: SpeechAudioFormat;\n};\n\n/**\n * Encoded media bytes (wav/mp3/…). Player decodes via Web Audio — not api/models.\n * `encoding` is a MIME type such as `audio/mpeg` or `audio/wav`.\n */\nexport type SpeechPlayEncodedAudio = {\n\treadonly data: ArrayBuffer | Uint8Array | Blob;\n\treadonly encoding: string;\n\t/** Preferred pcm sample rate after decode (default 24000 when decoded rate is unsupported). */\n\treadonly sampleRate?: number;\n};\n\n/** Fetch + decode in the player (URL must allow CORS from player.liforma.ai). */\nexport type SpeechPlayUrlAudio = {\n\treadonly url: string;\n\treadonly sampleRate?: number;\n};\n\n/**\n * Live audio track. Captured to PCM in the **host** SDK (not transferable across the embed).\n * Prefer `createUtterance({ track })` for long streams; `play({ audio: { track } })` runs until\n * the track ends then closes the utterance.\n */\nexport type SpeechPlayMediaStreamAudio = {\n\treadonly track: MediaStreamTrack;\n\t/** Target pcm sample rate after capture (default 24000). */\n\treadonly sampleRate?: number;\n};\n\nexport type SpeechPlayAudio =\n\t| SpeechPlayPcmAudio\n\t| SpeechPlayEncodedAudio\n\t| SpeechPlayUrlAudio\n\t| SpeechPlayMediaStreamAudio;\n\nexport type SpeechPlayOptions = {\n\treadonly audio: SpeechPlayAudio;\n\treadonly characterId?: string;\n\treadonly transcript?: string;\n\treadonly history?: 'none' | 'commit';\n\treadonly queue?: CompleteSpeechQueuePolicy;\n\treadonly signal?: AbortSignal;\n};\n\n/** Embed / player wire format for {@link SpeechPlayOptions.audio}. */\nexport type SpeechPlayEmbedSource =\n\t| {\n\t\t\treadonly kind: 'pcm';\n\t\t\treadonly data: ArrayBuffer;\n\t\t\treadonly format: SpeechAudioFormat;\n\t }\n\t| {\n\t\t\treadonly kind: 'encoded';\n\t\t\treadonly data: ArrayBuffer;\n\t\t\treadonly encoding: string;\n\t\t\treadonly sampleRate?: number;\n\t }\n\t| {\n\t\t\treadonly kind: 'url';\n\t\t\treadonly url: string;\n\t\t\treadonly sampleRate?: number;\n\t };\n\nexport function isSpeechPlayPcmAudio(audio: SpeechPlayAudio): audio is SpeechPlayPcmAudio {\n\treturn (\n\t\t'data' in audio &&\n\t\t'format' in audio &&\n\t\t(audio as SpeechPlayPcmAudio).format != null &&\n\t\t!('track' in audio)\n\t);\n}\n\nexport function isSpeechPlayUrlAudio(audio: SpeechPlayAudio): audio is SpeechPlayUrlAudio {\n\treturn 'url' in audio && typeof (audio as SpeechPlayUrlAudio).url === 'string';\n}\n\nexport function isSpeechPlayMediaStreamAudio(\n\taudio: SpeechPlayAudio\n): audio is SpeechPlayMediaStreamAudio {\n\tif (!('track' in audio)) return false;\n\tconst track = (audio as SpeechPlayMediaStreamAudio).track as unknown;\n\tif (track == null || typeof track !== 'object') return false;\n\tif (typeof MediaStreamTrack !== 'undefined' && track instanceof MediaStreamTrack) {\n\t\treturn true;\n\t}\n\t// Duck-type for non-DOM / test environments.\n\treturn 'kind' in track && 'readyState' in track;\n}\n\nexport function isSpeechPlayEncodedAudio(audio: SpeechPlayAudio): audio is SpeechPlayEncodedAudio {\n\treturn (\n\t\t!isSpeechPlayPcmAudio(audio) &&\n\t\t!isSpeechPlayUrlAudio(audio) &&\n\t\t!isSpeechPlayMediaStreamAudio(audio) &&\n\t\t'encoding' in audio &&\n\t\ttypeof (audio as SpeechPlayEncodedAudio).encoding === 'string'\n\t);\n}\n\nexport type SpeechCreateUtteranceOptions = {\n\t/**\n\t * Required unless `track` is set. When `track` is provided without `format`, defaults to\n\t * pcm_s16le mono at `sampleRate` (or 24000).\n\t */\n\treadonly format?: SpeechAudioFormat;\n\t/** Optional live track — host captures and writes until the track ends. */\n\treadonly track?: MediaStreamTrack;\n\t/** Used with `track` when `format` is omitted (default 24000). */\n\treadonly sampleRate?: number;\n\treadonly characterId?: string;\n\treadonly queue?: StreamingSpeechQueuePolicy;\n\t/**\n\t * Optional spoken text seed for force-aligned STA (lip sync).\n\t * Non-empty transcript enables force-align for this utterance; omit / whitespace → free CTC.\n\t * May be updated mid-turn via {@link SpeechUtterance.setTranscript} or finalized on\n\t * {@link SpeechUtterance.close} `{ transcript }`.\n\t */\n\treadonly transcript?: string;\n\treadonly signal?: AbortSignal;\n};\n\nexport type SpeechUtteranceCloseOptions = {\n\treadonly transcript?: string;\n\treadonly history?: 'none' | 'commit';\n};\n\nexport type SpeechWriteOptions = {\n\treadonly timeoutMs?: number;\n};\n\nexport type SpeechUtterance = {\n\treadonly id: string;\n\treadonly characterId: string;\n\treadonly result: Promise<SpeechResult>;\n\twrite(audio: ArrayBuffer | Uint8Array, options?: SpeechWriteOptions): Promise<void>;\n\t/**\n\t * Replace / set spoken text mid-turn for force-aligned STA.\n\t * Non-empty text upgrades free decode → force-align (full-utterance on close).\n\t * Empty / whitespace is a no-op.\n\t */\n\tsetTranscript(text: string): Promise<void>;\n\tclose(options?: SpeechUtteranceCloseOptions): Promise<SpeechResult>;\n\tcancel(): Promise<SpeechResult>;\n};\n\nexport type SpeechController = {\n\tspeak(options: SpeechSpeakOptions): Promise<SpeechResult>;\n\tplay(options: SpeechPlayOptions): Promise<SpeechResult>;\n\tcreateUtterance(options: SpeechCreateUtteranceOptions): SpeechUtterance;\n\tinterrupt(options?: SpeechInterruptOptions): Promise<readonly SpeechResult[]>;\n};\n\n/** Accepted PCM sample rates (Phase A). */\nexport const SPEECH_ACCEPTED_SAMPLE_RATES = [\n\t8000, 16000, 22050, 24000, 44100, 48000\n] as const;\n\nexport const SPEECH_LIMITS = {\n\tMAX_CHUNK_BYTES: 64 * 1024,\n\tRECOMMENDED_CHUNK_MS_MIN: 20,\n\tRECOMMENDED_CHUNK_MS_MAX: 200,\n\tMAX_BUFFERED_AUDIO_MS: 8_000,\n\tPLAYBACK_JITTER_BUFFER_MS: 150,\n\tPLAYBACK_JITTER_BUFFER_MS_MIN: 80,\n\tPLAYBACK_JITTER_BUFFER_MS_MAX: 250,\n\tMAX_UTTERANCE_DURATION_MS: 90_000,\n\tMAX_PENDING_WRITES: 8,\n\tDEFAULT_WRITE_TIMEOUT_MS: 5_000\n} as const;\n\nexport class UnsupportedSpeechOperationError extends Error {\n\treadonly name = 'UnsupportedSpeechOperationError';\n\tconstructor(\n\t\treadonly operation: string,\n\t\treadonly requiredCapability: string\n\t) {\n\t\tsuper(`Speech operation \"${operation}\" requires capability \"${requiredCapability}\".`);\n\t}\n}\n\nexport class SpeechUtteranceClosedError extends Error {\n\treadonly name = 'SpeechUtteranceClosedError';\n\tconstructor(message = 'Cannot write to a closed or cancelled speech utterance.') {\n\t\tsuper(message);\n\t}\n}\n\nexport class SpeechRuntimeError extends Error {\n\treadonly name = 'SpeechRuntimeError';\n\tconstructor(message: string, options?: { cause?: unknown }) {\n\t\tsuper(message, options);\n\t}\n}\n\nexport class SpeechBufferTimeoutError extends Error {\n\treadonly name = 'SpeechBufferTimeoutError';\n\tconstructor(message = 'Timed out waiting for speech buffer capacity.') {\n\t\tsuper(message);\n\t}\n}\n\nexport function emptyAnimationResult(\n\tmode: SpeechAnimationMode = 'none'\n): SpeechResult['animation'] {\n\treturn {\n\t\tmode,\n\t\ttrackedDurationMs: 0,\n\t\tfallbackDurationMs: 0\n\t};\n}\n\nexport function isAcceptedSampleRate(rate: number): boolean {\n\treturn (SPEECH_ACCEPTED_SAMPLE_RATES as readonly number[]).includes(rate);\n}\n\nexport function assertPcmFormat(format: SpeechAudioFormat): void {\n\tif (format.encoding !== 'pcm_s16le') {\n\t\tthrow new SpeechRuntimeError(`Unsupported audio encoding: ${format.encoding}`);\n\t}\n\tif (format.channels !== 1) {\n\t\tthrow new SpeechRuntimeError(`Unsupported channel count: ${format.channels}`);\n\t}\n\tif (!isAcceptedSampleRate(format.sampleRate)) {\n\t\tthrow new SpeechRuntimeError(`Unsupported sample rate: ${format.sampleRate}`);\n\t}\n}\n\nexport function assertSpeechPlayAudio(audio: SpeechPlayAudio): void {\n\tif (isSpeechPlayPcmAudio(audio)) {\n\t\tassertPcmFormat(audio.format);\n\t\treturn;\n\t}\n\tif (isSpeechPlayUrlAudio(audio)) {\n\t\tconst url = audio.url.trim();\n\t\tif (!url) throw new SpeechRuntimeError('Audio URL must be non-empty.');\n\t\tif (audio.sampleRate !== undefined && !isAcceptedSampleRate(audio.sampleRate)) {\n\t\t\tthrow new SpeechRuntimeError(`Unsupported sample rate: ${audio.sampleRate}`);\n\t\t}\n\t\treturn;\n\t}\n\tif (isSpeechPlayMediaStreamAudio(audio)) {\n\t\tif (audio.track.kind !== 'audio') {\n\t\t\tthrow new SpeechRuntimeError('speech.play track must be an audio MediaStreamTrack.');\n\t\t}\n\t\tif (audio.sampleRate !== undefined && !isAcceptedSampleRate(audio.sampleRate)) {\n\t\t\tthrow new SpeechRuntimeError(`Unsupported sample rate: ${audio.sampleRate}`);\n\t\t}\n\t\treturn;\n\t}\n\tif (isSpeechPlayEncodedAudio(audio)) {\n\t\tconst encoding = audio.encoding.trim().toLowerCase();\n\t\tif (!encoding) throw new SpeechRuntimeError('Encoded audio MIME type is required.');\n\t\tif (encoding === 'pcm_s16le') {\n\t\t\tthrow new SpeechRuntimeError('Use format: { encoding: \"pcm_s16le\", … } for raw PCM.');\n\t\t}\n\t\tif (audio.sampleRate !== undefined && !isAcceptedSampleRate(audio.sampleRate)) {\n\t\t\tthrow new SpeechRuntimeError(`Unsupported sample rate: ${audio.sampleRate}`);\n\t\t}\n\t\treturn;\n\t}\n\tthrow new SpeechRuntimeError('Unsupported speech.play audio shape.');\n}\n\nexport function resolveCreateUtteranceFormat(\n\toptions: SpeechCreateUtteranceOptions\n): SpeechAudioFormat {\n\tif (options.format) {\n\t\tassertPcmFormat(options.format);\n\t\treturn options.format;\n\t}\n\tif (options.track) {\n\t\tconst sampleRate = options.sampleRate ?? 24_000;\n\t\tconst format: SpeechAudioFormat = {\n\t\t\tencoding: 'pcm_s16le',\n\t\t\tsampleRate,\n\t\t\tchannels: 1\n\t\t};\n\t\tassertPcmFormat(format);\n\t\treturn format;\n\t}\n\tthrow new SpeechRuntimeError('createUtterance requires format or track.');\n}\n\nexport function toUint8Array(data: ArrayBuffer | Uint8Array): Uint8Array {\n\treturn data instanceof Uint8Array ? data : new Uint8Array(data);\n}\n\nexport function queuePolicyToEmbedBehavior(\n\tqueue: CompleteSpeechQueuePolicy | StreamingSpeechQueuePolicy | undefined\n): 'enqueue' | 'interrupt' {\n\tif (queue === 'replace-active' || queue === 'replace-all') return 'interrupt';\n\treturn 'enqueue';\n}\n","/** Liforma `speech.write` rejects chunks larger than 64 KiB. */\nexport const MAX_PCM_CHUNK_BYTES = 64 * 1024;\n\n/**\n * Playback / chunk guidance for custom BYO bridges (mirrors speech controller limits).\n * Prefer ~20–200 ms PCM frames; the player starts after an adaptive ~80–250 ms jitter\n * buffer (default 150 ms) based on chunk arrival variance.\n */\nexport const BYO_PLAYBACK_GUIDANCE = {\n\tRECOMMENDED_CHUNK_MS_MIN: 20,\n\tRECOMMENDED_CHUNK_MS_MAX: 200,\n\tPLAYBACK_JITTER_BUFFER_MS: 150,\n\tPLAYBACK_JITTER_BUFFER_MS_MIN: 80,\n\tPLAYBACK_JITTER_BUFFER_MS_MAX: 250\n} as const;\n\nexport function base64ToPcmBytes(b64: string): Uint8Array {\n\tconst bin = atob(b64);\n\tconst out = new Uint8Array(bin.length);\n\tfor (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n\treturn out;\n}\n\nexport function pcmBytesToBase64(bytes: Uint8Array): string {\n\tlet bin = '';\n\tconst chunk = 0x8000;\n\tfor (let i = 0; i < bytes.length; i += chunk) {\n\t\tbin += String.fromCharCode(...bytes.subarray(i, i + chunk));\n\t}\n\treturn btoa(bin);\n}\n\nexport function floatToPcm16Le(input: Float32Array): Uint8Array {\n\tconst out = new Uint8Array(input.length * 2);\n\tconst view = new DataView(out.buffer);\n\tfor (let i = 0; i < input.length; i++) {\n\t\tconst s = Math.max(-1, Math.min(1, input[i]!));\n\t\tview.setInt16(i * 2, s < 0 ? s * 0x8000 : s * 0x7fff, true);\n\t}\n\treturn out;\n}\n\n/** Naive linear resample Float32 → target rate. */\nexport function resampleFloat32(input: Float32Array, fromRate: number, toRate: number): Float32Array {\n\tif (fromRate === toRate || input.length === 0) return input;\n\tconst ratio = fromRate / toRate;\n\tconst outLen = Math.max(1, Math.round(input.length / ratio));\n\tconst out = new Float32Array(outLen);\n\tfor (let i = 0; i < outLen; i++) {\n\t\tconst src = i * ratio;\n\t\tconst i0 = Math.floor(src);\n\t\tconst i1 = Math.min(i0 + 1, input.length - 1);\n\t\tconst t = src - i0;\n\t\tout[i] = input[i0]! * (1 - t) + input[i1]! * t;\n\t}\n\treturn out;\n}\n\n/**\n * Parse vendor format strings like `pcm_16000` / `pcm_24000`.\n * Returns null when the format is missing or not PCM.\n */\nexport function parsePcmSampleRate(format: string | null | undefined): number | null {\n\tconst m = /^pcm_(\\d+)$/.exec(format ?? '');\n\tif (!m) return null;\n\tconst rate = Number(m[1]);\n\treturn Number.isFinite(rate) && rate > 0 ? rate : null;\n}\n\n/**\n * Write even-length PCM, splitting at MAX_PCM_CHUNK_BYTES on even boundaries.\n * Callers that may receive odd-length frames should run bytes through\n * {@link takeEvenPcmBytes} first so samples are not dropped across chunks.\n */\nexport async function writePcmInChunks(\n\tutterance: { write: (chunk: ArrayBuffer | ArrayBufferView) => Promise<unknown> },\n\tbytes: Uint8Array\n): Promise<void> {\n\tif (bytes.byteLength === 0) return;\n\tif ((bytes.byteLength & 1) !== 0) {\n\t\t// Defensive: drop trailing unpaired byte within a single call.\n\t\tbytes = bytes.subarray(0, bytes.byteLength - 1);\n\t\tif (bytes.byteLength === 0) return;\n\t}\n\tif (bytes.byteLength <= MAX_PCM_CHUNK_BYTES) {\n\t\tawait utterance.write(bytes);\n\t\treturn;\n\t}\n\tlet offset = 0;\n\twhile (offset < bytes.byteLength) {\n\t\tlet end = Math.min(offset + MAX_PCM_CHUNK_BYTES, bytes.byteLength);\n\t\tif ((end - offset) % 2 === 1) end -= 1;\n\t\tif (end <= offset) break;\n\t\tawait utterance.write(bytes.subarray(offset, end));\n\t\toffset = end;\n\t}\n}\n","/**\n * Stateful cubic (Catmull-Rom) resampler for continuous PCM capture streams.\n * Better than naive linear for uplink mic / track capture.\n */\n\nexport type FloatResampler = {\n\t/** Push a mono float buffer; returns samples at the target rate (may be empty). */\n\tpush(input: Float32Array): Float32Array;\n\t/** Flush any remaining fractional sample (usually silence). */\n\tflush(): Float32Array;\n\treadonly fromRate: number;\n\treadonly toRate: number;\n};\n\nfunction catmullRom(y0: number, y1: number, y2: number, y3: number, t: number): number {\n\tconst a0 = -0.5 * y0 + 1.5 * y1 - 1.5 * y2 + 0.5 * y3;\n\tconst a1 = y0 - 2.5 * y1 + 2 * y2 - 0.5 * y3;\n\tconst a2 = -0.5 * y0 + 0.5 * y2;\n\tconst a3 = y1;\n\treturn ((a0 * t + a1) * t + a2) * t + a3;\n}\n\n/**\n * Create a continuous resampler. When rates match, push() returns the input as-is\n * (no copy) when possible.\n */\nexport function createCubicResampler(fromRate: number, toRate: number): FloatResampler {\n\tif (!(fromRate > 0) || !(toRate > 0)) {\n\t\tthrow new Error('Resampler rates must be positive');\n\t}\n\n\tif (fromRate === toRate) {\n\t\treturn {\n\t\t\tfromRate,\n\t\t\ttoRate,\n\t\t\tpush(input) {\n\t\t\t\treturn input;\n\t\t\t},\n\t\t\tflush() {\n\t\t\t\treturn new Float32Array(0);\n\t\t\t}\n\t\t};\n\t}\n\n\tconst ratio = fromRate / toRate;\n\t/** History + pending input (keeps 3 samples of lookbehind for cubic). */\n\tlet pending = new Float32Array(0);\n\tlet pos = 0; // position in pending sample space for next output\n\n\treturn {\n\t\tfromRate,\n\t\ttoRate,\n\t\tpush(input) {\n\t\t\tif (input.length === 0) return new Float32Array(0);\n\t\t\tconst merged = new Float32Array(pending.length + input.length);\n\t\t\tmerged.set(pending);\n\t\t\tmerged.set(input, pending.length);\n\t\t\tpending = merged;\n\n\t\t\tif (pending.length < 4) return new Float32Array(0);\n\n\t\t\tconst out: number[] = [];\n\t\t\t// Need i+2 available for cubic; stop while pos+2 < length-1 equivalently floor(pos)+2 < len-?\n\t\t\twhile (pos + 2 < pending.length - 1) {\n\t\t\t\tconst i1 = Math.floor(pos);\n\t\t\t\tconst t = pos - i1;\n\t\t\t\tconst i0 = Math.max(0, i1 - 1);\n\t\t\t\tconst i2 = Math.min(pending.length - 1, i1 + 1);\n\t\t\t\tconst i3 = Math.min(pending.length - 1, i1 + 2);\n\t\t\t\tout.push(\n\t\t\t\t\tcatmullRom(pending[i0]!, pending[i1]!, pending[i2]!, pending[i3]!, t)\n\t\t\t\t);\n\t\t\t\tpos += ratio;\n\t\t\t}\n\n\t\t\t// Drop consumed samples but keep lookbehind (≥1) and unread tail.\n\t\t\tconst drop = Math.max(0, Math.floor(pos) - 1);\n\t\t\tif (drop > 0) {\n\t\t\t\tpending = pending.subarray(drop);\n\t\t\t\tpos -= drop;\n\t\t\t}\n\n\t\t\treturn out.length ? Float32Array.from(out) : new Float32Array(0);\n\t\t},\n\t\tflush() {\n\t\t\tif (pending.length === 0) return new Float32Array(0);\n\t\t\t// Emit one last sample if we have enough history; otherwise drop.\n\t\t\tpending = new Float32Array(0);\n\t\t\tpos = 0;\n\t\t\treturn new Float32Array(0);\n\t\t}\n\t};\n}\n","/**\n * Shared Web Audio capture: AudioWorklet when available, ScriptProcessor fallback.\n * Used by BYO mic uplink and MediaStreamTrack → PCM piping.\n */\n\nimport { floatToPcm16Le } from './pcm';\nimport { createCubicResampler, type FloatResampler } from './resample';\n\nexport type AudioCaptureSession = {\n\tstop(): void;\n\treadonly fromSampleRate: number;\n\treadonly usingWorklet: boolean;\n};\n\nexport type StartAudioCaptureOptions = {\n\treadonly mediaStream: MediaStream;\n\treadonly targetSampleRate: number;\n\t/** Called with pcm_s16le mono at targetSampleRate. */\n\treadonly onPcm: (bytes: Uint8Array) => void;\n\t/** When false, frames are dropped. */\n\treadonly shouldSend?: () => boolean;\n\treadonly onLog?: (line: string, kind?: 'info' | 'warn') => void;\n};\n\nconst WORKLET_NAME = 'liforma-pcm-capture';\n\nconst WORKLET_SOURCE = `\nclass LiformaPcmCaptureProcessor extends AudioWorkletProcessor {\n process(inputs) {\n const ch = inputs[0] && inputs[0][0];\n if (ch && ch.length) {\n const copy = new Float32Array(ch.length);\n copy.set(ch);\n this.port.postMessage(copy, [copy.buffer]);\n }\n return true;\n }\n}\nregisterProcessor('${WORKLET_NAME}', LiformaPcmCaptureProcessor);\n`;\n\nlet workletUrl: string | null = null;\n\nfunction getWorkletUrl(): string {\n\tif (!workletUrl) {\n\t\tworkletUrl = URL.createObjectURL(\n\t\t\tnew Blob([WORKLET_SOURCE], { type: 'application/javascript' })\n\t\t);\n\t}\n\treturn workletUrl;\n}\n\nfunction getAudioContextCtor(): typeof AudioContext | null {\n\treturn (\n\t\twindow.AudioContext ||\n\t\t(window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext ||\n\t\tnull\n\t);\n}\n\n/**\n * Capture a MediaStream as pcm_s16le at targetSampleRate.\n * Prefers AudioWorklet; falls back to ScriptProcessorNode.\n */\nexport async function startAudioCapture(\n\toptions: StartAudioCaptureOptions\n): Promise<AudioCaptureSession> {\n\tconst { mediaStream, targetSampleRate, onPcm, shouldSend, onLog } = options;\n\tconst AudioContextCtor = getAudioContextCtor();\n\tif (!AudioContextCtor) throw new Error('Web Audio is required for audio capture');\n\n\tconst audioCtx = new AudioContextCtor();\n\tconst source = audioCtx.createMediaStreamSource(mediaStream);\n\tconst silent = audioCtx.createGain();\n\tsilent.gain.value = 0;\n\tconst fromSampleRate = audioCtx.sampleRate;\n\tconst resampler: FloatResampler = createCubicResampler(fromSampleRate, targetSampleRate);\n\tlet stopped = false;\n\tlet usingWorklet = false;\n\n\tconst emitFloat = (input: Float32Array) => {\n\t\tif (stopped) return;\n\t\tif (shouldSend && !shouldSend()) return;\n\t\tconst resampled = resampler.push(input);\n\t\tif (resampled.length === 0) return;\n\t\tonPcm(floatToPcm16Le(resampled));\n\t};\n\n\tlet disconnectGraph: () => void = () => undefined;\n\n\tconst tryWorklet = async (): Promise<boolean> => {\n\t\tif (typeof audioCtx.audioWorklet?.addModule !== 'function') return false;\n\t\ttry {\n\t\t\tawait audioCtx.audioWorklet.addModule(getWorkletUrl());\n\t\t\tconst node = new AudioWorkletNode(audioCtx, WORKLET_NAME, {\n\t\t\t\tnumberOfInputs: 1,\n\t\t\t\tnumberOfOutputs: 1,\n\t\t\t\toutputChannelCount: [1]\n\t\t\t});\n\t\t\tnode.port.onmessage = (ev) => {\n\t\t\t\tif (ev.data instanceof Float32Array) emitFloat(ev.data);\n\t\t\t};\n\t\t\tsource.connect(node);\n\t\t\tnode.connect(silent);\n\t\t\tsilent.connect(audioCtx.destination);\n\t\t\tdisconnectGraph = () => {\n\t\t\t\tnode.port.onmessage = null;\n\t\t\t\ttry {\n\t\t\t\t\tnode.disconnect();\n\t\t\t\t} catch {\n\t\t\t\t\t/* ignore */\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tsource.disconnect();\n\t\t\t\t} catch {\n\t\t\t\t\t/* ignore */\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tsilent.disconnect();\n\t\t\t\t} catch {\n\t\t\t\t\t/* ignore */\n\t\t\t\t}\n\t\t\t};\n\t\t\tusingWorklet = true;\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t};\n\n\tconst useScriptProcessor = (): void => {\n\t\tconst createScriptProcessor = (\n\t\t\taudioCtx as AudioContext & {\n\t\t\t\tcreateScriptProcessor?: (\n\t\t\t\t\tbufferSize: number,\n\t\t\t\t\tinputChannels: number,\n\t\t\t\t\toutputChannels: number\n\t\t\t\t) => ScriptProcessorNode;\n\t\t\t}\n\t\t).createScriptProcessor?.bind(audioCtx);\n\n\t\tif (!createScriptProcessor) {\n\t\t\tthrow new Error('Neither AudioWorklet nor ScriptProcessor is available');\n\t\t}\n\n\t\tconst processor = createScriptProcessor(4096, 1, 1);\n\t\tprocessor.onaudioprocess = (ev) => {\n\t\t\temitFloat(ev.inputBuffer.getChannelData(0));\n\t\t};\n\t\tsource.connect(processor);\n\t\tprocessor.connect(silent);\n\t\tsilent.connect(audioCtx.destination);\n\t\tdisconnectGraph = () => {\n\t\t\tprocessor.onaudioprocess = null;\n\t\t\ttry {\n\t\t\t\tprocessor.disconnect();\n\t\t\t} catch {\n\t\t\t\t/* ignore */\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tsource.disconnect();\n\t\t\t} catch {\n\t\t\t\t/* ignore */\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tsilent.disconnect();\n\t\t\t} catch {\n\t\t\t\t/* ignore */\n\t\t\t}\n\t\t};\n\t\tusingWorklet = false;\n\t};\n\n\tif (!(await tryWorklet())) {\n\t\tuseScriptProcessor();\n\t\tonLog?.(\n\t\t\t`Mic/track capture via ScriptProcessor at ${fromSampleRate} Hz → ${targetSampleRate} Hz`,\n\t\t\t'warn'\n\t\t);\n\t} else {\n\t\tonLog?.(`Mic/track capture via AudioWorklet at ${fromSampleRate} Hz → ${targetSampleRate} Hz`);\n\t}\n\n\tif (audioCtx.state === 'suspended') {\n\t\tawait audioCtx.resume().catch(() => undefined);\n\t}\n\n\treturn {\n\t\tfromSampleRate,\n\t\tusingWorklet,\n\t\tstop() {\n\t\t\tif (stopped) return;\n\t\t\tstopped = true;\n\t\t\tresampler.flush();\n\t\t\tdisconnectGraph();\n\t\t\tvoid audioCtx.close().catch(() => undefined);\n\t\t}\n\t};\n}\n","/**\n * Host-side MediaStreamTrack → mono pcm_s16le capture for experience.speech.\n * Capture stays in the SDK (host page); player only receives PCM chunks.\n */\n\nimport { startAudioCapture } from '../../byo/audioCapture';\nimport { SPEECH_LIMITS, SpeechRuntimeError, toUint8Array } from './types';\nimport type { SpeechUtterance } from './types';\n\nexport type CaptureMediaStreamTrackOptions = {\n\treadonly track: MediaStreamTrack;\n\treadonly utterance: SpeechUtterance;\n\treadonly sampleRate: number;\n\treadonly signal?: AbortSignal;\n};\n\n/**\n * Capture a live audio track into an open utterance until the track ends or abort.\n * Prefers AudioWorklet + cubic resample (ScriptProcessor fallback).\n */\nexport async function pipeMediaStreamTrackToUtterance(\n\toptions: CaptureMediaStreamTrackOptions\n): Promise<void> {\n\tconst { track, utterance, sampleRate, signal } = options;\n\tif (typeof MediaStreamTrack === 'undefined' || !(track instanceof MediaStreamTrack)) {\n\t\tthrow new SpeechRuntimeError('MediaStreamTrack is not available in this environment.');\n\t}\n\tif (track.kind !== 'audio') {\n\t\tthrow new SpeechRuntimeError('speech.play track must be an audio MediaStreamTrack.');\n\t}\n\tif (track.readyState === 'ended') {\n\t\treturn;\n\t}\n\tif (signal?.aborted) {\n\t\treturn;\n\t}\n\n\tconst stream = new MediaStream([track]);\n\tlet writeChain: Promise<void> = Promise.resolve();\n\tlet stopped = false;\n\tlet capture: Awaited<ReturnType<typeof startAudioCapture>> | null = null;\n\n\tconst teardown = () => {\n\t\tif (stopped) return;\n\t\tstopped = true;\n\t\tcapture?.stop();\n\t\tcapture = null;\n\t};\n\n\ttry {\n\t\tcapture = await startAudioCapture({\n\t\t\tmediaStream: stream,\n\t\t\ttargetSampleRate: sampleRate,\n\t\t\tshouldSend: () => !stopped && !signal?.aborted,\n\t\t\tonPcm: (pcm) => {\n\t\t\t\tif (stopped || signal?.aborted) return;\n\t\t\t\tconst bytes = toUint8Array(pcm);\n\t\t\t\twriteChain = writeChain\n\t\t\t\t\t.then(async () => {\n\t\t\t\t\t\tif (stopped || signal?.aborted) return;\n\t\t\t\t\t\tlet offset = 0;\n\t\t\t\t\t\twhile (offset < bytes.byteLength) {\n\t\t\t\t\t\t\tlet end = Math.min(offset + SPEECH_LIMITS.MAX_CHUNK_BYTES, bytes.byteLength);\n\t\t\t\t\t\t\tif ((end - offset) % 2 === 1) end -= 1;\n\t\t\t\t\t\t\tif (end <= offset) break;\n\t\t\t\t\t\t\tconst slice = bytes.subarray(offset, end);\n\t\t\t\t\t\t\toffset = end;\n\t\t\t\t\t\t\tif (slice.byteLength === 0) continue;\n\t\t\t\t\t\t\tawait utterance.write(slice);\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\tteardown();\n\t\t\t\t\t});\n\t\t\t}\n\t\t});\n\t} catch (err) {\n\t\tteardown();\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tthrow new SpeechRuntimeError(`MediaStreamTrack capture failed: ${message}`);\n\t}\n\n\tawait new Promise<void>((resolve) => {\n\t\tconst finish = () => {\n\t\t\tteardown();\n\t\t\tvoid writeChain.finally(resolve);\n\t\t};\n\t\ttrack.addEventListener('ended', finish, { once: true });\n\t\tsignal?.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tvoid utterance.cancel().catch(() => undefined);\n\t\t\t\tfinish();\n\t\t\t},\n\t\t\t{ once: true }\n\t\t);\n\t\tif (track.readyState === 'ended' || signal?.aborted) {\n\t\t\tfinish();\n\t\t}\n\t});\n}\n","import type { IframeHost } from '../embed/iframeHost';\nimport type { SpeakBehavior } from '../types/sessionInteraction';\nimport type { SpeechResult as EmbedSpeakResult } from '../types/sessionInteraction';\nimport {\n\tSPEECH_LIMITS,\n\tSpeechBufferTimeoutError,\n\tSpeechRuntimeError,\n\tSpeechUtteranceClosedError,\n\tUnsupportedSpeechOperationError,\n\tassertSpeechPlayAudio,\n\temptyAnimationResult,\n\tisSpeechPlayEncodedAudio,\n\tisSpeechPlayMediaStreamAudio,\n\tisSpeechPlayPcmAudio,\n\tisSpeechPlayUrlAudio,\n\tqueuePolicyToEmbedBehavior,\n\tresolveCreateUtteranceFormat,\n\ttoUint8Array,\n\ttype SpeechAudioFormat,\n\ttype SpeechController,\n\ttype SpeechCreateUtteranceOptions,\n\ttype SpeechInterruptOptions,\n\ttype SpeechPlayAudio,\n\ttype SpeechPlayEmbedSource,\n\ttype SpeechPlayOptions,\n\ttype SpeechResult,\n\ttype SpeechSpeakOptions,\n\ttype SpeechTerminalStatus,\n\ttype SpeechUtterance,\n\ttype SpeechUtteranceCloseOptions,\n\ttype SpeechWriteOptions,\n\ttype StreamingSpeechQueuePolicy\n} from './types';\nimport { pipeMediaStreamTrackToUtterance } from './captureMediaStreamTrack';\n\nasync function toSpeechPlayEmbedSource(\n\taudio: SpeechPlayAudio,\n\tsignal?: AbortSignal\n): Promise<SpeechPlayEmbedSource> {\n\tif (isSpeechPlayMediaStreamAudio(audio)) {\n\t\tthrow new SpeechRuntimeError('MediaStreamTrack play is handled on the host before embed.');\n\t}\n\tif (isSpeechPlayPcmAudio(audio)) {\n\t\tconst data = toUint8Array(audio.data);\n\t\tif ((data.byteLength & 1) !== 0) {\n\t\t\tthrow new SpeechRuntimeError('PCM byte length must be even.');\n\t\t}\n\t\treturn {\n\t\t\tkind: 'pcm',\n\t\t\tdata: data.slice().buffer,\n\t\t\tformat: audio.format\n\t\t};\n\t}\n\tif (isSpeechPlayUrlAudio(audio)) {\n\t\treturn {\n\t\t\tkind: 'url',\n\t\t\turl: audio.url.trim(),\n\t\t\t...(audio.sampleRate !== undefined ? { sampleRate: audio.sampleRate } : {})\n\t\t};\n\t}\n\tif (!isSpeechPlayEncodedAudio(audio)) {\n\t\tthrow new SpeechRuntimeError('Unsupported speech.play audio shape.');\n\t}\n\tlet bytes: Uint8Array;\n\tif (typeof Blob !== 'undefined' && audio.data instanceof Blob) {\n\t\tif (signal?.aborted) throw new DOMException('Play aborted.', 'AbortError');\n\t\tbytes = new Uint8Array(await audio.data.arrayBuffer());\n\t} else {\n\t\tbytes = toUint8Array(audio.data as ArrayBuffer | Uint8Array);\n\t}\n\treturn {\n\t\tkind: 'encoded',\n\t\tdata: bytes.slice().buffer,\n\t\tencoding: audio.encoding.trim(),\n\t\t...(audio.sampleRate !== undefined ? { sampleRate: audio.sampleRate } : {})\n\t};\n}\n\nexport type {\n\tSpeechAudioFormat,\n\tSpeechController,\n\tSpeechCreateUtteranceOptions,\n\tSpeechInterruptOptions,\n\tSpeechPlayOptions,\n\tSpeechResult,\n\tSpeechSpeakOptions,\n\tSpeechUtterance,\n\tSpeechUtteranceCloseOptions,\n\tSpeechWriteOptions\n} from './types';\n\nexport type SpeechCapabilities = {\n\treadonly textSpeech: boolean;\n\treadonly externalSpeechAudio: boolean;\n};\n\nexport type SpeechControllerHost = {\n\treadonly getIframeHost: () => IframeHost | null;\n\treadonly assertSessionStarted: () => void;\n\treadonly getCapabilities: () => SpeechCapabilities;\n\treadonly getActiveCharacterId: () => string;\n\treadonly onProcessorInterrupt?: () => void;\n};\n\ntype PendingWrite = {\n\treadonly resolve: () => void;\n\treadonly reject: (error: Error) => void;\n};\n\nfunction newUtteranceId(): string {\n\tif (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n\t\treturn `utt_${crypto.randomUUID().replace(/-/g, '').slice(0, 12)}`;\n\t}\n\treturn `utt_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;\n}\n\nfunction mapEmbedSpeakResult(\n\tresult: EmbedSpeakResult,\n\tstatus: SpeechTerminalStatus = 'completed'\n): SpeechResult {\n\treturn {\n\t\tutteranceId: result.speechId,\n\t\tcharacterId: result.characterId,\n\t\tstatus,\n\t\tdurationMs: result.durationMs,\n\t\ttranscript: result.text,\n\t\tanimation: {\n\t\t\tmode: 'tracked',\n\t\t\ttrackedDurationMs: result.durationMs,\n\t\t\tfallbackDurationMs: 0\n\t\t}\n\t};\n}\n\nfunction settleError(error: unknown): Error {\n\tif (error instanceof Error) return error;\n\treturn new SpeechRuntimeError(String(error));\n}\n\nfunction isAbortError(error: unknown): boolean {\n\treturn (\n\t\t(error instanceof DOMException && error.name === 'AbortError') ||\n\t\t(error instanceof Error && error.name === 'AbortError')\n\t);\n}\n\nclass HostSpeechUtterance implements SpeechUtterance {\n\treadonly id: string;\n\treadonly characterId: string;\n\treadonly result: Promise<SpeechResult>;\n\n\tprivate readonly format: SpeechAudioFormat;\n\tprivate readonly host: SpeechControllerHost;\n\tprivate readonly signal?: AbortSignal;\n\tprivate settleResolve!: (value: SpeechResult) => void;\n\tprivate settleReject!: (error: Error) => void;\n\tprivate settled = false;\n\tprivate closed = false;\n\tprivate writeChain: Promise<void> = Promise.resolve();\n\tprivate pendingWriteCount = 0;\n\tprivate readonly pendingWriteWaiters: PendingWrite[] = [];\n\tprivate bufferedMs = 0;\n\tprivate readonly sampleRate: number;\n\tprivate readonly beginPromise: Promise<void>;\n\n\tconstructor(options: {\n\t\treadonly id: string;\n\t\treadonly characterId: string;\n\t\treadonly format: SpeechAudioFormat;\n\t\treadonly queue: StreamingSpeechQueuePolicy;\n\t\treadonly host: SpeechControllerHost;\n\t\treadonly transcript?: string;\n\t\treadonly signal?: AbortSignal;\n\t}) {\n\t\tthis.id = options.id;\n\t\tthis.characterId = options.characterId;\n\t\tthis.format = options.format;\n\t\tthis.host = options.host;\n\t\tthis.signal = options.signal;\n\t\tthis.sampleRate = options.format.sampleRate;\n\t\tthis.result = new Promise<SpeechResult>((resolve, reject) => {\n\t\t\tthis.settleResolve = resolve;\n\t\t\tthis.settleReject = reject;\n\t\t});\n\t\t// Prevent unhandled rejection if caller only uses close()/cancel().\n\t\tvoid this.result.catch(() => undefined);\n\n\t\tconst iframe = this.requireHost();\n\t\tthis.beginPromise = iframe\n\t\t\t.speechUtteranceBegin({\n\t\t\t\tutteranceId: this.id,\n\t\t\t\tformat: this.format,\n\t\t\t\tcharacterId: this.characterId,\n\t\t\t\tqueue: options.queue,\n\t\t\t\t...(options.transcript !== undefined ? { transcript: options.transcript } : {})\n\t\t\t})\n\t\t\t.catch((error: unknown) => {\n\t\t\t\tthis.fail(settleError(error));\n\t\t\t\tthrow settleError(error);\n\t\t\t});\n\n\t\tthis.signal?.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tvoid this.cancel();\n\t\t\t},\n\t\t\t{ once: true }\n\t\t);\n\t}\n\n\tasync write(audio: ArrayBuffer | Uint8Array, options?: SpeechWriteOptions): Promise<void> {\n\t\tif (this.closed || this.settled) {\n\t\t\tthrow new SpeechUtteranceClosedError();\n\t\t}\n\t\tawait this.beginPromise.catch(() => undefined);\n\t\tif (this.closed || this.settled) {\n\t\t\tthrow new SpeechUtteranceClosedError();\n\t\t}\n\t\tconst bytes = toUint8Array(audio);\n\t\tif ((bytes.byteLength & 1) !== 0) {\n\t\t\tthrow new SpeechRuntimeError('PCM chunk byte length must be even (complete s16 samples).');\n\t\t}\n\t\tif (bytes.byteLength > SPEECH_LIMITS.MAX_CHUNK_BYTES) {\n\t\t\tthrow new SpeechRuntimeError(\n\t\t\t\t`PCM chunk exceeds MAX_CHUNK_BYTES (${SPEECH_LIMITS.MAX_CHUNK_BYTES}).`\n\t\t\t);\n\t\t}\n\t\tif (bytes.byteLength === 0) return;\n\n\t\tconst timeoutMs = options?.timeoutMs ?? SPEECH_LIMITS.DEFAULT_WRITE_TIMEOUT_MS;\n\t\tawait this.acquireWriteSlot(timeoutMs);\n\n\t\tconst chunkMs = (bytes.byteLength / 2 / this.sampleRate) * 1000;\n\t\tif (this.bufferedMs + chunkMs > SPEECH_LIMITS.MAX_UTTERANCE_DURATION_MS) {\n\t\t\tthis.releaseWriteSlot();\n\t\t\tthrow new SpeechRuntimeError('Utterance exceeds MAX_UTTERANCE_DURATION_MS.');\n\t\t}\n\n\t\tconst run = async () => {\n\t\t\tif (this.closed || this.settled) {\n\t\t\t\tthrow new SpeechUtteranceClosedError();\n\t\t\t}\n\t\t\tconst iframe = this.requireHost();\n\t\t\tconst copy = bytes.slice();\n\t\t\tconst writePromise = iframe.speechUtteranceWrite({\n\t\t\t\tutteranceId: this.id,\n\t\t\t\taudio: copy.buffer,\n\t\t\t\tbyteLength: copy.byteLength\n\t\t\t});\n\t\t\tconst ack = await Promise.race([\n\t\t\t\twritePromise,\n\t\t\t\tnew Promise<never>((_, reject) => {\n\t\t\t\t\tsetTimeout(() => reject(new SpeechBufferTimeoutError()), timeoutMs);\n\t\t\t\t})\n\t\t\t]);\n\t\t\tthis.bufferedMs = Math.max(0, ack.bufferedMs);\n\t\t};\n\n\t\tconst tracked = this.writeChain.then(run, run);\n\t\tthis.writeChain = tracked.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined\n\t\t);\n\t\ttry {\n\t\t\tawait tracked;\n\t\t} finally {\n\t\t\tthis.releaseWriteSlot();\n\t\t}\n\t}\n\n\tasync setTranscript(text: string): Promise<void> {\n\t\tif (this.closed || this.settled) {\n\t\t\tthrow new SpeechUtteranceClosedError();\n\t\t}\n\t\tawait this.beginPromise.catch(() => undefined);\n\t\tif (this.closed || this.settled) {\n\t\t\tthrow new SpeechUtteranceClosedError();\n\t\t}\n\t\tconst iframe = this.requireHost();\n\t\tawait iframe.speechUtteranceSetTranscript({\n\t\t\tutteranceId: this.id,\n\t\t\ttranscript: text\n\t\t});\n\t}\n\n\tasync close(options?: SpeechUtteranceCloseOptions): Promise<SpeechResult> {\n\t\tif (this.settled) return this.result;\n\t\tthis.closed = true;\n\t\tawait this.beginPromise.catch(() => undefined);\n\t\tawait this.writeChain.catch(() => undefined);\n\t\ttry {\n\t\t\tconst iframe = this.requireHost();\n\t\t\tconst result = await iframe.speechUtteranceClose({\n\t\t\t\tutteranceId: this.id,\n\t\t\t\ttranscript: options?.transcript,\n\t\t\t\thistory: options?.history ?? 'none'\n\t\t\t});\n\t\t\tthis.resolve(result);\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\tconst err = settleError(error);\n\t\t\tthis.fail(err);\n\t\t\tthrow err;\n\t\t}\n\t}\n\n\tasync cancel(): Promise<SpeechResult> {\n\t\tif (this.settled) return this.result;\n\t\tthis.closed = true;\n\t\ttry {\n\t\t\tconst iframe = this.host.getIframeHost();\n\t\t\tif (iframe) {\n\t\t\t\tconst result = await iframe.speechUtteranceCancel({ utteranceId: this.id });\n\t\t\t\tthis.resolve(result);\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tconst cancelled: SpeechResult = {\n\t\t\t\tutteranceId: this.id,\n\t\t\t\tcharacterId: this.characterId,\n\t\t\t\tstatus: 'cancelled',\n\t\t\t\tdurationMs: 0,\n\t\t\t\tanimation: emptyAnimationResult('none')\n\t\t\t};\n\t\t\tthis.resolve(cancelled);\n\t\t\treturn cancelled;\n\t\t} catch (error) {\n\t\t\tconst err = settleError(error);\n\t\t\tthis.fail(err);\n\t\t\tthrow err;\n\t\t}\n\t}\n\n\t/** Adopt an interrupt settlement from the player without a second cancel RPC. */\n\tadoptExternalResult(result: SpeechResult): void {\n\t\tthis.resolve(result);\n\t}\n\n\tprivate requireHost(): IframeHost {\n\t\tconst iframe = this.host.getIframeHost();\n\t\tif (!iframe) {\n\t\t\tthrow new SpeechRuntimeError('Speech session is not attached.');\n\t\t}\n\t\treturn iframe;\n\t}\n\n\tprivate resolve(result: SpeechResult): void {\n\t\tif (this.settled) return;\n\t\tthis.settled = true;\n\t\tthis.settleResolve(Object.freeze(result));\n\t\tthis.flushWriteWaiters(new SpeechUtteranceClosedError());\n\t}\n\n\tprivate fail(error: Error): void {\n\t\tif (this.settled) return;\n\t\tthis.settled = true;\n\t\tthis.settleReject(error);\n\t\tthis.flushWriteWaiters(error);\n\t}\n\n\tprivate async acquireWriteSlot(timeoutMs: number): Promise<void> {\n\t\tif (this.pendingWriteCount < SPEECH_LIMITS.MAX_PENDING_WRITES) {\n\t\t\tthis.pendingWriteCount += 1;\n\t\t\treturn;\n\t\t}\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\treject(new SpeechBufferTimeoutError());\n\t\t\t}, timeoutMs);\n\t\t\tthis.pendingWriteWaiters.push({\n\t\t\t\tresolve: () => {\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\tthis.pendingWriteCount += 1;\n\t\t\t\t\tresolve();\n\t\t\t\t},\n\t\t\t\treject: (error) => {\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\treject(error);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate releaseWriteSlot(): void {\n\t\tthis.pendingWriteCount = Math.max(0, this.pendingWriteCount - 1);\n\t\tconst next = this.pendingWriteWaiters.shift();\n\t\tnext?.resolve();\n\t}\n\n\tprivate flushWriteWaiters(error: Error): void {\n\t\twhile (this.pendingWriteWaiters.length > 0) {\n\t\t\tthis.pendingWriteWaiters.shift()?.reject(error);\n\t\t}\n\t}\n}\n\nexport function createSpeechController(host: SpeechControllerHost): SpeechController {\n\tlet openUtterance: HostSpeechUtterance | null = null;\n\n\tconst requireCapability = (operation: string, capability: keyof SpeechCapabilities) => {\n\t\tconst caps = host.getCapabilities();\n\t\tif (!caps[capability]) {\n\t\t\tthrow new UnsupportedSpeechOperationError(operation, capability);\n\t\t}\n\t};\n\n\tconst controller: SpeechController = {\n\t\tasync speak(options: SpeechSpeakOptions): Promise<SpeechResult> {\n\t\t\thost.assertSessionStarted();\n\t\t\trequireCapability('speak', 'textSpeech');\n\t\t\tif (options.signal?.aborted) {\n\t\t\t\tthrow new DOMException('Speak aborted.', 'AbortError');\n\t\t\t}\n\t\t\tconst queue = options.queue ?? 'append';\n\t\t\tconst behavior: SpeakBehavior = queuePolicyToEmbedBehavior(queue);\n\t\t\tif (behavior === 'interrupt') {\n\t\t\t\thost.onProcessorInterrupt?.();\n\t\t\t\tif (openUtterance) {\n\t\t\t\t\tvoid openUtterance.cancel();\n\t\t\t\t\topenUtterance = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst iframe = host.getIframeHost();\n\t\t\tif (!iframe) throw new SpeechRuntimeError('Speech session is not attached.');\n\n\t\t\tconst speakPromise = iframe.speak({\n\t\t\t\ttext: options.text,\n\t\t\t\tcharacterId: options.characterId,\n\t\t\t\tbehavior\n\t\t\t});\n\n\t\t\tif (options.signal) {\n\t\t\t\tconst signal = options.signal;\n\t\t\t\treturn await new Promise<SpeechResult>((resolve, reject) => {\n\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\tvoid iframe.speechInterrupt({ scope: 'active' }).catch(() => undefined);\n\t\t\t\t\t\treject(new DOMException('Speak aborted.', 'AbortError'));\n\t\t\t\t\t};\n\t\t\t\t\tif (signal.aborted) {\n\t\t\t\t\t\tonAbort();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tsignal.addEventListener('abort', onAbort, { once: true });\n\t\t\t\t\tspeakPromise.then(\n\t\t\t\t\t\t(legacy) => {\n\t\t\t\t\t\t\tsignal.removeEventListener('abort', onAbort);\n\t\t\t\t\t\t\tresolve(mapEmbedSpeakResult(legacy, 'completed'));\n\t\t\t\t\t\t},\n\t\t\t\t\t\t(error: unknown) => {\n\t\t\t\t\t\t\tsignal.removeEventListener('abort', onAbort);\n\t\t\t\t\t\t\tif (isAbortError(error)) {\n\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\tutteranceId: `utt_interrupted`,\n\t\t\t\t\t\t\t\t\tcharacterId: options.characterId ?? host.getActiveCharacterId(),\n\t\t\t\t\t\t\t\t\tstatus: 'interrupted',\n\t\t\t\t\t\t\t\t\tdurationMs: 0,\n\t\t\t\t\t\t\t\t\ttranscript: options.text,\n\t\t\t\t\t\t\t\t\tanimation: emptyAnimationResult('none')\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treject(settleError(error));\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst legacy = await speakPromise;\n\t\t\t\treturn mapEmbedSpeakResult(legacy, 'completed');\n\t\t\t} catch (error) {\n\t\t\t\tif (isAbortError(error)) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tutteranceId: `utt_interrupted`,\n\t\t\t\t\t\tcharacterId: options.characterId ?? host.getActiveCharacterId(),\n\t\t\t\t\t\tstatus: 'interrupted',\n\t\t\t\t\t\tdurationMs: 0,\n\t\t\t\t\t\ttranscript: options.text,\n\t\t\t\t\t\tanimation: emptyAnimationResult('none')\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tthrow settleError(error);\n\t\t\t}\n\t\t},\n\n\t\tasync play(options: SpeechPlayOptions): Promise<SpeechResult> {\n\t\t\thost.assertSessionStarted();\n\t\t\trequireCapability('play', 'externalSpeechAudio');\n\t\t\tassertSpeechPlayAudio(options.audio);\n\t\t\tif (options.signal?.aborted) {\n\t\t\t\tthrow new DOMException('Play aborted.', 'AbortError');\n\t\t\t}\n\t\t\tconst queue = options.queue ?? 'append';\n\t\t\tif (queue === 'replace-active' || queue === 'replace-all') {\n\t\t\t\thost.onProcessorInterrupt?.();\n\t\t\t\tif (openUtterance) {\n\t\t\t\t\tvoid openUtterance.cancel();\n\t\t\t\t\topenUtterance = null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isSpeechPlayMediaStreamAudio(options.audio)) {\n\t\t\t\tconst sampleRate = options.audio.sampleRate ?? 24_000;\n\t\t\t\tconst utterance = controller.createUtterance({\n\t\t\t\t\tformat: { encoding: 'pcm_s16le', sampleRate, channels: 1 },\n\t\t\t\t\ttrack: options.audio.track,\n\t\t\t\t\tcharacterId: options.characterId,\n\t\t\t\t\tqueue: queue === 'append' ? 'replace-active' : queue,\n\t\t\t\t\tsignal: options.signal\n\t\t\t\t});\n\t\t\t\treturn utterance.result;\n\t\t\t}\n\n\t\t\tconst iframe = host.getIframeHost();\n\t\t\tif (!iframe) throw new SpeechRuntimeError('Speech session is not attached.');\n\t\t\tconst source = await toSpeechPlayEmbedSource(options.audio, options.signal);\n\t\t\treturn iframe.speechPlay({\n\t\t\t\tsource,\n\t\t\t\tcharacterId: options.characterId,\n\t\t\t\ttranscript: options.transcript,\n\t\t\t\thistory: options.history ?? 'none',\n\t\t\t\tqueue,\n\t\t\t\tsignal: options.signal\n\t\t\t});\n\t\t},\n\n\t\tcreateUtterance(options: SpeechCreateUtteranceOptions): SpeechUtterance {\n\t\t\thost.assertSessionStarted();\n\t\t\trequireCapability('createUtterance', 'externalSpeechAudio');\n\t\t\tconst format = resolveCreateUtteranceFormat(options);\n\t\t\tif (options.track && options.track.kind !== 'audio') {\n\t\t\t\tthrow new SpeechRuntimeError('createUtterance track must be an audio MediaStreamTrack.');\n\t\t\t}\n\t\t\tconst queue: StreamingSpeechQueuePolicy = options.queue ?? 'replace-active';\n\t\t\tif (queue !== 'replace-active' && queue !== 'replace-all') {\n\t\t\t\tthrow new SpeechRuntimeError('createUtterance queue must be replace-active or replace-all.');\n\t\t\t}\n\t\t\thost.onProcessorInterrupt?.();\n\t\t\tif (openUtterance) {\n\t\t\t\tvoid openUtterance.cancel();\n\t\t\t\topenUtterance = null;\n\t\t\t}\n\t\t\tconst utterance = new HostSpeechUtterance({\n\t\t\t\tid: newUtteranceId(),\n\t\t\t\tcharacterId: options.characterId ?? host.getActiveCharacterId(),\n\t\t\t\tformat,\n\t\t\t\tqueue,\n\t\t\t\thost,\n\t\t\t\t...(options.transcript !== undefined ? { transcript: options.transcript } : {}),\n\t\t\t\tsignal: options.signal\n\t\t\t});\n\t\t\topenUtterance = utterance;\n\t\t\tvoid utterance.result.finally(() => {\n\t\t\t\tif (openUtterance === utterance) openUtterance = null;\n\t\t\t});\n\t\t\tif (options.track) {\n\t\t\t\tvoid (async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait pipeMediaStreamTrackToUtterance({\n\t\t\t\t\t\t\ttrack: options.track!,\n\t\t\t\t\t\t\tutterance,\n\t\t\t\t\t\t\tsampleRate: format.sampleRate,\n\t\t\t\t\t\t\tsignal: options.signal\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (options.signal?.aborted) return;\n\t\t\t\t\t\tawait utterance.close({ history: 'none' });\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tawait utterance.cancel().catch(() => undefined);\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t}\n\t\t\treturn utterance;\n\t\t},\n\n\t\tasync interrupt(options?: SpeechInterruptOptions): Promise<readonly SpeechResult[]> {\n\t\t\thost.assertSessionStarted();\n\t\t\thost.onProcessorInterrupt?.();\n\t\t\tconst iframe = host.getIframeHost();\n\t\t\tif (!iframe) return [];\n\t\t\tconst results = await iframe.speechInterrupt(options ?? { scope: 'active' });\n\t\t\tif (openUtterance) {\n\t\t\t\tconst match = results.find((r) => r.utteranceId === openUtterance!.id);\n\t\t\t\tif (match) openUtterance.adoptExternalResult(match);\n\t\t\t\topenUtterance = null;\n\t\t\t}\n\t\t\treturn results;\n\t\t}\n\t};\n\n\treturn controller;\n}\n","export type ExperienceMode = 'conversation' | 'presenter';\nexport type ResponseMode = 'managed' | 'custom' | 'manual';\nexport type SpeechInputMode = 'auto' | 'manual' | 'off';\n/**\n * Viewport framing for the composed location + avatar scene.\n * - `full` (default): height-fit the full avatar into the host div.\n * - `medium`: height-fit a bust window — 0.75H above and 2H below the mesh face oval (3.75H total).\n * - `face`: cover-zoom the scene onto the mesh face oval (inset / PIP use cases).\n */\nexport type ExperienceFit = 'full' | 'face' | 'medium';\n\nexport function parseExperienceFit(value: string | null | undefined): ExperienceFit | undefined {\n\tconst trimmed = value?.trim();\n\treturn trimmed === 'full' || trimmed === 'face' || trimmed === 'medium' ? trimmed : undefined;\n}\n\nexport type SessionInteractionModes = {\n\treadonly mode: ExperienceMode;\n\treadonly responseMode: ResponseMode;\n\treadonly speechInputMode: SpeechInputMode;\n\treadonly processorId?: string;\n};\n\nexport type StartedEvent = {\n\treadonly mode: ExperienceMode;\n};\n\nexport type StartButtonPlacement = 'center' | 'bottom-center' | 'bottom-left' | 'bottom-right';\nexport type StartButtonVariant = 'primary' | 'secondary' | 'minimal';\nexport type StartButtonSize = 'small' | 'medium' | 'large';\nexport type StartButtonShadow = 'none' | 'soft' | 'strong';\nexport type StartButtonIconPosition = 'above' | 'left';\n\nexport type StartButtonAppearance = {\n\treadonly backgroundColor?: string;\n\treadonly textColor?: string;\n\treadonly borderColor?: string;\n\treadonly borderRadiusPx?: number;\n\treadonly borderWidthPx?: number;\n\t/** Explicit label size in px; when set, overrides `size` font scaling. */\n\treadonly fontSizePx?: number;\n\t/**\n\t * Font family stack available in the player iframe (system fonts / generic stacks).\n\t * Host-page webfonts are not loaded into the player frame.\n\t */\n\treadonly fontFamily?: string;\n\t/** CSS font-weight (100–900). */\n\treadonly fontWeight?: number;\n\treadonly size?: StartButtonSize;\n\treadonly shadow?: StartButtonShadow;\n};\n\nexport type StartButtonOptions = {\n\treadonly label?: string;\n\treadonly ariaLabel?: string;\n\treadonly placement?: StartButtonPlacement;\n\treadonly variant?: StartButtonVariant;\n\t/**\n\t * Tabler Iconify id (e.g. `player-play`, `tabler:microphone`) or an image URL\n\t * (`https://…` or `data:image/…`). Site-relative paths are not supported — they\n\t * would resolve against the player iframe origin, not the host page.\n\t */\n\treadonly icon?: string;\n\t/** Icon placement relative to the label. Defaults to `left`. */\n\treadonly iconPosition?: StartButtonIconPosition;\n\treadonly appearance?: StartButtonAppearance;\n};\n\n/**\n * Global player chrome theme (modals, shared buttons, panels).\n * Distinct from {@link StartButtonOptions} — start CTA keeps its own overrides.\n */\nexport type PlayerThemeColors = {\n\treadonly background?: string;\n\treadonly surface?: string;\n\treadonly surfaceMuted?: string;\n\treadonly text?: string;\n\treadonly textMuted?: string;\n\treadonly primary?: string;\n\treadonly primaryText?: string;\n\treadonly border?: string;\n};\n\nexport type PlayerThemeTypography = {\n\treadonly fontFamily?: string;\n\treadonly fontWeight?: number;\n\treadonly fontSizePx?: number;\n};\n\nexport type PlayerThemeButton = {\n\treadonly borderRadiusPx?: number;\n\treadonly borderWidthPx?: number;\n\treadonly shadow?: StartButtonShadow;\n};\n\nexport type PlayerTheme = {\n\treadonly colors?: PlayerThemeColors;\n\treadonly typography?: PlayerThemeTypography;\n\treadonly radiusPx?: number;\n\treadonly button?: PlayerThemeButton;\n};\n\nexport type SpeakBehavior = 'enqueue' | 'interrupt';\n\nexport type SpeakOptions = {\n\treadonly text: string;\n\treadonly characterId?: string;\n\treadonly behavior?: SpeakBehavior;\n};\n\n/** @deprecated Prefer {@link import('../speech').SpeechResult} from Experience.speech. */\nexport type TextSpeakResult = {\n\treadonly speechId: string;\n\treadonly turnId: string;\n\treadonly characterId: string;\n\treadonly text: string;\n\treadonly durationMs: number;\n};\n\n/** @deprecated Alias for TextSpeakResult — use Experience.speech SpeechResult for new code. */\nexport type SpeechResult = TextSpeakResult;\n\nexport type UtteranceResult = {\n\treadonly utteranceId: string;\n\treadonly text: string;\n};\n\nexport type UserTranscriptUpdate = {\n\treadonly utteranceId: string;\n\treadonly text: string;\n\treadonly revision: number;\n\treadonly isFinal: boolean;\n\treadonly delta?: string;\n};\n\nexport type ConversationMessageSource = 'user' | 'llm' | 'speak' | 'opening' | 'speechAudio';\n\nexport type ConversationMessage = {\n\treadonly messageId: string;\n\treadonly turnId: string;\n\treadonly role: 'user' | 'assistant';\n\treadonly text: string;\n\treadonly characterId?: string;\n\treadonly source: ConversationMessageSource;\n\treadonly status: 'final';\n\treadonly timestamp: number;\n};\n\nexport type CharacterSpeechSource = 'llm' | 'speak' | 'opening' | 'speechAudio';\n\nexport type CharacterSpeechTerminalReason =\n\t| 'completed'\n\t| 'interrupted'\n\t| 'error'\n\t| 'destroyed';\n\nexport type CharacterSpeechEvent = {\n\treadonly speechId: string;\n\treadonly turnId: string;\n\treadonly characterId: string;\n\treadonly text: string;\n\treadonly source: CharacterSpeechSource;\n\treadonly durationMs?: number;\n\treadonly reason?: CharacterSpeechTerminalReason;\n};\n\nexport type SessionModeChange = 'speaking' | 'listening' | 'thinking';\n\nexport type UserSpeechBoundaryEvent = {\n\treadonly utteranceId?: string;\n};\n\nexport type ConversationProcessorResult =\n\t| string\n\t| {\n\t\t\treadonly text: string;\n\t\t\treadonly characterId?: string;\n\t\t\treadonly behavior?: SpeakBehavior;\n\t };\n\nexport type ConversationProcessorContext = {\n\treadonly utteranceId: string;\n\treadonly text: string;\n\treadonly conversation: readonly ConversationMessage[];\n\treadonly signal: AbortSignal;\n};\n\nexport type ConversationProcessorFn = (\n\tcontext: ConversationProcessorContext\n) =>\n\t| ConversationProcessorResult\n\t| Promise<ConversationProcessorResult>\n\t| AsyncIterable<string>;\n\nexport type NormalizedProcessorSpeech = {\n\treadonly text: string;\n\treadonly characterId?: string;\n\treadonly behavior?: SpeakBehavior;\n};\n\nexport type ProcessorDispatchResult =\n\t| { readonly kind: 'complete'; readonly speech: NormalizedProcessorSpeech }\n\t| { readonly kind: 'stream'; readonly stream: AsyncIterable<string> };\n\nexport type ConversationProcessorErrorEvent = {\n\treadonly utteranceId: string;\n\treadonly message: string;\n};\n\nexport type ListenOnceOptions = {\n\treadonly signal?: AbortSignal;\n\treadonly timeoutMs?: number;\n};\n","import { fetchSessionLaunch, mintBrowserSession } from './api/mintPublicSession';\nimport { dispatchConversationProcessor } from './conversationProcessor';\nimport { createIframeHost, type IframeHost } from './embed/iframeHost';\nimport { createReadyGate } from './embed/readyGate';\nimport type { CloseEvent, EmbedState } from './embed/protocol';\nimport {\n\tbuildManifestEmbedUrl,\n\tresolvePlayerOrigin,\n\tresolvePublicPlayerEmbedUrl,\n\tresolveSceneHintId\n} from './shims/embedBaseUrl';\nimport type {\n\tCloseButtonOptions,\n\tPlayerStatus,\n\tSession,\n\tSessionActivity,\n\tSessionLaunchResponse\n} from './types/sessionLaunch';\nimport { warnLocaleVoiceFallbacks } from './types/sessionLaunch';\nimport {\n\tclearExperienceEventRegistry,\n\tcreateExperienceEventEnvelope,\n\tcreateExperienceEventRegistry,\n\temitExperienceEvent,\n\tsubscribeExperienceEvent,\n\ttype ExperienceEventName,\n\ttype ExperienceEvents\n} from './experienceEvents';\nimport {\n\tcreateSpeechController,\n\ttype SpeechCapabilities,\n\ttype SpeechController\n} from './speech/speechController';\nimport {\n\tparseExperienceFit,\n\ttype CharacterSpeechEvent,\n\ttype ConversationMessage,\n\ttype ConversationProcessorFn,\n\ttype ExperienceFit,\n\ttype ExperienceMode,\n\ttype ListenOnceOptions,\n\ttype SpeechInputMode,\n\ttype StartButtonOptions,\n\ttype PlayerTheme,\n\ttype StartedEvent,\n\ttype UserTranscriptUpdate,\n\ttype UtteranceResult\n} from './types/sessionInteraction';\nimport type { SessionManifest } from './types/sessionManifest';\n\nexport type { CloseEvent };\nexport type {\n\tCharacterSpeechEvent,\n\tCharacterSpeechSource,\n\tCharacterSpeechTerminalReason,\n\tConversationMessage,\n\tConversationProcessorContext,\n\tConversationProcessorErrorEvent,\n\tConversationProcessorFn,\n\tConversationProcessorResult,\n\tExperienceFit,\n\tListenOnceOptions,\n\tSpeakOptions,\n\tTextSpeakResult,\n\tSpeechResult as LegacySpeakResult,\n\tStartButtonAppearance,\n\tStartButtonOptions,\n\tStartButtonPlacement,\n\tStartButtonShadow,\n\tStartButtonSize,\n\tStartButtonVariant,\n\tStartButtonIconPosition,\n\tPlayerTheme,\n\tPlayerThemeButton,\n\tPlayerThemeColors,\n\tPlayerThemeTypography,\n\tUserSpeechBoundaryEvent,\n\tUserTranscriptUpdate,\n\tUtteranceResult\n} from './types/sessionInteraction';\nexport type {\n\tCloseButtonOptions,\n\tPlayerStatus,\n\tSession,\n\tSessionActivity,\n\tSessionCapabilities,\n\tSessionLaunchResponse,\n\tSessionMode\n} from './types/sessionLaunch';\nexport type {\n\tSpeechAudioFormat,\n\tSpeechController,\n\tSpeechCreateUtteranceOptions,\n\tSpeechInterruptOptions,\n\tSpeechPlayAudio,\n\tSpeechPlayEncodedAudio,\n\tSpeechPlayOptions,\n\tSpeechPlayPcmAudio,\n\tSpeechPlayUrlAudio,\n\tSpeechResult,\n\tSpeechSpeakOptions,\n\tSpeechUtterance\n} from './speech';\nexport {\n\tSPEECH_LIMITS,\n\tSpeechBufferTimeoutError,\n\tSpeechRuntimeError,\n\tSpeechUtteranceClosedError,\n\tUnsupportedSpeechOperationError\n} from './speech';\n\nexport type {\n\tExperienceEventEnvelope,\n\tExperienceEventName,\n\tExperienceEvents,\n\tFeedbackFailedEvent,\n\tFeedbackResult\n} from './experienceEvents';\n\ntype StartSessionShared = {\n\treadonly embedBaseUrl?: string;\n\treadonly debug?: boolean;\n\t/** ExperienceWidget warm embed chrome (`?ui=widget`). */\n\treadonly ui?: 'widget';\n\treadonly onStart?: (event: StartedEvent) => void | Promise<void>;\n\treadonly onUserTranscript?: (update: UserTranscriptUpdate) => void | Promise<void>;\n\treadonly conversationProcessor?: ConversationProcessorFn;\n\t/**\n\t * Whole-snapshot marketing attribution. `false` disables auto-capture.\n\t * When omitted, the SDK reads standard UTMs + document.referrer from the embedding page.\n\t */\n\treadonly attribution?: import('./api/captureAttribution').ExperienceAttribution | false;\n};\n\nexport type StartSessionOptions =\n\t| (StartSessionShared & {\n\t\t\treadonly experienceId: string;\n\t\t\t/** BCP 47 locale (preferred). When omitted in the browser, defaults to `navigator.language`. */\n\t\t\treadonly locale?: string;\n\t\t\treadonly secondaryLocale?: string;\n\t\t\treadonly learningLocale?: string;\n\t\t\t/** @deprecated Prefer `locale`. */\n\t\t\treadonly language?: 'en' | 'es' | string;\n\t\t\treadonly backdropId?: string;\n\t\t\t/** @deprecated Prefer `backdropId`. */\n\t\t\treadonly locationId?: string;\n\t\t\treadonly avatarId?: string;\n\t\t\treadonly castSize?: 2 | 3 | 4;\n\t\t\treadonly mode?: ExperienceMode;\n\t\t\treadonly speechInputMode?: SpeechInputMode;\n\t\t\t/** Voice-only session: skip avatar renderer and location scene asset loading. */\n\t\t\treadonly speechOnly?: boolean;\n\t })\n\t| (StartSessionShared & {\n\t\t\treadonly experienceId: string;\n\t\t\treadonly sessionEndpoint: string;\n\t\t\t/** BCP 47 locale (preferred). When omitted in the browser, defaults to `navigator.language`. */\n\t\t\treadonly locale?: string;\n\t\t\treadonly secondaryLocale?: string;\n\t\t\treadonly learningLocale?: string;\n\t\t\t/** @deprecated Prefer `locale`. */\n\t\t\treadonly language?: 'en' | 'es' | string;\n\t\t\treadonly backdropId?: string;\n\t\t\t/** @deprecated Prefer `backdropId`. */\n\t\t\treadonly locationId?: string;\n\t\t\treadonly avatarId?: string;\n\t\t\treadonly castSize?: 2 | 3 | 4;\n\t\t\treadonly mode?: ExperienceMode;\n\t\t\treadonly speechInputMode?: SpeechInputMode;\n\t\t\t/** Voice-only session: skip avatar renderer and location scene asset loading. */\n\t\t\treadonly speechOnly?: boolean;\n\t })\n\t| (StartSessionShared & {\n\t\t\t/**\n\t\t\t * Opaque signed launch string from a prior Session Launch response.\n\t\t\t * Prefer `sessionEndpoint` so page JS does not hold launch when avoidable.\n\t\t\t */\n\t\t\treadonly launch: string;\n\t\t\treadonly session?: Session;\n\t\t\treadonly backdropId?: string;\n\t\t\t/** @deprecated Prefer `backdropId`. */\n\t\t\treadonly locationId?: string;\n\t\t\treadonly avatarId?: string;\n\t\t\t/** Voice-only session: skip avatar renderer and location scene asset loading. */\n\t\t\treadonly speechOnly?: boolean;\n\t });\n\nexport type AttachOptions = {\n\treadonly container: HTMLElement;\n\t/** Initial scene framing. Change later with {@link Experience.setFit}. */\n\treadonly fit?: ExperienceFit;\n\treadonly startButton?: StartButtonOptions;\n\t/**\n\t * Global player chrome theme (introduction, feedback, shared buttons, panels).\n\t * Distinct from {@link AttachOptions.startButton} CTA overrides. Presentation only — does not remint.\n\t */\n\treadonly theme?: PlayerTheme;\n\t/**\n\t * When true (default), the Liforma player shows end-of-session Feedback UI.\n\t * When false, hosts receive scores via `feedback` / `feedbackFailed` and render their own UX.\n\t * Presentation only — does not remint.\n\t */\n\treadonly showFeedback?: boolean;\n\treadonly closeButton?: CloseButtonOptions | boolean;\n\treadonly returnUrl?: string;\n\treadonly onPlayerStatusChange?: (status: PlayerStatus) => void;\n\t/** @deprecated Prefer {@link AttachOptions.onPlayerStatusChange}. */\n\treadonly onStateUpdate?: (state: EmbedState) => void;\n\treadonly onWidgetReady?: () => void;\n\treadonly onWidgetExpand?: () => void;\n\treadonly onWidgetCollapse?: () => void;\n\treadonly onWidgetAudioSettings?: (open: boolean) => void;\n\t/** Docked shell: player surface drag → parent repositions the dock. */\n\treadonly onWidgetDragStart?: (event: { readonly pointerId: number }) => void;\n\treadonly onWidgetDragMove?: (event: {\n\t\treadonly pointerId: number;\n\t\treadonly dx: number;\n\t\treadonly dy: number;\n\t}) => void;\n\treadonly onWidgetDragEnd?: (event: { readonly pointerId: number }) => void;\n\t/**\n\t * Show the in-player close control. Set when the host provides `onClose`\n\t * and/or `returnUrl` / `closeButton`. Widget chrome keeps its own toolbar close separately.\n\t * @deprecated Prefer {@link AttachOptions.closeButton}.\n\t */\n\treadonly showClose?: boolean;\n};\n\nexport type { EmbedState };\n\nexport type ReadyEvent = {\n\treadonly session: Session;\n};\n\nexport type LiformaPlayer = {\n\tclose(): void;\n\tdestroy(): void;\n\ton(event: 'close', handler: (event: CloseEvent) => void): void;\n};\n\ntype SessionBootstrap =\n\t| {\n\t\t\treadonly kind: 'public';\n\t\t\treadonly experienceId: string;\n\t\t\treadonly locale?: string;\n\t\t\treadonly secondaryLocale?: string;\n\t\t\treadonly learningLocale?: string;\n\t\t\treadonly language?: string;\n\t\t\treadonly backdropId?: string;\n\t\t\treadonly locationId?: string;\n\t\t\treadonly avatarId?: string;\n\t\t\treadonly castSize?: 2 | 3 | 4;\n\t\t\treadonly embedBaseUrl?: string;\n\t\t\treadonly debug?: boolean;\n\t\t\treadonly mode?: ExperienceMode;\n\t\t\treadonly speechInputMode?: SpeechInputMode;\n\t\t\treadonly speechOnly?: boolean;\n\t\t\treadonly attribution?: import('./api/captureAttribution').ExperienceAttribution | false;\n\t\t\treadonly ui?: 'widget';\n\t\t\treadonly onStart?: (event: StartedEvent) => void | Promise<void>;\n\t\t\treadonly onUserTranscript?: (update: UserTranscriptUpdate) => void | Promise<void>;\n\t\t\treadonly conversationProcessor?: ConversationProcessorFn;\n\t }\n\t| {\n\t\t\treadonly kind: 'sessionEndpoint';\n\t\t\treadonly experienceId: string;\n\t\t\treadonly sessionEndpoint: string;\n\t\t\treadonly locale?: string;\n\t\t\treadonly secondaryLocale?: string;\n\t\t\treadonly learningLocale?: string;\n\t\t\treadonly language?: string;\n\t\t\treadonly backdropId?: string;\n\t\t\treadonly locationId?: string;\n\t\t\treadonly avatarId?: string;\n\t\t\treadonly castSize?: 2 | 3 | 4;\n\t\t\treadonly embedBaseUrl?: string;\n\t\t\treadonly debug?: boolean;\n\t\t\treadonly mode?: ExperienceMode;\n\t\t\treadonly speechInputMode?: SpeechInputMode;\n\t\t\treadonly speechOnly?: boolean;\n\t\t\treadonly attribution?: import('./api/captureAttribution').ExperienceAttribution | false;\n\t\t\treadonly ui?: 'widget';\n\t\t\treadonly onStart?: (event: StartedEvent) => void | Promise<void>;\n\t\t\treadonly onUserTranscript?: (update: UserTranscriptUpdate) => void | Promise<void>;\n\t\t\treadonly conversationProcessor?: ConversationProcessorFn;\n\t }\n\t| {\n\t\t\treadonly kind: 'launch';\n\t\t\treadonly launch: string;\n\t\t\treadonly session?: Session;\n\t\t\treadonly backdropId?: string;\n\t\t\treadonly locationId?: string;\n\t\t\treadonly avatarId?: string;\n\t\t\treadonly embedBaseUrl?: string;\n\t\t\treadonly debug?: boolean;\n\t\t\treadonly speechOnly?: boolean;\n\t\t\treadonly ui?: 'widget';\n\t\t\treadonly onStart?: (event: StartedEvent) => void | Promise<void>;\n\t\t\treadonly onUserTranscript?: (update: UserTranscriptUpdate) => void | Promise<void>;\n\t\t\treadonly conversationProcessor?: ConversationProcessorFn;\n\t };\n\nfunction resolveShowClose(options: AttachOptions): boolean {\n\tif (options.showClose === true) return true;\n\tif (options.returnUrl?.trim()) return true;\n\tif (options.closeButton === true) return true;\n\tif (\n\t\toptions.closeButton &&\n\t\ttypeof options.closeButton === 'object' &&\n\t\toptions.closeButton.visible !== false\n\t) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nexport class Experience {\n\tprivate readonly bootstrap: SessionBootstrap;\n\tprivate readonly conversationProcessor: ConversationProcessorFn | null;\n\tprivate iframeHost: IframeHost | null = null;\n\tprivate attachInFlight: Promise<LiformaPlayer> | null = null;\n\tprivate endpointAbortController: AbortController | null = null;\n\tprivate processorAbortController: AbortController | null = null;\n\tprivate processorChain: Promise<void> = Promise.resolve();\n\tprivate resolvedSession: Session | null;\n\tprivate launchToken: string | null;\n\tprivate attachReturnUrl: string | null = null;\n\tprivate closed = false;\n\tprivate attached = false;\n\tprivate pendingFit: ExperienceFit | null = null;\n\tprivate readonly closeHandlers: ((event: CloseEvent) => void)[] = [];\n\tprivate readonly eventRegistry = createExperienceEventRegistry();\n\tprivate readyEnvelope: ExperienceEvents['ready'] | null = null;\n\tprivate startedEnvelope: ExperienceEvents['started'] | null = null;\n\tprivate sessionMintedEnvelope: ExperienceEvents['sessionMinted'] | null = null;\n\tprivate conversationCache: readonly ConversationMessage[] = [];\n\t/** Public speech API — text TTS and BYO PCM (`speak` / `play` / `createUtterance` / `interrupt`). */\n\treadonly speech: SpeechController;\n\n\tprivate constructor(bootstrap: SessionBootstrap) {\n\t\tthis.bootstrap = bootstrap;\n\t\tthis.conversationProcessor = bootstrap.conversationProcessor ?? null;\n\t\tthis.resolvedSession = bootstrap.kind === 'launch' ? (bootstrap.session ?? null) : null;\n\t\tthis.launchToken = bootstrap.kind === 'launch' ? bootstrap.launch : null;\n\t\tthis.speech = createSpeechController({\n\t\t\tgetIframeHost: () => this.iframeHost,\n\t\t\tassertSessionStarted: () => this.assertSessionStarted(),\n\t\t\tgetCapabilities: () => resolveSpeechCapabilities(this.resolvedSession),\n\t\t\tgetActiveCharacterId: () => 'character_unknown',\n\t\t\tonProcessorInterrupt: () => {\n\t\t\t\tthis.processorAbortController?.abort();\n\t\t\t\tthis.processorAbortController = null;\n\t\t\t}\n\t\t});\n\t}\n\n\tstatic async startSession(options: StartSessionOptions): Promise<Experience> {\n\t\tif ('launch' in options && typeof options.launch === 'string') {\n\t\t\tconst launch = options.launch.trim();\n\t\t\tif (!launch) {\n\t\t\t\tthrow new Error('StartSessionOptions.launch must be a non-empty string.');\n\t\t\t}\n\t\t\treturn new Experience({\n\t\t\t\tkind: 'launch',\n\t\t\t\tlaunch,\n\t\t\t\tsession: options.session,\n\t\t\t\tbackdropId: options.backdropId,\n\t\t\t\tlocationId: options.locationId,\n\t\t\t\tavatarId: options.avatarId,\n\t\t\t\tembedBaseUrl: options.embedBaseUrl,\n\t\t\t\tdebug: options.debug,\n\t\t\t\tspeechOnly: options.speechOnly,\n\t\t\t\tui: options.ui,\n\t\t\t\tonStart: options.onStart,\n\t\t\t\tonUserTranscript: options.onUserTranscript,\n\t\t\t\tconversationProcessor: options.conversationProcessor\n\t\t\t});\n\t\t}\n\n\t\tif ('sessionEndpoint' in options) {\n\t\t\treturn new Experience({\n\t\t\t\tkind: 'sessionEndpoint',\n\t\t\t\texperienceId: options.experienceId,\n\t\t\t\tsessionEndpoint: options.sessionEndpoint,\n\t\t\t\tlocale: options.locale,\n\t\t\t\tsecondaryLocale: options.secondaryLocale,\n\t\t\t\tlearningLocale: options.learningLocale,\n\t\t\t\tlanguage: options.language,\n\t\t\t\tbackdropId: options.backdropId,\n\t\t\t\tlocationId: options.locationId,\n\t\t\t\tavatarId: options.avatarId,\n\t\t\t\tcastSize: options.castSize,\n\t\t\t\tembedBaseUrl: options.embedBaseUrl,\n\t\t\t\tdebug: options.debug,\n\t\t\t\tmode: options.mode,\n\t\t\t\tspeechInputMode: options.speechInputMode,\n\t\t\t\tspeechOnly: options.speechOnly,\n\t\t\t\tattribution: options.attribution,\n\t\t\t\tui: options.ui,\n\t\t\t\tonStart: options.onStart,\n\t\t\t\tonUserTranscript: options.onUserTranscript,\n\t\t\t\tconversationProcessor: options.conversationProcessor\n\t\t\t});\n\t\t}\n\n\t\tif ('experienceId' in options) {\n\t\t\treturn new Experience({\n\t\t\t\tkind: 'public',\n\t\t\t\texperienceId: options.experienceId,\n\t\t\t\tlocale: options.locale,\n\t\t\t\tsecondaryLocale: options.secondaryLocale,\n\t\t\t\tlearningLocale: options.learningLocale,\n\t\t\t\tlanguage: options.language,\n\t\t\t\tbackdropId: options.backdropId,\n\t\t\t\tlocationId: options.locationId,\n\t\t\t\tavatarId: options.avatarId,\n\t\t\t\tcastSize: options.castSize,\n\t\t\t\tembedBaseUrl: options.embedBaseUrl,\n\t\t\t\tdebug: options.debug,\n\t\t\t\tmode: options.mode,\n\t\t\t\tspeechInputMode: options.speechInputMode,\n\t\t\t\tspeechOnly: options.speechOnly,\n\t\t\t\tattribution: options.attribution,\n\t\t\t\tui: options.ui,\n\t\t\t\tonStart: options.onStart,\n\t\t\t\tonUserTranscript: options.onUserTranscript,\n\t\t\t\tconversationProcessor: options.conversationProcessor\n\t\t\t});\n\t\t}\n\n\t\tthrow new Error(\n\t\t\t'Experience.startSession requires experienceId, sessionEndpoint, or launch.'\n\t\t);\n\t}\n\n\tgetSession(): Session | null {\n\t\treturn this.resolvedSession;\n\t}\n\n\t/**\n\t * @deprecated Session Manifest is no longer a public SDK contract.\n\t * Use {@link Experience.getSession} for the public Session summary.\n\t */\n\tgetManifest(): SessionManifest | null {\n\t\treturn null;\n\t}\n\n\ton<K extends ExperienceEventName>(\n\t\tevent: K,\n\t\thandler: (event: ExperienceEvents[K]) => void\n\t): () => void {\n\t\tconst unsubscribe = subscribeExperienceEvent(this.eventRegistry, event, handler);\n\t\tif (event === 'ready' && this.readyEnvelope) {\n\t\t\tqueueMicrotask(() => handler(this.readyEnvelope as ExperienceEvents[K]));\n\t\t}\n\t\tif (event === 'started' && this.startedEnvelope) {\n\t\t\tqueueMicrotask(() => handler(this.startedEnvelope as ExperienceEvents[K]));\n\t\t}\n\t\tif (event === 'sessionMinted' && this.sessionMintedEnvelope) {\n\t\t\tqueueMicrotask(() => handler(this.sessionMintedEnvelope as ExperienceEvents[K]));\n\t\t}\n\t\treturn unsubscribe;\n\t}\n\n\tasync attach(options: AttachOptions): Promise<LiformaPlayer> {\n\t\tif (this.closed) {\n\t\t\tthrow new Error('Session has ended.');\n\t\t}\n\t\tif (!options.container) {\n\t\t\tthrow new Error('Experience.attach requires a DOM container element.');\n\t\t}\n\t\tif (this.attached && this.iframeHost) {\n\t\t\treturn this.createPlayerFacade();\n\t\t}\n\t\tif (this.attachInFlight) {\n\t\t\treturn this.attachInFlight;\n\t\t}\n\n\t\tthis.attachInFlight = this.attachInternal(options).finally(() => {\n\t\t\tthis.attachInFlight = null;\n\t\t});\n\t\treturn this.attachInFlight;\n\t}\n\n\tprivate async attachInternal(options: AttachOptions): Promise<LiformaPlayer> {\n\t\tif (this.closed) {\n\t\t\tthrow new Error('Session has ended.');\n\t\t}\n\t\tif (this.attached && this.iframeHost) {\n\t\t\treturn this.createPlayerFacade();\n\t\t}\n\t\tif (this.iframeHost) {\n\t\t\tthis.iframeHost.destroy();\n\t\t\tthis.iframeHost = null;\n\t\t}\n\n\t\tthis.attachReturnUrl = options.returnUrl?.trim() || null;\n\n\t\tconst embedBaseUrl = this.bootstrap.embedBaseUrl ?? resolvePublicPlayerEmbedUrl();\n\t\tconst debug = this.bootstrap.debug === true;\n\t\tconst speechOnly = this.bootstrap.speechOnly === true;\n\t\tconst locationId = speechOnly\n\t\t\t? undefined\n\t\t\t: resolveSceneHintId(this.bootstrap.backdropId, this.bootstrap.locationId);\n\t\tconst avatarId = speechOnly ? undefined : this.bootstrap.avatarId;\n\t\t// The SDK owns minting and posts the opaque launch. Do not put experienceId in the\n\t\t// iframe URL or the player will mint a second session before the parent launch arrives.\n\t\tconst iframeSrc = buildManifestEmbedUrl(\n\t\t\tembedBaseUrl,\n\t\t\tdebug,\n\t\t\tlocationId,\n\t\t\tavatarId,\n\t\t\toptions.fit,\n\t\t\tthis.bootstrap.ui,\n\t\t\tresolveShowClose(options),\n\t\t\tthis.bootstrap.kind === 'launch' ? undefined : this.bootstrap.castSize\n\t\t);\n\t\tconst playerOrigin = resolvePlayerOrigin(iframeSrc);\n\n\t\tlet resolveLoadingUi: (() => void) | null = null;\n\t\tconst loadingUiPromise = new Promise<void>((resolve) => {\n\t\t\tresolveLoadingUi = resolve;\n\t\t});\n\t\tlet resolveReadyUi: (() => void) | null = null;\n\t\tconst readyUiPromise = new Promise<void>((resolve) => {\n\t\t\tresolveReadyUi = resolve;\n\t\t});\n\t\tconst readyGate = createReadyGate<Session>((readySession) => {\n\t\t\tif (this.readyEnvelope) return;\n\t\t\tthis.resolvedSession = readySession;\n\t\t\tthis.readyEnvelope = this.emitWrapped('ready', { session: readySession });\n\t\t});\n\n\t\tconst onUserTranscript = this.bootstrap.onUserTranscript;\n\n\t\tconst onPlayerStatus = (status: PlayerStatus) => {\n\t\t\toptions.onPlayerStatusChange?.(status);\n\t\t\toptions.onStateUpdate?.(status);\n\t\t\tif (status === 'loading' && resolveLoadingUi) {\n\t\t\t\tresolveLoadingUi();\n\t\t\t\tresolveLoadingUi = null;\n\t\t\t}\n\t\t\tif (status === 'ready' && resolveReadyUi) {\n\t\t\t\tresolveReadyUi();\n\t\t\t\tresolveReadyUi = null;\n\t\t\t}\n\t\t\tif (status === 'ready') {\n\t\t\t\treadyGate.markReady();\n\t\t\t}\n\t\t};\n\n\t\tconst iframeHost = createIframeHost({\n\t\t\tcontainer: options.container,\n\t\t\tsrc: iframeSrc,\n\t\t\tplayerOrigin,\n\t\t\ttransparent: this.bootstrap.ui === 'widget',\n\t\t\tonClose: (event) => {\n\t\t\t\tconst enriched: CloseEvent =\n\t\t\t\t\tevent.returnUrl || !this.attachReturnUrl\n\t\t\t\t\t\t? event\n\t\t\t\t\t\t: { ...event, returnUrl: this.attachReturnUrl };\n\t\t\t\tfor (const handler of this.closeHandlers) {\n\t\t\t\t\thandler(enriched);\n\t\t\t\t}\n\t\t\t},\n\t\t\tonPlayerStatusChange: onPlayerStatus,\n\t\t\tonUserTranscript: (update) => {\n\t\t\t\tthis.emitWrapped('userTranscript', update);\n\t\t\t\tvoid onUserTranscript?.(update);\n\t\t\t\tthis.queueProcessorTurn(update);\n\t\t\t},\n\t\t\tonUserSpeechStarted: (event) => {\n\t\t\t\tthis.emitWrapped('userSpeechStarted', event);\n\t\t\t},\n\t\t\tonUserSpeechEnded: (event) => {\n\t\t\t\tthis.emitWrapped('userSpeechEnded', event);\n\t\t\t},\n\t\t\tonCharacterSpeechStarted: (event: CharacterSpeechEvent) => {\n\t\t\t\tthis.emitWrapped('characterSpeechStarted', event);\n\t\t\t},\n\t\t\tonCharacterSpeechEnded: (event: CharacterSpeechEvent) => {\n\t\t\t\tthis.emitWrapped('characterSpeechEnded', event);\n\t\t\t},\n\t\t\tonCharacterFocusChanged: (event) => {\n\t\t\t\tthis.emitWrapped('characterFocusChanged', event);\n\t\t\t},\n\t\t\tonListeningState: (listening) => {\n\t\t\t\tthis.emitWrapped('listeningState', listening);\n\t\t\t},\n\t\t\tonActivityChange: (activity: SessionActivity) => {\n\t\t\t\tthis.emitWrapped('activityChange', activity);\n\t\t\t},\n\t\t\tonFeedback: (result) => {\n\t\t\t\tthis.emitWrapped('feedback', result);\n\t\t\t},\n\t\t\tonFeedbackFailed: (event) => {\n\t\t\t\tthis.emitWrapped('feedbackFailed', event);\n\t\t\t},\n\t\t\tonMessage: (message) => {\n\t\t\t\tthis.emitWrapped('message', message);\n\t\t\t},\n\t\t\tonStarted: (event) => {\n\t\t\t\tif (!this.startedEnvelope) {\n\t\t\t\t\tthis.startedEnvelope = this.emitWrapped('started', event);\n\t\t\t\t\tvoid this.bootstrap.onStart?.(event);\n\t\t\t\t}\n\t\t\t},\n\t\t\tonConversationUpdate: (conversation) => {\n\t\t\t\tthis.conversationCache = conversation;\n\t\t\t\tthis.emitWrapped('conversationUpdate', conversation);\n\t\t\t},\n\t\t\tonWidgetReady: () => options.onWidgetReady?.(),\n\t\t\tonWidgetExpand: () => options.onWidgetExpand?.(),\n\t\t\tonWidgetCollapse: () => options.onWidgetCollapse?.(),\n\t\t\tonWidgetAudioSettings: (open) => options.onWidgetAudioSettings?.(open),\n\t\t\tonWidgetDragStart: (event) => options.onWidgetDragStart?.(event),\n\t\t\tonWidgetDragMove: (event) => options.onWidgetDragMove?.(event),\n\t\t\tonWidgetDragEnd: (event) => options.onWidgetDragEnd?.(event)\n\t\t});\n\t\tthis.iframeHost = iframeHost;\n\n\t\tconst mintInteraction = this.resolveMintInteraction();\n\n\t\tconst launchPromise: Promise<SessionLaunchResponse | null> =\n\t\t\tthis.bootstrap.kind === 'sessionEndpoint'\n\t\t\t\t? (() => {\n\t\t\t\t\t\tthis.endpointAbortController = new AbortController();\n\t\t\t\t\t\treturn fetchSessionLaunch(this.bootstrap.sessionEndpoint, {\n\t\t\t\t\t\t\texperienceId: this.bootstrap.experienceId,\n\t\t\t\t\t\t\tlocale: this.bootstrap.locale,\n\t\t\t\t\t\t\tsecondaryLocale: this.bootstrap.secondaryLocale,\n\t\t\t\t\t\t\tlearningLocale: this.bootstrap.learningLocale,\n\t\t\t\t\t\t\tlanguage: this.bootstrap.language,\n\t\t\t\t\t\t\tmode: mintInteraction.mode,\n\t\t\t\t\t\t\tspeechInputMode: mintInteraction.speechInputMode,\n\t\t\t\t\t\t\tspeechOnly: this.bootstrap.speechOnly,\n\t\t\t\t\t\t\tattribution: this.bootstrap.attribution,\n\t\t\t\t\t\t\tsignal: this.endpointAbortController.signal\n\t\t\t\t\t\t});\n\t\t\t\t\t})()\n\t\t\t\t: this.bootstrap.kind === 'public'\n\t\t\t\t\t? mintBrowserSession(this.bootstrap.experienceId, {\n\t\t\t\t\t\t\tlocale: this.bootstrap.locale,\n\t\t\t\t\t\t\tsecondaryLocale: this.bootstrap.secondaryLocale,\n\t\t\t\t\t\t\tlearningLocale: this.bootstrap.learningLocale,\n\t\t\t\t\t\t\tlanguage: this.bootstrap.language,\n\t\t\t\t\t\t\tmode: mintInteraction.mode,\n\t\t\t\t\t\t\tspeechInputMode: mintInteraction.speechInputMode,\n\t\t\t\t\t\t\tspeechOnly: this.bootstrap.speechOnly,\n\t\t\t\t\t\t\tattribution: this.bootstrap.attribution\n\t\t\t\t\t\t})\n\t\t\t\t\t: Promise.resolve(\n\t\t\t\t\t\t\tthis.bootstrap.session\n\t\t\t\t\t\t\t\t? { session: this.bootstrap.session, launch: this.bootstrap.launch }\n\t\t\t\t\t\t\t\t: null\n\t\t\t\t\t\t);\n\n\t\tlet launchResponse: SessionLaunchResponse | null;\n\t\ttry {\n\t\t\t[, launchResponse] = await Promise.all([iframeHost.waitForLoad(), launchPromise]);\n\t\t} catch (error) {\n\t\t\tiframeHost.destroy();\n\t\t\tif (this.iframeHost === iframeHost) {\n\t\t\t\tthis.iframeHost = null;\n\t\t\t}\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tthis.endpointAbortController = null;\n\t\t}\n\t\tiframeHost.postParentHello();\n\n\t\tconst launchToken =\n\t\t\tlaunchResponse?.launch ??\n\t\t\t(this.bootstrap.kind === 'launch' ? this.bootstrap.launch : null);\n\t\tconst session =\n\t\t\tlaunchResponse?.session ??\n\t\t\t(this.bootstrap.kind === 'launch' ? this.bootstrap.session : undefined);\n\n\t\tif (!launchToken) {\n\t\t\tiframeHost.destroy();\n\t\t\tif (this.iframeHost === iframeHost) {\n\t\t\t\tthis.iframeHost = null;\n\t\t\t}\n\t\t\tthrow new Error('Session Launch response did not include a launch token.');\n\t\t}\n\n\t\tthis.launchToken = launchToken;\n\t\tconst mintedSession =\n\t\t\tsession ??\n\t\t\t(this.bootstrap.kind === 'launch' ? this.bootstrap.session : undefined);\n\t\tif (mintedSession && !this.sessionMintedEnvelope) {\n\t\t\tthis.resolvedSession = mintedSession;\n\t\t\tthis.sessionMintedEnvelope = this.emitWrapped('sessionMinted', {\n\t\t\t\tsession: mintedSession\n\t\t\t});\n\t\t}\n\t\tif (session) {\n\t\t\tthis.resolvedSession = session;\n\t\t\t// Mint/endpoint paths already warn inside parseSessionLaunchResponse.\n\t\t\tif (this.bootstrap.kind === 'launch') {\n\t\t\t\twarnLocaleVoiceFallbacks(session);\n\t\t\t}\n\t\t\tiframeHost.postLaunch(launchToken, session, {\n\t\t\t\tstartButton: options.startButton,\n\t\t\t\ttheme: options.theme,\n\t\t\t\tshowFeedback: options.showFeedback\n\t\t\t});\n\t\t\treadyGate.setValue(session);\n\t\t} else {\n\t\t\tiframeHost.postLaunch(launchToken, undefined, {\n\t\t\t\tstartButton: options.startButton,\n\t\t\t\ttheme: options.theme,\n\t\t\t\tshowFeedback: options.showFeedback\n\t\t\t});\n\t\t}\n\n\t\tawait Promise.race([\n\t\t\tloadingUiPromise,\n\t\t\tnew Promise<void>((_, reject) => {\n\t\t\t\tsetTimeout(\n\t\t\t\t\t() => reject(new Error('Timed out waiting for player loading UI.')),\n\t\t\t\t\t120_000\n\t\t\t\t);\n\t\t\t})\n\t\t]);\n\n\t\tawait Promise.race([\n\t\t\treadyUiPromise,\n\t\t\tnew Promise<void>((_, reject) => {\n\t\t\t\tsetTimeout(\n\t\t\t\t\t() => reject(new Error('Timed out waiting for player ready state.')),\n\t\t\t\t\t120_000\n\t\t\t\t);\n\t\t\t})\n\t\t]);\n\n\t\tthis.attached = true;\n\t\tif (this.pendingFit) {\n\t\t\tawait iframeHost.setFit(this.pendingFit);\n\t\t}\n\t\treturn this.createPlayerFacade();\n\t}\n\n\tasync startListening(): Promise<void> {\n\t\tthis.assertSessionStarted();\n\t\tawait this.iframeHost!.startListening();\n\t}\n\n\tasync stopListening(): Promise<UtteranceResult> {\n\t\tthis.assertSessionStarted();\n\t\treturn this.iframeHost!.stopListening();\n\t}\n\n\tasync listenOnce(options?: ListenOnceOptions): Promise<UtteranceResult> {\n\t\tthis.assertSessionStarted();\n\t\treturn this.iframeHost!.listenOnce({\n\t\t\ttimeoutMs: options?.timeoutMs\n\t\t});\n\t}\n\n\tgetConversation(): readonly ConversationMessage[] {\n\t\treturn this.conversationCache;\n\t}\n\n\t/** Parent → player chrome mode for ExperienceWidget warm/cold expand / dock. */\n\tsetWidgetChrome(mode: 'collapsed' | 'loading' | 'expanded' | 'docked'): void {\n\t\tthis.iframeHost?.postWidgetSetChrome(mode);\n\t}\n\n\t/** Parent → player toggle for mic/speaker settings (ExperienceWidget toolbar). */\n\ttoggleAudioSettings(): void {\n\t\tthis.iframeHost?.postWidgetToggleAudioSettings();\n\t}\n\n\t/** Presentation-only. No-op on single-Character nodes. */\n\tasync focusCharacter(characterId: string): Promise<void> {\n\t\tthis.assertSessionStarted();\n\t\tawait this.iframeHost!.focusCharacter(characterId);\n\t}\n\n\t/** Live scene framing. Does not remint or restart the session. Queues until `attach()` if needed. */\n\tasync setFit(fit: ExperienceFit): Promise<void> {\n\t\tconst parsed = parseExperienceFit(fit);\n\t\tif (!parsed) {\n\t\t\tthrow new Error('setFit requires \"full\", \"medium\", or \"face\".');\n\t\t}\n\t\tif (this.closed) {\n\t\t\tthrow new Error('Session has ended.');\n\t\t}\n\t\tthis.pendingFit = parsed;\n\t\tif (!this.attached || !this.iframeHost) return;\n\t\tawait this.iframeHost.setFit(parsed);\n\t}\n\n\t/** Record a conversion milestone (once per session per key). Client-reported. */\n\tasync conversion(key: string): Promise<void> {\n\t\tif (this.closed) {\n\t\t\tthrow new Error('Session has ended.');\n\t\t}\n\t\tif (!this.iframeHost) {\n\t\t\tthrow new Error('conversion() requires attach() first.');\n\t\t}\n\t\tawait this.iframeHost.conversion(key);\n\t}\n\n\t/** Mark engagement from an authored choice / explicit interaction. Idempotent. */\n\tasync engage(): Promise<void> {\n\t\tif (this.closed) {\n\t\t\tthrow new Error('Session has ended.');\n\t\t}\n\t\tif (!this.iframeHost) {\n\t\t\tthrow new Error('engage() requires attach() first.');\n\t\t}\n\t\tawait this.iframeHost.engage();\n\t}\n\n\tgetLastTurn(): readonly ConversationMessage[] {\n\t\tif (this.conversationCache.length === 0) return [];\n\t\tconst lastTurnId = this.conversationCache[this.conversationCache.length - 1]!.turnId;\n\t\treturn this.conversationCache.filter((m) => m.turnId === lastTurnId);\n\t}\n\n\tasync end(): Promise<void> {\n\t\tthis.close();\n\t}\n\n\tdestroy(): void {\n\t\tif (this.closed) return;\n\t\tthis.closed = true;\n\t\tthis.processorAbortController?.abort();\n\t\tthis.processorAbortController = null;\n\t\tthis.endpointAbortController?.abort();\n\t\tthis.endpointAbortController = null;\n\t\tthis.attachInFlight = null;\n\t\tthis.iframeHost?.destroy();\n\t\tthis.iframeHost = null;\n\t\tclearExperienceEventRegistry(this.eventRegistry);\n\t\tthis.readyEnvelope = null;\n\t\tthis.startedEnvelope = null;\n\t\tthis.closeHandlers.length = 0;\n\t\tthis.attached = false;\n\t}\n\n\tprivate resolveMintInteraction(): {\n\t\treadonly mode?: ExperienceMode;\n\t\treadonly speechInputMode?: SpeechInputMode;\n\t} {\n\t\tif (this.bootstrap.kind === 'launch') {\n\t\t\treturn {};\n\t\t}\n\t\treturn {\n\t\t\tmode: this.bootstrap.mode,\n\t\t\tspeechInputMode: this.bootstrap.speechInputMode\n\t\t};\n\t}\n\n\tprivate getSessionId(): string {\n\t\treturn this.resolvedSession?.id ?? '';\n\t}\n\n\tprivate emitWrapped<K extends ExperienceEventName>(\n\t\tevent: K,\n\t\tdata: ExperienceEvents[K]['data']\n\t): ExperienceEvents[K] {\n\t\tconst envelope = createExperienceEventEnvelope(event, this.getSessionId(), data) as unknown as ExperienceEvents[K];\n\t\temitExperienceEvent(this.eventRegistry, event, envelope);\n\t\treturn envelope;\n\t}\n\n\tprivate queueProcessorTurn(update: UserTranscriptUpdate): void {\n\t\tif (!update.isFinal || !update.text.trim() || !this.conversationProcessor) return;\n\n\t\tconst processor = this.conversationProcessor;\n\t\tthis.processorAbortController?.abort();\n\t\tthis.processorAbortController = new AbortController();\n\t\tconst signal = this.processorAbortController.signal;\n\n\t\tthis.processorChain = this.processorChain.then(async () => {\n\t\t\tif (signal.aborted) return;\n\t\t\ttry {\n\t\t\t\tconst dispatch = await dispatchConversationProcessor(processor, {\n\t\t\t\t\tutteranceId: update.utteranceId,\n\t\t\t\t\ttext: update.text,\n\t\t\t\t\tconversation: this.conversationCache,\n\t\t\t\t\tsignal\n\t\t\t\t});\n\t\t\t\tif (signal.aborted) return;\n\t\t\t\tif (dispatch.kind === 'complete') {\n\t\t\t\t\tconst speech = dispatch.speech;\n\t\t\t\t\tawait this.speech.speak({\n\t\t\t\t\t\ttext: speech.text,\n\t\t\t\t\t\t...(speech.characterId ? { characterId: speech.characterId } : {}),\n\t\t\t\t\t\tqueue: speech.behavior === 'interrupt' ? 'replace-active' : 'append'\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tawait this.iframeHost!.speakProcessorStream(dispatch.stream, { signal });\n\t\t\t} catch (error) {\n\t\t\t\tif (signal.aborted) return;\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tthis.emitWrapped('conversationProcessorError', {\n\t\t\t\t\tutteranceId: update.utteranceId,\n\t\t\t\t\tmessage\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate assertAttached(): void {\n\t\tif (!this.attached || !this.iframeHost) {\n\t\t\tthrow new Error('Call Experience.attach() before using speech APIs.');\n\t\t}\n\t}\n\n\tprivate assertSessionStarted(): void {\n\t\tthis.assertAttached();\n\t\tif (!this.startedEnvelope) {\n\t\t\tthrow new Error(\n\t\t\t\t'Session has not started. Wait for the player start button and the started event before using speak() or listening APIs.'\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate close(): void {\n\t\tif (this.closed) return;\n\t\tthis.closed = true;\n\t\tthis.endpointAbortController?.abort();\n\t\tthis.endpointAbortController = null;\n\t\tthis.attachInFlight = null;\n\t\tthis.iframeHost?.destroy();\n\t\tthis.iframeHost = null;\n\t\tthis.attached = false;\n\t}\n\n\tprivate createPlayerFacade(): LiformaPlayer {\n\t\treturn {\n\t\t\tclose: () => {\n\t\t\t\tthis.close();\n\t\t\t},\n\t\t\tdestroy: () => {\n\t\t\t\tthis.destroy();\n\t\t\t},\n\t\t\ton: (event, handler) => {\n\t\t\t\tif (event === 'close') {\n\t\t\t\t\tthis.closeHandlers.push(handler);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n}\n\n/** Live session handle returned by {@link Experience.startSession}. */\nexport type ExperienceSession = Experience;\n\nfunction resolveSpeechCapabilities(session: Session | null): SpeechCapabilities {\n\tif (!session) {\n\t\treturn { textSpeech: true, externalSpeechAudio: true };\n\t}\n\treturn {\n\t\ttextSpeech: session.capabilities.speech.output,\n\t\texternalSpeechAudio: session.capabilities.speech.externalAudio\n\t};\n}\n","import './liforma-experience';\nimport './liforma-experience-thumbnail';\nimport './liforma-experience-widget';\n\nexport { Experience, type ExperienceSession } from './experience';\nexport { LiformaError, liformaErrorFromResponse } from './errors/LiformaError';\nexport type {\n\tAttachOptions,\n\tCloseEvent,\n\tEmbedState,\n\tLiformaPlayer,\n\tReadyEvent,\n\tStartSessionOptions\n} from './experience';\nexport type { SessionManifest, SessionManifestCharacter } from './types/sessionManifest';\nexport type {\n\tCloseButtonOptions,\n\tLocaleVoiceFallback,\n\tPlayerStatus,\n\tSession,\n\tSessionActivity,\n\tSessionCapabilities,\n\tSessionLaunchResponse,\n\tSessionMode\n} from './types/sessionLaunch';\nexport { warnLocaleVoiceFallbacks } from './types/sessionLaunch';\nexport type { ExperienceEventName, ExperienceEvents, ExperienceEventEnvelope, FeedbackResult, FeedbackFailedEvent } from './experienceEvents';\nexport type {\n\tCharacterSpeechEvent,\n\tCharacterSpeechSource,\n\tCharacterSpeechTerminalReason,\n\tConversationMessage,\n\tSpeakOptions,\n\tTextSpeakResult,\n\tSpeechResult as LegacySpeakResult,\n\tUserTranscriptUpdate,\n\tUtteranceResult,\n\tExperienceFit,\n\tExperienceMode,\n\tResponseMode,\n\tSpeechInputMode,\n\tStartButtonAppearance,\n\tStartButtonOptions,\n\tStartButtonPlacement,\n\tStartButtonShadow,\n\tStartButtonSize,\n\tStartButtonVariant,\n\tStartButtonIconPosition,\n\tPlayerTheme,\n\tPlayerThemeButton,\n\tPlayerThemeColors,\n\tPlayerThemeTypography,\n\tStartedEvent,\n} from './types/sessionInteraction';\nexport type {\n\tSpeechAudioFormat,\n\tSpeechController,\n\tSpeechCreateUtteranceOptions,\n\tSpeechInterruptOptions,\n\tSpeechPlayAudio,\n\tSpeechPlayEncodedAudio,\n\tSpeechPlayOptions,\n\tSpeechPlayPcmAudio,\n\tSpeechPlayUrlAudio,\n\tSpeechResult,\n\tSpeechSpeakOptions,\n\tSpeechUtterance\n} from './speech';\nexport {\n\tSPEECH_LIMITS,\n\tSpeechBufferTimeoutError,\n\tSpeechRuntimeError,\n\tSpeechUtteranceClosedError,\n\tUnsupportedSpeechOperationError\n} from './speech';\n\nimport { Experience } from './experience';\n\ndeclare global {\n\tinterface Window {\n\t\tLiforma?: {\n\t\t\tExperience: typeof Experience;\n\t\t\tsdkVersion: 'v2';\n\t\t\treadonly features: {\n\t\t\t\treadonly speakApi: boolean;\n\t\t\t\treadonly speechAudioApi: boolean;\n\t\t\t};\n\t\t};\n\t}\n}\n\nwindow.Liforma = {\n\tExperience,\n\tsdkVersion: 'v2',\n\tfeatures: {\n\t\tspeakApi: true,\n\t\tspeechAudioApi: true\n\t}\n};\n"],"mappings":"sFAIA,SAAgB,GAAiC,CAChD,GAAK,WAA4C,kBAAoB,QACpE,MAAO,GAGR,GAAI,OAAO,SAAa,IACvB,MAAO,GAGR,GAAI,CACH,OAAO,IAAI,gBAAgB,SAAS,MAAM,EAAE,IAAI,OAAO,IAAM,OAC9D,MAAQ,CACP,MAAO,EACR,CACD,CChBA,IAAM,EAA0B,yBAC1B,EAAqB,wBAE3B,SAAS,GAA0C,CAClD,IAAM,EAAe,WAAmD,uBACxE,GAAI,GAAa,KAAK,EACrB,OAAO,EAAY,KAAK,EAAE,QAAQ,MAAO,EAAE,EAG5C,GAAI,OAAO,SAAa,IACvB,OAAO,KAMR,IAAM,GAFL,SAAS,cAAc,4CAA4C,GACnE,SAAS,cAAc,kCAAkC,IAC/B,aAAa,mBAAmB,GAAG,KAAK,EAKnE,OAJI,EACI,EAAW,QAAQ,MAAO,EAAE,EAG7B,IACR,CAcA,SAAgB,GAAkC,CAUjD,OATmB,EACf,IAIA,EAAsB,EAClB,EAGD,EACR,CC7CA,IAAa,EAAb,cAAkC,KAAM,CACvC,KACA,UACA,OACA,QAEA,YACC,EACA,EAOC,CACD,MAAM,EAAS,GAAS,QAAU,IAAA,GAAuC,IAAA,GAA3B,CAAE,MAAO,EAAQ,KAAM,CAAa,EAClF,KAAK,KAAO,eACZ,KAAK,KAAO,GAAS,MAAM,KAAK,GAAK,UACrC,KAAK,UAAY,GAAS,WAAW,KAAK,GAAK,IAAA,GAC/C,KAAK,OAAS,GAAS,OACvB,KAAK,QAAU,GAAS,OACzB,CACD,EAcA,SAAS,EAAS,EAAqD,CAClE,MAAC,GAAS,OAAO,GAAU,UAAY,MAAM,QAAQ,CAAK,GAC9D,OAAO,CACR,CAMA,SAAgB,EACf,EACA,EACA,EACe,CACf,IAAM,EAAkB,GAAS,IAAI,oBAAoB,GAAG,KAAK,GAAK,IAAA,GAClE,EACJ,GAAI,CACH,EAAS,KAAK,MAAM,CAAI,CACzB,MAAQ,CAER,CAEA,IAAM,EAAS,GAAQ,OAAS,OAAO,EAAO,OAAU,SAAW,EAAO,MAAQ,IAAA,GAC5E,EAAU,GAAQ,MAAQ,GAAQ,KAClC,EAAa,GAAQ,SAAW,GAAQ,QACxC,EAAe,GAAQ,WAAa,GAAQ,WAAa,EAEzD,EAAO,OAAO,GAAY,UAAY,EAAQ,KAAK,EAAI,EAAQ,KAAK,EAAI,aACxE,EACL,OAAO,GAAe,UAAY,EAAW,KAAK,EAC/C,EAAW,KAAK,EAChB,EAAK,KAAK,EAAE,MAAM,EAAG,GAAG,GAAK,mBAAmB,EAAO,GACrD,EACL,OAAO,GAAiB,UAAY,EAAa,KAAK,EAAI,EAAa,KAAK,EAAI,EAG3E,CAAE,KAAM,EAAI,QAAS,EAAI,UAAW,EAAI,GAAG,GADjC,EAAS,CAAM,GAAK,EAAS,CAAM,GACkB,CAAC,EAKtE,OAAO,IAAI,EAAa,EAAS,CAChC,OACA,YACA,SACA,QAAS,OAAO,KAAK,CAAI,EAAE,OAAS,EAAI,EAAO,IAAA,EAChD,CAAC,CACF,CC/EA,IAAM,EAAW,IACX,EAAU,yBAEhB,SAAS,EAAM,EAAsD,CACpE,GAAI,CAAC,EAAO,OACZ,IAAM,EAAU,EAAM,QAAQ,EAAS,EAAE,EAAE,KAAK,EAC3C,KACL,OAAO,EAAQ,MAAM,EAAG,CAAQ,CACjC,CAEA,SAAS,EAAc,EAA0D,CAChF,IAAM,EAAS,IAAI,iBAAiB,GAAU,IAAI,WAAW,GAAG,GAAK,GAAU,IAAI,MAAM,CAAC,EAAK,GAAU,EAAG,EAC5G,MAAO,CACN,GAAI,EAAM,EAAO,IAAI,YAAY,CAAC,EAAI,CAAE,UAAW,EAAM,EAAO,IAAI,YAAY,CAAC,CAAE,EAAI,CAAC,EACxF,GAAI,EAAM,EAAO,IAAI,YAAY,CAAC,EAAI,CAAE,UAAW,EAAM,EAAO,IAAI,YAAY,CAAC,CAAE,EAAI,CAAC,EACxF,GAAI,EAAM,EAAO,IAAI,cAAc,CAAC,EAAI,CAAE,YAAa,EAAM,EAAO,IAAI,cAAc,CAAC,CAAE,EAAI,CAAC,EAC9F,GAAI,EAAM,EAAO,IAAI,aAAa,CAAC,EAAI,CAAE,WAAY,EAAM,EAAO,IAAI,aAAa,CAAC,CAAE,EAAI,CAAC,EAC3F,GAAI,EAAM,EAAO,IAAI,UAAU,CAAC,EAAI,CAAE,QAAS,EAAM,EAAO,IAAI,UAAU,CAAC,CAAE,EAAI,CAAC,CACnF,CACD,CAEA,SAAgB,EACf,EACoC,CACpC,GAAI,IAAgB,GAAO,OAC3B,GAAI,GAAe,OAAO,GAAgB,SAAU,CACnD,IAAM,EAAkC,CACvC,GAAI,EAAM,EAAY,SAAS,EAAI,CAAE,UAAW,EAAM,EAAY,SAAS,CAAE,EAAI,CAAC,EAClF,GAAI,EAAM,EAAY,SAAS,EAAI,CAAE,UAAW,EAAM,EAAY,SAAS,CAAE,EAAI,CAAC,EAClF,GAAI,EAAM,EAAY,WAAW,EAAI,CAAE,YAAa,EAAM,EAAY,WAAW,CAAE,EAAI,CAAC,EACxF,GAAI,EAAM,EAAY,UAAU,EAAI,CAAE,WAAY,EAAM,EAAY,UAAU,CAAE,EAAI,CAAC,EACrF,GAAI,EAAM,EAAY,OAAO,EAAI,CAAE,QAAS,EAAM,EAAY,OAAO,CAAE,EAAI,CAAC,EAC5E,GAAI,EAAM,EAAY,QAAQ,EAAI,CAAE,SAAU,EAAM,EAAY,QAAQ,CAAE,EAAI,CAAC,CAChF,EACA,OAAO,OAAO,KAAK,CAAQ,EAAE,OAAS,EAAW,IAAA,EAClD,CACA,GAAI,OAAO,OAAW,IAAa,OACnC,IAAM,EAAW,EAAc,OAAO,UAAU,MAAM,EAChD,EAAW,EAAM,SAAS,UAAY,IAAA,EAAS,EAC/C,EAA8B,CACnC,GAAG,EACH,GAAI,EAAW,CAAE,UAAS,EAAI,CAAC,CAChC,EACA,OAAO,OAAO,KAAK,CAAI,EAAE,OAAS,EAAO,IAAA,EAC1C,CCjCA,SAAS,EAAc,EAA4D,CAClF,IAAM,EAAS,EAAQ,QAAQ,KAAK,EACpC,GAAI,EAAQ,OAAO,EACnB,IAAM,EAAW,EAAQ,UAAU,KAAK,EACxC,GAAI,EAAU,OAAO,EACrB,GAAI,OAAO,UAAc,KAAe,UAAU,UAAU,KAAK,EAChE,OAAO,UAAU,SAAS,KAAK,CAGjC,CAEA,SAAS,EAAuB,EAA4D,CAC3F,IAAM,EAAY,EAAQ,iBAAiB,KAAK,EAC1C,EAAW,EAAQ,gBAAgB,KAAK,EAC9C,GAAI,GAAa,GAAY,IAAc,EAC1C,MAAU,MACT,gFACD,EAED,OAAO,GAAa,GAAY,IAAA,EACjC,CAEA,SAAgB,EACf,EACA,EACuD,CACvD,IAAM,EAAW,EAAgB,KAAK,EACtC,GAAI,CAAC,EACJ,MAAU,MAAM,oCAAoC,EAErD,GAAI,OAAO,SAAa,IACvB,MAAU,MAAM,iDAAiD,EAGlE,IAAM,EAAM,IAAI,IAAI,EAAU,SAAS,IAAI,EAC3C,GAAI,EAAI,SAAW,SAAS,OAC3B,MAAU,MAAM,sCAAsC,EAGvD,IAAM,EAAe,EAAQ,aAAa,KAAK,EAC/C,GAAI,CAAC,EACJ,MAAU,MAAM,wCAAwC,EAGzD,IAAM,EAAS,EAAc,CAAO,EAC9B,EAAkB,EAAuB,CAAO,EAChD,EAAiB,EAAQ,gBAAgB,KAAK,EAEpD,MAAO,CACN,IAAK,EAAI,SAAS,EAClB,KAAM,CACL,OAAQ,OACR,YAAa,cACb,QAAS,CACR,OAAQ,mBACR,eAAgB,mBAChB,GAAI,EAAiB,CAAE,kBAAmB,CAAe,EAAI,CAAC,CAC/D,EACA,KAAM,KAAK,UAAU,CACpB,eACA,GAAI,EAAS,CAAE,QAAO,EAAI,CAAC,EAC3B,GAAI,EAAkB,CAAE,iBAAgB,EAAI,CAAC,EAC7C,GAAI,EAAQ,KAAO,CAAE,KAAM,EAAQ,IAAK,EAAI,CAAC,EAC7C,GAAI,EAAQ,gBAAkB,CAAE,gBAAiB,EAAQ,eAAgB,EAAI,CAAC,EAC9E,GAAI,EAAQ,aAAe,IAAA,GAAiD,CAAC,EAAtC,CAAE,WAAY,EAAQ,UAAW,EACxE,QAAU,CACT,IAAM,EAAc,EAAuB,EAAQ,WAAW,EAC9D,OAAO,EAAc,CAAE,aAAY,EAAI,CAAC,CACzC,GAAG,CACJ,CAAC,CACF,CACD,CACD,CC/BA,SAAS,EAAS,EAAkD,CACnE,MAAO,EAAQ,GAAU,OAAO,GAAU,UAAY,CAAC,MAAM,QAAQ,CAAK,CAC3E,CAEA,SAAS,EAAU,EAAkC,CACpD,OAAO,OAAO,GAAU,SACzB,CAEA,SAAS,EAAwB,EAA0C,CAC1E,GAAI,CAAC,EAAS,CAAG,EAAG,OAAO,KAC3B,IAAM,EAAS,EAAI,OACb,EAAe,EAAI,aACnB,EAAS,EAAI,OACb,EAAQ,EAAI,MAelB,MAbC,CAAC,EAAS,CAAM,GAChB,CAAC,EAAS,CAAY,GACtB,CAAC,EAAS,CAAM,GAChB,CAAC,EAAS,CAAK,GACf,CAAC,EAAU,EAAO,KAAK,GACvB,CAAC,EAAU,EAAO,MAAM,GACxB,CAAC,EAAU,EAAO,aAAa,GAC/B,CAAC,EAAU,EAAa,OAAO,GAC/B,CAAC,EAAU,EAAO,OAAO,GACzB,CAAC,EAAU,EAAM,OAAO,EAEjB,KAED,CACN,OAAQ,CACP,MAAO,EAAO,MACd,OAAQ,EAAO,OACf,cAAe,EAAO,aACvB,EACA,aAAc,CAAE,QAAS,EAAa,OAAQ,EAC9C,OAAQ,CAAE,QAAS,EAAO,OAAQ,EAClC,MAAO,CAAE,QAAS,EAAM,OAAQ,CACjC,CACD,CAGA,SAAS,EAA4B,EAA0C,CAW9E,MAVI,CAAC,EAAS,CAAG,GAEhB,CAAC,EAAU,EAAI,MAAM,GACrB,CAAC,EAAU,EAAI,WAAW,GAC1B,CAAC,EAAU,EAAI,YAAY,GAC3B,CAAC,EAAU,EAAI,KAAK,GACpB,CAAC,EAAU,EAAI,aAAa,EAErB,KAED,CACN,OAAQ,CACP,MAAO,EAAI,YACX,OAAQ,EAAI,aACZ,cAAe,EAAI,aACpB,EACA,aAAc,CAAE,QAAS,EAAK,EAC9B,OAAQ,CAAE,QAAS,EAAI,MAAO,EAC9B,MAAO,CAAE,QAAS,EAAI,KAAM,CAC7B,CACD,CAEA,SAAS,EAAkB,EAA0C,CACpE,OAAO,EAAwB,CAAG,GAAK,EAA4B,CAAG,CACvE,CAEA,SAAgB,EAAa,EAAuB,CACnD,GAAI,CAAC,EAAS,CAAG,EAChB,MAAU,MAAM,6CAA6C,EAE9D,IAAM,EAAK,OAAO,EAAI,IAAO,SAAW,EAAI,GAAG,KAAK,EAAI,GAClD,EAAe,OAAO,EAAI,cAAiB,SAAW,EAAI,aAAa,KAAK,EAAI,GAChF,EACL,OAAO,EAAI,sBAAyB,SAAW,EAAI,qBAAqB,KAAK,EAAI,GAC5E,EAAY,OAAO,EAAI,WAAc,SAAW,EAAI,UAAU,KAAK,EAAI,GACvE,EAAS,OAAO,EAAI,QAAW,SAAW,EAAI,OAAO,KAAK,EAAI,GAC9D,EACL,OAAO,EAAI,iBAAoB,UAAY,EAAI,gBAAgB,KAAK,EACjE,EAAI,gBAAgB,KAAK,EACzB,IAAA,GACE,EAAO,EAAI,OAAS,gBAAkB,EAAI,OAAS,YAAc,EAAI,KAAO,KAC5E,EAAe,EAAkB,EAAI,YAAY,EACjD,EAAuB,EAA0B,EAAI,oBAAoB,EACzE,EACL,EAAI,SAAW,UAAY,EAAI,SAAW,QAAU,EAAI,OAAS,IAAA,GAC5D,EACL,OAAO,EAAI,WAAc,UAAY,EAAI,UAAU,KAAK,EAAI,EAAI,UAAU,KAAK,EAAI,IAAA,GAEpF,GAAI,CAAC,GAAM,CAAC,GAAgB,CAAC,GAAwB,CAAC,GAAa,CAAC,GAAU,CAAC,GAAQ,CAAC,EACvF,MAAU,MAAM,wDAAwD,EAGzE,MAAO,CACN,KACA,eACA,uBACA,YACA,SACA,GAAI,EAAkB,CAAE,iBAAgB,EAAI,CAAC,EAC7C,OACA,eACA,GAAI,EAAuB,CAAE,sBAAqB,EAAI,CAAC,EACvD,GAAI,EAAS,CAAE,QAAO,EAAI,CAAC,EAC3B,GAAI,EAAY,CAAE,WAAU,EAAI,CAAC,CAClC,CACD,CAEA,SAAS,EAA0B,EAA0D,CAC5F,GAAI,CAAC,MAAM,QAAQ,CAAG,GAAK,EAAI,SAAW,EAAG,OAC7C,IAAM,EAA6B,CAAC,EACpC,IAAK,IAAM,KAAQ,EAAK,CACvB,GAAI,CAAC,EAAS,CAAI,EAAG,SACrB,IAAM,EAAO,EAAK,OAAS,UAAY,EAAK,OAAS,kBAAoB,EAAK,KAAO,KAC/E,EAAY,OAAO,EAAK,WAAc,SAAW,EAAK,UAAU,KAAK,EAAI,GACzE,EAAW,OAAO,EAAK,UAAa,SAAW,EAAK,SAAS,KAAK,EAAI,GACxE,CAAC,GAAQ,CAAC,GAAa,CAAC,GAAY,EAAK,SAAW,qBACxD,EAAI,KAAK,CAAE,OAAM,YAAW,WAAU,OAAQ,mBAAoB,CAAC,CACpE,CACA,OAAO,EAAI,OAAS,EAAI,EAAM,IAAA,EAC/B,CAGA,SAAgB,EAAyB,EAAwB,CAChE,IAAM,EAAY,EAAQ,qBACrB,MAAW,OAChB,IAAK,IAAM,KAAM,EAAW,CAC3B,IAAM,EAAQ,EAAG,OAAS,kBAAoB,kBAAoB,SAClE,QAAQ,KACP,qBAAqB,EAAM,gBAAgB,EAAG,SAAS,sCAAsC,EAAG,UAAU,EAC3G,CACD,CACD,CAEA,SAAgB,EAA2B,EAAqC,CAC/E,GAAI,CAAC,EAAS,CAAG,EAChB,MAAU,MAAM,gDAAgD,EAEjE,IAAM,EAAS,OAAO,EAAI,QAAW,SAAW,EAAI,OAAO,KAAK,EAAI,GACpE,GAAI,CAAC,EACJ,MAAU,MAAM,4CAA4C,EAE7D,IAAM,EAAU,EAAa,EAAI,OAAO,EAExC,OADA,EAAyB,CAAO,EACzB,CACN,UACA,QACD,CACD,CCxLA,SAAS,IAAwC,CAChD,GAAI,CACH,GAAI,OAAO,WAAW,UAAU,QAAW,UAAY,WAAW,SAAS,OAC1E,OAAO,WAAW,SAAS,MAE7B,MAAQ,CAER,CAED,CAEA,SAAS,GAAuB,EAAkC,CAEjE,OADK,EACE,EAAK,KAAK,EAAE,YAAY,EAAE,QAAQ,KAAM,GAAG,EADhC,EAEnB,CAEA,SAAS,EAAsB,EAAsB,EAAiC,CACrF,IAAM,EAAa,GAAkB,EAC/B,EAAO,GAAuB,EAAI,IAAI,EACtC,EAAa,EAAI,QAAQ,KAAK,EAC9B,EAAU,EAAI,SAAW,CAAC,EAEhC,GACC,IAAS,sBACR,uBAAuB,KAAK,CAAU,GAAK,EAC3C,CACD,GAAI,EAAW,SAAS,CAAY,GAAK,EAAW,SAAS,gBAAgB,EAC5E,OAAO,EAER,IAAM,EACJ,OAAO,EAAQ,QAAW,UAAY,EAAQ,QAC/C,GACA,mBACD,OAAO,IAAI,EACV,eAAe,EAAO,2CAA2C,EAAa,mIAEjC,EAAO,2FAEpD,CAAE,KAAM,qBAAsB,UAAW,EAAI,UAAW,OAAQ,EAAI,OAAQ,SAAQ,CACrF,CACD,CAyCA,OAvCI,IAAS,2BAA6B,mCAAmC,KAAK,CAAU,EACvF,EAAW,SAAS,iCAAiC,EACjD,EAED,IAAI,EACV,iDAAiD,EAAa,4KAG9D,CACC,KAAM,0BACN,UAAW,EAAI,UACf,OAAQ,EAAI,OACZ,SACD,CACD,EAIA,IAAS,0BACT,oCAAoC,KAAK,CAAU,GACnD,2BAA2B,KAAK,CAAU,EAEtC,EAAW,SAAS,8BAA8B,EAC9C,EAED,IAAI,EACV,qCAAqC,EAAa,kQAIlD,CACC,KAAM,yBACN,UAAW,EAAI,UACf,OAAQ,EAAI,OACZ,SACD,CACD,EAGM,CACR,CAEA,SAAS,GAAc,EAAyD,CAC/E,IAAM,EAAS,GAAS,QAAQ,KAAK,EACrC,GAAI,EAAQ,OAAO,EACnB,IAAM,EAAW,GAAS,UAAU,KAAK,EACzC,GAAI,EAAU,OAAO,EACrB,GAAI,OAAO,UAAc,KAAe,UAAU,UAAU,KAAK,EAChE,OAAO,UAAU,SAAS,KAAK,CAGjC,CAEA,SAAS,GAAuB,EAAyD,CACxF,IAAM,EAAY,GAAS,iBAAiB,KAAK,EAC3C,EAAW,GAAS,gBAAgB,KAAK,EAC/C,GAAI,GAAa,GAAY,IAAc,EAC1C,MAAM,IAAI,EACT,iFACA,CAAE,KAAM,cAAe,CACxB,EAED,OAAO,GAAa,GAAY,IAAA,EACjC,CAEA,SAAS,GACR,EACA,EAC0B,CAC1B,IAAM,EAAgC,CAAE,cAAa,EAC/C,EAAS,GAAc,CAAO,EAChC,IAAQ,EAAK,OAAS,GAC1B,IAAM,EAAkB,GAAuB,CAAO,EAClD,IAAiB,EAAK,gBAAkB,GACxC,GAAS,OAAM,EAAK,KAAO,EAAQ,MACnC,GAAS,kBAAiB,EAAK,gBAAkB,EAAQ,iBACzD,GAAS,aAAe,IAAA,KAAW,EAAK,WAAa,EAAQ,YACjE,IAAM,EAAc,EAAuB,GAAS,WAAW,EAE/D,OADI,IAAa,EAAK,YAAc,GAC7B,CACR,CAGA,eAAsB,GACrB,EACA,EACiC,CACjC,IAAM,EAAa,EAAwB,EACrC,EAAiB,GAAS,gBAAgB,KAAK,EAC/C,EAAM,MAAM,MAAM,GAAG,EAAW,sBAAuB,CAC5D,OAAQ,OACR,QAAS,CACR,eAAgB,mBAChB,GAAI,EAAiB,CAAE,kBAAmB,CAAe,EAAI,CAAC,CAC/D,EACA,KAAM,KAAK,UAAU,GAAc,EAAc,CAAO,CAAC,CAC1D,CAAC,EAED,GAAI,CAAC,EAAI,GAAI,CACZ,IAAM,EAAO,MAAM,EAAI,KAAK,EAC5B,MAAM,EAAsB,EAAc,EAAyB,EAAI,OAAQ,EAAM,EAAI,OAAO,CAAC,CAClG,CACA,IAAI,EACJ,GAAI,CACH,EAAM,MAAM,EAAI,KAAK,CACtB,MAAQ,CACP,MAAM,IAAI,EAAa,8CAA+C,CACrE,KAAM,mBACN,OAAQ,EAAI,OACZ,UAAW,EAAI,QAAQ,IAAI,oBAAoB,GAAK,IAAA,EACrD,CAAC,CACF,CAEA,OAAO,EAA2B,CAAG,CACtC,CAcA,eAAsB,GACrB,EACA,EACiC,CACjC,IAAM,EAAU,EAA6B,EAAiB,CAAO,EAE/D,EAAa,IAAI,gBACjB,MAAwB,EAAW,MAAM,EAAQ,QAAQ,MAAM,EACjE,EAAQ,QAAQ,QACnB,EAAgB,EAEhB,EAAQ,QAAQ,iBAAiB,QAAS,EAAiB,CAAE,KAAM,EAAK,CAAC,EAE1E,IAAM,EAAY,WAAW,eACtB,EAAW,MAAM,IAAI,aAAa,8BAA+B,cAAc,CAAC,EACtF,EAAQ,WAAa,GACtB,EAEI,EACJ,GAAI,CACH,EAAM,MAAM,MAAM,EAAQ,IAAK,CAC9B,GAAG,EAAQ,KACX,OAAQ,EAAW,MACpB,CAAC,CACF,QAAU,CACT,WAAW,aAAa,CAAS,EACjC,EAAQ,QAAQ,oBAAoB,QAAS,CAAe,CAC7D,CAEA,GAAI,CAAC,EAAI,GAAI,CACZ,IAAM,EAAO,MAAM,EAAI,KAAK,EAC5B,MAAM,EAAyB,EAAI,OAAQ,EAAM,EAAI,OAAO,CAC7D,CACA,GAAI,CAAC,EAAI,QAAQ,IAAI,cAAc,GAAG,YAAY,EAAE,SAAS,kBAAkB,EAC9E,MAAM,IAAI,EAAa,+DAAgE,CACtF,KAAM,mBACN,OAAQ,EAAI,OACZ,UAAW,EAAI,QAAQ,IAAI,oBAAoB,GAAK,IAAA,EACrD,CAAC,EAGF,IAAI,EACJ,GAAI,CACH,EAAM,MAAM,EAAI,KAAK,CACtB,MAAQ,CACP,MAAM,IAAI,EAAa,0CAA2C,CACjE,KAAM,mBACN,OAAQ,EAAI,OACZ,UAAW,EAAI,QAAQ,IAAI,oBAAoB,GAAK,IAAA,EACrD,CAAC,CACF,CAEA,OAAO,EAA2B,CAAG,CACtC,CChPA,SAAgB,GAAsB,EAAgD,CAErF,OADqB,OAAO,GAAU,WAAlC,EAAmD,GAChD,OAAQ,EAAgC,OAAO,gBAAmB,UAC1E,CAEA,SAAgB,GACf,EAC4B,CAC5B,GAAI,OAAO,GAAW,SAAU,CAC/B,IAAM,EAAO,EAAO,KAAK,EACzB,GAAI,CAAC,EACJ,MAAU,MAAM,4CAA4C,EAE7D,MAAO,CAAE,MAAK,CACf,CAEA,IAAM,EAAO,EAAO,KAAK,KAAK,EAC9B,GAAI,CAAC,EACJ,MAAU,MAAM,4CAA4C,EAG7D,MAAO,CACN,OACA,GAAI,EAAO,YAAc,CAAE,YAAa,EAAO,WAAY,EAAI,CAAC,EAChE,GAAI,EAAO,SAAW,CAAE,SAAU,EAAO,QAAS,EAAI,CAAC,CACxD,CACD,CAaA,eAAsB,GACrB,EACA,EACmC,CACnC,IAAM,EAAS,MAAM,EAAU,CAAO,EAItC,OAHI,GAAsB,CAAM,EACxB,CAAE,KAAM,SAAU,OAAQ,CAAO,EAElC,CACN,KAAM,WACN,OAAQ,GAAqC,CAAM,CACpD,CACD,CC5DA,IAAM,GAAwB,OAE9B,SAAgB,EAA+B,EAA8B,CAC5E,IAAM,EAAM,IAAI,IAAI,CAAY,EAWhC,OAVoB,EAAI,WAAa,aAAe,EAAI,WAAa,YAKnE,2CAA2C,EAAa,kCAFzC,EAAI,MAAQ,GAEuE,mEAMnG,2CAA2C,EAAa,sFAG1D,CAEA,eAAsB,GACrB,EACA,EACgB,CAChB,GAAI,CACH,MAAM,MAAM,EAAU,CACrB,OAAQ,MACR,KAAM,UACN,OAAQ,YAAY,QAAQ,GAAK,CAClC,CAAC,CACF,MAAQ,CACP,MAAU,MAAM,EAA+B,CAAY,CAAC,CAC7D,CACD,CAEA,SAAgB,EACf,EACA,EACA,EACA,EACO,CACP,GAAI,CACC,GAAY,EAAS,OAAS,EACjC,EAAO,YAAY,EAAS,EAAc,CAAQ,EAElD,EAAO,YAAY,EAAS,CAAY,CAE1C,OAAS,EAAO,CAIf,MAHI,aAAiB,cAAgB,EAAM,OAAS,gBACzC,MAAM,EAA+B,CAAY,EAAG,CAAE,MAAO,CAAM,CAAC,EAEzE,CACP,CACD,CC/BA,IAAa,GAA+D,IAAI,IAAI,CAAC,EAAG,CAAC,CAAC,EAE1F,SAAgB,GAAqC,EAA2B,CAC/E,OAAO,OAAO,GAAY,UAAY,GAAwC,IAAI,CAAO,CAC1F,CAkYA,IAAM,GAAiB,IAAI,IAAI,iYA2B/B,CAAC,EAWD,SAAgB,GAAqB,EAA4C,CAChF,GAAI,CAAC,GAAQ,OAAO,GAAS,SAAU,OAAO,KAC9C,IAAM,EAAM,EAEZ,GADI,CAAC,GAAqC,EAAI,aAAa,GACvD,CAAC,EAAI,MAAQ,CAAC,GAAe,IAAI,EAAI,IAAI,EAAG,OAAO,KACvD,GACC,EAAI,OAAS,cACb,EAAI,OAAS,eACb,EAAI,OAAS,gBACb,EAAI,OAAS,iBAEb,OAAO,EAER,GAAI,EAAI,OAAS,aAAc,CAC9B,IAAM,EAAW,EAA8B,QAG/C,MAFI,CAAC,GAAW,OAAO,GAAY,UAC/B,OAAQ,EAAiC,QAAW,UAAkB,KACnE,CACR,CACA,GAAI,EAAI,OAAS,sBAAuB,CACvC,IAAM,EAAW,EAA8B,QAG/C,MAFI,CAAC,GAAW,OAAO,GAAY,UAC/B,OAAQ,EAA+B,MAAS,UAAkB,KAC/D,CACR,CACA,GAAI,EAAI,OAAS,mBAAqB,EAAI,OAAS,gBAAiB,CACnE,IAAM,EAAW,EAA8B,QAI/C,MAHI,CAAC,GAAW,OAAO,GAAY,UAC/B,OAAQ,EAAoC,WAAc,UAC1D,CAAC,OAAO,SAAU,EAAkC,SAAS,EAAU,KACpE,CACR,CACA,GAAI,EAAI,OAAS,iBAAkB,CAClC,IAAM,EAAW,EAA8B,QAC/C,GAAI,CAAC,GAAW,OAAO,GAAY,SAAU,OAAO,KACpD,GAAM,CAAE,YAAW,KAAI,MAAO,EAQ9B,OAHI,OAAO,GAAc,UAAY,CAAC,OAAO,SAAS,CAAS,GAC3D,OAAO,GAAO,UAAY,CAAC,OAAO,SAAS,CAAE,GAC7C,OAAO,GAAO,UAAY,CAAC,OAAO,SAAS,CAAE,EAAU,KACpD,CACR,CACA,IAAM,EAAW,EAA8B,QAE/C,MADI,CAAC,GAAW,OAAO,GAAY,SAAiB,KAC7C,CACR,CAyEA,SAAgB,GACf,EACA,EACA,EAKsB,CACtB,IAAM,EAAU,EAAO,KAAK,EAC5B,GAAI,CAAC,EACJ,MAAU,MAAM,yDAAyD,EAE1E,IAAM,EAAc,GAAQ,YACtB,EAAQ,GAAQ,MAChB,EAAe,GAAQ,aAC7B,MAAO,CACN,KAAM,SACN,cAAA,EACA,QAAS,CACR,OAAQ,EACR,GAAI,IAAY,IAAA,GAA0B,CAAC,EAAf,CAAE,SAAQ,EACtC,GAAI,EAAc,CAAE,aAAY,EAAI,CAAC,EACrC,GAAI,EAAQ,CAAE,OAAM,EAAI,CAAC,EACzB,GAAI,IAAiB,IAAA,GAA+B,CAAC,EAApB,CAAE,cAAa,CACjD,CACD,CACD,CAWA,SAAgB,IAAgD,CAC/D,MAAO,CACN,KAAM,cACN,cAAA,CACD,CACD,CASA,SAAgB,GAA6B,EAA6C,CACzF,MAAO,CACN,KAAM,kBACN,cAAA,EACA,QAAS,CAAE,MAAK,CACjB,CACD,CAEA,SAAgB,IAA8D,CAC7E,MAAO,CACN,KAAM,4BACN,cAAA,EACA,QAAS,CAAC,CACX,CACD,CC5mBA,IAAM,GAAsB,aAE5B,SAAgB,GAAyB,EAA0C,CAClF,GAAM,CAAE,SAAU,EAClB,MAAO,CACN,SAAU,EAAM,SAChB,IAAK,EAAM,IACX,MAAO,EAAM,MACb,OAAQ,EAAM,OACd,KAAM,EAAM,KACZ,MAAO,EAAM,MACb,MAAO,EAAM,MACb,OAAQ,EAAM,OACd,OAAQ,EAAM,OACd,OAAQ,EAAM,OACd,aAAc,EAAM,aACpB,SAAU,EAAM,SAChB,UAAW,EAAM,SAClB,CACD,CAEA,SAAgB,EAAsB,EAAuB,CAC5D,GAAM,CAAE,SAAU,EAClB,EAAM,SAAW,QACjB,EAAM,IAAM,IACZ,EAAM,MAAQ,IACd,EAAM,OAAS,IACf,EAAM,KAAO,IACb,EAAM,MAAQ,IACd,EAAM,MAAQ,QACd,EAAM,MAAQ,SACd,EAAM,OAAS,QACf,EAAM,OAAS,SACf,EAAM,OAAS,GACf,EAAM,OAAS,IACf,EAAM,aAAe,IACrB,EAAM,SAAW,OACjB,EAAM,UAAY,OAClB,EAAG,QAAQ,kBAAoB,GAChC,CAEA,SAAgB,EACf,EACA,EACO,CAEP,GADA,OAAO,EAAG,QAAQ,kBACd,CAAC,EAAU,CACd,EAAG,MAAM,SAAW,GACpB,EAAG,MAAM,IAAM,GACf,EAAG,MAAM,MAAQ,GACjB,EAAG,MAAM,OAAS,GAClB,EAAG,MAAM,KAAO,GAChB,EAAG,MAAM,MAAQ,GACjB,EAAG,MAAM,MAAQ,GACjB,EAAG,MAAM,OAAS,GAClB,EAAG,MAAM,OAAS,GAClB,EAAG,MAAM,OAAS,GAClB,EAAG,MAAM,aAAe,GACxB,EAAG,MAAM,SAAW,GACpB,EAAG,MAAM,UAAY,GACrB,MACD,CACA,GAAM,CAAE,SAAU,EAClB,EAAM,SAAW,EAAS,SAC1B,EAAM,IAAM,EAAS,IACrB,EAAM,MAAQ,EAAS,MACvB,EAAM,OAAS,EAAS,OACxB,EAAM,KAAO,EAAS,KACtB,EAAM,MAAQ,EAAS,MACvB,EAAM,MAAQ,EAAS,MACvB,EAAM,OAAS,EAAS,OACxB,EAAM,OAAS,EAAS,OACxB,EAAM,OAAS,EAAS,OACxB,EAAM,aAAe,EAAS,aAC9B,EAAM,SAAW,EAAS,SAC1B,EAAM,UAAY,EAAS,SAC5B,CCoBA,SAAS,EAAqB,EAA8D,CAC3F,OAAO,CACR,CAyEA,SAAS,GAA2B,CAInC,OAHI,OAAO,OAAW,KAAe,OAAO,OAAO,YAAe,WAC1D,OAAO,OAAO,WAAW,EAAE,QAAQ,KAAM,EAAE,EAAE,MAAM,EAAG,EAAE,IAEzD,OAAO,KAAK,IAAI,EAAE,SAAS,EAAE,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,EAAG,CAAC,GAC9E,CAEA,IAAM,GAAkC,IAExC,SAAgB,GAAiB,EAAwC,CACxE,IAAM,EAAY,EAAQ,UACA,iBAAiB,CAAS,EAAE,WAC5B,WACzB,EAAU,MAAM,SAAW,YAG5B,IAAM,EAAS,SAAS,cAAc,QAAQ,EAC9C,EAAO,IAAM,EAAQ,IACrB,EAAO,MAAQ,qBACf,EAAO,aACN,QACA,uDACD,EAGA,EAAO,MAAM,QAAU,EAAQ,YAC5B,kGACA,8FACC,EAAQ,aACX,EAAO,aAAa,oBAAqB,MAAM,EAGhD,IAAI,EAAY,GACZ,EAAmB,GACnB,EAAqD,KACnD,EACL,EAAU,QAAQ,2BAA2B,YAAa,YACtD,EAAU,QAAQ,2BAA2B,EAC9C,EAEE,EAAuB,GAAoB,CAC5C,IAAqB,IACzB,EAAmB,EACf,GACH,EAAqB,GAAyB,CAAgB,EAC9D,EAAsB,CAAgB,IAEtC,EAAwB,EAAkB,CAAkB,EAC5D,EAAqB,MAEtB,EAAQ,qBAAqB,CAAM,EACpC,EACM,EAAkB,IAAI,IAkBxB,EAAoC,KACpC,EAAiB,EACjB,EAAoB,EAElB,EAA8B,CAAC,EAEjC,EAAwC,KACxC,EAAmD,KACjD,EAAc,IAAI,SAAe,EAAS,IAAW,CAC1D,EAAmB,EACnB,EAAkB,CACnB,CAAC,EAEK,MAA+B,CACpC,IAAK,IAAM,KAAM,EAAmB,OAAO,aAAa,CAAE,EAC1D,EAAkB,OAAS,CAC5B,EAEM,EAAmB,GAA+B,CACvD,GAAI,EAAW,OACf,IAAM,EAAM,KAAK,IAAI,EACrB,GAAI,EAAoB,GAAK,EAAM,EAAoB,IACtD,OAED,EAAoB,EACpB,EAAuB,EACvB,IAAM,EAAU,GAAoB,EAAO,OAAQ,EAAO,QAAS,EAAO,MAAM,EAC1E,MAAiB,CACtB,GAAI,EAAW,OACf,IAAM,EAAS,EAAO,cACjB,GACL,EAAoB,EAAQ,EAAS,EAAQ,YAAY,CAC1D,EACA,EAAS,EACT,IAAK,IAAI,EAAU,EAAG,GAAW,GAAI,GAAW,EAC/C,EAAkB,KAAK,OAAO,WAAW,EAAU,EAAU,EAAE,CAAC,CAElE,EAEM,MAAiC,CAClC,GAAa,CAAC,GAClB,EAAgB,CAAY,CAC7B,EAEM,MAAqB,CAE1B,GADA,GAAkB,EACd,IAAmB,EAAG,CACzB,GAA2B,EAAQ,IAAK,EAAQ,YAAY,EAAE,SACvD,IAAmB,EACxB,GACA,IAAkB,aAAiB,MAAQ,EAAY,MAAM,OAAO,CAAK,CAAC,CAAC,CAC7E,EACA,MACD,CAGA,EAAoB,EACpB,EAAmB,CACpB,EACM,MAAsB,CACvB,EAAiB,GACrB,IAAsB,MAAM,EAA+B,EAAQ,YAAY,CAAC,CAAC,CAClF,EACA,EAAO,iBAAiB,OAAQ,CAAY,EAC5C,EAAO,iBAAiB,QAAS,CAAa,EAE9C,IAAM,EAAa,GAAwB,CAG1C,GAFI,GACA,EAAM,SAAW,EAAO,eACxB,EAAM,SAAW,EAAQ,aAAc,OAE3C,IAAM,EAAU,GAAqB,EAAM,IAAI,EAC1C,KAEL,OAAQ,EAAQ,KAAhB,CACC,IAAK,QACJ,EAAQ,UAAU,EAAQ,OAAO,EACjC,MACD,IAAK,cACJ,EAAQ,uBAAuB,EAAQ,QAAQ,KAAK,EACpD,EAAQ,gBAAgB,EAAQ,QAAQ,KAAK,EAC7C,MACD,IAAK,gBAAiB,CACrB,IAAM,EAAU,EAAgB,IAAI,EAAQ,QAAQ,aAAa,EACjE,GAAI,CAAC,EAAS,OACd,EAAgB,OAAO,EAAQ,QAAQ,aAAa,EAChD,EAAQ,QAAQ,GACnB,EAAQ,QAAQ,EAAQ,QAAQ,MAAM,EAEtC,EAAQ,OAAW,MAAM,EAAQ,QAAQ,OAAS,iBAAiB,CAAC,EAErE,KACD,CACA,IAAK,iBACJ,EAAQ,mBAAmB,EAAQ,OAAO,EAC1C,MACD,IAAK,yBACJ,EAAQ,2BAA2B,EAAQ,OAAO,EAClD,MACD,IAAK,uBACJ,EAAQ,yBAAyB,EAAQ,OAAO,EAChD,MACD,IAAK,wBACJ,EAAQ,0BAA0B,EAAQ,OAAO,EACjD,MACD,IAAK,qBACJ,EAAQ,uBAAuB,EAAQ,QAAQ,YAAY,EAC3D,MACD,IAAK,iBACJ,EAAQ,mBAAmB,EAAQ,QAAQ,SAAS,EACpD,MACD,IAAK,oBACJ,EAAQ,sBAAsB,EAAQ,OAAO,EAC7C,MACD,IAAK,kBACJ,EAAQ,oBAAoB,EAAQ,OAAO,EAC3C,MACD,IAAK,aACJ,EAAQ,mBAAmB,EAAqB,EAAQ,QAAQ,IAAI,CAAC,EACrE,MACD,IAAK,iBACJ,EAAQ,mBAAmB,EAAQ,QAAQ,QAAQ,EACnD,MACD,IAAK,WACJ,EAAQ,aAAa,EAAQ,OAAO,EACpC,MACD,IAAK,iBACJ,EAAQ,mBAAmB,EAAQ,OAAO,EAC1C,MACD,IAAK,UACJ,EAAQ,YAAY,EAAQ,OAAO,EACnC,MACD,IAAK,UACJ,EAAQ,YAAY,EAAQ,OAAO,EACnC,MACD,IAAK,aAEJ,EAAmB,EACnB,MACD,IAAK,cACJ,EAAQ,gBAAgB,EACxB,MACD,IAAK,eACJ,EAAQ,iBAAiB,EACzB,MACD,IAAK,iBACJ,EAAQ,mBAAmB,EAC3B,MACD,IAAK,sBACJ,EAAQ,wBAAwB,EAAQ,QAAQ,IAAI,EACpD,MACD,IAAK,kBACJ,EAAQ,oBAAoB,EAAQ,OAAO,EAC3C,MACD,IAAK,iBACJ,EAAQ,mBAAmB,EAAQ,OAAO,EAC1C,MACD,IAAK,gBACJ,EAAQ,kBAAkB,EAAQ,OAAO,EACzC,MACD,IAAK,aACJ,EAAoB,EAAQ,QAAQ,MAAM,EAC1C,KACF,CACD,EAMA,GAJA,OAAO,iBAAiB,UAAW,CAAS,EAC5C,EAAU,gBAAgB,CAAM,EAG5B,EAAU,aAAe,GAAK,CAAC,EAAU,MAAM,UAAW,CAC7D,IAAM,EAAc,iBAAiB,CAAS,EAAE,WAC5C,IAAgB,OAAS,IAAgB,UAC5C,EAAU,MAAM,UAAY,QAE9B,CAEA,IAAM,GAAgB,EAA8B,IAA8B,CACjF,GAAI,EAAW,OACf,IAAM,EAAS,EAAO,cACtB,GAAI,CAAC,EACJ,MAAU,MAAM,EAA+B,EAAQ,YAAY,CAAC,EAErE,EAAoB,EAAQ,EAAS,EAAQ,aAAc,CAAQ,CACpE,EAEM,GACL,EACA,EAAY,KACZ,IACgB,CAChB,IAAM,EACL,EAAQ,OAAS,eAAiB,EAAQ,SAAW,kBAAmB,EAAQ,QAC5E,EAAQ,QAAQ,cACjB,EAAiB,EAQrB,OANI,EAAQ,OAAS,eAAiB,EAAQ,SAAW,kBAAmB,EAAQ,SAEzE,EAAQ,OAAS,eAAiB,EAAQ,UACpD,EAAS,QAAsC,cAAgB,GAGzD,IAAI,SAAY,EAAS,IAAW,CAC1C,EAAgB,IAAI,EAAe,CAClC,QAAU,GAAU,EAAQ,CAAU,EACtC,QACD,CAAC,EACD,EAAa,EAAS,CAAQ,EAC9B,eAAiB,CACX,EAAgB,IAAI,CAAa,IACtC,EAAgB,OAAO,CAAa,EACpC,EAAW,MAAM,8CAA8C,CAAC,EACjE,EAAG,CAAS,CACb,CAAC,CACF,EAEA,MAAO,CACN,aAAc,CACb,OAAO,CACR,EACA,iBAAkB,CACjB,EAAa,GAAyB,CAAC,CACxC,EACA,WAAW,EAAQ,EAAS,EAAQ,CAC/B,IACJ,EAAe,CAAE,SAAQ,UAAS,QAAO,EACzC,EAAoB,EACpB,EAAgB,CAAY,EAC7B,EACA,aAAa,EAAU,CACtB,GAAI,OAAO,GAAa,SAAU,CACjC,KAAK,WAAW,CAAQ,EACxB,MACD,CACA,GACC,GACA,OAAO,GAAa,UACpB,OAAQ,EAAkC,QAAW,SACpD,CACD,IAAM,EAAS,OAAQ,EAAgC,MAAM,EACvD,EAAW,EAAkC,QACnD,KAAK,WAAW,EAAQ,CAAO,EAC/B,MACD,CACA,MAAU,MACT,qGACD,CACD,EACA,oBAAoB,EAAM,CACzB,EAAa,GAA6B,CAAI,CAAC,CAChD,EACA,+BAAgC,CAC/B,EAAa,GAAuC,CAAC,CACtD,EACA,MAAM,EAAS,CAEd,OAAO,EAA+B,CACrC,KAAM,QACN,cAAA,EACA,QAAS,CACR,cALoB,EAKpB,EACA,KAAM,EAAQ,KACd,GAAI,EAAQ,YAAc,CAAE,YAAa,EAAQ,WAAY,EAAI,CAAC,EAClE,GAAI,EAAQ,SAAW,CAAE,SAAU,EAAQ,QAAS,EAAI,CAAC,CAC1D,CACD,CAAC,CACF,EACA,gBAAiB,CAEhB,OAAO,EAAkB,CACxB,KAAM,iBACN,cAAA,EACA,QAAS,CAAE,cAJU,EAIV,CAAc,CAC1B,CAAC,CACF,EACA,eAAgB,CAEf,OAAO,EAA6B,CACnC,KAAM,gBACN,cAAA,EACA,QAAS,CAAE,cAJU,EAIV,CAAc,CAC1B,CAAC,CACF,EACA,WAAW,EAAS,CAEnB,OAAO,EAA6B,CACnC,KAAM,aACN,cAAA,EACA,QAAS,CACR,cALoB,EAKpB,EACA,GAAI,GAAS,YAAc,IAAA,GAA+C,CAAC,EAApC,CAAE,UAAW,EAAQ,SAAU,CACvE,CACD,CAAC,CACF,EACA,MAAM,qBAAqB,EAAQ,EAAS,CAC3C,IAAM,EAAqB,EAAiB,EACtC,EAAmB,EAAiB,EAUpC,GAAW,MATK,EAAkC,CACvD,KAAM,mBACN,cAAA,EACA,QAAS,CACR,cAAe,EACf,GAAI,GAAS,YAAc,CAAE,YAAa,EAAQ,WAAY,EAAI,CAAC,EACnE,GAAI,GAAS,SAAW,CAAE,SAAU,EAAQ,QAAS,EAAI,CAAC,CAC3D,CACD,CAAC,GACwB,SACzB,GAAI,CACH,UAAW,IAAM,KAAS,EAAQ,CACjC,GAAI,GAAS,QAAQ,QACpB,MAAM,IAAI,aAAa,4BAA6B,YAAY,EAE5D,GACL,EAAa,CACZ,KAAM,mBACN,cAAA,EACA,QAAS,CAAE,WAAU,KAAM,CAAM,CAClC,CAAC,CACF,CACA,GAAI,GAAS,QAAQ,QACpB,MAAM,IAAI,aAAa,4BAA6B,YAAY,EAEjE,OAAO,MAAM,EAA+B,CAC3C,KAAM,iBACN,cAAA,EACA,QAAS,CAAE,cAAe,EAAkB,UAAS,CACtD,CAAC,CACF,OAAS,EAAO,CACf,GAAI,CACH,MAAM,EAA+B,CACpC,KAAM,iBACN,cAAA,EACA,QAAS,CAAE,cAAe,EAAkB,UAAS,CACtD,CAAC,CACF,MAAQ,CAER,CACA,MAAM,CACP,CACD,EACA,WAAW,EAAS,CACnB,IAAM,EAAgB,EAAiB,EACjC,EAA2B,CAAC,EAIlC,OAHI,EAAQ,OAAO,OAAS,OAAS,EAAQ,OAAO,OAAS,YAC5D,EAAS,KAAK,EAAQ,OAAO,IAAI,EAE3B,EACN,CACC,KAAM,aACN,cAAA,EACA,QAAS,CACR,gBACA,OAAQ,EAAQ,OAChB,GAAI,EAAQ,YAAc,CAAE,YAAa,EAAQ,WAAY,EAAI,CAAC,EAClE,GAAI,EAAQ,aAAe,IAAA,GAAiD,CAAC,EAAtC,CAAE,WAAY,EAAQ,UAAW,EACxE,GAAI,EAAQ,QAAU,CAAE,QAAS,EAAQ,OAAQ,EAAI,CAAC,EACtD,GAAI,EAAQ,MAAQ,CAAE,MAAO,EAAQ,KAAM,EAAI,CAAC,CACjD,CACD,EACA,KACA,CACD,CACD,EACA,qBAAqB,EAAS,CAE7B,OAAO,EAAkB,CACxB,KAAM,uBACN,cAAA,EACA,QAAS,CACR,cALoB,EAKpB,EACA,YAAa,EAAQ,YACrB,OAAQ,EAAQ,OAChB,MAAO,EAAQ,MACf,GAAI,EAAQ,YAAc,CAAE,YAAa,EAAQ,WAAY,EAAI,CAAC,EAClE,GAAI,EAAQ,aAAe,IAAA,GAAiD,CAAC,EAAtC,CAAE,WAAY,EAAQ,UAAW,CACzE,CACD,CAAC,CACF,EACA,qBAAqB,EAAS,CAE7B,OAAO,EACN,CACC,KAAM,uBACN,cAAA,EACA,QAAS,CACR,cANmB,EAMnB,EACA,YAAa,EAAQ,YACrB,MAAO,EAAQ,MACf,WAAY,EAAQ,UACrB,CACD,EACA,GACA,CAAC,EAAQ,KAAK,CACf,CACD,EACA,6BAA6B,EAAS,CAErC,OAAO,EAAkB,CACxB,KAAM,+BACN,cAAA,EACA,QAAS,CACR,cALoB,EAKpB,EACA,YAAa,EAAQ,YACrB,WAAY,EAAQ,UACrB,CACD,CAAC,CACF,EACA,qBAAqB,EAAS,CAE7B,OAAO,EAA0B,CAChC,KAAM,uBACN,cAAA,EACA,QAAS,CACR,cALoB,EAKpB,EACA,YAAa,EAAQ,YACrB,GAAI,EAAQ,aAAe,IAAA,GAAiD,CAAC,EAAtC,CAAE,WAAY,EAAQ,UAAW,EACxE,GAAI,EAAQ,QAAU,CAAE,QAAS,EAAQ,OAAQ,EAAI,CAAC,CACvD,CACD,CAAC,CACF,EACA,sBAAsB,EAAS,CAE9B,OAAO,EAA0B,CAChC,KAAM,wBACN,cAAA,EACA,QAAS,CACR,cALoB,EAKpB,EACA,YAAa,EAAQ,WACtB,CACD,CAAC,CACF,EACA,gBAAgB,EAAS,CAExB,OAAO,EAAqC,CAC3C,KAAM,kBACN,cAAA,EACA,QAAS,CACR,cALoB,EAKpB,EACA,GAAG,CACJ,CACD,CAAC,CACF,EACA,iBAAkB,CAEjB,OAAO,EAA4C,CAClD,KAAM,kBACN,cAAA,EACA,QAAS,CAAE,cAJU,EAIV,CAAc,CAC1B,CAAC,CACF,EACA,eAAe,EAAa,CAE3B,OAAO,EAAkB,CACxB,KAAM,iBACN,cAAA,EACA,QAAS,CAAE,cAJU,EAIV,EAAe,aAAY,CACvC,CAAC,CACF,EACA,OAAO,EAAK,CAEX,OAAO,EAAkB,CACxB,KAAM,SACN,cAAA,EACA,QAAS,CAAE,cAJU,EAIV,EAAe,KAAI,CAC/B,CAAC,CACF,EACA,WAAW,EAAK,CAEf,OAAO,EAAkB,CACxB,KAAM,aACN,cAAA,EACA,QAAS,CAAE,cAJU,EAIV,EAAe,KAAI,CAC/B,CAAC,CACF,EACA,QAAS,CAER,OAAO,EAAkB,CACxB,KAAM,SACN,cAAA,EACA,QAAS,CAAE,cAJU,EAIV,CAAc,CAC1B,CAAC,CACF,EACA,SAAU,CACL,MAEJ,CADA,EAAY,GACR,GACH,EAAoB,EAAK,EAE1B,IAAK,IAAM,KAAW,EAAgB,OAAO,EAC5C,EAAQ,OAAW,MAAM,wBAAwB,CAAC,EAEnD,EAAgB,MAAM,EACtB,EAAuB,EACvB,EAAe,KACf,EAAO,oBAAoB,OAAQ,CAAY,EAC/C,EAAO,oBAAoB,QAAS,CAAa,EACjD,OAAO,oBAAoB,UAAW,CAAS,EAC/C,EAAO,OAAO,CAXY,CAY3B,CACD,CACD,CChvBA,SAAgB,GAAmB,EAA2C,CAC7E,IAAI,EACA,EAAQ,GACR,EAAU,GAER,MAA6B,CAC9B,GAAW,CAAC,GAAS,IAAU,IAAA,KACnC,EAAU,GACV,EAAQ,CAAK,EACd,EAEA,MAAO,CACN,SAAS,EAAW,CACnB,EAAQ,EACR,EAAe,CAChB,EACA,WAAY,CACX,EAAQ,GACR,EAAe,CAChB,CACD,CACD,CCzBA,IAAM,GAA8B,kCAC9B,GAAyB,8BAE/B,SAAS,IAAwC,CAChD,IAAM,EAAe,WACnB,2BACF,GAAI,GAAa,KAAK,EACrB,OAAO,EAAY,KAAK,EAAE,QAAQ,MAAO,EAAE,EAG5C,GAAI,OAAO,SAAa,IACvB,OAAO,KAMR,IAAM,GAFL,SAAS,cAAc,4CAA4C,GACnE,SAAS,cAAc,kCAAkC,IAC/B,aAAa,uBAAuB,GAAG,KAAK,EAKvE,OAJI,EACI,EAAW,QAAQ,MAAO,EAAE,EAG7B,IACR,CAcA,SAAgB,GAAsC,CACrD,IAAM,EAAa,GAAuB,EAS1C,OARI,EACI,EAAW,SAAS,QAAQ,EAAI,EAAa,GAAG,EAAW,QAG/D,EAAsB,EAClB,GAGD,EACR,CAEA,SAAgB,GAAmB,EAAqB,EAAyC,CAEhG,OADW,GAAY,KAAK,GAAK,GAAY,KAAK,GACrC,IAAA,EACd,CAEA,SAAgB,GACf,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACS,CACT,IAAM,GAAQ,GAAgB,EAA4B,GAAG,QAAQ,MAAO,EAAE,EACxE,EAAY,EAAK,SAAS,QAAQ,EAAI,EAAO,GAAG,EAAK,QACrD,EAAM,IAAI,IAAI,CAAS,EACvB,EAAM,GAAY,KAAK,EACzB,IACH,EAAI,aAAa,IAAI,aAAc,CAAG,EACtC,EAAI,aAAa,IAAI,aAAc,CAAG,GAEvC,IAAM,EAAS,GAAU,KAAK,EAmB9B,OAlBI,GACH,EAAI,aAAa,IAAI,WAAY,CAAM,GAEpC,IAAQ,QAAU,IAAQ,WAC7B,EAAI,aAAa,IAAI,MAAO,CAAG,EAE5B,IAAO,UACV,EAAI,aAAa,IAAI,KAAM,QAAQ,EAEhC,GACH,EAAI,aAAa,IAAI,QAAS,GAAG,EAE9B,GACH,EAAI,aAAa,IAAI,QAAS,MAAM,GAEjC,IAAa,GAAK,IAAa,GAAK,IAAa,IACpD,EAAI,aAAa,IAAI,OAAQ,OAAO,CAAQ,CAAC,EAEvC,GAAsB,EAAI,SAAS,CAAC,CAC5C,CAiCA,SAAgB,GAAsB,EAA0B,CAC/D,GAAI,OAAO,SAAa,IAAa,OAAO,EAC5C,IAAM,EAAM,IAAI,IAAI,CAAQ,EAE5B,OADA,EAAI,aAAa,IAAI,eAAgB,SAAS,MAAM,EAC7C,EAAI,SAAS,CACrB,CAEA,SAAgB,GAAoB,EAA0B,CAC7D,OAAO,IAAI,IAAI,CAAQ,EAAE,MAC1B,CCnGA,SAAS,IAAqB,CAI7B,OAHI,OAAO,OAAW,KAAe,OAAO,OAAO,YAAe,WAC1D,OAAO,OAAO,WAAW,EAAE,QAAQ,KAAM,EAAE,EAAE,MAAM,EAAG,EAAE,IAEzD,OAAO,KAAK,IAAI,EAAE,SAAS,EAAE,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,EAAG,CAAC,GAC9E,CAEA,SAAgB,GACf,EACA,EACA,EAC6B,CAC7B,MAAO,CACN,GAAI,GAAW,EACf,OACA,YACA,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,MACD,CACD,CAyCA,SAAgB,IAAyD,CACxE,MAAO,CACN,MAAO,IAAI,IACX,QAAS,IAAI,IACb,cAAe,IAAI,IACnB,eAAgB,IAAI,IACpB,kBAAmB,IAAI,IACvB,gBAAiB,IAAI,IACrB,uBAAwB,IAAI,IAC5B,qBAAsB,IAAI,IAC1B,sBAAuB,IAAI,IAC3B,mBAAoB,IAAI,IACxB,QAAS,IAAI,IACb,eAAgB,IAAI,IACpB,eAAgB,IAAI,IACpB,SAAU,IAAI,IACd,eAAgB,IAAI,IACpB,2BAA4B,IAAI,GACjC,CACD,CAEA,SAAgB,GACf,EACA,EACA,EACa,CAEb,OADA,EAAS,GAAO,IAAI,CAAO,MACd,EAAS,GAAO,OAAO,CAAO,CAC5C,CAEA,SAAgB,GACf,EACA,EACA,EACO,CACP,IAAK,IAAM,KAAW,EAAS,GAC9B,EAAQ,CAAO,CAEjB,CAEA,SAAgB,GAA6B,EAAyC,CACrF,IAAK,IAAM,KAAO,OAAO,KAAK,CAAQ,EACrC,EAAS,GAAK,MAAM,CAEtB,CC3BA,SAAgB,EAAqB,EAAqD,CACzF,MACC,SAAU,GACV,WAAY,GACX,EAA6B,QAAU,MACxC,EAAE,UAAW,EAEf,CAEA,SAAgB,EAAqB,EAAqD,CACzF,MAAO,QAAS,GAAS,OAAQ,EAA6B,KAAQ,QACvE,CAEA,SAAgB,EACf,EACsC,CACtC,GAAI,EAAE,UAAW,GAAQ,MAAO,GAChC,IAAM,EAAS,EAAqC,MAMpD,OALqB,OAAO,GAAU,WAAlC,EAAmD,GACnD,OAAO,iBAAqB,KAAe,aAAiB,iBACxD,GAGD,SAAU,GAAS,eAAgB,CAC3C,CAEA,SAAgB,EAAyB,EAAyD,CACjG,MACC,CAAC,EAAqB,CAAK,GAC3B,CAAC,EAAqB,CAAK,GAC3B,CAAC,EAA6B,CAAK,GACnC,aAAc,GACd,OAAQ,EAAiC,UAAa,QAExD,CAwDA,IAAa,GAA+B,CAC3C,IAAM,KAAO,MAAO,KAAO,MAAO,IACnC,EAEa,EAAgB,CAC5B,gBAAiB,GAAK,KACtB,yBAA0B,GAC1B,yBAA0B,IAC1B,sBAAuB,IACvB,0BAA2B,IAC3B,8BAA+B,GAC/B,8BAA+B,IAC/B,0BAA2B,IAC3B,mBAAoB,EACpB,yBAA0B,GAC3B,EAEa,EAAb,cAAqD,KAAM,CAGhD,UACA,mBAHV,KAAgB,kCAChB,YACC,EACA,EACC,CACD,MAAM,qBAAqB,EAAU,yBAAyB,EAAmB,GAAG,EAH3E,KAAA,UAAA,EACA,KAAA,mBAAA,CAGV,CACD,EAEa,EAAb,cAAgD,KAAM,CACrD,KAAgB,6BAChB,YAAY,EAAU,0DAA2D,CAChF,MAAM,CAAO,CACd,CACD,EAEa,EAAb,cAAwC,KAAM,CAC7C,KAAgB,qBAChB,YAAY,EAAiB,EAA+B,CAC3D,MAAM,EAAS,CAAO,CACvB,CACD,EAEa,EAAb,cAA8C,KAAM,CACnD,KAAgB,2BAChB,YAAY,EAAU,gDAAiD,CACtE,MAAM,CAAO,CACd,CACD,EAEA,SAAgB,EACf,EAA4B,OACA,CAC5B,MAAO,CACN,OACA,kBAAmB,EACnB,mBAAoB,CACrB,CACD,CAEA,SAAgB,EAAqB,EAAuB,CAC3D,OAAQ,GAAmD,SAAS,CAAI,CACzE,CAEA,SAAgB,EAAgB,EAAiC,CAChE,GAAI,EAAO,WAAa,YACvB,MAAM,IAAI,EAAmB,+BAA+B,EAAO,UAAU,EAE9E,GAAI,EAAO,WAAa,EACvB,MAAM,IAAI,EAAmB,8BAA8B,EAAO,UAAU,EAE7E,GAAI,CAAC,EAAqB,EAAO,UAAU,EAC1C,MAAM,IAAI,EAAmB,4BAA4B,EAAO,YAAY,CAE9E,CAEA,SAAgB,GAAsB,EAA8B,CACnE,GAAI,EAAqB,CAAK,EAAG,CAChC,EAAgB,EAAM,MAAM,EAC5B,MACD,CACA,GAAI,EAAqB,CAAK,EAAG,CAEhC,GAAI,CADQ,EAAM,IAAI,KACjB,EAAK,MAAM,IAAI,EAAmB,8BAA8B,EACrE,GAAI,EAAM,aAAe,IAAA,IAAa,CAAC,EAAqB,EAAM,UAAU,EAC3E,MAAM,IAAI,EAAmB,4BAA4B,EAAM,YAAY,EAE5E,MACD,CACA,GAAI,EAA6B,CAAK,EAAG,CACxC,GAAI,EAAM,MAAM,OAAS,QACxB,MAAM,IAAI,EAAmB,sDAAsD,EAEpF,GAAI,EAAM,aAAe,IAAA,IAAa,CAAC,EAAqB,EAAM,UAAU,EAC3E,MAAM,IAAI,EAAmB,4BAA4B,EAAM,YAAY,EAE5E,MACD,CACA,GAAI,EAAyB,CAAK,EAAG,CACpC,IAAM,EAAW,EAAM,SAAS,KAAK,EAAE,YAAY,EACnD,GAAI,CAAC,EAAU,MAAM,IAAI,EAAmB,sCAAsC,EAClF,GAAI,IAAa,YAChB,MAAM,IAAI,EAAmB,uDAAuD,EAErF,GAAI,EAAM,aAAe,IAAA,IAAa,CAAC,EAAqB,EAAM,UAAU,EAC3E,MAAM,IAAI,EAAmB,4BAA4B,EAAM,YAAY,EAE5E,MACD,CACA,MAAM,IAAI,EAAmB,sCAAsC,CACpE,CAEA,SAAgB,GACf,EACoB,CACpB,GAAI,EAAQ,OAEX,OADA,EAAgB,EAAQ,MAAM,EACvB,EAAQ,OAEhB,GAAI,EAAQ,MAAO,CAElB,IAAM,EAA4B,CACjC,SAAU,YACV,WAHkB,EAAQ,YAAc,KAIxC,SAAU,CACX,EAEA,OADA,EAAgB,CAAM,EACf,CACR,CACA,MAAM,IAAI,EAAmB,2CAA2C,CACzE,CAEA,SAAgB,EAAa,EAA4C,CACxE,OAAO,aAAgB,WAAa,EAAO,IAAI,WAAW,CAAI,CAC/D,CAEA,SAAgB,GACf,EAC0B,CAE1B,OADI,IAAU,kBAAoB,IAAU,cAAsB,YAC3D,SACR,CCxTA,SAAgB,GAAe,EAAiC,CAC/D,IAAM,EAAM,IAAI,WAAW,EAAM,OAAS,CAAC,EACrC,EAAO,IAAI,SAAS,EAAI,MAAM,EACpC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,OAAQ,IAAK,CACtC,IAAM,EAAI,KAAK,IAAI,GAAI,KAAK,IAAI,EAAG,EAAM,EAAG,CAAC,EAC7C,EAAK,SAAS,EAAI,EAAG,EAAI,EAAI,EAAI,MAAS,EAAI,MAAQ,EAAI,CAC3D,CACA,OAAO,CACR,CC1BA,SAAS,GAAW,EAAY,EAAY,EAAY,EAAY,EAAmB,CACtF,IAAM,EAAK,IAAO,EAAK,IAAM,EAAK,IAAM,EAAK,GAAM,EAC7C,EAAK,EAAK,IAAM,EAAK,EAAI,EAAK,GAAM,EACpC,EAAK,IAAO,EAAK,GAAM,EACvB,EAAK,EACX,QAAS,EAAK,EAAI,GAAM,EAAI,GAAM,EAAI,CACvC,CAMA,SAAgB,GAAqB,EAAkB,EAAgC,CACtF,GAAI,EAAE,EAAW,IAAM,EAAE,EAAS,GACjC,MAAU,MAAM,kCAAkC,EAGnD,GAAI,IAAa,EAChB,MAAO,CACN,WACA,SACA,KAAK,EAAO,CACX,OAAO,CACR,EACA,OAAQ,CACP,OAAO,IAAI,YACZ,CACD,EAGD,IAAM,EAAQ,EAAW,EAErB,EAAU,IAAI,aACd,EAAM,EAEV,MAAO,CACN,WACA,SACA,KAAK,EAAO,CACX,GAAI,EAAM,SAAW,EAAG,OAAO,IAAI,aACnC,IAAM,EAAS,IAAI,aAAa,EAAQ,OAAS,EAAM,MAAM,EAK7D,GAJA,EAAO,IAAI,CAAO,EAClB,EAAO,IAAI,EAAO,EAAQ,MAAM,EAChC,EAAU,EAEN,EAAQ,OAAS,EAAG,OAAO,IAAI,aAEnC,IAAM,EAAgB,CAAC,EAEvB,KAAO,EAAM,EAAI,EAAQ,OAAS,GAAG,CACpC,IAAM,EAAK,KAAK,MAAM,CAAG,EACnB,EAAI,EAAM,EACV,EAAK,KAAK,IAAI,EAAG,EAAK,CAAC,EACvB,EAAK,KAAK,IAAI,EAAQ,OAAS,EAAG,EAAK,CAAC,EACxC,EAAK,KAAK,IAAI,EAAQ,OAAS,EAAG,EAAK,CAAC,EAC9C,EAAI,KACH,GAAW,EAAQ,GAAM,EAAQ,GAAM,EAAQ,GAAM,EAAQ,GAAM,CAAC,CACrE,EACA,GAAO,CACR,CAGA,IAAM,EAAO,KAAK,IAAI,EAAG,KAAK,MAAM,CAAG,EAAI,CAAC,EAM5C,OALI,EAAO,IACV,EAAU,EAAQ,SAAS,CAAI,EAC/B,GAAO,GAGD,EAAI,OAAS,aAAa,KAAK,CAAG,EAAI,IAAI,YAClD,EACA,OAAQ,CAKP,OAJI,EAAQ,SAAW,EAAU,IAAI,cAErC,EAAU,IAAI,aACd,EAAM,EACC,IAAI,aACZ,CACD,CACD,CCpEA,IAAM,EAAe,sBAEf,GAAiB;;;;;;;;;;;;qBAYF,EAAa;EAG9B,EAA4B,KAEhC,SAAS,GAAwB,CAMhC,MALA,CACC,IAAa,IAAI,gBAChB,IAAI,KAAK,CAAC,EAAc,EAAG,CAAE,KAAM,wBAAyB,CAAC,CAC9D,EAEM,CACR,CAEA,SAAS,IAAkD,CAC1D,OACC,OAAO,cACN,OAAmE,oBACpE,IAEF,CAMA,eAAsB,GACrB,EAC+B,CAC/B,GAAM,CAAE,cAAa,mBAAkB,QAAO,aAAY,SAAU,EAC9D,EAAmB,GAAoB,EAC7C,GAAI,CAAC,EAAkB,MAAU,MAAM,yCAAyC,EAEhF,IAAM,EAAW,IAAI,EACf,EAAS,EAAS,wBAAwB,CAAW,EACrD,EAAS,EAAS,WAAW,EACnC,EAAO,KAAK,MAAQ,EACpB,IAAM,EAAiB,EAAS,WAC1B,EAA4B,GAAqB,EAAgB,CAAgB,EACnF,EAAU,GACV,EAAe,GAEb,EAAa,GAAwB,CAE1C,GADI,GACA,GAAc,CAAC,EAAW,EAAG,OACjC,IAAM,EAAY,EAAU,KAAK,CAAK,EAClC,EAAU,SAAW,GACzB,EAAM,GAAe,CAAS,CAAC,CAChC,EAEI,MAAoC,IAAA,GAmGxC,OAdM,MAAM,SAnFqC,CAChD,GAAI,OAAO,EAAS,cAAc,WAAc,WAAY,MAAO,GACnE,GAAI,CACH,MAAM,EAAS,aAAa,UAAU,EAAc,CAAC,EACrD,IAAM,EAAO,IAAI,iBAAiB,EAAU,EAAc,CACzD,eAAgB,EAChB,gBAAiB,EACjB,mBAAoB,CAAC,CAAC,CACvB,CAAC,EA0BD,MAzBA,GAAK,KAAK,UAAa,GAAO,CACzB,EAAG,gBAAgB,cAAc,EAAU,EAAG,IAAI,CACvD,EACA,EAAO,QAAQ,CAAI,EACnB,EAAK,QAAQ,CAAM,EACnB,EAAO,QAAQ,EAAS,WAAW,EACnC,MAAwB,CACvB,EAAK,KAAK,UAAY,KACtB,GAAI,CACH,EAAK,WAAW,CACjB,MAAQ,CAER,CACA,GAAI,CACH,EAAO,WAAW,CACnB,MAAQ,CAER,CACA,GAAI,CACH,EAAO,WAAW,CACnB,MAAQ,CAER,CACD,EACA,EAAe,GACR,EACR,MAAQ,CACP,MAAO,EACR,CACD,GA6CuB,EAOtB,IAAQ,yCAAyC,EAAe,QAAQ,EAAiB,IAAI,QAlDvD,CACtC,IAAM,EACL,EAOC,uBAAuB,KAAK,CAAQ,EAEtC,GAAI,CAAC,EACJ,MAAU,MAAM,uDAAuD,EAGxE,IAAM,EAAY,EAAsB,KAAM,EAAG,CAAC,EAClD,EAAU,eAAkB,GAAO,CAClC,EAAU,EAAG,YAAY,eAAe,CAAC,CAAC,CAC3C,EACA,EAAO,QAAQ,CAAS,EACxB,EAAU,QAAQ,CAAM,EACxB,EAAO,QAAQ,EAAS,WAAW,EACnC,MAAwB,CACvB,EAAU,eAAiB,KAC3B,GAAI,CACH,EAAU,WAAW,CACtB,MAAQ,CAER,CACA,GAAI,CACH,EAAO,WAAW,CACnB,MAAQ,CAER,CACA,GAAI,CACH,EAAO,WAAW,CACnB,MAAQ,CAER,CACD,EACA,EAAe,EAChB,GAGoB,EACnB,IACC,4CAA4C,EAAe,QAAQ,EAAiB,KACpF,MACD,GAKG,EAAS,QAAU,aACtB,MAAM,EAAS,OAAO,EAAE,UAAY,IAAA,EAAS,EAGvC,CACN,iBACA,eACA,MAAO,CACF,IACJ,EAAU,GACV,EAAU,MAAM,EAChB,EAAgB,EAChB,EAAc,MAAM,EAAE,UAAY,IAAA,EAAS,EAC5C,CACD,CACD,CClLA,eAAsB,GACrB,EACgB,CAChB,GAAM,CAAE,QAAO,YAAW,aAAY,UAAW,EACjD,GAAI,OAAO,iBAAqB,KAAe,EAAE,aAAiB,kBACjE,MAAM,IAAI,EAAmB,wDAAwD,EAEtF,GAAI,EAAM,OAAS,QAClB,MAAM,IAAI,EAAmB,sDAAsD,EAKpF,GAHI,EAAM,aAAe,SAGrB,GAAQ,QACX,OAGD,IAAM,EAAS,IAAI,YAAY,CAAC,CAAK,CAAC,EAClC,EAA4B,QAAQ,QAAQ,EAC5C,EAAU,GACV,EAAgE,KAE9D,MAAiB,CAClB,IACJ,EAAU,GACV,GAAS,KAAK,EACd,EAAU,KACX,EAEA,GAAI,CACH,EAAU,MAAM,GAAkB,CACjC,YAAa,EACb,iBAAkB,EAClB,eAAkB,CAAC,GAAW,CAAC,GAAQ,QACvC,MAAQ,GAAQ,CACf,GAAI,GAAW,GAAQ,QAAS,OAChC,IAAM,EAAQ,EAAa,CAAG,EAC9B,EAAa,EACX,KAAK,SAAY,CACjB,GAAI,GAAW,GAAQ,QAAS,OAChC,IAAI,EAAS,EACb,KAAO,EAAS,EAAM,YAAY,CACjC,IAAI,EAAM,KAAK,IAAI,EAAS,EAAc,gBAAiB,EAAM,UAAU,EAE3E,IADK,EAAM,GAAU,GAAM,GAAG,IAC1B,GAAO,EAAQ,MACnB,IAAM,EAAQ,EAAM,SAAS,EAAQ,CAAG,EACxC,EAAS,EACL,EAAM,aAAe,GACzB,MAAM,EAAU,MAAM,CAAK,CAC5B,CACD,CAAC,EACA,UAAY,CACZ,EAAS,CACV,CAAC,CACH,CACD,CAAC,CACF,OAAS,EAAK,CAGb,MAFA,EAAS,EAEH,IAAI,EAAmB,oCADb,aAAe,MAAQ,EAAI,QAAU,OAAO,CAAG,GACW,CAC3E,CAEA,MAAM,IAAI,QAAe,GAAY,CACpC,IAAM,MAAe,CACpB,EAAS,EACT,EAAgB,QAAQ,CAAO,CAChC,EACA,EAAM,iBAAiB,QAAS,EAAQ,CAAE,KAAM,EAAK,CAAC,EACtD,GAAQ,iBACP,YACM,CACL,EAAe,OAAO,EAAE,UAAY,IAAA,EAAS,EAC7C,EAAO,CACR,EACA,CAAE,KAAM,EAAK,CACd,GACI,EAAM,aAAe,SAAW,GAAQ,UAC3C,EAAO,CAET,CAAC,CACF,CCjEA,eAAe,GACd,EACA,EACiC,CACjC,GAAI,EAA6B,CAAK,EACrC,MAAM,IAAI,EAAmB,4DAA4D,EAE1F,GAAI,EAAqB,CAAK,EAAG,CAChC,IAAM,EAAO,EAAa,EAAM,IAAI,EACpC,GAAK,EAAK,WAAa,EACtB,MAAM,IAAI,EAAmB,+BAA+B,EAE7D,MAAO,CACN,KAAM,MACN,KAAM,EAAK,MAAM,EAAE,OACnB,OAAQ,EAAM,MACf,CACD,CACA,GAAI,EAAqB,CAAK,EAC7B,MAAO,CACN,KAAM,MACN,IAAK,EAAM,IAAI,KAAK,EACpB,GAAI,EAAM,aAAe,IAAA,GAA+C,CAAC,EAApC,CAAE,WAAY,EAAM,UAAW,CACrE,EAED,GAAI,CAAC,EAAyB,CAAK,EAClC,MAAM,IAAI,EAAmB,sCAAsC,EAEpE,IAAI,EACJ,GAAI,OAAO,KAAS,KAAe,EAAM,gBAAgB,KAAM,CAC9D,GAAI,GAAQ,QAAS,MAAM,IAAI,aAAa,gBAAiB,YAAY,EACzE,EAAQ,IAAI,WAAW,MAAM,EAAM,KAAK,YAAY,CAAC,CACtD,MACC,EAAQ,EAAa,EAAM,IAAgC,EAE5D,MAAO,CACN,KAAM,UACN,KAAM,EAAM,MAAM,EAAE,OACpB,SAAU,EAAM,SAAS,KAAK,EAC9B,GAAI,EAAM,aAAe,IAAA,GAA+C,CAAC,EAApC,CAAE,WAAY,EAAM,UAAW,CACrE,CACD,CAiCA,SAAS,IAAyB,CAIjC,OAHI,OAAO,OAAW,KAAe,OAAO,OAAO,YAAe,WAC1D,OAAO,OAAO,WAAW,EAAE,QAAQ,KAAM,EAAE,EAAE,MAAM,EAAG,EAAE,IAEzD,OAAO,KAAK,IAAI,EAAE,SAAS,EAAE,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,EAAG,CAAC,GAC9E,CAEA,SAAS,EACR,EACA,EAA+B,YAChB,CACf,MAAO,CACN,YAAa,EAAO,SACpB,YAAa,EAAO,YACpB,SACA,WAAY,EAAO,WACnB,WAAY,EAAO,KACnB,UAAW,CACV,KAAM,UACN,kBAAmB,EAAO,WAC1B,mBAAoB,CACrB,CACD,CACD,CAEA,SAAS,EAAY,EAAuB,CAE3C,OADI,aAAiB,MAAc,EAC5B,IAAI,EAAmB,OAAO,CAAK,CAAC,CAC5C,CAEA,SAAS,EAAa,EAAyB,CAC9C,OACE,aAAiB,cAAgB,EAAM,OAAS,cAChD,aAAiB,OAAS,EAAM,OAAS,YAE5C,CAEA,IAAM,GAAN,KAAqD,CACpD,GACA,YACA,OAEA,OACA,KACA,OACA,cACA,aACA,QAAkB,GAClB,OAAiB,GACjB,WAAoC,QAAQ,QAAQ,EACpD,kBAA4B,EAC5B,oBAAuD,CAAC,EACxD,WAAqB,EACrB,WACA,aAEA,YAAY,EAQT,CACF,KAAK,GAAK,EAAQ,GAClB,KAAK,YAAc,EAAQ,YAC3B,KAAK,OAAS,EAAQ,OACtB,KAAK,KAAO,EAAQ,KACpB,KAAK,OAAS,EAAQ,OACtB,KAAK,WAAa,EAAQ,OAAO,WACjC,KAAK,OAAS,IAAI,SAAuB,EAAS,IAAW,CAC5D,KAAK,cAAgB,EACrB,KAAK,aAAe,CACrB,CAAC,EAED,KAAU,OAAO,UAAY,IAAA,EAAS,EAEtC,IAAM,EAAS,KAAK,YAAY,EAChC,KAAK,aAAe,EAClB,qBAAqB,CACrB,YAAa,KAAK,GAClB,OAAQ,KAAK,OACb,YAAa,KAAK,YAClB,MAAO,EAAQ,MACf,GAAI,EAAQ,aAAe,IAAA,GAAiD,CAAC,EAAtC,CAAE,WAAY,EAAQ,UAAW,CACzE,CAAC,EACA,MAAO,GAAmB,CAE1B,MADA,KAAK,KAAK,EAAY,CAAK,CAAC,EACtB,EAAY,CAAK,CACxB,CAAC,EAEF,KAAK,QAAQ,iBACZ,YACM,CACL,KAAU,OAAO,CAClB,EACA,CAAE,KAAM,EAAK,CACd,CACD,CAEA,MAAM,MAAM,EAAiC,EAA6C,CAKzF,GAJI,KAAK,QAAU,KAAK,UAGxB,MAAM,KAAK,aAAa,UAAY,IAAA,EAAS,EACzC,KAAK,QAAU,KAAK,SACvB,MAAM,IAAI,EAEX,IAAM,EAAQ,EAAa,CAAK,EAChC,GAAK,EAAM,WAAa,EACvB,MAAM,IAAI,EAAmB,4DAA4D,EAE1F,GAAI,EAAM,WAAa,EAAc,gBACpC,MAAM,IAAI,EACT,sCAAsC,EAAc,gBAAgB,GACrE,EAED,GAAI,EAAM,aAAe,EAAG,OAE5B,IAAM,EAAY,GAAS,WAAa,EAAc,yBACtD,MAAM,KAAK,iBAAiB,CAAS,EAErC,IAAM,EAAW,EAAM,WAAa,EAAI,KAAK,WAAc,IAC3D,GAAI,KAAK,WAAa,EAAU,EAAc,0BAE7C,MADA,KAAK,iBAAiB,EAChB,IAAI,EAAmB,8CAA8C,EAG5E,IAAM,EAAM,SAAY,CACvB,GAAI,KAAK,QAAU,KAAK,QACvB,MAAM,IAAI,EAEX,IAAM,EAAS,KAAK,YAAY,EAC1B,EAAO,EAAM,MAAM,EACnB,EAAe,EAAO,qBAAqB,CAChD,YAAa,KAAK,GAClB,MAAO,EAAK,OACZ,WAAY,EAAK,UAClB,CAAC,EACK,EAAM,MAAM,QAAQ,KAAK,CAC9B,EACA,IAAI,SAAgB,EAAG,IAAW,CACjC,eAAiB,EAAO,IAAI,CAA0B,EAAG,CAAS,CACnE,CAAC,CACF,CAAC,EACD,KAAK,WAAa,KAAK,IAAI,EAAG,EAAI,UAAU,CAC7C,EAEM,EAAU,KAAK,WAAW,KAAK,EAAK,CAAG,EAC7C,KAAK,WAAa,EAAQ,SACnB,IAAA,OACA,IAAA,EACP,EACA,GAAI,CACH,MAAM,CACP,QAAU,CACT,KAAK,iBAAiB,CACvB,CACD,CAEA,MAAM,cAAc,EAA6B,CAKhD,GAJI,KAAK,QAAU,KAAK,UAGxB,MAAM,KAAK,aAAa,UAAY,IAAA,EAAS,EACzC,KAAK,QAAU,KAAK,SACvB,MAAM,IAAI,EAGX,MADe,KAAK,YACd,EAAO,6BAA6B,CACzC,YAAa,KAAK,GAClB,WAAY,CACb,CAAC,CACF,CAEA,MAAM,MAAM,EAA8D,CACzE,GAAI,KAAK,QAAS,OAAO,KAAK,OAC9B,KAAK,OAAS,GACd,MAAM,KAAK,aAAa,UAAY,IAAA,EAAS,EAC7C,MAAM,KAAK,WAAW,UAAY,IAAA,EAAS,EAC3C,GAAI,CAEH,IAAM,EAAS,MADA,KAAK,YACC,EAAO,qBAAqB,CAChD,YAAa,KAAK,GAClB,WAAY,GAAS,WACrB,QAAS,GAAS,SAAW,MAC9B,CAAC,EAED,OADA,KAAK,QAAQ,CAAM,EACZ,CACR,OAAS,EAAO,CACf,IAAM,EAAM,EAAY,CAAK,EAE7B,MADA,KAAK,KAAK,CAAG,EACP,CACP,CACD,CAEA,MAAM,QAAgC,CACrC,GAAI,KAAK,QAAS,OAAO,KAAK,OAC9B,KAAK,OAAS,GACd,GAAI,CACH,IAAM,EAAS,KAAK,KAAK,cAAc,EACvC,GAAI,EAAQ,CACX,IAAM,EAAS,MAAM,EAAO,sBAAsB,CAAE,YAAa,KAAK,EAAG,CAAC,EAE1E,OADA,KAAK,QAAQ,CAAM,EACZ,CACR,CACA,IAAM,EAA0B,CAC/B,YAAa,KAAK,GAClB,YAAa,KAAK,YAClB,OAAQ,YACR,WAAY,EACZ,UAAW,EAAqB,MAAM,CACvC,EAEA,OADA,KAAK,QAAQ,CAAS,EACf,CACR,OAAS,EAAO,CACf,IAAM,EAAM,EAAY,CAAK,EAE7B,MADA,KAAK,KAAK,CAAG,EACP,CACP,CACD,CAGA,oBAAoB,EAA4B,CAC/C,KAAK,QAAQ,CAAM,CACpB,CAEA,aAAkC,CACjC,IAAM,EAAS,KAAK,KAAK,cAAc,EACvC,GAAI,CAAC,EACJ,MAAM,IAAI,EAAmB,iCAAiC,EAE/D,OAAO,CACR,CAEA,QAAgB,EAA4B,CACvC,KAAK,UACT,KAAK,QAAU,GACf,KAAK,cAAc,OAAO,OAAO,CAAM,CAAC,EACxC,KAAK,kBAAkB,IAAI,CAA4B,EACxD,CAEA,KAAa,EAAoB,CAC5B,KAAK,UACT,KAAK,QAAU,GACf,KAAK,aAAa,CAAK,EACvB,KAAK,kBAAkB,CAAK,EAC7B,CAEA,MAAc,iBAAiB,EAAkC,CAChE,GAAI,KAAK,kBAAoB,EAAc,mBAAoB,CAC9D,KAAK,mBAAqB,EAC1B,MACD,CACA,MAAM,IAAI,SAAe,EAAS,IAAW,CAC5C,IAAM,EAAQ,eAAiB,CAC9B,EAAO,IAAI,CAA0B,CACtC,EAAG,CAAS,EACZ,KAAK,oBAAoB,KAAK,CAC7B,YAAe,CACd,aAAa,CAAK,EAClB,KAAK,mBAAqB,EAC1B,EAAQ,CACT,EACA,OAAS,GAAU,CAClB,aAAa,CAAK,EAClB,EAAO,CAAK,CACb,CACD,CAAC,CACF,CAAC,CACF,CAEA,kBAAiC,CAChC,KAAK,kBAAoB,KAAK,IAAI,EAAG,KAAK,kBAAoB,CAAC,EAE/D,KADkB,oBAAoB,MACtC,GAAM,QAAQ,CACf,CAEA,kBAA0B,EAAoB,CAC7C,KAAO,KAAK,oBAAoB,OAAS,GACxC,KAAK,oBAAoB,MAAM,GAAG,OAAO,CAAK,CAEhD,CACD,EAEA,SAAgB,GAAuB,EAA8C,CACpF,IAAI,EAA4C,KAE1C,GAAqB,EAAmB,IAAyC,CAEtF,GAAI,CADS,EAAK,gBACb,EAAK,GACT,MAAM,IAAI,EAAgC,EAAW,CAAU,CAEjE,EAEM,EAA+B,CACpC,MAAM,MAAM,EAAoD,CAG/D,GAFA,EAAK,qBAAqB,EAC1B,EAAkB,QAAS,YAAY,EACnC,EAAQ,QAAQ,QACnB,MAAM,IAAI,aAAa,iBAAkB,YAAY,EAGtD,IAAM,EAA0B,GADlB,EAAQ,OAAS,QACiC,EAC5D,IAAa,cAChB,EAAK,uBAAuB,EAC5B,AAEC,KADA,EAAmB,OAAO,EACV,OAGlB,IAAM,EAAS,EAAK,cAAc,EAClC,GAAI,CAAC,EAAQ,MAAM,IAAI,EAAmB,iCAAiC,EAE3E,IAAM,EAAe,EAAO,MAAM,CACjC,KAAM,EAAQ,KACd,YAAa,EAAQ,YACrB,UACD,CAAC,EAED,GAAI,EAAQ,OAAQ,CACnB,IAAM,EAAS,EAAQ,OACvB,OAAO,MAAM,IAAI,SAAuB,EAAS,IAAW,CAC3D,IAAM,MAAgB,CACrB,EAAY,gBAAgB,CAAE,MAAO,QAAS,CAAC,EAAE,UAAY,IAAA,EAAS,EACtE,EAAO,IAAI,aAAa,iBAAkB,YAAY,CAAC,CACxD,EACA,GAAI,EAAO,QAAS,CACnB,EAAQ,EACR,MACD,CACA,EAAO,iBAAiB,QAAS,EAAS,CAAE,KAAM,EAAK,CAAC,EACxD,EAAa,KACX,GAAW,CACX,EAAO,oBAAoB,QAAS,CAAO,EAC3C,EAAQ,EAAoB,EAAQ,WAAW,CAAC,CACjD,EACC,GAAmB,CAEnB,GADA,EAAO,oBAAoB,QAAS,CAAO,EACvC,EAAa,CAAK,EAAG,CACxB,EAAQ,CACP,YAAa,kBACb,YAAa,EAAQ,aAAe,EAAK,qBAAqB,EAC9D,OAAQ,cACR,WAAY,EACZ,WAAY,EAAQ,KACpB,UAAW,EAAqB,MAAM,CACvC,CAAC,EACD,MACD,CACA,EAAO,EAAY,CAAK,CAAC,CAC1B,CACD,CACD,CAAC,CACF,CAEA,GAAI,CAEH,OAAO,EAAoB,MADN,EACc,WAAW,CAC/C,OAAS,EAAO,CACf,GAAI,EAAa,CAAK,EACrB,MAAO,CACN,YAAa,kBACb,YAAa,EAAQ,aAAe,EAAK,qBAAqB,EAC9D,OAAQ,cACR,WAAY,EACZ,WAAY,EAAQ,KACpB,UAAW,EAAqB,MAAM,CACvC,EAED,MAAM,EAAY,CAAK,CACxB,CACD,EAEA,MAAM,KAAK,EAAmD,CAI7D,GAHA,EAAK,qBAAqB,EAC1B,EAAkB,OAAQ,qBAAqB,EAC/C,GAAsB,EAAQ,KAAK,EAC/B,EAAQ,QAAQ,QACnB,MAAM,IAAI,aAAa,gBAAiB,YAAY,EAErD,IAAM,EAAQ,EAAQ,OAAS,SAS/B,IARI,IAAU,kBAAoB,IAAU,iBAC3C,EAAK,uBAAuB,EAC5B,AAEC,KADA,EAAmB,OAAO,EACV,OAId,EAA6B,EAAQ,KAAK,EAAG,CAChD,IAAM,EAAa,EAAQ,MAAM,YAAc,KAQ/C,OAPkB,EAAW,gBAAgB,CAC5C,OAAQ,CAAE,SAAU,YAAa,aAAY,SAAU,CAAE,EACzD,MAAO,EAAQ,MAAM,MACrB,YAAa,EAAQ,YACrB,MAAO,IAAU,SAAW,iBAAmB,EAC/C,OAAQ,EAAQ,MACjB,CACO,EAAU,MAClB,CAEA,IAAM,EAAS,EAAK,cAAc,EAClC,GAAI,CAAC,EAAQ,MAAM,IAAI,EAAmB,iCAAiC,EAC3E,IAAM,EAAS,MAAM,GAAwB,EAAQ,MAAO,EAAQ,MAAM,EAC1E,OAAO,EAAO,WAAW,CACxB,SACA,YAAa,EAAQ,YACrB,WAAY,EAAQ,WACpB,QAAS,EAAQ,SAAW,OAC5B,QACA,OAAQ,EAAQ,MACjB,CAAC,CACF,EAEA,gBAAgB,EAAwD,CACvE,EAAK,qBAAqB,EAC1B,EAAkB,kBAAmB,qBAAqB,EAC1D,IAAM,EAAS,GAA6B,CAAO,EACnD,GAAI,EAAQ,OAAS,EAAQ,MAAM,OAAS,QAC3C,MAAM,IAAI,EAAmB,0DAA0D,EAExF,IAAM,EAAoC,EAAQ,OAAS,iBAC3D,GAAI,IAAU,kBAAoB,IAAU,cAC3C,MAAM,IAAI,EAAmB,8DAA8D,EAE5F,EAAK,uBAAuB,EAC5B,AAEC,KADA,EAAmB,OAAO,EACV,MAEjB,IAAM,EAAY,IAAI,GAAoB,CACzC,GAAI,GAAe,EACnB,YAAa,EAAQ,aAAe,EAAK,qBAAqB,EAC9D,SACA,QACA,OACA,GAAI,EAAQ,aAAe,IAAA,GAAiD,CAAC,EAAtC,CAAE,WAAY,EAAQ,UAAW,EACxE,OAAQ,EAAQ,MACjB,CAAC,EAqBD,MApBA,GAAgB,EAChB,EAAe,OAAO,YAAc,CAC/B,IAAkB,IAAW,EAAgB,KAClD,CAAC,EACG,EAAQ,QACL,SAAY,CACjB,GAAI,CAOH,GANA,MAAM,GAAgC,CACrC,MAAO,EAAQ,MACf,YACA,WAAY,EAAO,WACnB,OAAQ,EAAQ,MACjB,CAAC,EACG,EAAQ,QAAQ,QAAS,OAC7B,MAAM,EAAU,MAAM,CAAE,QAAS,MAAO,CAAC,CAC1C,MAAQ,CACP,MAAM,EAAU,OAAO,EAAE,UAAY,IAAA,EAAS,CAC/C,CACD,GAAG,EAEG,CACR,EAEA,MAAM,UAAU,EAAoE,CACnF,EAAK,qBAAqB,EAC1B,EAAK,uBAAuB,EAC5B,IAAM,EAAS,EAAK,cAAc,EAClC,GAAI,CAAC,EAAQ,MAAO,CAAC,EACrB,IAAM,EAAU,MAAM,EAAO,gBAAgB,GAAW,CAAE,MAAO,QAAS,CAAC,EAC3E,GAAI,EAAe,CAClB,IAAM,EAAQ,EAAQ,KAAM,GAAM,EAAE,cAAgB,EAAe,EAAE,EACjE,GAAO,EAAc,oBAAoB,CAAK,EAClD,EAAgB,IACjB,CACA,OAAO,CACR,CACD,EAEA,OAAO,CACR,CClkBA,SAAgB,GAAmB,EAA6D,CAC/F,IAAM,EAAU,GAAO,KAAK,EAC5B,OAAO,IAAY,QAAU,IAAY,QAAU,IAAY,SAAW,EAAU,IAAA,EACrF,CCgSA,SAAS,GAAiB,EAAiC,CAW1D,MAPA,GAHI,EAAQ,YAAc,IACtB,EAAQ,WAAW,KAAK,GACxB,EAAQ,cAAgB,IAE3B,EAAQ,aACR,OAAO,EAAQ,aAAgB,UAC/B,EAAQ,YAAY,UAAY,GAKlC,CAEA,IAAa,EAAb,MAAa,CAAW,CACvB,UACA,sBACA,WAAwC,KACxC,eAAwD,KACxD,wBAA0D,KAC1D,yBAA2D,KAC3D,eAAwC,QAAQ,QAAQ,EACxD,gBACA,YACA,gBAAyC,KACzC,OAAiB,GACjB,SAAmB,GACnB,WAA2C,KAC3C,cAAkE,CAAC,EACnE,cAAiC,GAA8B,EAC/D,cAA0D,KAC1D,gBAA8D,KAC9D,sBAA0E,KAC1E,kBAA4D,CAAC,EAE7D,OAEA,YAAoB,EAA6B,CAChD,KAAK,UAAY,EACjB,KAAK,sBAAwB,EAAU,uBAAyB,KAChE,KAAK,gBAAkB,EAAU,OAAS,SAAY,EAAU,SAAW,KAAQ,KACnF,KAAK,YAAc,EAAU,OAAS,SAAW,EAAU,OAAS,KACpE,KAAK,OAAS,GAAuB,CACpC,kBAAqB,KAAK,WAC1B,yBAA4B,KAAK,qBAAqB,EACtD,oBAAuB,GAA0B,KAAK,eAAe,EACrE,yBAA4B,oBAC5B,yBAA4B,CAC3B,KAAK,0BAA0B,MAAM,EACrC,KAAK,yBAA2B,IACjC,CACD,CAAC,CACF,CAEA,aAAa,aAAa,EAAmD,CAC5E,GAAI,WAAY,GAAW,OAAO,EAAQ,QAAW,SAAU,CAC9D,IAAM,EAAS,EAAQ,OAAO,KAAK,EACnC,GAAI,CAAC,EACJ,MAAU,MAAM,wDAAwD,EAEzE,OAAO,IAAI,EAAW,CACrB,KAAM,SACN,SACA,QAAS,EAAQ,QACjB,WAAY,EAAQ,WACpB,WAAY,EAAQ,WACpB,SAAU,EAAQ,SAClB,aAAc,EAAQ,aACtB,MAAO,EAAQ,MACf,WAAY,EAAQ,WACpB,GAAI,EAAQ,GACZ,QAAS,EAAQ,QACjB,iBAAkB,EAAQ,iBAC1B,sBAAuB,EAAQ,qBAChC,CAAC,CACF,CAEA,GAAI,oBAAqB,EACxB,OAAO,IAAI,EAAW,CACrB,KAAM,kBACN,aAAc,EAAQ,aACtB,gBAAiB,EAAQ,gBACzB,OAAQ,EAAQ,OAChB,gBAAiB,EAAQ,gBACzB,eAAgB,EAAQ,eACxB,SAAU,EAAQ,SAClB,WAAY,EAAQ,WACpB,WAAY,EAAQ,WACpB,SAAU,EAAQ,SAClB,SAAU,EAAQ,SAClB,aAAc,EAAQ,aACtB,MAAO,EAAQ,MACf,KAAM,EAAQ,KACd,gBAAiB,EAAQ,gBACzB,WAAY,EAAQ,WACpB,YAAa,EAAQ,YACrB,GAAI,EAAQ,GACZ,QAAS,EAAQ,QACjB,iBAAkB,EAAQ,iBAC1B,sBAAuB,EAAQ,qBAChC,CAAC,EAGF,GAAI,iBAAkB,EACrB,OAAO,IAAI,EAAW,CACrB,KAAM,SACN,aAAc,EAAQ,aACtB,OAAQ,EAAQ,OAChB,gBAAiB,EAAQ,gBACzB,eAAgB,EAAQ,eACxB,SAAU,EAAQ,SAClB,WAAY,EAAQ,WACpB,WAAY,EAAQ,WACpB,SAAU,EAAQ,SAClB,SAAU,EAAQ,SAClB,aAAc,EAAQ,aACtB,MAAO,EAAQ,MACf,KAAM,EAAQ,KACd,gBAAiB,EAAQ,gBACzB,WAAY,EAAQ,WACpB,YAAa,EAAQ,YACrB,GAAI,EAAQ,GACZ,QAAS,EAAQ,QACjB,iBAAkB,EAAQ,iBAC1B,sBAAuB,EAAQ,qBAChC,CAAC,EAGF,MAAU,MACT,4EACD,CACD,CAEA,YAA6B,CAC5B,OAAO,KAAK,eACb,CAMA,aAAsC,CACrC,OAAO,IACR,CAEA,GACC,EACA,EACa,CACb,IAAM,EAAc,GAAyB,KAAK,cAAe,EAAO,CAAO,EAU/E,OATI,IAAU,SAAW,KAAK,eAC7B,mBAAqB,EAAQ,KAAK,aAAoC,CAAC,EAEpE,IAAU,WAAa,KAAK,iBAC/B,mBAAqB,EAAQ,KAAK,eAAsC,CAAC,EAEtE,IAAU,iBAAmB,KAAK,uBACrC,mBAAqB,EAAQ,KAAK,qBAA4C,CAAC,EAEzE,CACR,CAEA,MAAM,OAAO,EAAgD,CAC5D,GAAI,KAAK,OACR,MAAU,MAAM,oBAAoB,EAErC,GAAI,CAAC,EAAQ,UACZ,MAAU,MAAM,qDAAqD,EAYtE,OAVI,KAAK,UAAY,KAAK,WAClB,KAAK,mBAAmB,GAE5B,AAIJ,KAAK,iBAAiB,KAAK,eAAe,CAAO,EAAE,YAAc,CAChE,KAAK,eAAiB,IACvB,CAAC,EALO,KAAK,eAOd,CAEA,MAAc,eAAe,EAAgD,CAC5E,GAAI,KAAK,OACR,MAAU,MAAM,oBAAoB,EAErC,GAAI,KAAK,UAAY,KAAK,WACzB,OAAO,KAAK,mBAAmB,EAEhC,AAEC,KAAK,cADL,KAAK,WAAW,QAAQ,EACN,MAGnB,KAAK,gBAAkB,EAAQ,WAAW,KAAK,GAAK,KAEpD,IAAM,EAAe,KAAK,UAAU,cAAgB,EAA4B,EAC1E,EAAQ,KAAK,UAAU,QAAU,GACjC,EAAa,KAAK,UAAU,aAAe,GAO3C,EAAY,GACjB,EACA,EARkB,EAChB,IAAA,GACA,GAAmB,KAAK,UAAU,WAAY,KAAK,UAAU,UAAU,EACzD,EAAa,IAAA,GAAY,KAAK,UAAU,SAQxD,EAAQ,IACR,KAAK,UAAU,GACf,GAAiB,CAAO,EACxB,KAAK,UAAU,OAAS,SAAW,IAAA,GAAY,KAAK,UAAU,QAC/D,EACM,EAAe,GAAoB,CAAS,EAE9C,EAAwC,KACtC,EAAmB,IAAI,QAAe,GAAY,CACvD,EAAmB,CACpB,CAAC,EACG,EAAsC,KACpC,EAAiB,IAAI,QAAe,GAAY,CACrD,EAAiB,CAClB,CAAC,EACK,EAAY,GAA0B,GAAiB,CACxD,AAEJ,KAAK,iBADL,KAAK,gBAAkB,EACF,KAAK,YAAY,QAAS,CAAE,QAAS,CAAa,CAAC,EACzE,CAAC,EAEK,EAAmB,KAAK,UAAU,iBAkBlC,EAAa,GAAiB,CACnC,UAAW,EAAQ,UACnB,IAAK,EACL,eACA,YAAa,KAAK,UAAU,KAAO,SACnC,QAAU,GAAU,CACnB,IAAM,EACL,EAAM,WAAa,CAAC,KAAK,gBACtB,EACA,CAAE,GAAG,EAAO,UAAW,KAAK,eAAgB,EAChD,IAAK,IAAM,KAAW,KAAK,cAC1B,EAAQ,CAAQ,CAElB,EACA,qBA9BuB,GAAyB,CAChD,EAAQ,uBAAuB,CAAM,EACrC,EAAQ,gBAAgB,CAAM,EAC1B,IAAW,WAAa,IAC3B,EAAiB,EACjB,EAAmB,MAEhB,IAAW,SAAW,IACzB,EAAe,EACf,EAAiB,MAEd,IAAW,SACd,EAAU,UAAU,CAEtB,EAiBC,iBAAmB,GAAW,CAC7B,KAAK,YAAY,iBAAkB,CAAM,EACzC,IAAwB,CAAM,EAC9B,KAAK,mBAAmB,CAAM,CAC/B,EACA,oBAAsB,GAAU,CAC/B,KAAK,YAAY,oBAAqB,CAAK,CAC5C,EACA,kBAAoB,GAAU,CAC7B,KAAK,YAAY,kBAAmB,CAAK,CAC1C,EACA,yBAA2B,GAAgC,CAC1D,KAAK,YAAY,yBAA0B,CAAK,CACjD,EACA,uBAAyB,GAAgC,CACxD,KAAK,YAAY,uBAAwB,CAAK,CAC/C,EACA,wBAA0B,GAAU,CACnC,KAAK,YAAY,wBAAyB,CAAK,CAChD,EACA,iBAAmB,GAAc,CAChC,KAAK,YAAY,iBAAkB,CAAS,CAC7C,EACA,iBAAmB,GAA8B,CAChD,KAAK,YAAY,iBAAkB,CAAQ,CAC5C,EACA,WAAa,GAAW,CACvB,KAAK,YAAY,WAAY,CAAM,CACpC,EACA,iBAAmB,GAAU,CAC5B,KAAK,YAAY,iBAAkB,CAAK,CACzC,EACA,UAAY,GAAY,CACvB,KAAK,YAAY,UAAW,CAAO,CACpC,EACA,UAAY,GAAU,CAChB,KAAK,kBACT,KAAK,gBAAkB,KAAK,YAAY,UAAW,CAAK,EACxD,KAAU,UAAU,UAAU,CAAK,EAErC,EACA,qBAAuB,GAAiB,CACvC,KAAK,kBAAoB,EACzB,KAAK,YAAY,qBAAsB,CAAY,CACpD,EACA,kBAAqB,EAAQ,gBAAgB,EAC7C,mBAAsB,EAAQ,iBAAiB,EAC/C,qBAAwB,EAAQ,mBAAmB,EACnD,sBAAwB,GAAS,EAAQ,wBAAwB,CAAI,EACrE,kBAAoB,GAAU,EAAQ,oBAAoB,CAAK,EAC/D,iBAAmB,GAAU,EAAQ,mBAAmB,CAAK,EAC7D,gBAAkB,GAAU,EAAQ,kBAAkB,CAAK,CAC5D,CAAC,EACD,KAAK,WAAa,EAElB,IAAM,EAAkB,KAAK,uBAAuB,EAE9C,EACL,KAAK,UAAU,OAAS,mBAErB,KAAK,wBAA0B,IAAI,gBAC5B,GAAmB,KAAK,UAAU,gBAAiB,CACzD,aAAc,KAAK,UAAU,aAC7B,OAAQ,KAAK,UAAU,OACvB,gBAAiB,KAAK,UAAU,gBAChC,eAAgB,KAAK,UAAU,eAC/B,SAAU,KAAK,UAAU,SACzB,KAAM,EAAgB,KACtB,gBAAiB,EAAgB,gBACjC,WAAY,KAAK,UAAU,WAC3B,YAAa,KAAK,UAAU,YAC5B,OAAQ,KAAK,wBAAwB,MACtC,CAAC,GAED,KAAK,UAAU,OAAS,SACvB,GAAmB,KAAK,UAAU,aAAc,CAChD,OAAQ,KAAK,UAAU,OACvB,gBAAiB,KAAK,UAAU,gBAChC,eAAgB,KAAK,UAAU,eAC/B,SAAU,KAAK,UAAU,SACzB,KAAM,EAAgB,KACtB,gBAAiB,EAAgB,gBACjC,WAAY,KAAK,UAAU,WAC3B,YAAa,KAAK,UAAU,WAC7B,CAAC,EACA,QAAQ,QACR,KAAK,UAAU,QACZ,CAAE,QAAS,KAAK,UAAU,QAAS,OAAQ,KAAK,UAAU,MAAO,EACjE,IACJ,EAEA,EACJ,GAAI,CACH,EAAG,GAAkB,MAAM,QAAQ,IAAI,CAAC,EAAW,YAAY,EAAG,CAAa,CAAC,CACjF,OAAS,EAAO,CAKf,MAJA,EAAW,QAAQ,EACf,KAAK,aAAe,IACvB,KAAK,WAAa,MAEb,CACP,QAAU,CACT,KAAK,wBAA0B,IAChC,CACA,EAAW,gBAAgB,EAE3B,IAAM,EACL,GAAgB,SACf,KAAK,UAAU,OAAS,SAAW,KAAK,UAAU,OAAS,MACvD,EACL,GAAgB,UACf,KAAK,UAAU,OAAS,SAAW,KAAK,UAAU,QAAU,IAAA,IAE9D,GAAI,CAAC,EAKJ,MAJA,EAAW,QAAQ,EACf,KAAK,aAAe,IACvB,KAAK,WAAa,MAET,MAAM,yDAAyD,EAG1E,KAAK,YAAc,EACnB,IAAM,EACL,IACC,KAAK,UAAU,OAAS,SAAW,KAAK,UAAU,QAAU,IAAA,IAmD9D,OAlDI,GAAiB,CAAC,KAAK,wBAC1B,KAAK,gBAAkB,EACvB,KAAK,sBAAwB,KAAK,YAAY,gBAAiB,CAC9D,QAAS,CACV,CAAC,GAEE,GACH,KAAK,gBAAkB,EAEnB,KAAK,UAAU,OAAS,UAC3B,EAAyB,CAAO,EAEjC,EAAW,WAAW,EAAa,EAAS,CAC3C,YAAa,EAAQ,YACrB,MAAO,EAAQ,MACf,aAAc,EAAQ,YACvB,CAAC,EACD,EAAU,SAAS,CAAO,GAE1B,EAAW,WAAW,EAAa,IAAA,GAAW,CAC7C,YAAa,EAAQ,YACrB,MAAO,EAAQ,MACf,aAAc,EAAQ,YACvB,CAAC,EAGF,MAAM,QAAQ,KAAK,CAClB,EACA,IAAI,SAAe,EAAG,IAAW,CAChC,eACO,EAAW,MAAM,0CAA0C,CAAC,EAClE,IACD,CACD,CAAC,CACF,CAAC,EAED,MAAM,QAAQ,KAAK,CAClB,EACA,IAAI,SAAe,EAAG,IAAW,CAChC,eACO,EAAW,MAAM,2CAA2C,CAAC,EACnE,IACD,CACD,CAAC,CACF,CAAC,EAED,KAAK,SAAW,GACZ,KAAK,YACR,MAAM,EAAW,OAAO,KAAK,UAAU,EAEjC,KAAK,mBAAmB,CAChC,CAEA,MAAM,gBAAgC,CACrC,KAAK,qBAAqB,EAC1B,MAAM,KAAK,WAAY,eAAe,CACvC,CAEA,MAAM,eAA0C,CAE/C,OADA,KAAK,qBAAqB,EACnB,KAAK,WAAY,cAAc,CACvC,CAEA,MAAM,WAAW,EAAuD,CAEvE,OADA,KAAK,qBAAqB,EACnB,KAAK,WAAY,WAAW,CAClC,UAAW,GAAS,SACrB,CAAC,CACF,CAEA,iBAAkD,CACjD,OAAO,KAAK,iBACb,CAGA,gBAAgB,EAA6D,CAC5E,KAAK,YAAY,oBAAoB,CAAI,CAC1C,CAGA,qBAA4B,CAC3B,KAAK,YAAY,8BAA8B,CAChD,CAGA,MAAM,eAAe,EAAoC,CACxD,KAAK,qBAAqB,EAC1B,MAAM,KAAK,WAAY,eAAe,CAAW,CAClD,CAGA,MAAM,OAAO,EAAmC,CAC/C,IAAM,EAAS,GAAmB,CAAG,EACrC,GAAI,CAAC,EACJ,MAAU,MAAM,8CAA8C,EAE/D,GAAI,KAAK,OACR,MAAU,MAAM,oBAAoB,EAErC,KAAK,WAAa,EACd,GAAC,KAAK,UAAY,CAAC,KAAK,aAC5B,MAAM,KAAK,WAAW,OAAO,CAAM,CACpC,CAGA,MAAM,WAAW,EAA4B,CAC5C,GAAI,KAAK,OACR,MAAU,MAAM,oBAAoB,EAErC,GAAI,CAAC,KAAK,WACT,MAAU,MAAM,uCAAuC,EAExD,MAAM,KAAK,WAAW,WAAW,CAAG,CACrC,CAGA,MAAM,QAAwB,CAC7B,GAAI,KAAK,OACR,MAAU,MAAM,oBAAoB,EAErC,GAAI,CAAC,KAAK,WACT,MAAU,MAAM,mCAAmC,EAEpD,MAAM,KAAK,WAAW,OAAO,CAC9B,CAEA,aAA8C,CAC7C,GAAI,KAAK,kBAAkB,SAAW,EAAG,MAAO,CAAC,EACjD,IAAM,EAAa,KAAK,kBAAkB,KAAK,kBAAkB,OAAS,GAAI,OAC9E,OAAO,KAAK,kBAAkB,OAAQ,GAAM,EAAE,SAAW,CAAU,CACpE,CAEA,MAAM,KAAqB,CAC1B,KAAK,MAAM,CACZ,CAEA,SAAgB,CACX,KAAK,SACT,KAAK,OAAS,GACd,KAAK,0BAA0B,MAAM,EACrC,KAAK,yBAA2B,KAChC,KAAK,yBAAyB,MAAM,EACpC,KAAK,wBAA0B,KAC/B,KAAK,eAAiB,KACtB,KAAK,YAAY,QAAQ,EACzB,KAAK,WAAa,KAClB,GAA6B,KAAK,aAAa,EAC/C,KAAK,cAAgB,KACrB,KAAK,gBAAkB,KACvB,KAAK,cAAc,OAAS,EAC5B,KAAK,SAAW,GACjB,CAEA,wBAGE,CAID,OAHI,KAAK,UAAU,OAAS,SACpB,CAAC,EAEF,CACN,KAAM,KAAK,UAAU,KACrB,gBAAiB,KAAK,UAAU,eACjC,CACD,CAEA,cAA+B,CAC9B,OAAO,KAAK,iBAAiB,IAAM,EACpC,CAEA,YACC,EACA,EACsB,CACtB,IAAM,EAAW,GAA8B,EAAO,KAAK,aAAa,EAAG,CAAI,EAE/E,OADA,GAAoB,KAAK,cAAe,EAAO,CAAQ,EAChD,CACR,CAEA,mBAA2B,EAAoC,CAC9D,GAAI,CAAC,EAAO,SAAW,CAAC,EAAO,KAAK,KAAK,GAAK,CAAC,KAAK,sBAAuB,OAE3E,IAAM,EAAY,KAAK,sBACvB,KAAK,0BAA0B,MAAM,EACrC,KAAK,yBAA2B,IAAI,gBACpC,IAAM,EAAS,KAAK,yBAAyB,OAE7C,KAAK,eAAiB,KAAK,eAAe,KAAK,SAAY,CACtD,MAAO,QACX,GAAI,CACH,IAAM,EAAW,MAAM,GAA8B,EAAW,CAC/D,YAAa,EAAO,YACpB,KAAM,EAAO,KACb,aAAc,KAAK,kBACnB,QACD,CAAC,EACD,GAAI,EAAO,QAAS,OACpB,GAAI,EAAS,OAAS,WAAY,CACjC,IAAM,EAAS,EAAS,OACxB,MAAM,KAAK,OAAO,MAAM,CACvB,KAAM,EAAO,KACb,GAAI,EAAO,YAAc,CAAE,YAAa,EAAO,WAAY,EAAI,CAAC,EAChE,MAAO,EAAO,WAAa,YAAc,iBAAmB,QAC7D,CAAC,EACD,MACD,CACA,MAAM,KAAK,WAAY,qBAAqB,EAAS,OAAQ,CAAE,QAAO,CAAC,CACxE,OAAS,EAAO,CACf,GAAI,EAAO,QAAS,OACpB,IAAM,EAAU,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EACrE,KAAK,YAAY,6BAA8B,CAC9C,YAAa,EAAO,YACpB,SACD,CAAC,CACF,CACD,CAAC,CACF,CAEA,gBAA+B,CAC9B,GAAI,CAAC,KAAK,UAAY,CAAC,KAAK,WAC3B,MAAU,MAAM,oDAAoD,CAEtE,CAEA,sBAAqC,CAEpC,GADA,KAAK,eAAe,EAChB,CAAC,KAAK,gBACT,MAAU,MACT,yHACD,CAEF,CAEA,OAAsB,CACjB,KAAK,SACT,KAAK,OAAS,GACd,KAAK,yBAAyB,MAAM,EACpC,KAAK,wBAA0B,KAC/B,KAAK,eAAiB,KACtB,KAAK,YAAY,QAAQ,EACzB,KAAK,WAAa,KAClB,KAAK,SAAW,GACjB,CAEA,oBAA4C,CAC3C,MAAO,CACN,UAAa,CACZ,KAAK,MAAM,CACZ,EACA,YAAe,CACd,KAAK,QAAQ,CACd,EACA,IAAK,EAAO,IAAY,CACnB,IAAU,SACb,KAAK,cAAc,KAAK,CAAO,CAEjC,CACD,CACD,CACD,EAKA,SAAS,GAA0B,EAA6C,CAI/E,OAHK,EAGE,CACN,WAAY,EAAQ,aAAa,OAAO,OACxC,oBAAqB,EAAQ,aAAa,OAAO,aAClD,EALQ,CAAE,WAAY,GAAM,oBAAqB,EAAK,CAMvD,OCv2BA,QAAO,QAAU,CAChB,aACA,WAAY,KACZ,SAAU,CACT,SAAU,GACV,eAAgB,EACjB,CACD"}
|
|
1
|
+
{"version":3,"file":"client.js","names":[],"sources":["../../../src/shims/localStack.ts","../../../src/shims/apiBaseUrl.ts","../../../src/v2/errors/LiformaError.ts","../../../src/v2/api/captureAttribution.ts","../../../src/v2/api/sessionEndpointRequest.ts","../../../src/v2/types/sessionLaunch.ts","../../../src/v2/api/mintPublicSession.ts","../../../src/v2/conversationProcessor.ts","../../../src/v2/embed/playerReachability.ts","../../../src/v2/embed/protocol.ts","../../../src/v2/embed/fullWindowHost.ts","../../../src/v2/embed/iframeHost.ts","../../../src/v2/embed/readyGate.ts","../../../package.json","../../../src/v2/sdkRelease.ts","../../../src/v2/shims/embedBaseUrl.ts","../../../src/v2/experienceEvents.ts","../../../src/v2/speech/types.ts","../../../src/byo/pcm.ts","../../../src/byo/resample.ts","../../../src/byo/audioCapture.ts","../../../src/v2/speech/captureMediaStreamTrack.ts","../../../src/v2/speech/speechController.ts","../../../src/v2/types/sessionInteraction.ts","../../../src/v2/experience.ts","../../../src/v2/index.ts"],"sourcesContent":["/**\n * Opt-in local monorepo stack (api :3001, player :3002).\n * Never inferred from hostname alone — third-party demos run on localhost against production.\n */\nexport function useExplicitLocalStack(): boolean {\n\tif ((globalThis as { __LIFORMA_STACK?: string }).__LIFORMA_STACK === 'local') {\n\t\treturn true;\n\t}\n\n\tif (typeof location === 'undefined') {\n\t\treturn false;\n\t}\n\n\ttry {\n\t\treturn new URLSearchParams(location.search).get('stack') === 'local';\n\t} catch {\n\t\treturn false;\n\t}\n}\n","import { useExplicitLocalStack } from './localStack';\n\nconst PRODUCTION_API_BASE_URL = 'https://api.liforma.ai';\nconst LOCAL_API_BASE_URL = 'http://localhost:3001';\n\nfunction readConfiguredApiBaseUrl(): string | null {\n\tconst globalValue = (globalThis as { __LIFORMA_API_BASE_URL?: string }).__LIFORMA_API_BASE_URL;\n\tif (globalValue?.trim()) {\n\t\treturn globalValue.trim().replace(/\\/$/, '');\n\t}\n\n\tif (typeof document === 'undefined') {\n\t\treturn null;\n\t}\n\n\tconst script =\n\t\tdocument.querySelector('script[data-liforma-sdk][src*=\"client.js\"]') ??\n\t\tdocument.querySelector('script[src*=\"/sdk/v2/client.js\"]');\n\tconst fromScript = script?.getAttribute('data-api-base-url')?.trim();\n\tif (fromScript) {\n\t\treturn fromScript.replace(/\\/$/, '');\n\t}\n\n\treturn null;\n}\n\n/**\n * Browser-visible API origin for Liforma HTTP calls from the CDN SDK.\n *\n * Defaults to production. Local stack is opt-in only — never inferred from\n * `localhost` hostname (third-party demos run on localhost against production).\n *\n * Override order:\n * 1. `window.__LIFORMA_API_BASE_URL`\n * 2. `data-api-base-url` on the SDK script tag\n * 3. `window.__LIFORMA_STACK === 'local'` or host `?stack=local` → http://localhost:3001\n * 4. production default → https://api.liforma.ai\n */\nexport function resolvePublicApiBaseUrl(): string {\n\tconst configured = readConfiguredApiBaseUrl();\n\tif (configured) {\n\t\treturn configured;\n\t}\n\n\tif (useExplicitLocalStack()) {\n\t\treturn LOCAL_API_BASE_URL;\n\t}\n\n\treturn PRODUCTION_API_BASE_URL;\n}\n","/**\n * Structured API / mint error from Liforma.\n * Prefer `.code` and `.requestId` over parsing `.message`.\n */\nexport class LiformaError extends Error {\n\treadonly code: string;\n\treadonly requestId: string | undefined;\n\treadonly status: number | undefined;\n\treadonly details: Record<string, unknown> | undefined;\n\n\tconstructor(\n\t\tmessage: string,\n\t\toptions?: {\n\t\t\treadonly code?: string;\n\t\t\treadonly requestId?: string;\n\t\t\treadonly status?: number;\n\t\t\treadonly details?: Record<string, unknown>;\n\t\t\treadonly cause?: unknown;\n\t\t}\n\t) {\n\t\tsuper(message, options?.cause !== undefined ? { cause: options.cause } : undefined);\n\t\tthis.name = 'LiformaError';\n\t\tthis.code = options?.code?.trim() || 'UNKNOWN';\n\t\tthis.requestId = options?.requestId?.trim() || undefined;\n\t\tthis.status = options?.status;\n\t\tthis.details = options?.details;\n\t}\n}\n\ntype NestedErrorShape = {\n\treadonly error?: {\n\t\treadonly code?: unknown;\n\t\treadonly message?: unknown;\n\t\treadonly requestId?: unknown;\n\t\treadonly [key: string]: unknown;\n\t};\n\treadonly code?: unknown;\n\treadonly message?: unknown;\n\treadonly requestId?: unknown;\n};\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n\tif (!value || typeof value !== 'object' || Array.isArray(value)) return undefined;\n\treturn value as Record<string, unknown>;\n}\n\n/**\n * Parse a mint/API error response body + optional `Liforma-Request-Id` header\n * into a {@link LiformaError}. Falls back to flat `{ code, message }` shapes.\n */\nexport function liformaErrorFromResponse(\n\tstatus: number,\n\ttext: string,\n\theaders?: Headers\n): LiformaError {\n\tconst headerRequestId = headers?.get('Liforma-Request-Id')?.trim() || undefined;\n\tlet parsed: NestedErrorShape | undefined;\n\ttry {\n\t\tparsed = JSON.parse(text) as NestedErrorShape;\n\t} catch {\n\t\t/* keep */\n\t}\n\n\tconst nested = parsed?.error && typeof parsed.error === 'object' ? parsed.error : undefined;\n\tconst codeRaw = nested?.code ?? parsed?.code;\n\tconst messageRaw = nested?.message ?? parsed?.message;\n\tconst requestIdRaw = nested?.requestId ?? parsed?.requestId ?? headerRequestId;\n\n\tconst code = typeof codeRaw === 'string' && codeRaw.trim() ? codeRaw.trim() : 'HTTP_ERROR';\n\tconst message =\n\t\ttypeof messageRaw === 'string' && messageRaw.trim()\n\t\t\t? messageRaw.trim()\n\t\t\t: text.trim().slice(0, 500) || `Request failed (${status})`;\n\tconst requestId =\n\t\ttypeof requestIdRaw === 'string' && requestIdRaw.trim() ? requestIdRaw.trim() : headerRequestId;\n\n\tconst details = asRecord(nested) ?? asRecord(parsed);\n\tconst { code: _c, message: _m, requestId: _r, ...rest } = details ?? {};\n\tvoid _c;\n\tvoid _m;\n\tvoid _r;\n\n\treturn new LiformaError(message, {\n\t\tcode,\n\t\trequestId,\n\t\tstatus,\n\t\tdetails: Object.keys(rest).length > 0 ? rest : undefined\n\t});\n}\n","export type ExperienceAttribution = {\n\treadonly utmSource?: string;\n\treadonly utmMedium?: string;\n\treadonly utmCampaign?: string;\n\treadonly utmContent?: string;\n\treadonly utmTerm?: string;\n\treadonly referrer?: string;\n};\n\nconst ATTR_MAX = 128;\nconst CONTROL = /[\\u0000-\\u001f\\u007f]/g;\n\nfunction bound(value: string | null | undefined): string | undefined {\n\tif (!value) return undefined;\n\tconst trimmed = value.replace(CONTROL, '').trim();\n\tif (!trimmed) return undefined;\n\treturn trimmed.slice(0, ATTR_MAX);\n}\n\nfunction utmFromSearch(search: string | null | undefined): ExperienceAttribution {\n\tconst params = new URLSearchParams((search ?? '').startsWith('?') ? (search ?? '').slice(1) : (search ?? ''));\n\treturn {\n\t\t...(bound(params.get('utm_source')) ? { utmSource: bound(params.get('utm_source')) } : {}),\n\t\t...(bound(params.get('utm_medium')) ? { utmMedium: bound(params.get('utm_medium')) } : {}),\n\t\t...(bound(params.get('utm_campaign')) ? { utmCampaign: bound(params.get('utm_campaign')) } : {}),\n\t\t...(bound(params.get('utm_content')) ? { utmContent: bound(params.get('utm_content')) } : {}),\n\t\t...(bound(params.get('utm_term')) ? { utmTerm: bound(params.get('utm_term')) } : {})\n\t};\n}\n\nexport function resolveMintAttribution(\n\tattribution: ExperienceAttribution | false | undefined\n): ExperienceAttribution | undefined {\n\tif (attribution === false) return undefined;\n\tif (attribution && typeof attribution === 'object') {\n\t\tconst explicit: ExperienceAttribution = {\n\t\t\t...(bound(attribution.utmSource) ? { utmSource: bound(attribution.utmSource) } : {}),\n\t\t\t...(bound(attribution.utmMedium) ? { utmMedium: bound(attribution.utmMedium) } : {}),\n\t\t\t...(bound(attribution.utmCampaign) ? { utmCampaign: bound(attribution.utmCampaign) } : {}),\n\t\t\t...(bound(attribution.utmContent) ? { utmContent: bound(attribution.utmContent) } : {}),\n\t\t\t...(bound(attribution.utmTerm) ? { utmTerm: bound(attribution.utmTerm) } : {}),\n\t\t\t...(bound(attribution.referrer) ? { referrer: bound(attribution.referrer) } : {})\n\t\t};\n\t\treturn Object.keys(explicit).length ? explicit : undefined;\n\t}\n\tif (typeof window === 'undefined') return undefined;\n\tconst fromPage = utmFromSearch(window.location?.search);\n\tconst referrer = bound(document.referrer || undefined);\n\tconst auto: ExperienceAttribution = {\n\t\t...fromPage,\n\t\t...(referrer ? { referrer } : {})\n\t};\n\treturn Object.keys(auto).length ? auto : undefined;\n}\n","import { resolveMintAttribution } from './captureAttribution';\n\nexport type SessionEndpointRequestOptions = {\n\treadonly experienceId: string;\n\t/** BCP 47 locale (preferred). When omitted in the browser, defaults to `navigator.language`. */\n\treadonly locale?: string;\n\t/** Paired / learning language for dual experiences (BCP 47). */\n\treadonly secondaryLocale?: string;\n\t/** Alias of `secondaryLocale` — language-learning apps (tutors + roleplay). */\n\treadonly learningLocale?: string;\n\t/** @deprecated Prefer `locale`. */\n\treadonly language?: 'en' | 'es' | string;\n\treadonly mode?: 'conversation' | 'presenter';\n\treadonly speechInputMode?: 'auto' | 'manual' | 'off';\n\treadonly speechOnly?: boolean;\n\t/** Optional Idempotency-Key header value (max 256 chars). */\n\treadonly idempotencyKey?: string;\n\treadonly attribution?: import('./captureAttribution').ExperienceAttribution | false;\n\t/**\n\t * Conversion keys this play is already ineligible for (for example `registration`).\n\t */\n\treadonly alreadyConverted?: readonly string[];\n};\n\nfunction resolveLocale(options: SessionEndpointRequestOptions): string | undefined {\n\tconst locale = options.locale?.trim();\n\tif (locale) return locale;\n\tconst language = options.language?.trim();\n\tif (language) return language;\n\tif (typeof navigator !== 'undefined' && navigator.language?.trim()) {\n\t\treturn navigator.language.trim();\n\t}\n\treturn undefined;\n}\n\nfunction resolveSecondaryLocale(options: SessionEndpointRequestOptions): string | undefined {\n\tconst secondary = options.secondaryLocale?.trim();\n\tconst learning = options.learningLocale?.trim();\n\tif (secondary && learning && secondary !== learning) {\n\t\tthrow new Error(\n\t\t\t'secondaryLocale and learningLocale disagree; pass only one or make them equal.'\n\t\t);\n\t}\n\treturn secondary || learning || undefined;\n}\n\nexport function createSessionEndpointRequest(\n\tsessionEndpoint: string,\n\toptions: SessionEndpointRequestOptions\n): { readonly url: string; readonly init: RequestInit } {\n\tconst endpoint = sessionEndpoint.trim();\n\tif (!endpoint) {\n\t\tthrow new Error('sessionEndpoint must not be empty.');\n\t}\n\tif (typeof location === 'undefined') {\n\t\tthrow new Error('sessionEndpoint is only available in a browser.');\n\t}\n\n\tconst url = new URL(endpoint, location.href);\n\tif (url.origin !== location.origin) {\n\t\tthrow new Error('sessionEndpoint must be same-origin.');\n\t}\n\n\tconst experienceId = options.experienceId.trim();\n\tif (!experienceId) {\n\t\tthrow new Error('sessionEndpoint requires experienceId.');\n\t}\n\n\tconst locale = resolveLocale(options);\n\tconst secondaryLocale = resolveSecondaryLocale(options);\n\tconst idempotencyKey = options.idempotencyKey?.trim();\n\n\treturn {\n\t\turl: url.toString(),\n\t\tinit: {\n\t\t\tmethod: 'POST',\n\t\t\tcredentials: 'same-origin',\n\t\t\theaders: {\n\t\t\t\tAccept: 'application/json',\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t...(idempotencyKey ? { 'Idempotency-Key': idempotencyKey } : {})\n\t\t\t},\n\t\t\tbody: JSON.stringify({\n\t\t\t\texperienceId,\n\t\t\t\t...(locale ? { locale } : {}),\n\t\t\t\t...(secondaryLocale ? { secondaryLocale } : {}),\n\t\t\t\t...(options.mode ? { mode: options.mode } : {}),\n\t\t\t\t...(options.speechInputMode ? { speechInputMode: options.speechInputMode } : {}),\n\t\t\t\t...(options.speechOnly !== undefined ? { speechOnly: options.speechOnly } : {}),\n\t\t\t\t...(() => {\n\t\t\t\t\tconst attribution = resolveMintAttribution(options.attribution);\n\t\t\t\t\treturn attribution ? { attribution } : {};\n\t\t\t\t})(),\n\t\t\t\t...(options.alreadyConverted?.length\n\t\t\t\t\t? { alreadyConverted: [...options.alreadyConverted] }\n\t\t\t\t\t: {})\n\t\t\t})\n\t\t}\n\t};\n}\n","/**\n * Public Session Launch contract (integrator-facing).\n * Runtime internals live inside the opaque `launch` string — do not parse it.\n */\n\nexport type SessionCapabilities = {\n\treadonly speech: { readonly input: boolean; readonly output: boolean; readonly externalAudio: boolean };\n\treadonly conversation: { readonly managed: boolean };\n\treadonly avatar: { readonly enabled: boolean };\n\treadonly tools: { readonly enabled: boolean };\n};\n\nexport type SessionMode = 'conversation' | 'presenter';\n\nexport type SessionStatus = 'active' | 'ended';\n\n/** Mint collapsed a non-English locale onto English because TTS cannot synthesize it. */\nexport type LocaleVoiceFallback = {\n\treadonly axis: 'locale' | 'secondaryLocale';\n\treadonly requested: string;\n\treadonly resolved: string;\n\treadonly reason: 'voice_unsupported';\n};\n\nexport type Session = {\n\treadonly id: string;\n\treadonly experienceId: string;\n\treadonly experienceRevisionId: string;\n\treadonly expiresAt: string;\n\treadonly locale: string;\n\t/** Paired / learning language when dual; omitted for plain sessions. */\n\treadonly secondaryLocale?: string;\n\treadonly mode: SessionMode;\n\treadonly capabilities: SessionCapabilities;\n\treadonly localeVoiceFallbacks?: readonly LocaleVoiceFallback[];\n\t/** Present on mint when RuntimeSession was persisted. */\n\treadonly status?: SessionStatus;\n\treadonly createdAt?: string;\n};\n\nexport type SessionLaunchResponse = {\n\treadonly session: Session;\n\t/**\n\t * Asymmetrically signed opaque runtime bootstrap for the player.\n\t * Contract-opaque (unsupported to parse), not confidentiality-opaque.\n\t */\n\treadonly launch: string;\n};\n\nexport type PlayerStatus = 'loading' | 'scene' | 'ready' | 'error';\n\n/** Listening / speaking activity (replaces overloaded modeChange). */\nexport type SessionActivity = 'idle' | 'listening' | 'thinking' | 'speaking';\n\nexport type CloseButtonOptions = {\n\treadonly visible?: boolean;\n\treadonly style?: 'icon' | 'text';\n\treadonly label?: string | null;\n\treadonly position?: string;\n};\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isBoolean(value: unknown): value is boolean {\n\treturn typeof value === 'boolean';\n}\n\nfunction parseNestedCapabilities(raw: unknown): SessionCapabilities | null {\n\tif (!isRecord(raw)) return null;\n\tconst speech = raw.speech;\n\tconst conversation = raw.conversation;\n\tconst avatar = raw.avatar;\n\tconst tools = raw.tools;\n\tif (\n\t\t!isRecord(speech) ||\n\t\t!isRecord(conversation) ||\n\t\t!isRecord(avatar) ||\n\t\t!isRecord(tools) ||\n\t\t!isBoolean(speech.input) ||\n\t\t!isBoolean(speech.output) ||\n\t\t!isBoolean(speech.externalAudio) ||\n\t\t!isBoolean(conversation.managed) ||\n\t\t!isBoolean(avatar.enabled) ||\n\t\t!isBoolean(tools.enabled)\n\t) {\n\t\treturn null;\n\t}\n\treturn {\n\t\tspeech: {\n\t\t\tinput: speech.input,\n\t\t\toutput: speech.output,\n\t\t\texternalAudio: speech.externalAudio\n\t\t},\n\t\tconversation: { managed: conversation.managed },\n\t\tavatar: { enabled: avatar.enabled },\n\t\ttools: { enabled: tools.enabled }\n\t};\n}\n\n/** @deprecated Flat capabilities from pre-v1 mint responses. */\nfunction parseLegacyFlatCapabilities(raw: unknown): SessionCapabilities | null {\n\tif (!isRecord(raw)) return null;\n\tif (\n\t\t!isBoolean(raw.avatar) ||\n\t\t!isBoolean(raw.speechInput) ||\n\t\t!isBoolean(raw.speechOutput) ||\n\t\t!isBoolean(raw.tools) ||\n\t\t!isBoolean(raw.externalAudio)\n\t) {\n\t\treturn null;\n\t}\n\treturn {\n\t\tspeech: {\n\t\t\tinput: raw.speechInput,\n\t\t\toutput: raw.speechOutput,\n\t\t\texternalAudio: raw.externalAudio\n\t\t},\n\t\tconversation: { managed: true },\n\t\tavatar: { enabled: raw.avatar },\n\t\ttools: { enabled: raw.tools }\n\t};\n}\n\nfunction parseCapabilities(raw: unknown): SessionCapabilities | null {\n\treturn parseNestedCapabilities(raw) ?? parseLegacyFlatCapabilities(raw);\n}\n\nexport function parseSession(raw: unknown): Session {\n\tif (!isRecord(raw)) {\n\t\tthrow new Error('Session Launch response is missing session.');\n\t}\n\tconst id = typeof raw.id === 'string' ? raw.id.trim() : '';\n\tconst experienceId = typeof raw.experienceId === 'string' ? raw.experienceId.trim() : '';\n\tconst experienceRevisionId =\n\t\ttypeof raw.experienceRevisionId === 'string' ? raw.experienceRevisionId.trim() : '';\n\tconst expiresAt = typeof raw.expiresAt === 'string' ? raw.expiresAt.trim() : '';\n\tconst locale = typeof raw.locale === 'string' ? raw.locale.trim() : '';\n\tconst secondaryLocale =\n\t\ttypeof raw.secondaryLocale === 'string' && raw.secondaryLocale.trim()\n\t\t\t? raw.secondaryLocale.trim()\n\t\t\t: undefined;\n\tconst mode = raw.mode === 'conversation' || raw.mode === 'presenter' ? raw.mode : null;\n\tconst capabilities = parseCapabilities(raw.capabilities);\n\tconst localeVoiceFallbacks = parseLocaleVoiceFallbacks(raw.localeVoiceFallbacks);\n\tconst status =\n\t\traw.status === 'active' || raw.status === 'ended' ? raw.status : undefined;\n\tconst createdAt =\n\t\ttypeof raw.createdAt === 'string' && raw.createdAt.trim() ? raw.createdAt.trim() : undefined;\n\n\tif (!id || !experienceId || !experienceRevisionId || !expiresAt || !locale || !mode || !capabilities) {\n\t\tthrow new Error('Session Launch response has an invalid session object.');\n\t}\n\n\treturn {\n\t\tid,\n\t\texperienceId,\n\t\texperienceRevisionId,\n\t\texpiresAt,\n\t\tlocale,\n\t\t...(secondaryLocale ? { secondaryLocale } : {}),\n\t\tmode,\n\t\tcapabilities,\n\t\t...(localeVoiceFallbacks ? { localeVoiceFallbacks } : {}),\n\t\t...(status ? { status } : {}),\n\t\t...(createdAt ? { createdAt } : {})\n\t};\n}\n\nfunction parseLocaleVoiceFallbacks(raw: unknown): readonly LocaleVoiceFallback[] | undefined {\n\tif (!Array.isArray(raw) || raw.length === 0) return undefined;\n\tconst out: LocaleVoiceFallback[] = [];\n\tfor (const item of raw) {\n\t\tif (!isRecord(item)) continue;\n\t\tconst axis = item.axis === 'locale' || item.axis === 'secondaryLocale' ? item.axis : null;\n\t\tconst requested = typeof item.requested === 'string' ? item.requested.trim() : '';\n\t\tconst resolved = typeof item.resolved === 'string' ? item.resolved.trim() : '';\n\t\tif (!axis || !requested || !resolved || item.reason !== 'voice_unsupported') continue;\n\t\tout.push({ axis, requested, resolved, reason: 'voice_unsupported' });\n\t}\n\treturn out.length > 0 ? out : undefined;\n}\n\n/** Browser console warnings when mint fell back to English for voice support. */\nexport function warnLocaleVoiceFallbacks(session: Session): void {\n\tconst fallbacks = session.localeVoiceFallbacks;\n\tif (!fallbacks?.length) return;\n\tfor (const fb of fallbacks) {\n\t\tconst label = fb.axis === 'secondaryLocale' ? 'secondaryLocale' : 'locale';\n\t\tconsole.warn(\n\t\t\t`[liforma] Session ${label} fell back to ${fb.resolved} because the voice does not support ${fb.requested}.`\n\t\t);\n\t}\n}\n\nexport function parseSessionLaunchResponse(raw: unknown): SessionLaunchResponse {\n\tif (!isRecord(raw)) {\n\t\tthrow new Error('Session Launch response must be a JSON object.');\n\t}\n\tconst launch = typeof raw.launch === 'string' ? raw.launch.trim() : '';\n\tif (!launch) {\n\t\tthrow new Error('Session Launch response is missing launch.');\n\t}\n\tconst session = parseSession(raw.session);\n\twarnLocaleVoiceFallbacks(session);\n\treturn {\n\t\tsession,\n\t\tlaunch\n\t};\n}\n","import { resolvePublicApiBaseUrl } from '../../shims/apiBaseUrl';\nimport { LiformaError, liformaErrorFromResponse } from '../errors/LiformaError';\nimport { createSessionEndpointRequest } from './sessionEndpointRequest';\nimport { resolveMintAttribution } from './captureAttribution';\nimport {\n\tparseSessionLaunchResponse,\n\ttype SessionLaunchResponse\n} from '../types/sessionLaunch';\n\nexport type MintBrowserSessionOptions = {\n\t/** BCP 47 locale (preferred). When omitted in the browser, defaults to `navigator.language`. */\n\treadonly locale?: string;\n\t/** Paired / learning language for dual experiences (BCP 47). */\n\treadonly secondaryLocale?: string;\n\t/** Alias of `secondaryLocale` — language-learning apps (tutors + roleplay). */\n\treadonly learningLocale?: string;\n\t/** @deprecated Prefer `locale`. */\n\treadonly language?: 'en' | 'es' | string;\n\treadonly mode?: 'conversation' | 'presenter';\n\treadonly speechInputMode?: 'auto' | 'manual' | 'off';\n\treadonly speechOnly?: boolean;\n\t/** Optional Idempotency-Key header value (max 256 chars). */\n\treadonly idempotencyKey?: string;\n\treadonly attribution?: import('./captureAttribution').ExperienceAttribution | false;\n\treadonly alreadyConverted?: readonly string[];\n};\n\nfunction currentPageOrigin(): string | undefined {\n\ttry {\n\t\tif (typeof globalThis.location?.origin === 'string' && globalThis.location.origin) {\n\t\t\treturn globalThis.location.origin;\n\t\t}\n\t} catch {\n\t\t/* ignore */\n\t}\n\treturn undefined;\n}\n\nfunction normalizeMintErrorCode(code: string | undefined): string {\n\tif (!code) return '';\n\treturn code.trim().toUpperCase().replace(/-/g, '_');\n}\n\nfunction enrichPublicMintError(experienceId: string, err: LiformaError): LiformaError {\n\tconst pageOrigin = currentPageOrigin();\n\tconst code = normalizeMintErrorCode(err.code);\n\tconst apiMessage = err.message.trim();\n\tconst details = err.details ?? {};\n\n\tif (\n\t\tcode === 'ORIGIN_NOT_ALLOWED' ||\n\t\t(/^Origin not allowed/i.test(apiMessage) && pageOrigin)\n\t) {\n\t\tif (apiMessage.includes(experienceId) && apiMessage.includes('allowed origin')) {\n\t\t\treturn err;\n\t\t}\n\t\tconst origin =\n\t\t\t(typeof details.origin === 'string' && details.origin) ||\n\t\t\tpageOrigin ||\n\t\t\t'(unknown origin)';\n\t\treturn new LiformaError(\n\t\t\t`Your origin ${origin} is not an allowed origin for experience ${experienceId}. ` +\n\t\t\t\t`If you own this experience, sign in to the Liforma developer portal (app.liforma.ai), ` +\n\t\t\t\t`open Workspace → Settings → Origins, add ${origin} to the list of allowed origins, ` +\n\t\t\t\t`and ensure “Allow public client-only embeds” is enabled.`,\n\t\t\t{ code: 'ORIGIN_NOT_ALLOWED', requestId: err.requestId, status: err.status, details }\n\t\t);\n\t}\n\n\tif (code === 'BROWSER_EMBEDS_DISABLED' || /^Browser embeds are not enabled/i.test(apiMessage)) {\n\t\tif (apiMessage.includes('Allow public client-only embeds')) {\n\t\t\treturn err;\n\t\t}\n\t\treturn new LiformaError(\n\t\t\t`Browser embeds are not enabled for experience ${experienceId}. ` +\n\t\t\t\t`If you own this experience, sign in to the Liforma developer portal (app.liforma.ai), ` +\n\t\t\t\t`open Workspace → Settings → Origins, and enable “Allow public client-only embeds”.`,\n\t\t\t{\n\t\t\t\tcode: 'BROWSER_EMBEDS_DISABLED',\n\t\t\t\trequestId: err.requestId,\n\t\t\t\tstatus: err.status,\n\t\t\t\tdetails\n\t\t\t}\n\t\t);\n\t}\n\n\tif (\n\t\tcode === 'EXPERIENCE_UNAVAILABLE' ||\n\t\t/^Experience is not available\\.?$/i.test(apiMessage) ||\n\t\t/^Unknown experience\\.?$/i.test(apiMessage)\n\t) {\n\t\tif (apiMessage.includes('No playable experience found')) {\n\t\t\treturn err;\n\t\t}\n\t\treturn new LiformaError(\n\t\t\t`No playable experience found for “${experienceId}”. ` +\n\t\t\t\t`Check that the experience id is correct (it should look like exp_…), ` +\n\t\t\t\t`and that the experience exists and is published in the Liforma developer portal (app.liforma.ai). ` +\n\t\t\t\t`Deleted, archived, and unpublished experiences cannot be started from a browser embed.`,\n\t\t\t{\n\t\t\t\tcode: 'EXPERIENCE_UNAVAILABLE',\n\t\t\t\trequestId: err.requestId,\n\t\t\t\tstatus: err.status,\n\t\t\t\tdetails\n\t\t\t}\n\t\t);\n\t}\n\n\treturn err;\n}\n\nfunction resolveLocale(options?: MintBrowserSessionOptions): string | undefined {\n\tconst locale = options?.locale?.trim();\n\tif (locale) return locale;\n\tconst language = options?.language?.trim();\n\tif (language) return language;\n\tif (typeof navigator !== 'undefined' && navigator.language?.trim()) {\n\t\treturn navigator.language.trim();\n\t}\n\treturn undefined;\n}\n\nfunction resolveSecondaryLocale(options?: MintBrowserSessionOptions): string | undefined {\n\tconst secondary = options?.secondaryLocale?.trim();\n\tconst learning = options?.learningLocale?.trim();\n\tif (secondary && learning && secondary !== learning) {\n\t\tthrow new LiformaError(\n\t\t\t'secondaryLocale and learningLocale disagree; pass only one or make them equal.',\n\t\t\t{ code: 'INVALID_BODY' }\n\t\t);\n\t}\n\treturn secondary || learning || undefined;\n}\n\nfunction buildMintBody(\n\texperienceId: string,\n\toptions?: MintBrowserSessionOptions\n): Record<string, unknown> {\n\tconst body: Record<string, unknown> = { experienceId };\n\tconst locale = resolveLocale(options);\n\tif (locale) body.locale = locale;\n\tconst secondaryLocale = resolveSecondaryLocale(options);\n\tif (secondaryLocale) body.secondaryLocale = secondaryLocale;\n\tif (options?.mode) body.mode = options.mode;\n\tif (options?.speechInputMode) body.speechInputMode = options.speechInputMode;\n\tif (options?.speechOnly !== undefined) body.speechOnly = options.speechOnly;\n\tconst attribution = resolveMintAttribution(options?.attribution);\n\tif (attribution) body.attribution = attribution;\n\tif (options?.alreadyConverted?.length) body.alreadyConverted = [...options.alreadyConverted];\n\treturn body;\n}\n\n/** Mint a browser session via `POST /v1/browser-sessions`. */\nexport async function mintBrowserSession(\n\texperienceId: string,\n\toptions?: MintBrowserSessionOptions\n): Promise<SessionLaunchResponse> {\n\tconst apiBaseUrl = resolvePublicApiBaseUrl();\n\tconst idempotencyKey = options?.idempotencyKey?.trim();\n\tconst res = await fetch(`${apiBaseUrl}/v1/browser-sessions`, {\n\t\tmethod: 'POST',\n\t\theaders: {\n\t\t\t'Content-Type': 'application/json',\n\t\t\t...(idempotencyKey ? { 'Idempotency-Key': idempotencyKey } : {})\n\t\t},\n\t\tbody: JSON.stringify(buildMintBody(experienceId, options))\n\t});\n\n\tif (!res.ok) {\n\t\tconst text = await res.text();\n\t\tthrow enrichPublicMintError(experienceId, liformaErrorFromResponse(res.status, text, res.headers));\n\t}\n\tlet raw: unknown;\n\ttry {\n\t\traw = await res.json();\n\t} catch {\n\t\tthrow new LiformaError('Browser session mint returned invalid JSON.', {\n\t\t\tcode: 'INVALID_RESPONSE',\n\t\t\tstatus: res.status,\n\t\t\trequestId: res.headers.get('Liforma-Request-Id') ?? undefined\n\t\t});\n\t}\n\n\treturn parseSessionLaunchResponse(raw);\n}\n\n/** @deprecated Prefer {@link mintBrowserSession}. */\nexport const mintPublicSession = mintBrowserSession;\n\nexport type FetchSessionLaunchOptions = MintBrowserSessionOptions & {\n\treadonly experienceId: string;\n\treadonly signal?: AbortSignal;\n\treadonly timeoutMs?: number;\n};\n\n/** @deprecated Prefer {@link FetchSessionLaunchOptions}. */\nexport type FetchSessionManifestOptions = FetchSessionLaunchOptions;\n\nexport async function fetchSessionLaunch(\n\tsessionEndpoint: string,\n\toptions: FetchSessionLaunchOptions\n): Promise<SessionLaunchResponse> {\n\tconst request = createSessionEndpointRequest(sessionEndpoint, options);\n\n\tconst controller = new AbortController();\n\tconst abortFromCaller = () => controller.abort(options.signal?.reason);\n\tif (options.signal?.aborted) {\n\t\tabortFromCaller();\n\t} else {\n\t\toptions.signal?.addEventListener('abort', abortFromCaller, { once: true });\n\t}\n\tconst timeoutId = globalThis.setTimeout(\n\t\t() => controller.abort(new DOMException('Session endpoint timed out.', 'TimeoutError')),\n\t\toptions.timeoutMs ?? 30_000\n\t);\n\n\tlet res: Response;\n\ttry {\n\t\tres = await fetch(request.url, {\n\t\t\t...request.init,\n\t\t\tsignal: controller.signal\n\t\t});\n\t} finally {\n\t\tglobalThis.clearTimeout(timeoutId);\n\t\toptions.signal?.removeEventListener('abort', abortFromCaller);\n\t}\n\n\tif (!res.ok) {\n\t\tconst text = await res.text();\n\t\tthrow liformaErrorFromResponse(res.status, text, res.headers);\n\t}\n\tif (!res.headers.get('content-type')?.toLowerCase().includes('application/json')) {\n\t\tthrow new LiformaError('Session endpoint must return a JSON Session Launch response.', {\n\t\t\tcode: 'INVALID_RESPONSE',\n\t\t\tstatus: res.status,\n\t\t\trequestId: res.headers.get('Liforma-Request-Id') ?? undefined\n\t\t});\n\t}\n\n\tlet raw: unknown;\n\ttry {\n\t\traw = await res.json();\n\t} catch {\n\t\tthrow new LiformaError('Session endpoint returned invalid JSON.', {\n\t\t\tcode: 'INVALID_RESPONSE',\n\t\t\tstatus: res.status,\n\t\t\trequestId: res.headers.get('Liforma-Request-Id') ?? undefined\n\t\t});\n\t}\n\n\treturn parseSessionLaunchResponse(raw);\n}\n\n/** @deprecated Prefer {@link fetchSessionLaunch}. */\nexport const fetchSessionManifest = fetchSessionLaunch;\n","import type {\n\tConversationProcessorContext,\n\tConversationProcessorFn,\n\tConversationProcessorResult,\n\tNormalizedProcessorSpeech,\n\tProcessorDispatchResult,\n\tSpeakBehavior\n} from './types/sessionInteraction';\n\nexport function isAsyncIterableString(value: unknown): value is AsyncIterable<string> {\n\tif (value == null || typeof value !== 'object') return false;\n\treturn typeof (value as AsyncIterable<string>)[Symbol.asyncIterator] === 'function';\n}\n\nexport function normalizeConversationProcessorResult(\n\tresult: ConversationProcessorResult\n): NormalizedProcessorSpeech {\n\tif (typeof result === 'string') {\n\t\tconst text = result.trim();\n\t\tif (!text) {\n\t\t\tthrow new Error('conversationProcessor returned empty text.');\n\t\t}\n\t\treturn { text };\n\t}\n\n\tconst text = result.text.trim();\n\tif (!text) {\n\t\tthrow new Error('conversationProcessor returned empty text.');\n\t}\n\n\treturn {\n\t\ttext,\n\t\t...(result.characterId ? { characterId: result.characterId } : {}),\n\t\t...(result.behavior ? { behavior: result.behavior } : {})\n\t};\n}\n\nexport async function runConversationProcessor(\n\tprocessor: ConversationProcessorFn,\n\tcontext: ConversationProcessorContext\n): Promise<NormalizedProcessorSpeech> {\n\tconst dispatch = await dispatchConversationProcessor(processor, context);\n\tif (dispatch.kind !== 'complete') {\n\t\tthrow new Error('conversationProcessor returned a stream; use dispatchConversationProcessor.');\n\t}\n\treturn dispatch.speech;\n}\n\nexport async function dispatchConversationProcessor(\n\tprocessor: ConversationProcessorFn,\n\tcontext: ConversationProcessorContext\n): Promise<ProcessorDispatchResult> {\n\tconst result = await processor(context);\n\tif (isAsyncIterableString(result)) {\n\t\treturn { kind: 'stream', stream: result };\n\t}\n\treturn {\n\t\tkind: 'complete',\n\t\tspeech: normalizeConversationProcessorResult(result)\n\t};\n}\n","const LOCAL_PLAYER_DEV_PORT = '3002';\n\nexport function formatPlayerUnreachableMessage(playerOrigin: string): string {\n\tconst url = new URL(playerOrigin);\n\tconst isLocalHost = url.hostname === 'localhost' || url.hostname === '127.0.0.1';\n\n\tif (isLocalHost) {\n\t\tconst devPort = url.port || LOCAL_PLAYER_DEV_PORT;\n\t\treturn (\n\t\t\t`Cannot connect to the Liforma player at ${playerOrigin} — nothing is listening on port ${devPort}. ` +\n\t\t\t`Start the player dev server in player.liforma.ai (npm run dev).`\n\t\t);\n\t}\n\n\treturn (\n\t\t`Cannot connect to the Liforma player at ${playerOrigin}. ` +\n\t\t`The embed did not load; check your network connection and player URL configuration.`\n\t);\n}\n\nexport async function assertPlayerReachable(\n\tembedUrl: string,\n\tplayerOrigin: string\n): Promise<void> {\n\ttry {\n\t\tawait fetch(embedUrl, {\n\t\t\tmethod: 'GET',\n\t\t\tmode: 'no-cors',\n\t\t\tsignal: AbortSignal.timeout(8_000)\n\t\t});\n\t} catch {\n\t\tthrow new Error(formatPlayerUnreachableMessage(playerOrigin));\n\t}\n}\n\nexport function postMessageToPlayer(\n\ttarget: Window,\n\tmessage: unknown,\n\tplayerOrigin: string,\n\ttransfer?: Transferable[]\n): void {\n\ttry {\n\t\tif (transfer && transfer.length > 0) {\n\t\t\ttarget.postMessage(message, playerOrigin, transfer);\n\t\t} else {\n\t\t\ttarget.postMessage(message, playerOrigin);\n\t\t}\n\t} catch (error) {\n\t\tif (error instanceof DOMException && error.name === 'SecurityError') {\n\t\t\tthrow new Error(formatPlayerUnreachableMessage(playerOrigin), { cause: error });\n\t\t}\n\t\tthrow error;\n\t}\n}\n","import type {\n\tCharacterSpeechEvent,\n\tConversationMessage,\n\tExperienceInteraction,\n\tExperienceInteractionPatch,\n\tSpeakBehavior,\n\tSessionModeChange,\n\tUserSpeechBoundaryEvent,\n\tUserTranscriptUpdate,\n\tUtteranceResult\n} from '../types/sessionInteraction';\nimport type { Session, SessionActivity } from '../types/sessionLaunch';\nimport type { StartButtonOptions, PlayerTheme } from '../types/sessionInteraction';\nimport type {\n\tCompleteSpeechQueuePolicy,\n\tSpeechAudioFormat,\n\tSpeechInterruptOptions,\n\tSpeechPlayEmbedSource,\n\tStreamingSpeechQueuePolicy\n} from '../speech/types';\n\nexport const EMBED_MESSAGE_SCHEMA_VERSION = 2 as const;\n\n/** Outbound postMessage versions accepted from the player embed. */\nexport const SUPPORTED_EMBED_MESSAGE_SCHEMA_VERSIONS: ReadonlySet<number> = new Set([1, 2]);\n\nexport function isSupportedEmbedMessageSchemaVersion(version: unknown): boolean {\n\treturn typeof version === 'number' && SUPPORTED_EMBED_MESSAGE_SCHEMA_VERSIONS.has(version);\n}\n\nexport type CloseEvent = {\n\treadonly sessionId?: string;\n\treadonly reason: 'user' | 'destroy';\n\treadonly returnUrl?: string;\n};\n\nexport type EmbedOutboundMessage =\n\t| {\n\t\t\treadonly type: 'close';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: CloseEvent;\n\t }\n\t| {\n\t\t\treadonly type: 'stateUpdate';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly state: 'loading' | 'scene' | 'ready' | 'error' };\n\t }\n\t| {\n\t\t\treadonly type: 'commandResult';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly ok: boolean;\n\t\t\t\treadonly error?: string;\n\t\t\t\treadonly result?: unknown;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'userTranscript';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: UserTranscriptUpdate;\n\t }\n\t| {\n\t\t\treadonly type: 'characterSpeechStarted';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: CharacterSpeechEvent;\n\t }\n\t| {\n\t\t\treadonly type: 'characterSpeechEnded';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: CharacterSpeechEvent;\n\t }\n\t| {\n\t\t\treadonly type: 'characterFocusChanged';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly characterId: string;\n\t\t\t\treadonly reason: 'speech' | 'api' | 'node_enter';\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'conversationUpdate';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly conversation: readonly ConversationMessage[] };\n\t }\n\t| {\n\t\t\treadonly type: 'listeningState';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly listening: boolean };\n\t }\n\t| {\n\t\t\treadonly type: 'userSpeechStarted';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: UserSpeechBoundaryEvent;\n\t }\n\t| {\n\t\t\treadonly type: 'userSpeechEnded';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: UserSpeechBoundaryEvent;\n\t }\n\t| {\n\t\t\treadonly type: 'modeChange';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly mode: SessionModeChange };\n\t }\n\t| {\n\t\t\treadonly type: 'activityChange';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly activity: SessionActivity };\n\t }\n\t| {\n\t\t\treadonly type: 'feedback';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly contractVersion: 'feedback.v1';\n\t\t\t\treadonly types: readonly {\n\t\t\t\t\treadonly feedbackId: string;\n\t\t\t\t\treadonly name: string;\n\t\t\t\t\treadonly criteria: readonly {\n\t\t\t\t\t\treadonly criterionId: string;\n\t\t\t\t\t\treadonly label: string;\n\t\t\t\t\t\treadonly score: number | string;\n\t\t\t\t\t\treadonly rationale: string;\n\t\t\t\t\t}[];\n\t\t\t\t}[];\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'feedbackFailed';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly error: string; readonly model?: string };\n\t }\n\t| {\n\t\t\treadonly type: 'message';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: ConversationMessage;\n\t }\n\t| {\n\t\t\treadonly type: 'started';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly mode: 'conversation' | 'presenter' };\n\t }\n\t| {\n\t\t\t/**\n\t\t\t * Player document is ready to receive `launch` (iframe HMR / Vite reload).\n\t\t\t * Parent re-posts the last launch token so bootstrap does not hang.\n\t\t\t */\n\t\t\treadonly type: 'embedReady';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t }\n\t| {\n\t\t\treadonly type: 'widgetReady';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: Record<string, never>;\n\t }\n\t| {\n\t\t\treadonly type: 'widgetExpand';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: Record<string, never>;\n\t }\n\t| {\n\t\t\treadonly type: 'widgetCollapse';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: Record<string, never>;\n\t }\n\t| {\n\t\t\treadonly type: 'widgetAudioSettings';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly open: boolean };\n\t }\n\t| {\n\t\t\treadonly type: 'widgetDragStart';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly pointerId: number;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'widgetDragMove';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly pointerId: number;\n\t\t\t\t/** Pointer deltas in CSS pixels (not iframe-local coordinates). */\n\t\t\t\treadonly dx: number;\n\t\t\t\treadonly dy: number;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'widgetDragEnd';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly pointerId: number;\n\t\t\t};\n\t }\n\t| {\n\t\t\t/** Expand / collapse the parent embed host to fill the browser window. */\n\t\t\treadonly type: 'fullWindow';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly active: boolean };\n\t }\n\t| {\n\t\t\treadonly type: 'interactionChange';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly interaction: ExperienceInteraction };\n\t };\n\nexport type WidgetChromeMode = 'collapsed' | 'loading' | 'expanded' | 'docked';\n\nexport type WidgetDragStartEvent = {\n\treadonly pointerId: number;\n};\n\nexport type WidgetDragMoveEvent = {\n\treadonly pointerId: number;\n\treadonly dx: number;\n\treadonly dy: number;\n};\n\n/** @deprecated Prefer WidgetDragStartEvent / WidgetDragMoveEvent */\nexport type WidgetDragPointerEvent = WidgetDragMoveEvent;\n\nexport type EmbedInboundMessage =\n\t| {\n\t\t\treadonly type: 'launch';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly launch: string;\n\t\t\t\treadonly session?: Session | object;\n\t\t\t\t/** Player chrome from attach — not part of the signed launch string. */\n\t\t\t\treadonly startButton?: StartButtonOptions;\n\t\t\t\t/** Global player chrome theme from attach. */\n\t\t\t\treadonly theme?: PlayerTheme;\n\t\t\t\t/**\n\t\t\t\t * When false, player skips Feedback step-through UI (host renders scores).\n\t\t\t\t * Default when omitted: true (player shows Feedback).\n\t\t\t\t */\n\t\t\t\treadonly showFeedback?: boolean;\n\t\t\t\treadonly interaction?: ExperienceInteractionPatch;\n\t\t\t};\n\t }\n\t| {\n\t\t\t/** @deprecated Prefer `launch`. Kept briefly for older players. */\n\t\t\treadonly type: 'manifest';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly manifest: unknown };\n\t }\n\t| {\n\t\t\treadonly type: 'parentHello';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t }\n\t| {\n\t\t\treadonly type: 'speak';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly text: string;\n\t\t\t\treadonly characterId?: string;\n\t\t\t\treadonly behavior?: SpeakBehavior;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'startListening';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly correlationId: string };\n\t }\n\t| {\n\t\t\treadonly type: 'stopListening';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly correlationId: string };\n\t }\n\t| {\n\t\t\treadonly type: 'getConversation';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly correlationId: string };\n\t }\n\t| {\n\t\t\treadonly type: 'listenOnce';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly timeoutMs?: number;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'speakStreamStart';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly characterId?: string;\n\t\t\t\treadonly behavior?: SpeakBehavior;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'speakStreamChunk';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly streamId: string;\n\t\t\t\treadonly text: string;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'speakStreamEnd';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly streamId: string;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'widgetSetChrome';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: { readonly mode: WidgetChromeMode };\n\t }\n\t| {\n\t\t\treadonly type: 'widgetToggleAudioSettings';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: Record<string, never>;\n\t }\n\t| {\n\t\t\treadonly type: 'speechPlay';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly source: SpeechPlayEmbedSource;\n\t\t\t\treadonly characterId?: string;\n\t\t\t\treadonly transcript?: string;\n\t\t\t\treadonly history?: 'none' | 'commit';\n\t\t\t\treadonly queue?: CompleteSpeechQueuePolicy;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'speechUtteranceBegin';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly utteranceId: string;\n\t\t\t\treadonly format: SpeechAudioFormat;\n\t\t\t\treadonly characterId?: string;\n\t\t\t\treadonly queue: StreamingSpeechQueuePolicy;\n\t\t\t\treadonly transcript?: string;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'speechUtteranceWrite';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly utteranceId: string;\n\t\t\t\treadonly audio: ArrayBuffer;\n\t\t\t\treadonly byteLength: number;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'speechUtteranceSetTranscript';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly utteranceId: string;\n\t\t\t\treadonly transcript: string;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'speechUtteranceClose';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly utteranceId: string;\n\t\t\t\treadonly transcript?: string;\n\t\t\t\treadonly history?: 'none' | 'commit';\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'speechUtteranceCancel';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly utteranceId: string;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'speechInterrupt';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t} & SpeechInterruptOptions;\n\t }\n\t| {\n\t\t\treadonly type: 'focusCharacter';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly characterId: string;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'setFit';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly fit: 'full' | 'face' | 'medium';\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'setInteraction';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly interaction: ExperienceInteractionPatch;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'getInteraction';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'conversion';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly key: string;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'engage';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly type: 'reportSdkError';\n\t\t\treadonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;\n\t\t\treadonly payload: {\n\t\t\t\treadonly correlationId: string;\n\t\t\t\treadonly errorCode?: string;\n\t\t\t\treadonly message?: string;\n\t\t\t\treadonly stack?: string;\n\t\t\t\treadonly severity?: 'warning' | 'error' | 'fatal';\n\t\t\t\treadonly operation?: string;\n\t\t\t\t/** SDK package release (e.g. sdk@0.4.8) — not the player deploy SHA. */\n\t\t\t\treadonly release?: string;\n\t\t\t};\n\t };\n\nexport type EmbedState = 'loading' | 'scene' | 'ready' | 'error';\n\nconst OUTBOUND_TYPES = new Set([\n\t'close',\n\t'stateUpdate',\n\t'commandResult',\n\t'userTranscript',\n\t'characterSpeechStarted',\n\t'characterSpeechEnded',\n\t'characterFocusChanged',\n\t'conversationUpdate',\n\t'listeningState',\n\t'userSpeechStarted',\n\t'userSpeechEnded',\n\t'modeChange',\n\t'activityChange',\n\t'feedback',\n\t'feedbackFailed',\n\t'message',\n\t'started',\n\t'embedReady',\n\t'widgetReady',\n\t'widgetExpand',\n\t'widgetCollapse',\n\t'widgetAudioSettings',\n\t'widgetDragStart',\n\t'widgetDragMove',\n\t'widgetDragEnd',\n\t'fullWindow',\n\t'interactionChange'\n]);\n\nfunction isWidgetChromeMode(value: unknown): value is WidgetChromeMode {\n\treturn (\n\t\tvalue === 'collapsed' ||\n\t\tvalue === 'loading' ||\n\t\tvalue === 'expanded' ||\n\t\tvalue === 'docked'\n\t);\n}\n\nexport function parseOutboundMessage(data: unknown): EmbedOutboundMessage | null {\n\tif (!data || typeof data !== 'object') return null;\n\tconst msg = data as Partial<EmbedOutboundMessage>;\n\tif (!isSupportedEmbedMessageSchemaVersion(msg.schemaVersion)) return null;\n\tif (!msg.type || !OUTBOUND_TYPES.has(msg.type)) return null;\n\tif (\n\t\tmsg.type === 'embedReady' ||\n\t\tmsg.type === 'widgetReady' ||\n\t\tmsg.type === 'widgetExpand' ||\n\t\tmsg.type === 'widgetCollapse'\n\t) {\n\t\treturn msg as EmbedOutboundMessage;\n\t}\n\tif (msg.type === 'fullWindow') {\n\t\tconst payload = (msg as { payload?: unknown }).payload;\n\t\tif (!payload || typeof payload !== 'object') return null;\n\t\tif (typeof (payload as { active?: unknown }).active !== 'boolean') return null;\n\t\treturn msg as EmbedOutboundMessage;\n\t}\n\tif (msg.type === 'widgetAudioSettings') {\n\t\tconst payload = (msg as { payload?: unknown }).payload;\n\t\tif (!payload || typeof payload !== 'object') return null;\n\t\tif (typeof (payload as { open?: unknown }).open !== 'boolean') return null;\n\t\treturn msg as EmbedOutboundMessage;\n\t}\n\tif (msg.type === 'widgetDragStart' || msg.type === 'widgetDragEnd') {\n\t\tconst payload = (msg as { payload?: unknown }).payload;\n\t\tif (!payload || typeof payload !== 'object') return null;\n\t\tif (typeof (payload as { pointerId?: unknown }).pointerId !== 'number') return null;\n\t\tif (!Number.isFinite((payload as { pointerId: number }).pointerId)) return null;\n\t\treturn msg as EmbedOutboundMessage;\n\t}\n\tif (msg.type === 'widgetDragMove') {\n\t\tconst payload = (msg as { payload?: unknown }).payload;\n\t\tif (!payload || typeof payload !== 'object') return null;\n\t\tconst { pointerId, dx, dy } = payload as {\n\t\t\tpointerId?: unknown;\n\t\t\tdx?: unknown;\n\t\t\tdy?: unknown;\n\t\t};\n\t\tif (typeof pointerId !== 'number' || !Number.isFinite(pointerId)) return null;\n\t\tif (typeof dx !== 'number' || !Number.isFinite(dx)) return null;\n\t\tif (typeof dy !== 'number' || !Number.isFinite(dy)) return null;\n\t\treturn msg as EmbedOutboundMessage;\n\t}\n\tconst payload = (msg as { payload?: unknown }).payload;\n\tif (!payload || typeof payload !== 'object') return null;\n\treturn msg as EmbedOutboundMessage;\n}\n\nconst INBOUND_TYPES = new Set([\n\t'launch',\n\t'manifest',\n\t'parentHello',\n\t'speak',\n\t'startListening',\n\t'stopListening',\n\t'getConversation',\n\t'listenOnce',\n\t'speakStreamStart',\n\t'speakStreamChunk',\n\t'speakStreamEnd',\n\t'widgetSetChrome',\n\t'widgetToggleAudioSettings',\n\t'speechPlay',\n\t'speechUtteranceBegin',\n\t'speechUtteranceWrite',\n\t'speechUtteranceSetTranscript',\n\t'speechUtteranceClose',\n\t'speechUtteranceCancel',\n\t'speechInterrupt',\n\t'focusCharacter',\n\t'setFit',\n\t'setInteraction',\n\t'getInteraction',\n\t'conversion',\n\t'engage',\n\t'reportSdkError'\n]);\n\nexport function parseInboundMessage(data: unknown): EmbedInboundMessage | null {\n\tif (!data || typeof data !== 'object') return null;\n\tconst msg = data as Partial<EmbedInboundMessage>;\n\tif (!isSupportedEmbedMessageSchemaVersion(msg.schemaVersion)) return null;\n\tif (!msg.type || !INBOUND_TYPES.has(msg.type)) return null;\n\tif (msg.type === 'parentHello') return msg as EmbedInboundMessage;\n\tif (msg.type === 'widgetToggleAudioSettings') return msg as EmbedInboundMessage;\n\tif (msg.type === 'widgetSetChrome') {\n\t\tconst payload = (msg as { payload?: unknown }).payload;\n\t\tif (!payload || typeof payload !== 'object') return null;\n\t\tconst mode = (payload as { mode?: unknown }).mode;\n\t\tif (!isWidgetChromeMode(mode)) return null;\n\t\treturn msg as EmbedInboundMessage;\n\t}\n\tif (msg.type === 'setFit') {\n\t\tconst payload = (msg as { payload?: unknown }).payload;\n\t\tif (!payload || typeof payload !== 'object') return null;\n\t\tconst fit = (payload as { fit?: unknown }).fit;\n\t\tconst correlationId = (payload as { correlationId?: unknown }).correlationId;\n\t\tif (fit !== 'full' && fit !== 'medium' && fit !== 'face') return null;\n\t\tif (typeof correlationId !== 'string' || !correlationId.trim()) return null;\n\t\treturn msg as EmbedInboundMessage;\n\t}\n\tif (msg.type === 'setInteraction') {\n\t\tconst payload = (msg as { payload?: unknown }).payload;\n\t\tif (!payload || typeof payload !== 'object') return null;\n\t\tconst correlationId = (payload as { correlationId?: unknown }).correlationId;\n\t\tconst interaction = (payload as { interaction?: unknown }).interaction;\n\t\tif (typeof correlationId !== 'string' || !correlationId.trim()) return null;\n\t\tif (!interaction || typeof interaction !== 'object' || Array.isArray(interaction)) return null;\n\t\treturn msg as EmbedInboundMessage;\n\t}\n\tif (msg.type === 'getInteraction') {\n\t\tconst payload = (msg as { payload?: unknown }).payload;\n\t\tif (!payload || typeof payload !== 'object') return null;\n\t\tconst correlationId = (payload as { correlationId?: unknown }).correlationId;\n\t\tif (typeof correlationId !== 'string' || !correlationId.trim()) return null;\n\t\treturn msg as EmbedInboundMessage;\n\t}\n\tif (msg.type === 'speakStreamChunk') {\n\t\tconst payload = (msg as { payload?: unknown }).payload;\n\t\tif (!payload || typeof payload !== 'object') return null;\n\t\tconst streamId = (payload as { streamId?: unknown }).streamId;\n\t\tconst text = (payload as { text?: unknown }).text;\n\t\tif (typeof streamId !== 'string' || !streamId.trim()) return null;\n\t\tif (typeof text !== 'string') return null;\n\t\treturn msg as EmbedInboundMessage;\n\t}\n\tif (msg.type === 'launch') {\n\t\tconst payload = (msg as { payload?: unknown }).payload;\n\t\tif (!payload || typeof payload !== 'object') return null;\n\t\tconst launch = (payload as { launch?: unknown }).launch;\n\t\tif (typeof launch !== 'string' || !launch.trim()) return null;\n\t\treturn msg as EmbedInboundMessage;\n\t}\n\tconst payload = (msg as { payload?: unknown }).payload;\n\tif (!payload || typeof payload !== 'object') return null;\n\treturn msg as EmbedInboundMessage;\n}\n\nexport function createLaunchMessage(\n\tlaunch: string,\n\tsession?: Session | object,\n\tchrome?: {\n\t\treadonly startButton?: StartButtonOptions;\n\t\treadonly theme?: PlayerTheme;\n\t\treadonly showFeedback?: boolean;\n\t\treadonly interaction?: ExperienceInteractionPatch;\n\t}\n): EmbedInboundMessage {\n\tconst trimmed = launch.trim();\n\tif (!trimmed) {\n\t\tthrow new Error('createLaunchMessage requires a non-empty launch string.');\n\t}\n\tconst startButton = chrome?.startButton;\n\tconst theme = chrome?.theme;\n\tconst showFeedback = chrome?.showFeedback;\n\tconst interaction = chrome?.interaction;\n\treturn {\n\t\ttype: 'launch',\n\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\tpayload: {\n\t\t\tlaunch: trimmed,\n\t\t\t...(session !== undefined ? { session } : {}),\n\t\t\t...(startButton ? { startButton } : {}),\n\t\t\t...(theme ? { theme } : {}),\n\t\t\t...(showFeedback !== undefined ? { showFeedback } : {}),\n\t\t\t...(interaction ? { interaction } : {})\n\t\t}\n\t};\n}\n\n/** @deprecated Prefer {@link createLaunchMessage}. */\nexport function createManifestMessage(manifest: unknown): EmbedInboundMessage {\n\treturn {\n\t\ttype: 'manifest',\n\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\tpayload: { manifest }\n\t};\n}\n\nexport function createParentHelloMessage(): EmbedInboundMessage {\n\treturn {\n\t\ttype: 'parentHello',\n\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION\n\t};\n}\n\nexport function createEmbedReadyMessage(): EmbedOutboundMessage {\n\treturn {\n\t\ttype: 'embedReady',\n\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION\n\t};\n}\n\nexport function createWidgetSetChromeMessage(mode: WidgetChromeMode): EmbedInboundMessage {\n\treturn {\n\t\ttype: 'widgetSetChrome',\n\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\tpayload: { mode }\n\t};\n}\n\nexport function createWidgetToggleAudioSettingsMessage(): EmbedInboundMessage {\n\treturn {\n\t\ttype: 'widgetToggleAudioSettings',\n\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\tpayload: {}\n\t};\n}\n","/** Saved inline styles so full-window can be restored cleanly. */\nexport type FullWindowStyleSnapshot = {\n\treadonly position: string;\n\treadonly top: string;\n\treadonly right: string;\n\treadonly bottom: string;\n\treadonly left: string;\n\treadonly inset: string;\n\treadonly width: string;\n\treadonly height: string;\n\treadonly zIndex: string;\n\treadonly margin: string;\n\treadonly borderRadius: string;\n\treadonly maxWidth: string;\n\treadonly maxHeight: string;\n};\n\nconst FULL_WINDOW_Z_INDEX = '2147483000';\n\nexport function snapshotFullWindowStyles(el: HTMLElement): FullWindowStyleSnapshot {\n\tconst { style } = el;\n\treturn {\n\t\tposition: style.position,\n\t\ttop: style.top,\n\t\tright: style.right,\n\t\tbottom: style.bottom,\n\t\tleft: style.left,\n\t\tinset: style.inset,\n\t\twidth: style.width,\n\t\theight: style.height,\n\t\tzIndex: style.zIndex,\n\t\tmargin: style.margin,\n\t\tborderRadius: style.borderRadius,\n\t\tmaxWidth: style.maxWidth,\n\t\tmaxHeight: style.maxHeight\n\t};\n}\n\nexport function applyFullWindowStyles(el: HTMLElement): void {\n\tconst { style } = el;\n\tstyle.position = 'fixed';\n\tstyle.top = '0';\n\tstyle.right = '0';\n\tstyle.bottom = '0';\n\tstyle.left = '0';\n\tstyle.inset = '0';\n\tstyle.width = '100vw';\n\tstyle.width = '100dvw';\n\tstyle.height = '100vh';\n\tstyle.height = '100dvh';\n\tstyle.zIndex = FULL_WINDOW_Z_INDEX;\n\tstyle.margin = '0';\n\tstyle.borderRadius = '0';\n\tstyle.maxWidth = 'none';\n\tstyle.maxHeight = 'none';\n\tel.dataset.liformaFullWindow = '1';\n}\n\nexport function restoreFullWindowStyles(\n\tel: HTMLElement,\n\tsnapshot: FullWindowStyleSnapshot | null\n): void {\n\tdelete el.dataset.liformaFullWindow;\n\tif (!snapshot) {\n\t\tel.style.position = '';\n\t\tel.style.top = '';\n\t\tel.style.right = '';\n\t\tel.style.bottom = '';\n\t\tel.style.left = '';\n\t\tel.style.inset = '';\n\t\tel.style.width = '';\n\t\tel.style.height = '';\n\t\tel.style.zIndex = '';\n\t\tel.style.margin = '';\n\t\tel.style.borderRadius = '';\n\t\tel.style.maxWidth = '';\n\t\tel.style.maxHeight = '';\n\t\treturn;\n\t}\n\tconst { style } = el;\n\tstyle.position = snapshot.position;\n\tstyle.top = snapshot.top;\n\tstyle.right = snapshot.right;\n\tstyle.bottom = snapshot.bottom;\n\tstyle.left = snapshot.left;\n\tstyle.inset = snapshot.inset;\n\tstyle.width = snapshot.width;\n\tstyle.height = snapshot.height;\n\tstyle.zIndex = snapshot.zIndex;\n\tstyle.margin = snapshot.margin;\n\tstyle.borderRadius = snapshot.borderRadius;\n\tstyle.maxWidth = snapshot.maxWidth;\n\tstyle.maxHeight = snapshot.maxHeight;\n}\n","import {\n\tassertPlayerReachable,\n\tformatPlayerUnreachableMessage,\n\tpostMessageToPlayer\n} from './playerReachability';\nimport type { CloseEvent, EmbedInboundMessage, EmbedOutboundMessage, EmbedState } from './protocol';\nimport {\n\tcreateLaunchMessage,\n\tcreateManifestMessage,\n\tcreateParentHelloMessage,\n\tcreateWidgetSetChromeMessage,\n\tcreateWidgetToggleAudioSettingsMessage,\n\tEMBED_MESSAGE_SCHEMA_VERSION,\n\tparseOutboundMessage,\n\ttype WidgetChromeMode,\n\ttype WidgetDragMoveEvent,\n\ttype WidgetDragStartEvent\n} from './protocol';\nimport {\n\tapplyFullWindowStyles,\n\trestoreFullWindowStyles,\n\tsnapshotFullWindowStyles,\n\ttype FullWindowStyleSnapshot\n} from './fullWindowHost';\nimport type {\n\tCharacterSpeechEvent,\n\tConversationMessage,\n\tExperienceInteraction,\n\tExperienceInteractionPatch,\n\tSpeakBehavior,\n\tSpeechResult as LegacySpeakResult,\n\tUserSpeechBoundaryEvent,\n\tUserTranscriptUpdate,\n\tUtteranceResult\n} from '../types/sessionInteraction';\nimport type { PlayerStatus, Session, SessionActivity } from '../types/sessionLaunch';\nimport type { StartButtonOptions, PlayerTheme } from '../types/sessionInteraction';\nimport type {\n\tCompleteSpeechQueuePolicy,\n\tSpeechAudioFormat,\n\tSpeechInterruptOptions,\n\tSpeechPlayEmbedSource,\n\tSpeechResult,\n\tStreamingSpeechQueuePolicy\n} from '../speech/types';\n\nexport type IframeHostEventMap = {\n\tclose: CloseEvent;\n\tstateUpdate: EmbedState;\n\tuserTranscript: UserTranscriptUpdate;\n\tcharacterSpeechStarted: CharacterSpeechEvent;\n\tcharacterSpeechEnded: CharacterSpeechEvent;\n\tconversationUpdate: readonly ConversationMessage[];\n\tlisteningState: boolean;\n\tstarted: { readonly mode: 'conversation' | 'presenter' };\n\twidgetReady: void;\n\twidgetExpand: void;\n\twidgetCollapse: void;\n\twidgetAudioSettings: boolean;\n\twidgetDragStart: WidgetDragStartEvent;\n\twidgetDragMove: WidgetDragMoveEvent;\n\twidgetDragEnd: { readonly pointerId: number };\n};\n\nexport type IframeHostOptions = {\n\treadonly container: HTMLElement;\n\treadonly src: string;\n\treadonly playerOrigin: string;\n\t/** Transparent iframe for ExperienceWidget warm overlay over a thumb. */\n\treadonly transparent?: boolean;\n\treadonly onClose?: (event: CloseEvent) => void;\n\t/** @deprecated Prefer {@link IframeHostOptions.onPlayerStatusChange}. */\n\treadonly onStateUpdate?: (state: EmbedState) => void;\n\treadonly onPlayerStatusChange?: (status: PlayerStatus) => void;\n\treadonly onUserTranscript?: (update: UserTranscriptUpdate) => void;\n\treadonly onUserSpeechStarted?: (event: UserSpeechBoundaryEvent) => void;\n\treadonly onUserSpeechEnded?: (event: UserSpeechBoundaryEvent) => void;\n\treadonly onCharacterSpeechStarted?: (event: CharacterSpeechEvent) => void;\n\treadonly onCharacterSpeechEnded?: (event: CharacterSpeechEvent) => void;\n\treadonly onCharacterFocusChanged?: (event: {\n\t\treadonly characterId: string;\n\t\treadonly reason: 'speech' | 'api' | 'node_enter';\n\t}) => void;\n\treadonly onConversationUpdate?: (conversation: readonly ConversationMessage[]) => void;\n\treadonly onMessage?: (message: ConversationMessage) => void;\n\treadonly onListeningState?: (listening: boolean) => void;\n\treadonly onActivityChange?: (activity: SessionActivity) => void;\n\treadonly onFeedback?: (result: {\n\t\treadonly contractVersion: 'feedback.v1';\n\t\treadonly types: readonly {\n\t\t\treadonly feedbackId: string;\n\t\t\treadonly name: string;\n\t\t\treadonly criteria: readonly {\n\t\t\t\treadonly criterionId: string;\n\t\t\t\treadonly label: string;\n\t\t\t\treadonly score: number | string;\n\t\t\t\treadonly rationale: string;\n\t\t\t}[];\n\t\t}[];\n\t}) => void;\n\treadonly onFeedbackFailed?: (event: {\n\t\treadonly error: string;\n\t\treadonly model?: string;\n\t}) => void;\n\treadonly onStarted?: (event: { readonly mode: 'conversation' | 'presenter' }) => void;\n\treadonly onWidgetReady?: () => void;\n\treadonly onWidgetExpand?: () => void;\n\treadonly onWidgetCollapse?: () => void;\n\treadonly onWidgetAudioSettings?: (open: boolean) => void;\n\treadonly onWidgetDragStart?: (event: WidgetDragStartEvent) => void;\n\treadonly onWidgetDragMove?: (event: WidgetDragMoveEvent) => void;\n\treadonly onWidgetDragEnd?: (event: { readonly pointerId: number }) => void;\n\treadonly onFullWindowChange?: (active: boolean) => void;\n\treadonly onInteractionChange?: (interaction: ExperienceInteraction) => void;\n};\n\nfunction legacyModeToActivity(mode: 'speaking' | 'listening' | 'thinking'): SessionActivity {\n\treturn mode;\n}\n\nexport type IframeHost = {\n\twaitForLoad(): Promise<void>;\n\tpostParentHello(): void;\n\tpostLaunch(\n\t\tlaunch: string,\n\t\tsession?: Session | object,\n\t\tchrome?: {\n\t\t\treadonly startButton?: StartButtonOptions;\n\t\t\treadonly theme?: PlayerTheme;\n\t\t\treadonly showFeedback?: boolean;\n\t\t\treadonly interaction?: ExperienceInteractionPatch;\n\t\t}\n\t): void;\n\t/** @deprecated Prefer {@link IframeHost.postLaunch}. */\n\tpostManifest(manifest: unknown): void;\n\tpostWidgetSetChrome(mode: WidgetChromeMode): void;\n\tpostWidgetToggleAudioSettings(): void;\n\tspeak(options: {\n\t\ttext: string;\n\t\tcharacterId?: string;\n\t\tbehavior?: SpeakBehavior;\n\t}): Promise<LegacySpeakResult>;\n\tstartListening(): Promise<void>;\n\tstopListening(): Promise<UtteranceResult>;\n\tlistenOnce(options?: { readonly timeoutMs?: number }): Promise<UtteranceResult>;\n\tspeakProcessorStream(\n\t\tstream: AsyncIterable<string>,\n\t\toptions?: {\n\t\t\treadonly characterId?: string;\n\t\t\treadonly behavior?: SpeakBehavior;\n\t\t\treadonly signal?: AbortSignal;\n\t\t}\n\t): Promise<LegacySpeakResult>;\n\tspeechPlay(options: {\n\t\tsource: SpeechPlayEmbedSource;\n\t\tcharacterId?: string;\n\t\ttranscript?: string;\n\t\thistory?: 'none' | 'commit';\n\t\tqueue?: CompleteSpeechQueuePolicy;\n\t\tsignal?: AbortSignal;\n\t}): Promise<SpeechResult>;\n\tspeechUtteranceBegin(options: {\n\t\tutteranceId: string;\n\t\tformat: SpeechAudioFormat;\n\t\tcharacterId?: string;\n\t\tqueue: StreamingSpeechQueuePolicy;\n\t\ttranscript?: string;\n\t}): Promise<void>;\n\tspeechUtteranceWrite(options: {\n\t\tutteranceId: string;\n\t\taudio: ArrayBuffer;\n\t\tbyteLength: number;\n\t}): Promise<{ readonly bufferedMs: number }>;\n\tspeechUtteranceSetTranscript(options: {\n\t\tutteranceId: string;\n\t\ttranscript: string;\n\t}): Promise<void>;\n\tspeechUtteranceClose(options: {\n\t\tutteranceId: string;\n\t\ttranscript?: string;\n\t\thistory?: 'none' | 'commit';\n\t}): Promise<SpeechResult>;\n\tspeechUtteranceCancel(options: { utteranceId: string }): Promise<SpeechResult>;\n\tspeechInterrupt(options: SpeechInterruptOptions): Promise<readonly SpeechResult[]>;\n\tgetConversation(): Promise<readonly ConversationMessage[]>;\n\tfocusCharacter(characterId: string): Promise<void>;\n\tsetFit(fit: 'full' | 'face' | 'medium'): Promise<void>;\n\tsetInteraction(patch: ExperienceInteractionPatch): Promise<ExperienceInteraction>;\n\tgetInteraction(): Promise<ExperienceInteraction>;\n\tconversion(key: string): Promise<void>;\n\tengage(): Promise<void>;\n\treportSdkError(event: {\n\t\treadonly errorCode?: string;\n\t\treadonly message?: string;\n\t\treadonly stack?: string;\n\t\treadonly severity?: 'warning' | 'error' | 'fatal';\n\t\treadonly operation?: string;\n\t\treadonly release?: string;\n\t}): Promise<void>;\n\tdestroy(): void;\n};\n\nfunction newCorrelationId(): string {\n\tif (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n\t\treturn `cmd_${crypto.randomUUID().replace(/-/g, '').slice(0, 12)}`;\n\t}\n\treturn `cmd_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;\n}\n\nconst SPEECH_WRITE_COMMAND_TIMEOUT_MS = 30_000;\n\nexport function createIframeHost(options: IframeHostOptions): IframeHost {\n\tconst container = options.container;\n\tconst containerPosition = getComputedStyle(container).position;\n\tif (containerPosition === 'static') {\n\t\tcontainer.style.position = 'relative';\n\t}\n\n\tconst iframe = document.createElement('iframe');\n\tiframe.src = options.src;\n\tiframe.title = 'Liforma experience';\n\tiframe.setAttribute(\n\t\t'allow',\n\t\t'microphone; autoplay; clipboard-read; clipboard-write'\n\t);\n\t// Absolute fill so the player viewport matches the host box even when the host\n\t// height comes from flex or min-height (percentage height:100% often collapses).\n\tiframe.style.cssText = options.transparent\n\t\t? 'display:block;position:absolute;inset:0;width:100%;height:100%;border:0;background:transparent;'\n\t\t: 'display:block;position:absolute;inset:0;width:100%;height:100%;border:0;background:#030508;';\n\tif (options.transparent) {\n\t\tiframe.setAttribute('allowtransparency', 'true');\n\t}\n\n\tlet destroyed = false;\n\tlet fullWindowActive = false;\n\tlet fullWindowSnapshot: FullWindowStyleSnapshot | null = null;\n\tconst fullWindowTarget =\n\t\tcontainer.closest('.liforma-experience-shell') instanceof HTMLElement\n\t\t\t? (container.closest('.liforma-experience-shell') as HTMLElement)\n\t\t\t: container;\n\n\tconst setFullWindowActive = (active: boolean) => {\n\t\tif (fullWindowActive === active) return;\n\t\tfullWindowActive = active;\n\t\tif (active) {\n\t\t\tfullWindowSnapshot = snapshotFullWindowStyles(fullWindowTarget);\n\t\t\tapplyFullWindowStyles(fullWindowTarget);\n\t\t} else {\n\t\t\trestoreFullWindowStyles(fullWindowTarget, fullWindowSnapshot);\n\t\t\tfullWindowSnapshot = null;\n\t\t}\n\t\toptions.onFullWindowChange?.(active);\n\t};\n\tconst pendingCommands = new Map<\n\t\tstring,\n\t\t{\n\t\t\tresolve: (value: unknown) => void;\n\t\t\treject: (error: Error) => void;\n\t\t}\n\t>();\n\n\ttype StoredLaunch = {\n\t\treadonly launch: string;\n\t\treadonly session?: Session | object;\n\t\treadonly chrome?: {\n\t\t\treadonly startButton?: StartButtonOptions;\n\t\t\treadonly theme?: PlayerTheme;\n\t\t\treadonly showFeedback?: boolean;\n\t\t\treadonly interaction?: ExperienceInteractionPatch;\n\t\t};\n\t};\n\n\tlet storedLaunch: StoredLaunch | null = null;\n\tlet loadGeneration = 0;\n\tlet lastLaunchBurstAt = 0;\n\tconst LAUNCH_BURST_COOLDOWN_MS = 250;\n\tconst launchBurstTimers: number[] = [];\n\n\tlet firstLoadResolve: (() => void) | null = null;\n\tlet firstLoadReject: ((error: Error) => void) | null = null;\n\tconst loadPromise = new Promise<void>((resolve, reject) => {\n\t\tfirstLoadResolve = resolve;\n\t\tfirstLoadReject = reject;\n\t});\n\n\tconst clearLaunchBurstTimers = () => {\n\t\tfor (const id of launchBurstTimers) window.clearTimeout(id);\n\t\tlaunchBurstTimers.length = 0;\n\t};\n\n\tconst postLaunchBurst = (stored: StoredLaunch): void => {\n\t\tif (destroyed) return;\n\t\tconst now = Date.now();\n\t\tif (lastLaunchBurstAt > 0 && now - lastLaunchBurstAt < LAUNCH_BURST_COOLDOWN_MS) {\n\t\t\treturn;\n\t\t}\n\t\tlastLaunchBurstAt = now;\n\t\tclearLaunchBurstTimers();\n\t\tconst message = createLaunchMessage(stored.launch, stored.session, stored.chrome);\n\t\tconst postOnce = () => {\n\t\t\tif (destroyed) return;\n\t\t\tconst target = iframe.contentWindow;\n\t\t\tif (!target) return;\n\t\t\tpostMessageToPlayer(target, message, options.playerOrigin);\n\t\t};\n\t\tpostOnce();\n\t\tfor (let attempt = 1; attempt <= 12; attempt += 1) {\n\t\t\tlaunchBurstTimers.push(window.setTimeout(postOnce, attempt * 75));\n\t\t}\n\t};\n\n\tconst replayStoredLaunch = (): void => {\n\t\tif (destroyed || !storedLaunch) return;\n\t\tpostLaunchBurst(storedLaunch);\n\t};\n\n\tconst onIframeLoad = () => {\n\t\tloadGeneration += 1;\n\t\tif (loadGeneration === 1) {\n\t\t\tvoid assertPlayerReachable(options.src, options.playerOrigin).then(\n\t\t\t\t() => firstLoadResolve?.(),\n\t\t\t\t(error) =>\n\t\t\t\t\tfirstLoadReject?.(error instanceof Error ? error : new Error(String(error)))\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\t// Vite / HMR reloads the player document in-place. The first-load handshake\n\t\t// already completed, so re-post launch to the new contentWindow.\n\t\tlastLaunchBurstAt = 0;\n\t\treplayStoredLaunch();\n\t};\n\tconst onIframeError = () => {\n\t\tif (loadGeneration > 0) return;\n\t\tfirstLoadReject?.(new Error(formatPlayerUnreachableMessage(options.playerOrigin)));\n\t};\n\tiframe.addEventListener('load', onIframeLoad);\n\tiframe.addEventListener('error', onIframeError);\n\n\tconst onMessage = (event: MessageEvent) => {\n\t\tif (destroyed) return;\n\t\tif (event.source !== iframe.contentWindow) return;\n\t\tif (event.origin !== options.playerOrigin) return;\n\n\t\tconst message = parseOutboundMessage(event.data);\n\t\tif (!message) return;\n\n\t\tswitch (message.type) {\n\t\t\tcase 'close':\n\t\t\t\toptions.onClose?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'stateUpdate':\n\t\t\t\toptions.onPlayerStatusChange?.(message.payload.state);\n\t\t\t\toptions.onStateUpdate?.(message.payload.state);\n\t\t\t\tbreak;\n\t\t\tcase 'commandResult': {\n\t\t\t\tconst pending = pendingCommands.get(message.payload.correlationId);\n\t\t\t\tif (!pending) return;\n\t\t\t\tpendingCommands.delete(message.payload.correlationId);\n\t\t\t\tif (message.payload.ok) {\n\t\t\t\t\tpending.resolve(message.payload.result);\n\t\t\t\t} else {\n\t\t\t\t\tpending.reject(new Error(message.payload.error ?? 'Command failed.'));\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'userTranscript':\n\t\t\t\toptions.onUserTranscript?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'characterSpeechStarted':\n\t\t\t\toptions.onCharacterSpeechStarted?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'characterSpeechEnded':\n\t\t\t\toptions.onCharacterSpeechEnded?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'characterFocusChanged':\n\t\t\t\toptions.onCharacterFocusChanged?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'conversationUpdate':\n\t\t\t\toptions.onConversationUpdate?.(message.payload.conversation);\n\t\t\t\tbreak;\n\t\t\tcase 'listeningState':\n\t\t\t\toptions.onListeningState?.(message.payload.listening);\n\t\t\t\tbreak;\n\t\t\tcase 'userSpeechStarted':\n\t\t\t\toptions.onUserSpeechStarted?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'userSpeechEnded':\n\t\t\t\toptions.onUserSpeechEnded?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'modeChange':\n\t\t\t\toptions.onActivityChange?.(legacyModeToActivity(message.payload.mode));\n\t\t\t\tbreak;\n\t\t\tcase 'activityChange':\n\t\t\t\toptions.onActivityChange?.(message.payload.activity);\n\t\t\t\tbreak;\n\t\t\tcase 'feedback':\n\t\t\t\toptions.onFeedback?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'feedbackFailed':\n\t\t\t\toptions.onFeedbackFailed?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'message':\n\t\t\t\toptions.onMessage?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'started':\n\t\t\t\toptions.onStarted?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'embedReady':\n\t\t\t\t// Soft HMR remounts the player without an iframe `load` event.\n\t\t\t\treplayStoredLaunch();\n\t\t\t\tbreak;\n\t\t\tcase 'widgetReady':\n\t\t\t\toptions.onWidgetReady?.();\n\t\t\t\tbreak;\n\t\t\tcase 'widgetExpand':\n\t\t\t\toptions.onWidgetExpand?.();\n\t\t\t\tbreak;\n\t\t\tcase 'widgetCollapse':\n\t\t\t\toptions.onWidgetCollapse?.();\n\t\t\t\tbreak;\n\t\t\tcase 'widgetAudioSettings':\n\t\t\t\toptions.onWidgetAudioSettings?.(message.payload.open);\n\t\t\t\tbreak;\n\t\t\tcase 'widgetDragStart':\n\t\t\t\toptions.onWidgetDragStart?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'widgetDragMove':\n\t\t\t\toptions.onWidgetDragMove?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'widgetDragEnd':\n\t\t\t\toptions.onWidgetDragEnd?.(message.payload);\n\t\t\t\tbreak;\n\t\t\tcase 'fullWindow':\n\t\t\t\tsetFullWindowActive(message.payload.active);\n\t\t\t\tbreak;\n\t\t\tcase 'interactionChange':\n\t\t\t\toptions.onInteractionChange?.(message.payload.interaction);\n\t\t\t\tbreak;\n\t\t}\n\t};\n\n\twindow.addEventListener('message', onMessage);\n\tcontainer.replaceChildren(iframe);\n\t// Absolute iframe does not contribute to parent height — keep a usable floor when\n\t// the host only sized itself from previous in-flow content.\n\tif (container.clientHeight < 2 && !container.style.minHeight) {\n\t\tconst computedMin = getComputedStyle(container).minHeight;\n\t\tif (computedMin === '0px' || computedMin === 'auto') {\n\t\t\tcontainer.style.minHeight = '480px';\n\t\t}\n\t}\n\n\tconst postToIframe = (message: EmbedInboundMessage, transfer?: Transferable[]) => {\n\t\tif (destroyed) return;\n\t\tconst target = iframe.contentWindow;\n\t\tif (!target) {\n\t\t\tthrow new Error(formatPlayerUnreachableMessage(options.playerOrigin));\n\t\t}\n\t\tpostMessageToPlayer(target, message, options.playerOrigin, transfer);\n\t};\n\n\tconst postCommand = <T>(\n\t\tmessage: EmbedInboundMessage,\n\t\ttimeoutMs = 120_000,\n\t\ttransfer?: Transferable[]\n\t): Promise<T> => {\n\t\tconst correlationId =\n\t\t\tmessage.type !== 'parentHello' && message.payload && 'correlationId' in message.payload\n\t\t\t\t? (message.payload.correlationId as string)\n\t\t\t\t: newCorrelationId();\n\n\t\tif (message.type !== 'parentHello' && message.payload && 'correlationId' in message.payload) {\n\t\t\t// correlationId already set\n\t\t} else if (message.type !== 'parentHello' && message.payload) {\n\t\t\t(message.payload as { correlationId: string }).correlationId = correlationId;\n\t\t}\n\n\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\tpendingCommands.set(correlationId, {\n\t\t\t\tresolve: (value) => resolve(value as T),\n\t\t\t\treject\n\t\t\t});\n\t\t\tpostToIframe(message, transfer);\n\t\t\tsetTimeout(() => {\n\t\t\t\tif (!pendingCommands.has(correlationId)) return;\n\t\t\t\tpendingCommands.delete(correlationId);\n\t\t\t\treject(new Error('Timed out waiting for player command result.'));\n\t\t\t}, timeoutMs);\n\t\t});\n\t};\n\n\treturn {\n\t\twaitForLoad() {\n\t\t\treturn loadPromise;\n\t\t},\n\t\tpostParentHello() {\n\t\t\tpostToIframe(createParentHelloMessage());\n\t\t},\n\t\tpostLaunch(launch, session, chrome) {\n\t\t\tif (destroyed) return;\n\t\t\tstoredLaunch = { launch, session, chrome };\n\t\t\tlastLaunchBurstAt = 0;\n\t\t\tpostLaunchBurst(storedLaunch);\n\t\t},\n\t\tpostManifest(manifest) {\n\t\t\tif (typeof manifest === 'string') {\n\t\t\t\tthis.postLaunch(manifest);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (\n\t\t\t\tmanifest &&\n\t\t\t\ttypeof manifest === 'object' &&\n\t\t\t\ttypeof (manifest as { launch?: unknown }).launch === 'string'\n\t\t\t) {\n\t\t\t\tconst launch = String((manifest as { launch: string }).launch);\n\t\t\t\tconst session = (manifest as { session?: object }).session;\n\t\t\t\tthis.postLaunch(launch, session);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow new Error(\n\t\t\t\t'postManifest is deprecated; use postLaunch with an opaque launch string from SessionLaunchResponse.'\n\t\t\t);\n\t\t},\n\t\tpostWidgetSetChrome(mode) {\n\t\t\tpostToIframe(createWidgetSetChromeMessage(mode));\n\t\t},\n\t\tpostWidgetToggleAudioSettings() {\n\t\t\tpostToIframe(createWidgetToggleAudioSettingsMessage());\n\t\t},\n\t\tspeak(options) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<LegacySpeakResult>({\n\t\t\t\ttype: 'speak',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: {\n\t\t\t\t\tcorrelationId,\n\t\t\t\t\ttext: options.text,\n\t\t\t\t\t...(options.characterId ? { characterId: options.characterId } : {}),\n\t\t\t\t\t...(options.behavior ? { behavior: options.behavior } : {})\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\tstartListening() {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<void>({\n\t\t\t\ttype: 'startListening',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: { correlationId }\n\t\t\t});\n\t\t},\n\t\tstopListening() {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<UtteranceResult>({\n\t\t\t\ttype: 'stopListening',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: { correlationId }\n\t\t\t});\n\t\t},\n\t\tlistenOnce(options) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<UtteranceResult>({\n\t\t\t\ttype: 'listenOnce',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: {\n\t\t\t\t\tcorrelationId,\n\t\t\t\t\t...(options?.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {})\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\tasync speakProcessorStream(stream, options) {\n\t\t\tconst startCorrelationId = newCorrelationId();\n\t\t\tconst endCorrelationId = newCorrelationId();\n\t\t\tconst started = await postCommand<{ streamId: string }>({\n\t\t\t\ttype: 'speakStreamStart',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: {\n\t\t\t\t\tcorrelationId: startCorrelationId,\n\t\t\t\t\t...(options?.characterId ? { characterId: options.characterId } : {}),\n\t\t\t\t\t...(options?.behavior ? { behavior: options.behavior } : {})\n\t\t\t\t}\n\t\t\t});\n\t\t\tconst streamId = started.streamId;\n\t\t\ttry {\n\t\t\t\tfor await (const chunk of stream) {\n\t\t\t\t\tif (options?.signal?.aborted) {\n\t\t\t\t\t\tthrow new DOMException('Processor stream aborted.', 'AbortError');\n\t\t\t\t\t}\n\t\t\t\t\tif (!chunk) continue;\n\t\t\t\t\tpostToIframe({\n\t\t\t\t\t\ttype: 'speakStreamChunk',\n\t\t\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\t\t\tpayload: { streamId, text: chunk }\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (options?.signal?.aborted) {\n\t\t\t\t\tthrow new DOMException('Processor stream aborted.', 'AbortError');\n\t\t\t\t}\n\t\t\t\treturn await postCommand<LegacySpeakResult>({\n\t\t\t\t\ttype: 'speakStreamEnd',\n\t\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\t\tpayload: { correlationId: endCorrelationId, streamId }\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\ttry {\n\t\t\t\t\tawait postCommand<LegacySpeakResult>({\n\t\t\t\t\t\ttype: 'speakStreamEnd',\n\t\t\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\t\t\tpayload: { correlationId: endCorrelationId, streamId }\n\t\t\t\t\t});\n\t\t\t\t} catch {\n\t\t\t\t\t/* stream may already be torn down */\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t\tspeechPlay(options) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\tconst transfer: Transferable[] = [];\n\t\t\tif (options.source.kind === 'pcm' || options.source.kind === 'encoded') {\n\t\t\t\ttransfer.push(options.source.data);\n\t\t\t}\n\t\t\treturn postCommand<SpeechResult>(\n\t\t\t\t{\n\t\t\t\t\ttype: 'speechPlay',\n\t\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\t\tpayload: {\n\t\t\t\t\t\tcorrelationId,\n\t\t\t\t\t\tsource: options.source,\n\t\t\t\t\t\t...(options.characterId ? { characterId: options.characterId } : {}),\n\t\t\t\t\t\t...(options.transcript !== undefined ? { transcript: options.transcript } : {}),\n\t\t\t\t\t\t...(options.history ? { history: options.history } : {}),\n\t\t\t\t\t\t...(options.queue ? { queue: options.queue } : {})\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t120_000,\n\t\t\t\ttransfer\n\t\t\t);\n\t\t},\n\t\tspeechUtteranceBegin(options) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<void>({\n\t\t\t\ttype: 'speechUtteranceBegin',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: {\n\t\t\t\t\tcorrelationId,\n\t\t\t\t\tutteranceId: options.utteranceId,\n\t\t\t\t\tformat: options.format,\n\t\t\t\t\tqueue: options.queue,\n\t\t\t\t\t...(options.characterId ? { characterId: options.characterId } : {}),\n\t\t\t\t\t...(options.transcript !== undefined ? { transcript: options.transcript } : {})\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\tspeechUtteranceWrite(options) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<{ bufferedMs: number }>(\n\t\t\t\t{\n\t\t\t\t\ttype: 'speechUtteranceWrite',\n\t\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\t\tpayload: {\n\t\t\t\t\t\tcorrelationId,\n\t\t\t\t\t\tutteranceId: options.utteranceId,\n\t\t\t\t\t\taudio: options.audio,\n\t\t\t\t\t\tbyteLength: options.byteLength\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tSPEECH_WRITE_COMMAND_TIMEOUT_MS,\n\t\t\t\t[options.audio]\n\t\t\t);\n\t\t},\n\t\tspeechUtteranceSetTranscript(options) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<void>({\n\t\t\t\ttype: 'speechUtteranceSetTranscript',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: {\n\t\t\t\t\tcorrelationId,\n\t\t\t\t\tutteranceId: options.utteranceId,\n\t\t\t\t\ttranscript: options.transcript\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\tspeechUtteranceClose(options) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<SpeechResult>({\n\t\t\t\ttype: 'speechUtteranceClose',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: {\n\t\t\t\t\tcorrelationId,\n\t\t\t\t\tutteranceId: options.utteranceId,\n\t\t\t\t\t...(options.transcript !== undefined ? { transcript: options.transcript } : {}),\n\t\t\t\t\t...(options.history ? { history: options.history } : {})\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\tspeechUtteranceCancel(options) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<SpeechResult>({\n\t\t\t\ttype: 'speechUtteranceCancel',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: {\n\t\t\t\t\tcorrelationId,\n\t\t\t\t\tutteranceId: options.utteranceId\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\tspeechInterrupt(options) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<readonly SpeechResult[]>({\n\t\t\t\ttype: 'speechInterrupt',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: {\n\t\t\t\t\tcorrelationId,\n\t\t\t\t\t...options\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\tgetConversation() {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<readonly ConversationMessage[]>({\n\t\t\t\ttype: 'getConversation',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: { correlationId }\n\t\t\t});\n\t\t},\n\t\tfocusCharacter(characterId) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<void>({\n\t\t\t\ttype: 'focusCharacter',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: { correlationId, characterId }\n\t\t\t});\n\t\t},\n\t\tsetFit(fit) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<void>({\n\t\t\t\ttype: 'setFit',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: { correlationId, fit }\n\t\t\t});\n\t\t},\n\t\tsetInteraction(patch) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<ExperienceInteraction>({\n\t\t\t\ttype: 'setInteraction',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: { correlationId, interaction: patch }\n\t\t\t});\n\t\t},\n\t\tgetInteraction() {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<ExperienceInteraction>({\n\t\t\t\ttype: 'getInteraction',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: { correlationId }\n\t\t\t});\n\t\t},\n\t\tconversion(key) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<void>({\n\t\t\t\ttype: 'conversion',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: { correlationId, key }\n\t\t\t});\n\t\t},\n\t\tengage() {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<void>({\n\t\t\t\ttype: 'engage',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: { correlationId }\n\t\t\t});\n\t\t},\n\t\treportSdkError(event) {\n\t\t\tconst correlationId = newCorrelationId();\n\t\t\treturn postCommand<void>({\n\t\t\t\ttype: 'reportSdkError',\n\t\t\t\tschemaVersion: EMBED_MESSAGE_SCHEMA_VERSION,\n\t\t\t\tpayload: {\n\t\t\t\t\tcorrelationId,\n\t\t\t\t\terrorCode: event.errorCode,\n\t\t\t\t\tmessage: event.message,\n\t\t\t\t\tstack: event.stack,\n\t\t\t\t\tseverity: event.severity,\n\t\t\t\t\toperation: event.operation,\n\t\t\t\t\trelease: event.release\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\tdestroy() {\n\t\t\tif (destroyed) return;\n\t\t\tdestroyed = true;\n\t\t\tif (fullWindowActive) {\n\t\t\t\tsetFullWindowActive(false);\n\t\t\t}\n\t\t\tfor (const pending of pendingCommands.values()) {\n\t\t\t\tpending.reject(new Error('Iframe host destroyed.'));\n\t\t\t}\n\t\t\tpendingCommands.clear();\n\t\t\tclearLaunchBurstTimers();\n\t\t\tstoredLaunch = null;\n\t\t\tiframe.removeEventListener('load', onIframeLoad);\n\t\t\tiframe.removeEventListener('error', onIframeError);\n\t\t\twindow.removeEventListener('message', onMessage);\n\t\t\tiframe.remove();\n\t\t}\n\t};\n}\n\n","export type ReadyGate<T> = {\n\tsetValue(value: T): void;\n\tmarkReady(): void;\n};\n\n/** Emits once after both an asynchronous value and readiness signal are available. */\nexport function createReadyGate<T>(onReady: (value: T) => void): ReadyGate<T> {\n\tlet value: T | undefined;\n\tlet ready = false;\n\tlet emitted = false;\n\n\tconst emitIfPossible = (): void => {\n\t\tif (emitted || !ready || value === undefined) return;\n\t\temitted = true;\n\t\tonReady(value);\n\t};\n\n\treturn {\n\t\tsetValue(nextValue) {\n\t\t\tvalue = nextValue;\n\t\t\temitIfPossible();\n\t\t},\n\t\tmarkReady() {\n\t\t\tready = true;\n\t\t\temitIfPossible();\n\t\t}\n\t};\n}\n","{\n\t\"name\": \"@liforma/client\",\n\t\"version\": \"0.4.10\",\n\t\"type\": \"module\",\n\t\"description\": \"Liforma browser SDK — Experience sessions, speech API, and Svelte embed component.\",\n\t\"license\": \"MIT\",\n\t\"homepage\": \"https://docs.liforma.ai\",\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"git+https://github.com/LiformaLtd/cdn.liforma.ai.git\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/LiformaLtd/cdn.liforma.ai/issues\"\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\"\n\t},\n\t\"sideEffects\": false,\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"types\": \"./dist/npm/v2/npm.d.ts\",\n\t\t\t\"import\": \"./dist/npm/index.js\"\n\t\t},\n\t\t\"./svelte\": {\n\t\t\t\"types\": \"./dist/svelte/index.d.ts\",\n\t\t\t\"import\": \"./dist/svelte/index.js\",\n\t\t\t\"svelte\": \"./dist/svelte/index.js\"\n\t\t},\n\t\t\"./svelte/thumbnail\": {\n\t\t\t\"types\": \"./dist/svelte/thumbnail.d.ts\",\n\t\t\t\"import\": \"./dist/svelte/thumbnail.js\",\n\t\t\t\"svelte\": \"./dist/svelte/thumbnail.js\"\n\t\t},\n\t\t\"./thumbnail\": {\n\t\t\t\"types\": \"./dist/npm/thumbnail/index.d.ts\",\n\t\t\t\"import\": \"./dist/npm/thumbnail/index.js\"\n\t\t},\n\t\t\"./react\": {\n\t\t\t\"types\": \"./dist/react/react/index.d.ts\",\n\t\t\t\"import\": \"./dist/react/index.js\"\n\t\t},\n\t\t\"./react/thumbnail\": {\n\t\t\t\"types\": \"./dist/react/react/thumbnail.d.ts\",\n\t\t\t\"import\": \"./dist/react/thumbnail.js\"\n\t\t},\n\t\t\"./next\": {\n\t\t\t\"types\": \"./dist/next/next/index.d.ts\",\n\t\t\t\"import\": \"./dist/next/index.js\"\n\t\t},\n\t\t\"./next/thumbnail\": {\n\t\t\t\"types\": \"./dist/next/next/thumbnail.d.ts\",\n\t\t\t\"import\": \"./dist/next/thumbnail.js\"\n\t\t},\n\t\t\"./byo\": {\n\t\t\t\"types\": \"./dist/byo/index.d.ts\",\n\t\t\t\"import\": \"./dist/byo/index.js\"\n\t\t},\n\t\t\"./elevenlabs\": {\n\t\t\t\"types\": \"./dist/elevenlabs/index.d.ts\",\n\t\t\t\"import\": \"./dist/elevenlabs/index.js\"\n\t\t},\n\t\t\"./openai\": {\n\t\t\t\"types\": \"./dist/openai/index.d.ts\",\n\t\t\t\"import\": \"./dist/openai/index.js\"\n\t\t},\n\t\t\"./deepgram\": {\n\t\t\t\"types\": \"./dist/deepgram/index.d.ts\",\n\t\t\t\"import\": \"./dist/deepgram/index.js\"\n\t\t},\n\t\t\"./google\": {\n\t\t\t\"types\": \"./dist/google/index.d.ts\",\n\t\t\t\"import\": \"./dist/google/index.js\"\n\t\t},\n\t\t\"./livekit\": {\n\t\t\t\"types\": \"./dist/livekit/index.d.ts\",\n\t\t\t\"import\": \"./dist/livekit/index.js\"\n\t\t}\n\t},\n\t\"files\": [\n\t\t\"dist/npm\",\n\t\t\"dist/svelte\",\n\t\t\"dist/react\",\n\t\t\"dist/next\",\n\t\t\"dist/byo\",\n\t\t\"dist/elevenlabs\",\n\t\t\"dist/openai\",\n\t\t\"dist/deepgram\",\n\t\t\"dist/google\",\n\t\t\"dist/livekit\",\n\t\t\"dist/sdk\",\n\t\t\"README.md\",\n\t\t\"CHANGELOG.md\",\n\t\t\"LICENSE\"\n\t],\n\t\"peerDependencies\": {\n\t\t\"@elevenlabs/client\": \">=1.0.0\",\n\t\t\"livekit-client\": \">=2.0.0\",\n\t\t\"react\": \"^18.0.0 || ^19.0.0\",\n\t\t\"react-dom\": \"^18.0.0 || ^19.0.0\",\n\t\t\"svelte\": \"^5.0.0\"\n\t},\n\t\"peerDependenciesMeta\": {\n\t\t\"svelte\": {\n\t\t\t\"optional\": true\n\t\t},\n\t\t\"react\": {\n\t\t\t\"optional\": true\n\t\t},\n\t\t\"react-dom\": {\n\t\t\t\"optional\": true\n\t\t},\n\t\t\"@elevenlabs/client\": {\n\t\t\t\"optional\": true\n\t\t},\n\t\t\"livekit-client\": {\n\t\t\t\"optional\": true\n\t\t}\n\t},\n\t\"scripts\": {\n\t\t\"build\": \"npm run build:v2 && npm run build:npm && npm run build:svelte && npm run build:react && npm run build:next && npm run build:byo && npm run build:elevenlabs && npm run build:openai && npm run build:deepgram && npm run build:google && npm run build:livekit && npm run copy:preview\",\n\t\t\"build:react\": \"vite build --config vite.config.react.ts && vite build --config vite.config.react-thumbnail.ts && tsc -p tsconfig.react.json\",\n\t\t\"build:next\": \"vite build --config vite.config.next.ts && vite build --config vite.config.next-thumbnail.ts && tsc -p tsconfig.next.json\",\n\t\t\"build:byo\": \"vite build --config vite.config.byo.ts && tsc -p tsconfig.byo.json\",\n\t\t\"build:elevenlabs\": \"vite build --config vite.config.elevenlabs.ts && tsc -p tsconfig.elevenlabs.json\",\n\t\t\"build:openai\": \"vite build --config vite.config.openai.ts && tsc -p tsconfig.openai.json\",\n\t\t\"build:deepgram\": \"vite build --config vite.config.deepgram.ts && tsc -p tsconfig.deepgram.json\",\n\t\t\"build:google\": \"vite build --config vite.config.google.ts && tsc -p tsconfig.google.json\",\n\t\t\"build:livekit\": \"vite build --config vite.config.livekit.ts && tsc -p tsconfig.livekit.json\",\n\t\t\"copy:preview\": \"mkdir -p dist/preview && cp preview/v2-embed-test.html dist/preview/ && cp preview/v2-embed-test-redirect.html dist/preview/\",\n\t\t\"build:v2\": \"vite build --config vite.config.v2.ts && vite build --config vite.config.v2-thumbnail.ts\",\n\t\t\"build:npm\": \"vite build --config vite.config.npm.ts && vite build --config vite.config.thumbnail.ts && tsc -p tsconfig.npm.json\",\n\t\t\"build:svelte\": \"svelte-package -i src/svelte -o dist/svelte && vite build --config vite.config.svelte.ts\",\n\t\t\"check:consumer\": \"svelte-check --workspace test/consumer --tsconfig ./tsconfig.json\",\n\t\t\"test\": \"vitest run\",\n\t\t\"preview\": \"node scripts/preview-local.mjs\",\n\t\t\"dev:sdk\": \"npm run build:v2 && npm run copy:preview && npm run preview\",\n\t\t\"dev\": \"npm run build && npm run preview\",\n\t\t\"publish:sdk\": \"node scripts/publish-sdk.mjs\",\n\t\t\"publish:npm\": \"node scripts/publish-npm.mjs\",\n\t\t\"publish:avatar\": \"node scripts/publish-avatar.mjs\",\n\t\t\"publish:avatars-dist\": \"node scripts/publish-avatars.mjs\",\n\t\t\"publish:avatars\": \"node scripts/republish-avatars.mjs\",\n\t\t\"build:avatars\": \"node scripts/build-avatars.mjs\",\n\t\t\"republish:avatars\": \"node scripts/republish-avatars.mjs\",\n\t\t\"catalogue:avatars\": \"node ../labs.liforma.ai/scripts/generate-avatar-index.mjs\",\n\t\t\"verify:avatars-dist\": \"node scripts/verify-avatars-dist.mjs\",\n\t\t\"verify:avatar-pack\": \"node scripts/verify-avatar-pack.mjs\",\n\t\t\"repair:render-plate-metadata\": \"node scripts/repair-render-plate-metadata.mjs\",\n\t\t\"verify:render-plate-crop\": \"node scripts/verify-render-plate-crop.mjs\",\n\t\t\"migrate:avatar-render-prep\": \"npm run migrate:avatar-render-prep --prefix ../labs.liforma.ai --\",\n\t\t\"convert:avatar-teeth\": \"node scripts/convert-avatar-teeth-webp.mjs\",\n\t\t\"warm:avatar-composites\": \"node scripts/warm-avatar-composites.mjs\",\n\t\t\"test:compose-costume\": \"node scripts/test-compose-costume-layers.mjs\",\n\t\t\"test:compose-costume-wasm\": \"node scripts/test-compose-costume-wasm.mjs\",\n\t\t\"test:parse-composite-filename\": \"node scripts/test-parse-composite-filename.mjs\",\n\t\t\"test:avatar-composite-rendered-path\": \"node scripts/test-avatar-composite-rendered-path.mjs\",\n\t\t\"test:avatar-compose-worker-cors\": \"node scripts/test-avatar-compose-worker-cors.mjs\",\n\t\t\"test:experience-thumb-url\": \"node scripts/test-experience-thumb-url.mjs\",\n\t\t\"test:compose-experience-thumb\": \"node scripts/test-compose-experience-thumb.mjs\",\n\t\t\"test:location-depth-paths\": \"node scripts/test-location-depth-paths.mjs\",\n\t\t\"test:location-binary-assets\": \"node scripts/test-location-binary-assets.mjs\",\n\t\t\"test:location-da3-depth\": \"node scripts/test-location-da3-depth.mjs\",\n\t\t\"test:location-interactions\": \"node scripts/test-location-interactions.mjs\",\n\t\t\"test:render-plate-chroma-key\": \"node scripts/test-render-plate-chroma-key.mjs\",\n\t\t\"test:sparse-plate\": \"node scripts/test-sparse-plate.mjs\",\n\t\t\"test:face-meshes-publish-depth\": \"node scripts/test-face-meshes-publish-depth.mjs\",\n\t\t\"test:avatar-avif-sibling\": \"node scripts/test-avatar-avif-sibling.mjs\",\n\t\t\"test:screen-chroma-key\": \"node scripts/test-screen-chroma-key.mjs\",\n\t\t\"pull:sources\": \"node scripts/sync-authoring-sources.mjs\",\n\t\t\"push:sources\": \"node scripts/sync-authoring-sources.mjs\",\n\t\t\"catalogue:locations\": \"node scripts/catalogue-locations.mjs\",\n\t\t\"generate:location-interactions\": \"node scripts/generate-location-interactions.mjs\",\n\t\t\"generate:location-depth\": \"node scripts/generate-location-depth.mjs\",\n\t\t\"generate:location-depth16-da3\": \"node scripts/generate-location-depth16-da3.mjs\",\n\t\t\"generate:location-discontinuities\": \"node scripts/generate-location-discontinuities.mjs\",\n\t\t\"build:locations\": \"node scripts/build-locations.mjs\",\n\t\t\"publish:locations\": \"node scripts/publish-locations.mjs\",\n\t\t\"verify:locations\": \"node scripts/verify-location-sources.mjs\",\n\t\t\"publish:models\": \"node scripts/publish-models.mjs\",\n\t\t\"publish:models:krea-int8\": \"node scripts/_upload-model-prefix.mjs text-to-image/lf-t2i-turbo-int8\",\n\t\t\"publish:models:ltx-int8\": \"node scripts/_upload-model-prefix.mjs text-to-video/lf-t2v-distill-int8\",\n\t\t\"publish:models:video-omni\": \"node scripts/_upload-model-prefix.mjs text-to-video/lf-video-omni-v1\",\n\t\t\"fetch:depth-anything-v2\": \"node scripts/fetch-depth-anything-v2.mjs\",\n\t\t\"fetch:video-depth-anything\": \"node scripts/fetch-video-depth-anything.mjs\",\n\t\t\"fetch:depth-pro\": \"node scripts/fetch-depth-pro.mjs\",\n\t\t\"fetch:face-landmarker\": \"node scripts/fetch-face-landmarker.mjs\",\n\t\t\"fetch:anime-face-detector\": \"node scripts/fetch-anime-face-detector.mjs\",\n\t\t\"fetch:face-parsing\": \"node scripts/fetch-face-parsing.mjs\",\n\t\t\"fetch:vitmatte\": \"node scripts/fetch-vitmatte.mjs\",\n\t\t\"fetch:liveportrait-mlx\": \"node scripts/fetch-liveportrait-mlx.mjs\",\n\t\t\"fetch:wav2vec-phoneme-ctc\": \"node scripts/fetch-wav2vec-phoneme-ctc.mjs\",\n\t\t\"fetch:lf-sta\": \"node scripts/fetch-wav2vec-phoneme-ctc.mjs\",\n\t\t\"fetch:supertonic-3\": \"node scripts/fetch-supertonic-3.mjs\",\n\t\t\"fetch:lf-tts\": \"node scripts/fetch-supertonic-3.mjs\",\n\t\t\"fetch:lf-t2i-turbo\": \"python3 ../tools/krea-2-salad/scripts/fetch_cdn_snapshot.py\",\n\t\t\"fetch:models\": \"npm run fetch:depth-anything-v2 && npm run fetch:video-depth-anything && npm run fetch:depth-pro && npm run fetch:face-landmarker && npm run fetch:anime-face-detector && npm run fetch:face-parsing && npm run fetch:vitmatte && npm run fetch:lf-sta && npm run fetch:lf-tts\",\n\t\t\"locations\": \"npm run catalogue:locations && npm run build:locations\",\n\t\t\"configure:cors\": \"node scripts/configure-r2-cors.mjs\",\n\t\t\"verify:cors\": \"node scripts/verify-cdn-cors.mjs\",\n\t\t\"deploy:worker:avatar-compose\": \"node scripts/deploy-avatar-compose-worker.mjs\",\n\t\t\"deploy:worker:experience-thumb\": \"node scripts/deploy-experience-thumb-worker.mjs\",\n\t\t\"deploy\": \"npm run build && npm run publish:sdk\",\n\t\t\"verify\": \"npm run build && node scripts/check-sdk-size.mjs && node scripts/verify-thumbnail-light.mjs && node scripts/test-embed-protocol.mjs && node scripts/test-manifest-embed-url.mjs && node scripts/test-player-reachability.mjs && node scripts/test-session-endpoint.mjs && node scripts/verify-package.mjs\",\n\t\t\"preview:test\": \"npm run build && npm run preview\"\n\t},\n\t\"dependencies\": {\n\t\t\"@jsquash/webp\": \"^1.5.0\",\n\t\t\"zod\": \"^4.4.3\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@aws-sdk/client-s3\": \"^3.1000.0\",\n\t\t\"@aws-sdk/lib-storage\": \"^3.1110.0\",\n\t\t\"@elevenlabs/client\": \"^1.17.0\",\n\t\t\"@sveltejs/package\": \"^2.5.8\",\n\t\t\"@sveltejs/vite-plugin-svelte\": \"^7.0.0\",\n\t\t\"@testing-library/react\": \"^16.3.0\",\n\t\t\"@testing-library/svelte\": \"^5.4.2\",\n\t\t\"@types/node\": \"^25.9.3\",\n\t\t\"@types/react\": \"^19.1.12\",\n\t\t\"@types/react-dom\": \"^19.1.9\",\n\t\t\"@vitejs/plugin-react\": \"^5.0.2\",\n\t\t\"@webgpu/types\": \"^0.1.70\",\n\t\t\"dotenv\": \"^17.2.3\",\n\t\t\"jsdom\": \"^30.0.1\",\n\t\t\"livekit-client\": \"^2.21.0\",\n\t\t\"react\": \"^19.1.1\",\n\t\t\"react-dom\": \"^19.1.1\",\n\t\t\"sharp\": \"^0.34.2\",\n\t\t\"svelte\": \"^5.55.2\",\n\t\t\"svelte-check\": \"^4.7.4\",\n\t\t\"typescript\": \"^6.0.3\",\n\t\t\"vite\": \"^8.0.16\",\n\t\t\"vitest\": \"^4.1.10\",\n\t\t\"wrangler\": \"^4.101.0\"\n\t}\n}\n","import packageJson from '../../package.json' with { type: 'json' };\n\n/** Opaque SDK release id stamped on sdk.* ErrorEvents (not the player deploy SHA). */\nexport const SDK_RELEASE = `sdk@${packageJson.version}`;\n","import { useExplicitLocalStack } from '../../shims/localStack';\n\nconst PRODUCTION_PLAYER_EMBED_URL = 'https://player.liforma.ai/embed';\nconst LOCAL_PLAYER_EMBED_URL = 'http://localhost:3002/embed';\n\nfunction readConfiguredEmbedUrl(): string | null {\n\tconst globalValue = (globalThis as { __LIFORMA_PLAYER_EMBED_URL?: string })\n\t\t.__LIFORMA_PLAYER_EMBED_URL;\n\tif (globalValue?.trim()) {\n\t\treturn globalValue.trim().replace(/\\/$/, '');\n\t}\n\n\tif (typeof document === 'undefined') {\n\t\treturn null;\n\t}\n\n\tconst script =\n\t\tdocument.querySelector('script[data-liforma-sdk][src*=\"client.js\"]') ??\n\t\tdocument.querySelector('script[src*=\"/sdk/v2/client.js\"]');\n\tconst fromScript = script?.getAttribute('data-player-embed-url')?.trim();\n\tif (fromScript) {\n\t\treturn fromScript.replace(/\\/$/, '');\n\t}\n\n\treturn null;\n}\n\n/**\n * Hosted player embed document URL (iframe `src` base).\n *\n * Defaults to production. Local stack is opt-in only — never inferred from\n * `localhost` hostname (third-party demos run on localhost against production).\n *\n * Override order:\n * 1. `window.__LIFORMA_PLAYER_EMBED_URL`\n * 2. `data-player-embed-url` on the SDK script tag\n * 3. `window.__LIFORMA_STACK === 'local'` or host `?stack=local` → http://localhost:3002/embed\n * 4. production → https://player.liforma.ai/embed\n */\nexport function resolvePublicPlayerEmbedUrl(): string {\n\tconst configured = readConfiguredEmbedUrl();\n\tif (configured) {\n\t\treturn configured.endsWith('/embed') ? configured : `${configured}/embed`;\n\t}\n\n\tif (useExplicitLocalStack()) {\n\t\treturn LOCAL_PLAYER_EMBED_URL;\n\t}\n\n\treturn PRODUCTION_PLAYER_EMBED_URL;\n}\n\nexport function resolveSceneHintId(backdropId?: string, locationId?: string): string | undefined {\n\tconst id = backdropId?.trim() || locationId?.trim();\n\treturn id || undefined;\n}\n\nexport function buildManifestEmbedUrl(\n\tembedBaseUrl?: string,\n\tdebug?: boolean,\n\tbackdropId?: string,\n\tavatarId?: string,\n\tfit?: 'full' | 'face' | 'medium',\n\tui?: 'widget',\n\tshowClose?: boolean,\n\tcastSize?: 2 | 3 | 4\n): string {\n\tconst base = (embedBaseUrl ?? resolvePublicPlayerEmbedUrl()).replace(/\\/$/, '');\n\tconst embedRoot = base.endsWith('/embed') ? base : `${base}/embed`;\n\tconst url = new URL(embedRoot);\n\tconst loc = backdropId?.trim();\n\tif (loc) {\n\t\turl.searchParams.set('backdropId', loc);\n\t\turl.searchParams.set('locationId', loc);\n\t}\n\tconst avatar = avatarId?.trim();\n\tif (avatar) {\n\t\turl.searchParams.set('avatarId', avatar);\n\t}\n\tif (fit === 'face' || fit === 'medium') {\n\t\turl.searchParams.set('fit', fit);\n\t}\n\tif (ui === 'widget') {\n\t\turl.searchParams.set('ui', 'widget');\n\t}\n\tif (showClose) {\n\t\turl.searchParams.set('close', '1');\n\t}\n\tif (debug) {\n\t\turl.searchParams.set('debug', 'true');\n\t}\n\tif (castSize === 2 || castSize === 3 || castSize === 4) {\n\t\turl.searchParams.set('cast', String(castSize));\n\t}\n\treturn withEmbedParentOrigin(url.toString());\n}\n\nexport function buildPublicEmbedUrl(\n\texperienceId: string,\n\tembedBaseUrl?: string,\n\tlanguage?: 'en' | 'es',\n\tbackdropId?: string,\n\tavatarId?: string,\n\tdebug?: boolean\n): string {\n\tconst base = (embedBaseUrl ?? resolvePublicPlayerEmbedUrl()).replace(/\\/$/, '');\n\tconst embedRoot = base.endsWith('/embed') ? base : `${base}/embed`;\n\tconst url = new URL(embedRoot);\n\turl.searchParams.set('experienceId', experienceId);\n\tif (language && language !== 'en') {\n\t\turl.searchParams.set('language', language);\n\t}\n\tconst loc = backdropId?.trim();\n\tif (loc) {\n\t\turl.searchParams.set('backdropId', loc);\n\t\turl.searchParams.set('locationId', loc);\n\t}\n\tconst avatar = avatarId?.trim();\n\tif (avatar) {\n\t\turl.searchParams.set('avatarId', avatar);\n\t}\n\tif (debug) {\n\t\turl.searchParams.set('debug', 'true');\n\t}\n\treturn withEmbedParentOrigin(url.toString());\n}\n\n/** Tell the player embed which origin may receive postMessage events (SDK parent page). */\nexport function withEmbedParentOrigin(embedUrl: string): string {\n\tif (typeof location === 'undefined') return embedUrl;\n\tconst url = new URL(embedUrl);\n\turl.searchParams.set('parentOrigin', location.origin);\n\treturn url.toString();\n}\n\nexport function resolvePlayerOrigin(embedUrl: string): string {\n\treturn new URL(embedUrl).origin;\n}\n","import type { ReadyEvent } from './experience';\nimport type {\n\tCharacterSpeechEvent,\n\tConversationMessage,\n\tConversationProcessorErrorEvent,\n\tExperienceInteraction,\n\tStartedEvent,\n\tUserSpeechBoundaryEvent,\n\tUserTranscriptUpdate\n} from './types/sessionInteraction';\nimport type { SessionActivity } from './types/sessionLaunch';\n\nexport type FeedbackResult = {\n\treadonly contractVersion: 'feedback.v1';\n\treadonly types: readonly {\n\t\treadonly feedbackId: string;\n\t\treadonly name: string;\n\t\treadonly criteria: readonly {\n\t\t\treadonly criterionId: string;\n\t\t\treadonly label: string;\n\t\t\treadonly score: number | string;\n\t\t\treadonly rationale: string;\n\t\t}[];\n\t}[];\n};\n\nexport type FeedbackFailedEvent = {\n\treadonly error: string;\n\treadonly model?: string;\n};\n\nexport type ExperienceEventEnvelope<T = unknown> = {\n\treadonly id: string;\n\treadonly type: string;\n\treadonly sessionId: string;\n\treadonly timestamp: string;\n\treadonly data: T;\n};\n\nfunction newEventId(): string {\n\tif (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n\t\treturn `evt_${crypto.randomUUID().replace(/-/g, '').slice(0, 12)}`;\n\t}\n\treturn `evt_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;\n}\n\nexport function createExperienceEventEnvelope<T>(\n\ttype: string,\n\tsessionId: string,\n\tdata: T\n): ExperienceEventEnvelope<T> {\n\treturn {\n\t\tid: newEventId(),\n\t\ttype,\n\t\tsessionId,\n\t\ttimestamp: new Date().toISOString(),\n\t\tdata\n\t};\n}\n\nexport type ExperienceEvents = {\n\treadonly ready: ExperienceEventEnvelope<ReadyEvent>;\n\treadonly started: ExperienceEventEnvelope<StartedEvent>;\n\t/** Fired once after a successful Session Launch mint (before player ready). */\n\treadonly sessionMinted: ExperienceEventEnvelope<ReadyEvent>;\n\treadonly userTranscript: ExperienceEventEnvelope<UserTranscriptUpdate>;\n\treadonly userSpeechStarted: ExperienceEventEnvelope<UserSpeechBoundaryEvent>;\n\treadonly userSpeechEnded: ExperienceEventEnvelope<UserSpeechBoundaryEvent>;\n\treadonly characterSpeechStarted: ExperienceEventEnvelope<CharacterSpeechEvent>;\n\treadonly characterSpeechEnded: ExperienceEventEnvelope<CharacterSpeechEvent>;\n\treadonly characterFocusChanged: ExperienceEventEnvelope<{\n\t\treadonly characterId: string;\n\t\treadonly reason: 'speech' | 'api' | 'node_enter';\n\t}>;\n\treadonly conversationUpdate: ExperienceEventEnvelope<readonly ConversationMessage[]>;\n\treadonly message: ExperienceEventEnvelope<ConversationMessage>;\n\treadonly listeningState: ExperienceEventEnvelope<boolean>;\n\treadonly activityChange: ExperienceEventEnvelope<SessionActivity>;\n\t/** Live captions / mic / text / Edit allow + state after player resolve. */\n\treadonly interactionChange: ExperienceEventEnvelope<ExperienceInteraction>;\n\t/** End-of-session Feedback scores (`feedback.v1`). Emitted when scoring succeeds. */\n\treadonly feedback: ExperienceEventEnvelope<FeedbackResult>;\n\t/** End-of-session Feedback scoring failed. */\n\treadonly feedbackFailed: ExperienceEventEnvelope<FeedbackFailedEvent>;\n\treadonly conversationProcessorError: ExperienceEventEnvelope<ConversationProcessorErrorEvent>;\n};\n\n/**\n * Reserved integrator event name: `backdropChange`.\n * The hosted player does not emit `locationChange` or `backdropChange` today.\n * Do not invent a client-side fake until the runtime actually changes scene mid-session.\n */\n\nexport type ExperienceEventName = keyof ExperienceEvents;\n\ntype HandlerSet<K extends ExperienceEventName> = Set<(event: ExperienceEvents[K]) => void>;\n\nexport type ExperienceEventRegistry = {\n\treadonly [K in ExperienceEventName]: HandlerSet<K>;\n};\n\nexport function createExperienceEventRegistry(): ExperienceEventRegistry {\n\treturn {\n\t\tready: new Set(),\n\t\tstarted: new Set(),\n\t\tsessionMinted: new Set(),\n\t\tuserTranscript: new Set(),\n\t\tuserSpeechStarted: new Set(),\n\t\tuserSpeechEnded: new Set(),\n\t\tcharacterSpeechStarted: new Set(),\n\t\tcharacterSpeechEnded: new Set(),\n\t\tcharacterFocusChanged: new Set(),\n\t\tconversationUpdate: new Set(),\n\t\tmessage: new Set(),\n\t\tlisteningState: new Set(),\n\t\tactivityChange: new Set(),\n\t\tinteractionChange: new Set(),\n\t\tfeedback: new Set(),\n\t\tfeedbackFailed: new Set(),\n\t\tconversationProcessorError: new Set()\n\t};\n}\n\nexport function subscribeExperienceEvent<K extends ExperienceEventName>(\n\tregistry: ExperienceEventRegistry,\n\tevent: K,\n\thandler: (payload: ExperienceEvents[K]) => void\n): () => void {\n\tregistry[event].add(handler);\n\treturn () => registry[event].delete(handler);\n}\n\nexport function emitExperienceEvent<K extends ExperienceEventName>(\n\tregistry: ExperienceEventRegistry,\n\tevent: K,\n\tpayload: ExperienceEvents[K]\n): void {\n\tfor (const handler of registry[event]) {\n\t\thandler(payload);\n\t}\n}\n\nexport function clearExperienceEventRegistry(registry: ExperienceEventRegistry): void {\n\tfor (const key of Object.keys(registry) as ExperienceEventName[]) {\n\t\tregistry[key].clear();\n\t}\n}\n","/**\n * Phase A public speech contract for Experience.speech\n * (docs/plans/2026/08/experience-play-audio-api.plan.md).\n */\n\nexport type SpeechAudioFormat = {\n\treadonly encoding: 'pcm_s16le';\n\treadonly sampleRate: number;\n\treadonly channels: 1;\n};\n\n/** Complete one-shot ops only (`speak` / `play`). */\nexport type CompleteSpeechQueuePolicy = 'append' | 'replace-active' | 'replace-all';\n\n/** Live streams only — `append` is forbidden. */\nexport type StreamingSpeechQueuePolicy = 'replace-active' | 'replace-all';\n\nexport type SpeechTerminalStatus = 'completed' | 'interrupted' | 'cancelled' | 'destroyed';\n\nexport type SpeechAnimationMode = 'tracked' | 'partially-tracked' | 'energy-fallback' | 'none';\n\nexport type SpeechResult = {\n\treadonly utteranceId: string;\n\treadonly characterId: string;\n\treadonly status: SpeechTerminalStatus;\n\treadonly durationMs: number;\n\treadonly transcript?: string;\n\treadonly animation: {\n\t\treadonly mode: SpeechAnimationMode;\n\t\treadonly trackedDurationMs: number;\n\t\treadonly fallbackDurationMs: number;\n\t\treadonly warningCodes?: readonly string[];\n\t};\n};\n\nexport type SpeechInterruptOptions =\n\t| { readonly utteranceId: string }\n\t| { readonly characterId: string }\n\t| { readonly scope?: 'active' | 'all' };\n\nexport type SpeechSpeakOptions = {\n\treadonly text: string;\n\treadonly characterId?: string;\n\treadonly queue?: CompleteSpeechQueuePolicy;\n\treadonly signal?: AbortSignal;\n};\n\n/** Raw PCM one-shot (Phase A). */\nexport type SpeechPlayPcmAudio = {\n\treadonly data: ArrayBuffer | Uint8Array;\n\treadonly format: SpeechAudioFormat;\n};\n\n/**\n * Encoded media bytes (wav/mp3/…). Player decodes via Web Audio — not api/models.\n * `encoding` is a MIME type such as `audio/mpeg` or `audio/wav`.\n */\nexport type SpeechPlayEncodedAudio = {\n\treadonly data: ArrayBuffer | Uint8Array | Blob;\n\treadonly encoding: string;\n\t/** Preferred pcm sample rate after decode (default 24000 when decoded rate is unsupported). */\n\treadonly sampleRate?: number;\n};\n\n/** Fetch + decode in the player (URL must allow CORS from player.liforma.ai). */\nexport type SpeechPlayUrlAudio = {\n\treadonly url: string;\n\treadonly sampleRate?: number;\n};\n\n/**\n * Live audio track. Captured to PCM in the **host** SDK (not transferable across the embed).\n * Prefer `createUtterance({ track })` for long streams; `play({ audio: { track } })` runs until\n * the track ends then closes the utterance.\n */\nexport type SpeechPlayMediaStreamAudio = {\n\treadonly track: MediaStreamTrack;\n\t/** Target pcm sample rate after capture (default 24000). */\n\treadonly sampleRate?: number;\n};\n\nexport type SpeechPlayAudio =\n\t| SpeechPlayPcmAudio\n\t| SpeechPlayEncodedAudio\n\t| SpeechPlayUrlAudio\n\t| SpeechPlayMediaStreamAudio;\n\nexport type SpeechPlayOptions = {\n\treadonly audio: SpeechPlayAudio;\n\treadonly characterId?: string;\n\treadonly transcript?: string;\n\treadonly history?: 'none' | 'commit';\n\treadonly queue?: CompleteSpeechQueuePolicy;\n\treadonly signal?: AbortSignal;\n};\n\n/** Embed / player wire format for {@link SpeechPlayOptions.audio}. */\nexport type SpeechPlayEmbedSource =\n\t| {\n\t\t\treadonly kind: 'pcm';\n\t\t\treadonly data: ArrayBuffer;\n\t\t\treadonly format: SpeechAudioFormat;\n\t }\n\t| {\n\t\t\treadonly kind: 'encoded';\n\t\t\treadonly data: ArrayBuffer;\n\t\t\treadonly encoding: string;\n\t\t\treadonly sampleRate?: number;\n\t }\n\t| {\n\t\t\treadonly kind: 'url';\n\t\t\treadonly url: string;\n\t\t\treadonly sampleRate?: number;\n\t };\n\nexport function isSpeechPlayPcmAudio(audio: SpeechPlayAudio): audio is SpeechPlayPcmAudio {\n\treturn (\n\t\t'data' in audio &&\n\t\t'format' in audio &&\n\t\t(audio as SpeechPlayPcmAudio).format != null &&\n\t\t!('track' in audio)\n\t);\n}\n\nexport function isSpeechPlayUrlAudio(audio: SpeechPlayAudio): audio is SpeechPlayUrlAudio {\n\treturn 'url' in audio && typeof (audio as SpeechPlayUrlAudio).url === 'string';\n}\n\nexport function isSpeechPlayMediaStreamAudio(\n\taudio: SpeechPlayAudio\n): audio is SpeechPlayMediaStreamAudio {\n\tif (!('track' in audio)) return false;\n\tconst track = (audio as SpeechPlayMediaStreamAudio).track as unknown;\n\tif (track == null || typeof track !== 'object') return false;\n\tif (typeof MediaStreamTrack !== 'undefined' && track instanceof MediaStreamTrack) {\n\t\treturn true;\n\t}\n\t// Duck-type for non-DOM / test environments.\n\treturn 'kind' in track && 'readyState' in track;\n}\n\nexport function isSpeechPlayEncodedAudio(audio: SpeechPlayAudio): audio is SpeechPlayEncodedAudio {\n\treturn (\n\t\t!isSpeechPlayPcmAudio(audio) &&\n\t\t!isSpeechPlayUrlAudio(audio) &&\n\t\t!isSpeechPlayMediaStreamAudio(audio) &&\n\t\t'encoding' in audio &&\n\t\ttypeof (audio as SpeechPlayEncodedAudio).encoding === 'string'\n\t);\n}\n\nexport type SpeechCreateUtteranceOptions = {\n\t/**\n\t * Required unless `track` is set. When `track` is provided without `format`, defaults to\n\t * pcm_s16le mono at `sampleRate` (or 24000).\n\t */\n\treadonly format?: SpeechAudioFormat;\n\t/** Optional live track — host captures and writes until the track ends. */\n\treadonly track?: MediaStreamTrack;\n\t/** Used with `track` when `format` is omitted (default 24000). */\n\treadonly sampleRate?: number;\n\treadonly characterId?: string;\n\treadonly queue?: StreamingSpeechQueuePolicy;\n\t/**\n\t * Optional spoken text seed for force-aligned STA (lip sync).\n\t * Non-empty transcript enables force-align for this utterance; omit / whitespace → free CTC.\n\t * May be updated mid-turn via {@link SpeechUtterance.setTranscript} or finalized on\n\t * {@link SpeechUtterance.close} `{ transcript }`.\n\t */\n\treadonly transcript?: string;\n\treadonly signal?: AbortSignal;\n};\n\nexport type SpeechUtteranceCloseOptions = {\n\treadonly transcript?: string;\n\treadonly history?: 'none' | 'commit';\n};\n\nexport type SpeechWriteOptions = {\n\treadonly timeoutMs?: number;\n};\n\nexport type SpeechUtterance = {\n\treadonly id: string;\n\treadonly characterId: string;\n\treadonly result: Promise<SpeechResult>;\n\twrite(audio: ArrayBuffer | Uint8Array, options?: SpeechWriteOptions): Promise<void>;\n\t/**\n\t * Replace / set spoken text mid-turn for force-aligned STA.\n\t * Non-empty text upgrades free decode → force-align (full-utterance on close).\n\t * Empty / whitespace is a no-op.\n\t */\n\tsetTranscript(text: string): Promise<void>;\n\tclose(options?: SpeechUtteranceCloseOptions): Promise<SpeechResult>;\n\tcancel(): Promise<SpeechResult>;\n};\n\nexport type SpeechController = {\n\tspeak(options: SpeechSpeakOptions): Promise<SpeechResult>;\n\tplay(options: SpeechPlayOptions): Promise<SpeechResult>;\n\tcreateUtterance(options: SpeechCreateUtteranceOptions): SpeechUtterance;\n\tinterrupt(options?: SpeechInterruptOptions): Promise<readonly SpeechResult[]>;\n};\n\n/** Accepted PCM sample rates (Phase A). */\nexport const SPEECH_ACCEPTED_SAMPLE_RATES = [\n\t8000, 16000, 22050, 24000, 44100, 48000\n] as const;\n\nexport const SPEECH_LIMITS = {\n\tMAX_CHUNK_BYTES: 64 * 1024,\n\tRECOMMENDED_CHUNK_MS_MIN: 20,\n\tRECOMMENDED_CHUNK_MS_MAX: 200,\n\tMAX_BUFFERED_AUDIO_MS: 8_000,\n\tPLAYBACK_JITTER_BUFFER_MS: 150,\n\tPLAYBACK_JITTER_BUFFER_MS_MIN: 80,\n\tPLAYBACK_JITTER_BUFFER_MS_MAX: 250,\n\tMAX_UTTERANCE_DURATION_MS: 90_000,\n\tMAX_PENDING_WRITES: 8,\n\tDEFAULT_WRITE_TIMEOUT_MS: 5_000\n} as const;\n\nexport class UnsupportedSpeechOperationError extends Error {\n\treadonly name = 'UnsupportedSpeechOperationError';\n\tconstructor(\n\t\treadonly operation: string,\n\t\treadonly requiredCapability: string\n\t) {\n\t\tsuper(`Speech operation \"${operation}\" requires capability \"${requiredCapability}\".`);\n\t}\n}\n\nexport class SpeechUtteranceClosedError extends Error {\n\treadonly name = 'SpeechUtteranceClosedError';\n\tconstructor(message = 'Cannot write to a closed or cancelled speech utterance.') {\n\t\tsuper(message);\n\t}\n}\n\nexport class SpeechRuntimeError extends Error {\n\treadonly name = 'SpeechRuntimeError';\n\tconstructor(message: string, options?: { cause?: unknown }) {\n\t\tsuper(message, options);\n\t}\n}\n\nexport class SpeechBufferTimeoutError extends Error {\n\treadonly name = 'SpeechBufferTimeoutError';\n\tconstructor(message = 'Timed out waiting for speech buffer capacity.') {\n\t\tsuper(message);\n\t}\n}\n\nexport function emptyAnimationResult(\n\tmode: SpeechAnimationMode = 'none'\n): SpeechResult['animation'] {\n\treturn {\n\t\tmode,\n\t\ttrackedDurationMs: 0,\n\t\tfallbackDurationMs: 0\n\t};\n}\n\nexport function isAcceptedSampleRate(rate: number): boolean {\n\treturn (SPEECH_ACCEPTED_SAMPLE_RATES as readonly number[]).includes(rate);\n}\n\nexport function assertPcmFormat(format: SpeechAudioFormat): void {\n\tif (format.encoding !== 'pcm_s16le') {\n\t\tthrow new SpeechRuntimeError(`Unsupported audio encoding: ${format.encoding}`);\n\t}\n\tif (format.channels !== 1) {\n\t\tthrow new SpeechRuntimeError(`Unsupported channel count: ${format.channels}`);\n\t}\n\tif (!isAcceptedSampleRate(format.sampleRate)) {\n\t\tthrow new SpeechRuntimeError(`Unsupported sample rate: ${format.sampleRate}`);\n\t}\n}\n\nexport function assertSpeechPlayAudio(audio: SpeechPlayAudio): void {\n\tif (isSpeechPlayPcmAudio(audio)) {\n\t\tassertPcmFormat(audio.format);\n\t\treturn;\n\t}\n\tif (isSpeechPlayUrlAudio(audio)) {\n\t\tconst url = audio.url.trim();\n\t\tif (!url) throw new SpeechRuntimeError('Audio URL must be non-empty.');\n\t\tif (audio.sampleRate !== undefined && !isAcceptedSampleRate(audio.sampleRate)) {\n\t\t\tthrow new SpeechRuntimeError(`Unsupported sample rate: ${audio.sampleRate}`);\n\t\t}\n\t\treturn;\n\t}\n\tif (isSpeechPlayMediaStreamAudio(audio)) {\n\t\tif (audio.track.kind !== 'audio') {\n\t\t\tthrow new SpeechRuntimeError('speech.play track must be an audio MediaStreamTrack.');\n\t\t}\n\t\tif (audio.sampleRate !== undefined && !isAcceptedSampleRate(audio.sampleRate)) {\n\t\t\tthrow new SpeechRuntimeError(`Unsupported sample rate: ${audio.sampleRate}`);\n\t\t}\n\t\treturn;\n\t}\n\tif (isSpeechPlayEncodedAudio(audio)) {\n\t\tconst encoding = audio.encoding.trim().toLowerCase();\n\t\tif (!encoding) throw new SpeechRuntimeError('Encoded audio MIME type is required.');\n\t\tif (encoding === 'pcm_s16le') {\n\t\t\tthrow new SpeechRuntimeError('Use format: { encoding: \"pcm_s16le\", … } for raw PCM.');\n\t\t}\n\t\tif (audio.sampleRate !== undefined && !isAcceptedSampleRate(audio.sampleRate)) {\n\t\t\tthrow new SpeechRuntimeError(`Unsupported sample rate: ${audio.sampleRate}`);\n\t\t}\n\t\treturn;\n\t}\n\tthrow new SpeechRuntimeError('Unsupported speech.play audio shape.');\n}\n\nexport function resolveCreateUtteranceFormat(\n\toptions: SpeechCreateUtteranceOptions\n): SpeechAudioFormat {\n\tif (options.format) {\n\t\tassertPcmFormat(options.format);\n\t\treturn options.format;\n\t}\n\tif (options.track) {\n\t\tconst sampleRate = options.sampleRate ?? 24_000;\n\t\tconst format: SpeechAudioFormat = {\n\t\t\tencoding: 'pcm_s16le',\n\t\t\tsampleRate,\n\t\t\tchannels: 1\n\t\t};\n\t\tassertPcmFormat(format);\n\t\treturn format;\n\t}\n\tthrow new SpeechRuntimeError('createUtterance requires format or track.');\n}\n\nexport function toUint8Array(data: ArrayBuffer | Uint8Array): Uint8Array {\n\treturn data instanceof Uint8Array ? data : new Uint8Array(data);\n}\n\nexport function queuePolicyToEmbedBehavior(\n\tqueue: CompleteSpeechQueuePolicy | StreamingSpeechQueuePolicy | undefined\n): 'enqueue' | 'interrupt' {\n\tif (queue === 'replace-active' || queue === 'replace-all') return 'interrupt';\n\treturn 'enqueue';\n}\n","/** Liforma `speech.write` rejects chunks larger than 64 KiB. */\nexport const MAX_PCM_CHUNK_BYTES = 64 * 1024;\n\n/**\n * Playback / chunk guidance for custom BYO bridges (mirrors speech controller limits).\n * Prefer ~20–200 ms PCM frames; the player starts after an adaptive ~80–250 ms jitter\n * buffer (default 150 ms) based on chunk arrival variance.\n */\nexport const BYO_PLAYBACK_GUIDANCE = {\n\tRECOMMENDED_CHUNK_MS_MIN: 20,\n\tRECOMMENDED_CHUNK_MS_MAX: 200,\n\tPLAYBACK_JITTER_BUFFER_MS: 150,\n\tPLAYBACK_JITTER_BUFFER_MS_MIN: 80,\n\tPLAYBACK_JITTER_BUFFER_MS_MAX: 250\n} as const;\n\nexport function base64ToPcmBytes(b64: string): Uint8Array {\n\tconst bin = atob(b64);\n\tconst out = new Uint8Array(bin.length);\n\tfor (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n\treturn out;\n}\n\nexport function pcmBytesToBase64(bytes: Uint8Array): string {\n\tlet bin = '';\n\tconst chunk = 0x8000;\n\tfor (let i = 0; i < bytes.length; i += chunk) {\n\t\tbin += String.fromCharCode(...bytes.subarray(i, i + chunk));\n\t}\n\treturn btoa(bin);\n}\n\nexport function floatToPcm16Le(input: Float32Array): Uint8Array {\n\tconst out = new Uint8Array(input.length * 2);\n\tconst view = new DataView(out.buffer);\n\tfor (let i = 0; i < input.length; i++) {\n\t\tconst s = Math.max(-1, Math.min(1, input[i]!));\n\t\tview.setInt16(i * 2, s < 0 ? s * 0x8000 : s * 0x7fff, true);\n\t}\n\treturn out;\n}\n\n/** Naive linear resample Float32 → target rate. */\nexport function resampleFloat32(input: Float32Array, fromRate: number, toRate: number): Float32Array {\n\tif (fromRate === toRate || input.length === 0) return input;\n\tconst ratio = fromRate / toRate;\n\tconst outLen = Math.max(1, Math.round(input.length / ratio));\n\tconst out = new Float32Array(outLen);\n\tfor (let i = 0; i < outLen; i++) {\n\t\tconst src = i * ratio;\n\t\tconst i0 = Math.floor(src);\n\t\tconst i1 = Math.min(i0 + 1, input.length - 1);\n\t\tconst t = src - i0;\n\t\tout[i] = input[i0]! * (1 - t) + input[i1]! * t;\n\t}\n\treturn out;\n}\n\n/**\n * Parse vendor format strings like `pcm_16000` / `pcm_24000`.\n * Returns null when the format is missing or not PCM.\n */\nexport function parsePcmSampleRate(format: string | null | undefined): number | null {\n\tconst m = /^pcm_(\\d+)$/.exec(format ?? '');\n\tif (!m) return null;\n\tconst rate = Number(m[1]);\n\treturn Number.isFinite(rate) && rate > 0 ? rate : null;\n}\n\n/**\n * Write even-length PCM, splitting at MAX_PCM_CHUNK_BYTES on even boundaries.\n * Callers that may receive odd-length frames should run bytes through\n * {@link takeEvenPcmBytes} first so samples are not dropped across chunks.\n */\nexport async function writePcmInChunks(\n\tutterance: { write: (chunk: ArrayBuffer | ArrayBufferView) => Promise<unknown> },\n\tbytes: Uint8Array\n): Promise<void> {\n\tif (bytes.byteLength === 0) return;\n\tif ((bytes.byteLength & 1) !== 0) {\n\t\t// Defensive: drop trailing unpaired byte within a single call.\n\t\tbytes = bytes.subarray(0, bytes.byteLength - 1);\n\t\tif (bytes.byteLength === 0) return;\n\t}\n\tif (bytes.byteLength <= MAX_PCM_CHUNK_BYTES) {\n\t\tawait utterance.write(bytes);\n\t\treturn;\n\t}\n\tlet offset = 0;\n\twhile (offset < bytes.byteLength) {\n\t\tlet end = Math.min(offset + MAX_PCM_CHUNK_BYTES, bytes.byteLength);\n\t\tif ((end - offset) % 2 === 1) end -= 1;\n\t\tif (end <= offset) break;\n\t\tawait utterance.write(bytes.subarray(offset, end));\n\t\toffset = end;\n\t}\n}\n","/**\n * Stateful cubic (Catmull-Rom) resampler for continuous PCM capture streams.\n * Better than naive linear for uplink mic / track capture.\n */\n\nexport type FloatResampler = {\n\t/** Push a mono float buffer; returns samples at the target rate (may be empty). */\n\tpush(input: Float32Array): Float32Array;\n\t/** Flush any remaining fractional sample (usually silence). */\n\tflush(): Float32Array;\n\treadonly fromRate: number;\n\treadonly toRate: number;\n};\n\nfunction catmullRom(y0: number, y1: number, y2: number, y3: number, t: number): number {\n\tconst a0 = -0.5 * y0 + 1.5 * y1 - 1.5 * y2 + 0.5 * y3;\n\tconst a1 = y0 - 2.5 * y1 + 2 * y2 - 0.5 * y3;\n\tconst a2 = -0.5 * y0 + 0.5 * y2;\n\tconst a3 = y1;\n\treturn ((a0 * t + a1) * t + a2) * t + a3;\n}\n\n/**\n * Create a continuous resampler. When rates match, push() returns the input as-is\n * (no copy) when possible.\n */\nexport function createCubicResampler(fromRate: number, toRate: number): FloatResampler {\n\tif (!(fromRate > 0) || !(toRate > 0)) {\n\t\tthrow new Error('Resampler rates must be positive');\n\t}\n\n\tif (fromRate === toRate) {\n\t\treturn {\n\t\t\tfromRate,\n\t\t\ttoRate,\n\t\t\tpush(input) {\n\t\t\t\treturn input;\n\t\t\t},\n\t\t\tflush() {\n\t\t\t\treturn new Float32Array(0);\n\t\t\t}\n\t\t};\n\t}\n\n\tconst ratio = fromRate / toRate;\n\t/** History + pending input (keeps 3 samples of lookbehind for cubic). */\n\tlet pending = new Float32Array(0);\n\tlet pos = 0; // position in pending sample space for next output\n\n\treturn {\n\t\tfromRate,\n\t\ttoRate,\n\t\tpush(input) {\n\t\t\tif (input.length === 0) return new Float32Array(0);\n\t\t\tconst merged = new Float32Array(pending.length + input.length);\n\t\t\tmerged.set(pending);\n\t\t\tmerged.set(input, pending.length);\n\t\t\tpending = merged;\n\n\t\t\tif (pending.length < 4) return new Float32Array(0);\n\n\t\t\tconst out: number[] = [];\n\t\t\t// Need i+2 available for cubic; stop while pos+2 < length-1 equivalently floor(pos)+2 < len-?\n\t\t\twhile (pos + 2 < pending.length - 1) {\n\t\t\t\tconst i1 = Math.floor(pos);\n\t\t\t\tconst t = pos - i1;\n\t\t\t\tconst i0 = Math.max(0, i1 - 1);\n\t\t\t\tconst i2 = Math.min(pending.length - 1, i1 + 1);\n\t\t\t\tconst i3 = Math.min(pending.length - 1, i1 + 2);\n\t\t\t\tout.push(\n\t\t\t\t\tcatmullRom(pending[i0]!, pending[i1]!, pending[i2]!, pending[i3]!, t)\n\t\t\t\t);\n\t\t\t\tpos += ratio;\n\t\t\t}\n\n\t\t\t// Drop consumed samples but keep lookbehind (≥1) and unread tail.\n\t\t\tconst drop = Math.max(0, Math.floor(pos) - 1);\n\t\t\tif (drop > 0) {\n\t\t\t\tpending = pending.subarray(drop);\n\t\t\t\tpos -= drop;\n\t\t\t}\n\n\t\t\treturn out.length ? Float32Array.from(out) : new Float32Array(0);\n\t\t},\n\t\tflush() {\n\t\t\tif (pending.length === 0) return new Float32Array(0);\n\t\t\t// Emit one last sample if we have enough history; otherwise drop.\n\t\t\tpending = new Float32Array(0);\n\t\t\tpos = 0;\n\t\t\treturn new Float32Array(0);\n\t\t}\n\t};\n}\n","/**\n * Shared Web Audio capture: AudioWorklet when available, ScriptProcessor fallback.\n * Used by BYO mic uplink and MediaStreamTrack → PCM piping.\n */\n\nimport { floatToPcm16Le } from './pcm';\nimport { createCubicResampler, type FloatResampler } from './resample';\n\nexport type AudioCaptureSession = {\n\tstop(): void;\n\treadonly fromSampleRate: number;\n\treadonly usingWorklet: boolean;\n};\n\nexport type StartAudioCaptureOptions = {\n\treadonly mediaStream: MediaStream;\n\treadonly targetSampleRate: number;\n\t/** Called with pcm_s16le mono at targetSampleRate. */\n\treadonly onPcm: (bytes: Uint8Array) => void;\n\t/** When false, frames are dropped. */\n\treadonly shouldSend?: () => boolean;\n\treadonly onLog?: (line: string, kind?: 'info' | 'warn') => void;\n};\n\nconst WORKLET_NAME = 'liforma-pcm-capture';\n\nconst WORKLET_SOURCE = `\nclass LiformaPcmCaptureProcessor extends AudioWorkletProcessor {\n process(inputs) {\n const ch = inputs[0] && inputs[0][0];\n if (ch && ch.length) {\n const copy = new Float32Array(ch.length);\n copy.set(ch);\n this.port.postMessage(copy, [copy.buffer]);\n }\n return true;\n }\n}\nregisterProcessor('${WORKLET_NAME}', LiformaPcmCaptureProcessor);\n`;\n\nlet workletUrl: string | null = null;\n\nfunction getWorkletUrl(): string {\n\tif (!workletUrl) {\n\t\tworkletUrl = URL.createObjectURL(\n\t\t\tnew Blob([WORKLET_SOURCE], { type: 'application/javascript' })\n\t\t);\n\t}\n\treturn workletUrl;\n}\n\nfunction getAudioContextCtor(): typeof AudioContext | null {\n\treturn (\n\t\twindow.AudioContext ||\n\t\t(window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext ||\n\t\tnull\n\t);\n}\n\n/**\n * Capture a MediaStream as pcm_s16le at targetSampleRate.\n * Prefers AudioWorklet; falls back to ScriptProcessorNode.\n */\nexport async function startAudioCapture(\n\toptions: StartAudioCaptureOptions\n): Promise<AudioCaptureSession> {\n\tconst { mediaStream, targetSampleRate, onPcm, shouldSend, onLog } = options;\n\tconst AudioContextCtor = getAudioContextCtor();\n\tif (!AudioContextCtor) throw new Error('Web Audio is required for audio capture');\n\n\tconst audioCtx = new AudioContextCtor();\n\tconst source = audioCtx.createMediaStreamSource(mediaStream);\n\tconst silent = audioCtx.createGain();\n\tsilent.gain.value = 0;\n\tconst fromSampleRate = audioCtx.sampleRate;\n\tconst resampler: FloatResampler = createCubicResampler(fromSampleRate, targetSampleRate);\n\tlet stopped = false;\n\tlet usingWorklet = false;\n\n\tconst emitFloat = (input: Float32Array) => {\n\t\tif (stopped) return;\n\t\tif (shouldSend && !shouldSend()) return;\n\t\tconst resampled = resampler.push(input);\n\t\tif (resampled.length === 0) return;\n\t\tonPcm(floatToPcm16Le(resampled));\n\t};\n\n\tlet disconnectGraph: () => void = () => undefined;\n\n\tconst tryWorklet = async (): Promise<boolean> => {\n\t\tif (typeof audioCtx.audioWorklet?.addModule !== 'function') return false;\n\t\ttry {\n\t\t\tawait audioCtx.audioWorklet.addModule(getWorkletUrl());\n\t\t\tconst node = new AudioWorkletNode(audioCtx, WORKLET_NAME, {\n\t\t\t\tnumberOfInputs: 1,\n\t\t\t\tnumberOfOutputs: 1,\n\t\t\t\toutputChannelCount: [1]\n\t\t\t});\n\t\t\tnode.port.onmessage = (ev) => {\n\t\t\t\tif (ev.data instanceof Float32Array) emitFloat(ev.data);\n\t\t\t};\n\t\t\tsource.connect(node);\n\t\t\tnode.connect(silent);\n\t\t\tsilent.connect(audioCtx.destination);\n\t\t\tdisconnectGraph = () => {\n\t\t\t\tnode.port.onmessage = null;\n\t\t\t\ttry {\n\t\t\t\t\tnode.disconnect();\n\t\t\t\t} catch {\n\t\t\t\t\t/* ignore */\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tsource.disconnect();\n\t\t\t\t} catch {\n\t\t\t\t\t/* ignore */\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tsilent.disconnect();\n\t\t\t\t} catch {\n\t\t\t\t\t/* ignore */\n\t\t\t\t}\n\t\t\t};\n\t\t\tusingWorklet = true;\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t};\n\n\tconst useScriptProcessor = (): void => {\n\t\tconst createScriptProcessor = (\n\t\t\taudioCtx as AudioContext & {\n\t\t\t\tcreateScriptProcessor?: (\n\t\t\t\t\tbufferSize: number,\n\t\t\t\t\tinputChannels: number,\n\t\t\t\t\toutputChannels: number\n\t\t\t\t) => ScriptProcessorNode;\n\t\t\t}\n\t\t).createScriptProcessor?.bind(audioCtx);\n\n\t\tif (!createScriptProcessor) {\n\t\t\tthrow new Error('Neither AudioWorklet nor ScriptProcessor is available');\n\t\t}\n\n\t\tconst processor = createScriptProcessor(4096, 1, 1);\n\t\tprocessor.onaudioprocess = (ev) => {\n\t\t\temitFloat(ev.inputBuffer.getChannelData(0));\n\t\t};\n\t\tsource.connect(processor);\n\t\tprocessor.connect(silent);\n\t\tsilent.connect(audioCtx.destination);\n\t\tdisconnectGraph = () => {\n\t\t\tprocessor.onaudioprocess = null;\n\t\t\ttry {\n\t\t\t\tprocessor.disconnect();\n\t\t\t} catch {\n\t\t\t\t/* ignore */\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tsource.disconnect();\n\t\t\t} catch {\n\t\t\t\t/* ignore */\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tsilent.disconnect();\n\t\t\t} catch {\n\t\t\t\t/* ignore */\n\t\t\t}\n\t\t};\n\t\tusingWorklet = false;\n\t};\n\n\tif (!(await tryWorklet())) {\n\t\tuseScriptProcessor();\n\t\tonLog?.(\n\t\t\t`Mic/track capture via ScriptProcessor at ${fromSampleRate} Hz → ${targetSampleRate} Hz`,\n\t\t\t'warn'\n\t\t);\n\t} else {\n\t\tonLog?.(`Mic/track capture via AudioWorklet at ${fromSampleRate} Hz → ${targetSampleRate} Hz`);\n\t}\n\n\tif (audioCtx.state === 'suspended') {\n\t\tawait audioCtx.resume().catch(() => undefined);\n\t}\n\n\treturn {\n\t\tfromSampleRate,\n\t\tusingWorklet,\n\t\tstop() {\n\t\t\tif (stopped) return;\n\t\t\tstopped = true;\n\t\t\tresampler.flush();\n\t\t\tdisconnectGraph();\n\t\t\tvoid audioCtx.close().catch(() => undefined);\n\t\t}\n\t};\n}\n","/**\n * Host-side MediaStreamTrack → mono pcm_s16le capture for experience.speech.\n * Capture stays in the SDK (host page); player only receives PCM chunks.\n */\n\nimport { startAudioCapture } from '../../byo/audioCapture';\nimport { SPEECH_LIMITS, SpeechRuntimeError, toUint8Array } from './types';\nimport type { SpeechUtterance } from './types';\n\nexport type CaptureMediaStreamTrackOptions = {\n\treadonly track: MediaStreamTrack;\n\treadonly utterance: SpeechUtterance;\n\treadonly sampleRate: number;\n\treadonly signal?: AbortSignal;\n};\n\n/**\n * Capture a live audio track into an open utterance until the track ends or abort.\n * Prefers AudioWorklet + cubic resample (ScriptProcessor fallback).\n */\nexport async function pipeMediaStreamTrackToUtterance(\n\toptions: CaptureMediaStreamTrackOptions\n): Promise<void> {\n\tconst { track, utterance, sampleRate, signal } = options;\n\tif (typeof MediaStreamTrack === 'undefined' || !(track instanceof MediaStreamTrack)) {\n\t\tthrow new SpeechRuntimeError('MediaStreamTrack is not available in this environment.');\n\t}\n\tif (track.kind !== 'audio') {\n\t\tthrow new SpeechRuntimeError('speech.play track must be an audio MediaStreamTrack.');\n\t}\n\tif (track.readyState === 'ended') {\n\t\treturn;\n\t}\n\tif (signal?.aborted) {\n\t\treturn;\n\t}\n\n\tconst stream = new MediaStream([track]);\n\tlet writeChain: Promise<void> = Promise.resolve();\n\tlet stopped = false;\n\tlet capture: Awaited<ReturnType<typeof startAudioCapture>> | null = null;\n\n\tconst teardown = () => {\n\t\tif (stopped) return;\n\t\tstopped = true;\n\t\tcapture?.stop();\n\t\tcapture = null;\n\t};\n\n\ttry {\n\t\tcapture = await startAudioCapture({\n\t\t\tmediaStream: stream,\n\t\t\ttargetSampleRate: sampleRate,\n\t\t\tshouldSend: () => !stopped && !signal?.aborted,\n\t\t\tonPcm: (pcm) => {\n\t\t\t\tif (stopped || signal?.aborted) return;\n\t\t\t\tconst bytes = toUint8Array(pcm);\n\t\t\t\twriteChain = writeChain\n\t\t\t\t\t.then(async () => {\n\t\t\t\t\t\tif (stopped || signal?.aborted) return;\n\t\t\t\t\t\tlet offset = 0;\n\t\t\t\t\t\twhile (offset < bytes.byteLength) {\n\t\t\t\t\t\t\tlet end = Math.min(offset + SPEECH_LIMITS.MAX_CHUNK_BYTES, bytes.byteLength);\n\t\t\t\t\t\t\tif ((end - offset) % 2 === 1) end -= 1;\n\t\t\t\t\t\t\tif (end <= offset) break;\n\t\t\t\t\t\t\tconst slice = bytes.subarray(offset, end);\n\t\t\t\t\t\t\toffset = end;\n\t\t\t\t\t\t\tif (slice.byteLength === 0) continue;\n\t\t\t\t\t\t\tawait utterance.write(slice);\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\tteardown();\n\t\t\t\t\t});\n\t\t\t}\n\t\t});\n\t} catch (err) {\n\t\tteardown();\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tthrow new SpeechRuntimeError(`MediaStreamTrack capture failed: ${message}`);\n\t}\n\n\tawait new Promise<void>((resolve) => {\n\t\tconst finish = () => {\n\t\t\tteardown();\n\t\t\tvoid writeChain.finally(resolve);\n\t\t};\n\t\ttrack.addEventListener('ended', finish, { once: true });\n\t\tsignal?.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tvoid utterance.cancel().catch(() => undefined);\n\t\t\t\tfinish();\n\t\t\t},\n\t\t\t{ once: true }\n\t\t);\n\t\tif (track.readyState === 'ended' || signal?.aborted) {\n\t\t\tfinish();\n\t\t}\n\t});\n}\n","import type { IframeHost } from '../embed/iframeHost';\nimport type { SpeakBehavior } from '../types/sessionInteraction';\nimport type { SpeechResult as EmbedSpeakResult } from '../types/sessionInteraction';\nimport {\n\tSPEECH_LIMITS,\n\tSpeechBufferTimeoutError,\n\tSpeechRuntimeError,\n\tSpeechUtteranceClosedError,\n\tUnsupportedSpeechOperationError,\n\tassertSpeechPlayAudio,\n\temptyAnimationResult,\n\tisSpeechPlayEncodedAudio,\n\tisSpeechPlayMediaStreamAudio,\n\tisSpeechPlayPcmAudio,\n\tisSpeechPlayUrlAudio,\n\tqueuePolicyToEmbedBehavior,\n\tresolveCreateUtteranceFormat,\n\ttoUint8Array,\n\ttype SpeechAudioFormat,\n\ttype SpeechController,\n\ttype SpeechCreateUtteranceOptions,\n\ttype SpeechInterruptOptions,\n\ttype SpeechPlayAudio,\n\ttype SpeechPlayEmbedSource,\n\ttype SpeechPlayOptions,\n\ttype SpeechResult,\n\ttype SpeechSpeakOptions,\n\ttype SpeechTerminalStatus,\n\ttype SpeechUtterance,\n\ttype SpeechUtteranceCloseOptions,\n\ttype SpeechWriteOptions,\n\ttype StreamingSpeechQueuePolicy\n} from './types';\nimport { pipeMediaStreamTrackToUtterance } from './captureMediaStreamTrack';\n\nasync function toSpeechPlayEmbedSource(\n\taudio: SpeechPlayAudio,\n\tsignal?: AbortSignal\n): Promise<SpeechPlayEmbedSource> {\n\tif (isSpeechPlayMediaStreamAudio(audio)) {\n\t\tthrow new SpeechRuntimeError('MediaStreamTrack play is handled on the host before embed.');\n\t}\n\tif (isSpeechPlayPcmAudio(audio)) {\n\t\tconst data = toUint8Array(audio.data);\n\t\tif ((data.byteLength & 1) !== 0) {\n\t\t\tthrow new SpeechRuntimeError('PCM byte length must be even.');\n\t\t}\n\t\treturn {\n\t\t\tkind: 'pcm',\n\t\t\tdata: data.slice().buffer,\n\t\t\tformat: audio.format\n\t\t};\n\t}\n\tif (isSpeechPlayUrlAudio(audio)) {\n\t\treturn {\n\t\t\tkind: 'url',\n\t\t\turl: audio.url.trim(),\n\t\t\t...(audio.sampleRate !== undefined ? { sampleRate: audio.sampleRate } : {})\n\t\t};\n\t}\n\tif (!isSpeechPlayEncodedAudio(audio)) {\n\t\tthrow new SpeechRuntimeError('Unsupported speech.play audio shape.');\n\t}\n\tlet bytes: Uint8Array;\n\tif (typeof Blob !== 'undefined' && audio.data instanceof Blob) {\n\t\tif (signal?.aborted) throw new DOMException('Play aborted.', 'AbortError');\n\t\tbytes = new Uint8Array(await audio.data.arrayBuffer());\n\t} else {\n\t\tbytes = toUint8Array(audio.data as ArrayBuffer | Uint8Array);\n\t}\n\treturn {\n\t\tkind: 'encoded',\n\t\tdata: bytes.slice().buffer,\n\t\tencoding: audio.encoding.trim(),\n\t\t...(audio.sampleRate !== undefined ? { sampleRate: audio.sampleRate } : {})\n\t};\n}\n\nexport type {\n\tSpeechAudioFormat,\n\tSpeechController,\n\tSpeechCreateUtteranceOptions,\n\tSpeechInterruptOptions,\n\tSpeechPlayOptions,\n\tSpeechResult,\n\tSpeechSpeakOptions,\n\tSpeechUtterance,\n\tSpeechUtteranceCloseOptions,\n\tSpeechWriteOptions\n} from './types';\n\nexport type SpeechCapabilities = {\n\treadonly textSpeech: boolean;\n\treadonly externalSpeechAudio: boolean;\n};\n\nexport type SpeechControllerHost = {\n\treadonly getIframeHost: () => IframeHost | null;\n\treadonly assertSessionStarted: () => void;\n\treadonly getCapabilities: () => SpeechCapabilities;\n\treadonly getActiveCharacterId: () => string;\n\treadonly onProcessorInterrupt?: () => void;\n};\n\ntype PendingWrite = {\n\treadonly resolve: () => void;\n\treadonly reject: (error: Error) => void;\n};\n\nfunction newUtteranceId(): string {\n\tif (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n\t\treturn `utt_${crypto.randomUUID().replace(/-/g, '').slice(0, 12)}`;\n\t}\n\treturn `utt_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;\n}\n\nfunction mapEmbedSpeakResult(\n\tresult: EmbedSpeakResult,\n\tstatus: SpeechTerminalStatus = 'completed'\n): SpeechResult {\n\treturn {\n\t\tutteranceId: result.speechId,\n\t\tcharacterId: result.characterId,\n\t\tstatus,\n\t\tdurationMs: result.durationMs,\n\t\ttranscript: result.text,\n\t\tanimation: {\n\t\t\tmode: 'tracked',\n\t\t\ttrackedDurationMs: result.durationMs,\n\t\t\tfallbackDurationMs: 0\n\t\t}\n\t};\n}\n\nfunction settleError(error: unknown): Error {\n\tif (error instanceof Error) return error;\n\treturn new SpeechRuntimeError(String(error));\n}\n\nfunction isAbortError(error: unknown): boolean {\n\treturn (\n\t\t(error instanceof DOMException && error.name === 'AbortError') ||\n\t\t(error instanceof Error && error.name === 'AbortError')\n\t);\n}\n\nclass HostSpeechUtterance implements SpeechUtterance {\n\treadonly id: string;\n\treadonly characterId: string;\n\treadonly result: Promise<SpeechResult>;\n\n\tprivate readonly format: SpeechAudioFormat;\n\tprivate readonly host: SpeechControllerHost;\n\tprivate readonly signal?: AbortSignal;\n\tprivate settleResolve!: (value: SpeechResult) => void;\n\tprivate settleReject!: (error: Error) => void;\n\tprivate settled = false;\n\tprivate closed = false;\n\tprivate writeChain: Promise<void> = Promise.resolve();\n\tprivate pendingWriteCount = 0;\n\tprivate readonly pendingWriteWaiters: PendingWrite[] = [];\n\tprivate bufferedMs = 0;\n\tprivate readonly sampleRate: number;\n\tprivate readonly beginPromise: Promise<void>;\n\n\tconstructor(options: {\n\t\treadonly id: string;\n\t\treadonly characterId: string;\n\t\treadonly format: SpeechAudioFormat;\n\t\treadonly queue: StreamingSpeechQueuePolicy;\n\t\treadonly host: SpeechControllerHost;\n\t\treadonly transcript?: string;\n\t\treadonly signal?: AbortSignal;\n\t}) {\n\t\tthis.id = options.id;\n\t\tthis.characterId = options.characterId;\n\t\tthis.format = options.format;\n\t\tthis.host = options.host;\n\t\tthis.signal = options.signal;\n\t\tthis.sampleRate = options.format.sampleRate;\n\t\tthis.result = new Promise<SpeechResult>((resolve, reject) => {\n\t\t\tthis.settleResolve = resolve;\n\t\t\tthis.settleReject = reject;\n\t\t});\n\t\t// Prevent unhandled rejection if caller only uses close()/cancel().\n\t\tvoid this.result.catch(() => undefined);\n\n\t\tconst iframe = this.requireHost();\n\t\tthis.beginPromise = iframe\n\t\t\t.speechUtteranceBegin({\n\t\t\t\tutteranceId: this.id,\n\t\t\t\tformat: this.format,\n\t\t\t\tcharacterId: this.characterId,\n\t\t\t\tqueue: options.queue,\n\t\t\t\t...(options.transcript !== undefined ? { transcript: options.transcript } : {})\n\t\t\t})\n\t\t\t.catch((error: unknown) => {\n\t\t\t\tthis.fail(settleError(error));\n\t\t\t\tthrow settleError(error);\n\t\t\t});\n\n\t\tthis.signal?.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tvoid this.cancel();\n\t\t\t},\n\t\t\t{ once: true }\n\t\t);\n\t}\n\n\tasync write(audio: ArrayBuffer | Uint8Array, options?: SpeechWriteOptions): Promise<void> {\n\t\tif (this.closed || this.settled) {\n\t\t\tthrow new SpeechUtteranceClosedError();\n\t\t}\n\t\tawait this.beginPromise.catch(() => undefined);\n\t\tif (this.closed || this.settled) {\n\t\t\tthrow new SpeechUtteranceClosedError();\n\t\t}\n\t\tconst bytes = toUint8Array(audio);\n\t\tif ((bytes.byteLength & 1) !== 0) {\n\t\t\tthrow new SpeechRuntimeError('PCM chunk byte length must be even (complete s16 samples).');\n\t\t}\n\t\tif (bytes.byteLength > SPEECH_LIMITS.MAX_CHUNK_BYTES) {\n\t\t\tthrow new SpeechRuntimeError(\n\t\t\t\t`PCM chunk exceeds MAX_CHUNK_BYTES (${SPEECH_LIMITS.MAX_CHUNK_BYTES}).`\n\t\t\t);\n\t\t}\n\t\tif (bytes.byteLength === 0) return;\n\n\t\tconst timeoutMs = options?.timeoutMs ?? SPEECH_LIMITS.DEFAULT_WRITE_TIMEOUT_MS;\n\t\tawait this.acquireWriteSlot(timeoutMs);\n\n\t\tconst chunkMs = (bytes.byteLength / 2 / this.sampleRate) * 1000;\n\t\tif (this.bufferedMs + chunkMs > SPEECH_LIMITS.MAX_UTTERANCE_DURATION_MS) {\n\t\t\tthis.releaseWriteSlot();\n\t\t\tthrow new SpeechRuntimeError('Utterance exceeds MAX_UTTERANCE_DURATION_MS.');\n\t\t}\n\n\t\tconst run = async () => {\n\t\t\tif (this.closed || this.settled) {\n\t\t\t\tthrow new SpeechUtteranceClosedError();\n\t\t\t}\n\t\t\tconst iframe = this.requireHost();\n\t\t\tconst copy = bytes.slice();\n\t\t\tconst writePromise = iframe.speechUtteranceWrite({\n\t\t\t\tutteranceId: this.id,\n\t\t\t\taudio: copy.buffer,\n\t\t\t\tbyteLength: copy.byteLength\n\t\t\t});\n\t\t\tconst ack = await Promise.race([\n\t\t\t\twritePromise,\n\t\t\t\tnew Promise<never>((_, reject) => {\n\t\t\t\t\tsetTimeout(() => reject(new SpeechBufferTimeoutError()), timeoutMs);\n\t\t\t\t})\n\t\t\t]);\n\t\t\tthis.bufferedMs = Math.max(0, ack.bufferedMs);\n\t\t};\n\n\t\tconst tracked = this.writeChain.then(run, run);\n\t\tthis.writeChain = tracked.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined\n\t\t);\n\t\ttry {\n\t\t\tawait tracked;\n\t\t} finally {\n\t\t\tthis.releaseWriteSlot();\n\t\t}\n\t}\n\n\tasync setTranscript(text: string): Promise<void> {\n\t\tif (this.closed || this.settled) {\n\t\t\tthrow new SpeechUtteranceClosedError();\n\t\t}\n\t\tawait this.beginPromise.catch(() => undefined);\n\t\tif (this.closed || this.settled) {\n\t\t\tthrow new SpeechUtteranceClosedError();\n\t\t}\n\t\tconst iframe = this.requireHost();\n\t\tawait iframe.speechUtteranceSetTranscript({\n\t\t\tutteranceId: this.id,\n\t\t\ttranscript: text\n\t\t});\n\t}\n\n\tasync close(options?: SpeechUtteranceCloseOptions): Promise<SpeechResult> {\n\t\tif (this.settled) return this.result;\n\t\tthis.closed = true;\n\t\tawait this.beginPromise.catch(() => undefined);\n\t\tawait this.writeChain.catch(() => undefined);\n\t\ttry {\n\t\t\tconst iframe = this.requireHost();\n\t\t\tconst result = await iframe.speechUtteranceClose({\n\t\t\t\tutteranceId: this.id,\n\t\t\t\ttranscript: options?.transcript,\n\t\t\t\thistory: options?.history ?? 'none'\n\t\t\t});\n\t\t\tthis.resolve(result);\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\tconst err = settleError(error);\n\t\t\tthis.fail(err);\n\t\t\tthrow err;\n\t\t}\n\t}\n\n\tasync cancel(): Promise<SpeechResult> {\n\t\tif (this.settled) return this.result;\n\t\tthis.closed = true;\n\t\ttry {\n\t\t\tconst iframe = this.host.getIframeHost();\n\t\t\tif (iframe) {\n\t\t\t\tconst result = await iframe.speechUtteranceCancel({ utteranceId: this.id });\n\t\t\t\tthis.resolve(result);\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tconst cancelled: SpeechResult = {\n\t\t\t\tutteranceId: this.id,\n\t\t\t\tcharacterId: this.characterId,\n\t\t\t\tstatus: 'cancelled',\n\t\t\t\tdurationMs: 0,\n\t\t\t\tanimation: emptyAnimationResult('none')\n\t\t\t};\n\t\t\tthis.resolve(cancelled);\n\t\t\treturn cancelled;\n\t\t} catch (error) {\n\t\t\tconst err = settleError(error);\n\t\t\tthis.fail(err);\n\t\t\tthrow err;\n\t\t}\n\t}\n\n\t/** Adopt an interrupt settlement from the player without a second cancel RPC. */\n\tadoptExternalResult(result: SpeechResult): void {\n\t\tthis.resolve(result);\n\t}\n\n\tprivate requireHost(): IframeHost {\n\t\tconst iframe = this.host.getIframeHost();\n\t\tif (!iframe) {\n\t\t\tthrow new SpeechRuntimeError('Speech session is not attached.');\n\t\t}\n\t\treturn iframe;\n\t}\n\n\tprivate resolve(result: SpeechResult): void {\n\t\tif (this.settled) return;\n\t\tthis.settled = true;\n\t\tthis.settleResolve(Object.freeze(result));\n\t\tthis.flushWriteWaiters(new SpeechUtteranceClosedError());\n\t}\n\n\tprivate fail(error: Error): void {\n\t\tif (this.settled) return;\n\t\tthis.settled = true;\n\t\tthis.settleReject(error);\n\t\tthis.flushWriteWaiters(error);\n\t}\n\n\tprivate async acquireWriteSlot(timeoutMs: number): Promise<void> {\n\t\tif (this.pendingWriteCount < SPEECH_LIMITS.MAX_PENDING_WRITES) {\n\t\t\tthis.pendingWriteCount += 1;\n\t\t\treturn;\n\t\t}\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\treject(new SpeechBufferTimeoutError());\n\t\t\t}, timeoutMs);\n\t\t\tthis.pendingWriteWaiters.push({\n\t\t\t\tresolve: () => {\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\tthis.pendingWriteCount += 1;\n\t\t\t\t\tresolve();\n\t\t\t\t},\n\t\t\t\treject: (error) => {\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\treject(error);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate releaseWriteSlot(): void {\n\t\tthis.pendingWriteCount = Math.max(0, this.pendingWriteCount - 1);\n\t\tconst next = this.pendingWriteWaiters.shift();\n\t\tnext?.resolve();\n\t}\n\n\tprivate flushWriteWaiters(error: Error): void {\n\t\twhile (this.pendingWriteWaiters.length > 0) {\n\t\t\tthis.pendingWriteWaiters.shift()?.reject(error);\n\t\t}\n\t}\n}\n\nexport function createSpeechController(host: SpeechControllerHost): SpeechController {\n\tlet openUtterance: HostSpeechUtterance | null = null;\n\n\tconst requireCapability = (operation: string, capability: keyof SpeechCapabilities) => {\n\t\tconst caps = host.getCapabilities();\n\t\tif (!caps[capability]) {\n\t\t\tthrow new UnsupportedSpeechOperationError(operation, capability);\n\t\t}\n\t};\n\n\tconst controller: SpeechController = {\n\t\tasync speak(options: SpeechSpeakOptions): Promise<SpeechResult> {\n\t\t\thost.assertSessionStarted();\n\t\t\trequireCapability('speak', 'textSpeech');\n\t\t\tif (options.signal?.aborted) {\n\t\t\t\tthrow new DOMException('Speak aborted.', 'AbortError');\n\t\t\t}\n\t\t\tconst queue = options.queue ?? 'append';\n\t\t\tconst behavior: SpeakBehavior = queuePolicyToEmbedBehavior(queue);\n\t\t\tif (behavior === 'interrupt') {\n\t\t\t\thost.onProcessorInterrupt?.();\n\t\t\t\tif (openUtterance) {\n\t\t\t\t\tvoid openUtterance.cancel();\n\t\t\t\t\topenUtterance = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst iframe = host.getIframeHost();\n\t\t\tif (!iframe) throw new SpeechRuntimeError('Speech session is not attached.');\n\n\t\t\tconst speakPromise = iframe.speak({\n\t\t\t\ttext: options.text,\n\t\t\t\tcharacterId: options.characterId,\n\t\t\t\tbehavior\n\t\t\t});\n\n\t\t\tif (options.signal) {\n\t\t\t\tconst signal = options.signal;\n\t\t\t\treturn await new Promise<SpeechResult>((resolve, reject) => {\n\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\tvoid iframe.speechInterrupt({ scope: 'active' }).catch(() => undefined);\n\t\t\t\t\t\treject(new DOMException('Speak aborted.', 'AbortError'));\n\t\t\t\t\t};\n\t\t\t\t\tif (signal.aborted) {\n\t\t\t\t\t\tonAbort();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tsignal.addEventListener('abort', onAbort, { once: true });\n\t\t\t\t\tspeakPromise.then(\n\t\t\t\t\t\t(legacy) => {\n\t\t\t\t\t\t\tsignal.removeEventListener('abort', onAbort);\n\t\t\t\t\t\t\tresolve(mapEmbedSpeakResult(legacy, 'completed'));\n\t\t\t\t\t\t},\n\t\t\t\t\t\t(error: unknown) => {\n\t\t\t\t\t\t\tsignal.removeEventListener('abort', onAbort);\n\t\t\t\t\t\t\tif (isAbortError(error)) {\n\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\tutteranceId: `utt_interrupted`,\n\t\t\t\t\t\t\t\t\tcharacterId: options.characterId ?? host.getActiveCharacterId(),\n\t\t\t\t\t\t\t\t\tstatus: 'interrupted',\n\t\t\t\t\t\t\t\t\tdurationMs: 0,\n\t\t\t\t\t\t\t\t\ttranscript: options.text,\n\t\t\t\t\t\t\t\t\tanimation: emptyAnimationResult('none')\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treject(settleError(error));\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst legacy = await speakPromise;\n\t\t\t\treturn mapEmbedSpeakResult(legacy, 'completed');\n\t\t\t} catch (error) {\n\t\t\t\tif (isAbortError(error)) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tutteranceId: `utt_interrupted`,\n\t\t\t\t\t\tcharacterId: options.characterId ?? host.getActiveCharacterId(),\n\t\t\t\t\t\tstatus: 'interrupted',\n\t\t\t\t\t\tdurationMs: 0,\n\t\t\t\t\t\ttranscript: options.text,\n\t\t\t\t\t\tanimation: emptyAnimationResult('none')\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tthrow settleError(error);\n\t\t\t}\n\t\t},\n\n\t\tasync play(options: SpeechPlayOptions): Promise<SpeechResult> {\n\t\t\thost.assertSessionStarted();\n\t\t\trequireCapability('play', 'externalSpeechAudio');\n\t\t\tassertSpeechPlayAudio(options.audio);\n\t\t\tif (options.signal?.aborted) {\n\t\t\t\tthrow new DOMException('Play aborted.', 'AbortError');\n\t\t\t}\n\t\t\tconst queue = options.queue ?? 'append';\n\t\t\tif (queue === 'replace-active' || queue === 'replace-all') {\n\t\t\t\thost.onProcessorInterrupt?.();\n\t\t\t\tif (openUtterance) {\n\t\t\t\t\tvoid openUtterance.cancel();\n\t\t\t\t\topenUtterance = null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isSpeechPlayMediaStreamAudio(options.audio)) {\n\t\t\t\tconst sampleRate = options.audio.sampleRate ?? 24_000;\n\t\t\t\tconst utterance = controller.createUtterance({\n\t\t\t\t\tformat: { encoding: 'pcm_s16le', sampleRate, channels: 1 },\n\t\t\t\t\ttrack: options.audio.track,\n\t\t\t\t\tcharacterId: options.characterId,\n\t\t\t\t\tqueue: queue === 'append' ? 'replace-active' : queue,\n\t\t\t\t\tsignal: options.signal\n\t\t\t\t});\n\t\t\t\treturn utterance.result;\n\t\t\t}\n\n\t\t\tconst iframe = host.getIframeHost();\n\t\t\tif (!iframe) throw new SpeechRuntimeError('Speech session is not attached.');\n\t\t\tconst source = await toSpeechPlayEmbedSource(options.audio, options.signal);\n\t\t\treturn iframe.speechPlay({\n\t\t\t\tsource,\n\t\t\t\tcharacterId: options.characterId,\n\t\t\t\ttranscript: options.transcript,\n\t\t\t\thistory: options.history ?? 'none',\n\t\t\t\tqueue,\n\t\t\t\tsignal: options.signal\n\t\t\t});\n\t\t},\n\n\t\tcreateUtterance(options: SpeechCreateUtteranceOptions): SpeechUtterance {\n\t\t\thost.assertSessionStarted();\n\t\t\trequireCapability('createUtterance', 'externalSpeechAudio');\n\t\t\tconst format = resolveCreateUtteranceFormat(options);\n\t\t\tif (options.track && options.track.kind !== 'audio') {\n\t\t\t\tthrow new SpeechRuntimeError('createUtterance track must be an audio MediaStreamTrack.');\n\t\t\t}\n\t\t\tconst queue: StreamingSpeechQueuePolicy = options.queue ?? 'replace-active';\n\t\t\tif (queue !== 'replace-active' && queue !== 'replace-all') {\n\t\t\t\tthrow new SpeechRuntimeError('createUtterance queue must be replace-active or replace-all.');\n\t\t\t}\n\t\t\thost.onProcessorInterrupt?.();\n\t\t\tif (openUtterance) {\n\t\t\t\tvoid openUtterance.cancel();\n\t\t\t\topenUtterance = null;\n\t\t\t}\n\t\t\tconst utterance = new HostSpeechUtterance({\n\t\t\t\tid: newUtteranceId(),\n\t\t\t\tcharacterId: options.characterId ?? host.getActiveCharacterId(),\n\t\t\t\tformat,\n\t\t\t\tqueue,\n\t\t\t\thost,\n\t\t\t\t...(options.transcript !== undefined ? { transcript: options.transcript } : {}),\n\t\t\t\tsignal: options.signal\n\t\t\t});\n\t\t\topenUtterance = utterance;\n\t\t\tvoid utterance.result.finally(() => {\n\t\t\t\tif (openUtterance === utterance) openUtterance = null;\n\t\t\t});\n\t\t\tif (options.track) {\n\t\t\t\tvoid (async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait pipeMediaStreamTrackToUtterance({\n\t\t\t\t\t\t\ttrack: options.track!,\n\t\t\t\t\t\t\tutterance,\n\t\t\t\t\t\t\tsampleRate: format.sampleRate,\n\t\t\t\t\t\t\tsignal: options.signal\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (options.signal?.aborted) return;\n\t\t\t\t\t\tawait utterance.close({ history: 'none' });\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tawait utterance.cancel().catch(() => undefined);\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t}\n\t\t\treturn utterance;\n\t\t},\n\n\t\tasync interrupt(options?: SpeechInterruptOptions): Promise<readonly SpeechResult[]> {\n\t\t\thost.assertSessionStarted();\n\t\t\thost.onProcessorInterrupt?.();\n\t\t\tconst iframe = host.getIframeHost();\n\t\t\tif (!iframe) return [];\n\t\t\tconst results = await iframe.speechInterrupt(options ?? { scope: 'active' });\n\t\t\tif (openUtterance) {\n\t\t\t\tconst match = results.find((r) => r.utteranceId === openUtterance!.id);\n\t\t\t\tif (match) openUtterance.adoptExternalResult(match);\n\t\t\t\topenUtterance = null;\n\t\t\t}\n\t\t\treturn results;\n\t\t}\n\t};\n\n\treturn controller;\n}\n","export type ExperienceMode = 'conversation' | 'presenter';\nexport type ResponseMode = 'managed' | 'custom' | 'manual';\nexport type SpeechInputMode = 'auto' | 'manual' | 'off';\n/**\n * Viewport framing for the composed location + avatar scene.\n * - `full` (default): height-fit the full avatar into the host div.\n * - `medium`: height-fit a bust window — 0.75H above and 2H below the mesh face oval (3.75H total).\n * - `face`: cover-zoom the scene onto the mesh face oval (inset / PIP use cases).\n */\nexport type ExperienceFit = 'full' | 'face' | 'medium';\n\nexport function parseExperienceFit(value: string | null | undefined): ExperienceFit | undefined {\n\tconst trimmed = value?.trim();\n\treturn trimmed === 'full' || trimmed === 'face' || trimmed === 'medium' ? trimmed : undefined;\n}\n\nexport type SessionInteractionModes = {\n\treadonly mode: ExperienceMode;\n\treadonly responseMode: ResponseMode;\n\treadonly speechInputMode: SpeechInputMode;\n\treadonly processorId?: string;\n};\n\nexport type StartedEvent = {\n\treadonly mode: ExperienceMode;\n};\n\nexport type StartButtonPlacement = 'center' | 'bottom-center' | 'bottom-left' | 'bottom-right';\nexport type StartButtonVariant = 'primary' | 'secondary' | 'minimal';\nexport type StartButtonSize = 'small' | 'medium' | 'large';\nexport type StartButtonShadow = 'none' | 'soft' | 'strong';\nexport type StartButtonIconPosition = 'above' | 'left';\n\nexport type StartButtonAppearance = {\n\treadonly backgroundColor?: string;\n\treadonly textColor?: string;\n\treadonly borderColor?: string;\n\treadonly borderRadiusPx?: number;\n\treadonly borderWidthPx?: number;\n\t/** Explicit label size in px; when set, overrides `size` font scaling. */\n\treadonly fontSizePx?: number;\n\t/**\n\t * Font family stack available in the player iframe (system fonts / generic stacks).\n\t * Host-page webfonts are not loaded into the player frame.\n\t */\n\treadonly fontFamily?: string;\n\t/** CSS font-weight (100–900). */\n\treadonly fontWeight?: number;\n\treadonly size?: StartButtonSize;\n\treadonly shadow?: StartButtonShadow;\n};\n\nexport type StartButtonOptions = {\n\treadonly label?: string;\n\treadonly ariaLabel?: string;\n\treadonly placement?: StartButtonPlacement;\n\treadonly variant?: StartButtonVariant;\n\t/**\n\t * Tabler Iconify id (e.g. `player-play`, `tabler:microphone`) or an image URL\n\t * (`https://…` or `data:image/…`). Site-relative paths are not supported — they\n\t * would resolve against the player iframe origin, not the host page.\n\t */\n\treadonly icon?: string;\n\t/** Icon placement relative to the label. Defaults to `left`. */\n\treadonly iconPosition?: StartButtonIconPosition;\n\treadonly appearance?: StartButtonAppearance;\n};\n\n/**\n * Global player chrome theme (modals, shared buttons, panels).\n * Distinct from {@link StartButtonOptions} — start CTA keeps its own overrides.\n */\nexport type PlayerThemeColors = {\n\treadonly background?: string;\n\treadonly surface?: string;\n\treadonly surfaceMuted?: string;\n\treadonly text?: string;\n\treadonly textMuted?: string;\n\treadonly primary?: string;\n\treadonly primaryText?: string;\n\treadonly border?: string;\n};\n\nexport type PlayerThemeTypography = {\n\treadonly fontFamily?: string;\n\treadonly fontWeight?: number;\n\treadonly fontSizePx?: number;\n};\n\nexport type PlayerThemeButton = {\n\treadonly borderRadiusPx?: number;\n\treadonly borderWidthPx?: number;\n\treadonly shadow?: StartButtonShadow;\n};\n\nexport type PlayerTheme = {\n\treadonly colors?: PlayerThemeColors;\n\treadonly typography?: PlayerThemeTypography;\n\treadonly radiusPx?: number;\n\treadonly button?: PlayerThemeButton;\n};\n\nexport type SpeakBehavior = 'enqueue' | 'interrupt';\n\nexport type SpeakOptions = {\n\treadonly text: string;\n\treadonly characterId?: string;\n\treadonly behavior?: SpeakBehavior;\n};\n\n/** @deprecated Prefer {@link import('../speech').SpeechResult} from Experience.speech. */\nexport type TextSpeakResult = {\n\treadonly speechId: string;\n\treadonly turnId: string;\n\treadonly characterId: string;\n\treadonly text: string;\n\treadonly durationMs: number;\n};\n\n/** @deprecated Alias for TextSpeakResult — use Experience.speech SpeechResult for new code. */\nexport type SpeechResult = TextSpeakResult;\n\nexport type UtteranceResult = {\n\treadonly utteranceId: string;\n\treadonly text: string;\n};\n\nexport type UserTranscriptUpdate = {\n\treadonly utteranceId: string;\n\treadonly text: string;\n\treadonly revision: number;\n\treadonly isFinal: boolean;\n\treadonly delta?: string;\n};\n\nexport type ConversationMessageSource = 'user' | 'llm' | 'speak' | 'opening' | 'speechAudio';\n\nexport type ConversationMessage = {\n\treadonly messageId: string;\n\treadonly turnId: string;\n\treadonly role: 'user' | 'assistant';\n\treadonly text: string;\n\treadonly characterId?: string;\n\treadonly source: ConversationMessageSource;\n\treadonly status: 'final';\n\treadonly timestamp: number;\n};\n\nexport type CharacterSpeechSource = 'llm' | 'speak' | 'opening' | 'speechAudio';\n\nexport type CharacterSpeechTerminalReason =\n\t| 'completed'\n\t| 'interrupted'\n\t| 'error'\n\t| 'destroyed';\n\nexport type CharacterSpeechEvent = {\n\treadonly speechId: string;\n\treadonly turnId: string;\n\treadonly characterId: string;\n\treadonly text: string;\n\treadonly source: CharacterSpeechSource;\n\treadonly durationMs?: number;\n\treadonly reason?: CharacterSpeechTerminalReason;\n};\n\nexport type SessionModeChange = 'speaking' | 'listening' | 'thinking';\n\nexport type UserSpeechBoundaryEvent = {\n\treadonly utteranceId?: string;\n};\n\nexport type ConversationProcessorResult =\n\t| string\n\t| {\n\t\t\treadonly text: string;\n\t\t\treadonly characterId?: string;\n\t\t\treadonly behavior?: SpeakBehavior;\n\t };\n\nexport type ConversationProcessorContext = {\n\treadonly utteranceId: string;\n\treadonly text: string;\n\treadonly conversation: readonly ConversationMessage[];\n\treadonly signal: AbortSignal;\n};\n\nexport type ConversationProcessorFn = (\n\tcontext: ConversationProcessorContext\n) =>\n\t| ConversationProcessorResult\n\t| Promise<ConversationProcessorResult>\n\t| AsyncIterable<string>;\n\nexport type NormalizedProcessorSpeech = {\n\treadonly text: string;\n\treadonly characterId?: string;\n\treadonly behavior?: SpeakBehavior;\n};\n\nexport type ProcessorDispatchResult =\n\t| { readonly kind: 'complete'; readonly speech: NormalizedProcessorSpeech }\n\t| { readonly kind: 'stream'; readonly stream: AsyncIterable<string> };\n\nexport type ConversationProcessorErrorEvent = {\n\treadonly utteranceId: string;\n\treadonly message: string;\n};\n\nexport type ListenOnceOptions = {\n\treadonly signal?: AbortSignal;\n\treadonly timeoutMs?: number;\n};\n\n/** Caption history window: integer exchange count, or `'all'`. */\nexport type VisibleTurns = number | 'all';\n\n/** Composer button visibility. Independent of capability and live state. */\nexport type InteractionControls = {\n\treadonly voice: boolean;\n\treadonly captions: boolean;\n\treadonly microphone: boolean;\n\treadonly textInput: boolean;\n};\n\n/**\n * Runtime interaction allow-flags, live UI state, and control visibility.\n * Authoring defaults live in the published revision; the player resolves and enforces constraints.\n */\nexport type ExperienceInteraction = {\n\treadonly allowTextInput: boolean;\n\treadonly allowMicInput: boolean;\n\treadonly allowRewind: boolean;\n\treadonly showUserSpeech: boolean;\n\treadonly showCharacterSpeech: boolean;\n\treadonly playCharacterSpeech: boolean;\n\treadonly textInputEnabled: boolean;\n\treadonly micInputEnabled: boolean;\n\treadonly visibleTurns: VisibleTurns;\n\treadonly controls: InteractionControls;\n};\n\n/** Nested patch for attach and setInteraction. Omitted keys (including nested controls) are retained. */\nexport type ExperienceInteractionPatch = Partial<Omit<ExperienceInteraction, 'controls'>> & {\n\treadonly controls?: Partial<InteractionControls>;\n};\n","import { fetchSessionLaunch, mintBrowserSession } from './api/mintPublicSession';\nimport { dispatchConversationProcessor } from './conversationProcessor';\nimport { createIframeHost, type IframeHost } from './embed/iframeHost';\nimport { createReadyGate } from './embed/readyGate';\nimport type { CloseEvent, EmbedState } from './embed/protocol';\nimport { SDK_RELEASE } from './sdkRelease';\nimport {\n\tbuildManifestEmbedUrl,\n\tresolvePlayerOrigin,\n\tresolvePublicPlayerEmbedUrl,\n\tresolveSceneHintId\n} from './shims/embedBaseUrl';\nimport type {\n\tCloseButtonOptions,\n\tPlayerStatus,\n\tSession,\n\tSessionActivity,\n\tSessionLaunchResponse\n} from './types/sessionLaunch';\nimport { warnLocaleVoiceFallbacks } from './types/sessionLaunch';\nimport {\n\tclearExperienceEventRegistry,\n\tcreateExperienceEventEnvelope,\n\tcreateExperienceEventRegistry,\n\temitExperienceEvent,\n\tsubscribeExperienceEvent,\n\ttype ExperienceEventName,\n\ttype ExperienceEvents\n} from './experienceEvents';\nimport {\n\tcreateSpeechController,\n\ttype SpeechCapabilities,\n\ttype SpeechController\n} from './speech/speechController';\nimport {\n\tparseExperienceFit,\n\ttype CharacterSpeechEvent,\n\ttype ConversationMessage,\n\ttype ConversationProcessorFn,\n\ttype ExperienceFit,\n\ttype ExperienceInteraction,\n\ttype ExperienceInteractionPatch,\n\ttype ExperienceMode,\n\ttype ListenOnceOptions,\n\ttype SpeechInputMode,\n\ttype StartButtonOptions,\n\ttype PlayerTheme,\n\ttype StartedEvent,\n\ttype UserTranscriptUpdate,\n\ttype UtteranceResult\n} from './types/sessionInteraction';\nimport type { SessionManifest } from './types/sessionManifest';\n\nexport type { CloseEvent };\nexport type {\n\tCharacterSpeechEvent,\n\tCharacterSpeechSource,\n\tCharacterSpeechTerminalReason,\n\tConversationMessage,\n\tConversationProcessorContext,\n\tConversationProcessorErrorEvent,\n\tConversationProcessorFn,\n\tConversationProcessorResult,\n\tExperienceFit,\n\tExperienceInteraction,\n\tExperienceInteractionPatch,\n\tListenOnceOptions,\n\tSpeakOptions,\n\tVisibleTurns,\n\tTextSpeakResult,\n\tSpeechResult as LegacySpeakResult,\n\tStartButtonAppearance,\n\tStartButtonOptions,\n\tStartButtonPlacement,\n\tStartButtonShadow,\n\tStartButtonSize,\n\tStartButtonVariant,\n\tStartButtonIconPosition,\n\tPlayerTheme,\n\tPlayerThemeButton,\n\tPlayerThemeColors,\n\tPlayerThemeTypography,\n\tUserSpeechBoundaryEvent,\n\tUserTranscriptUpdate,\n\tUtteranceResult\n} from './types/sessionInteraction';\nexport type {\n\tCloseButtonOptions,\n\tPlayerStatus,\n\tSession,\n\tSessionActivity,\n\tSessionCapabilities,\n\tSessionLaunchResponse,\n\tSessionMode\n} from './types/sessionLaunch';\nexport type {\n\tSpeechAudioFormat,\n\tSpeechController,\n\tSpeechCreateUtteranceOptions,\n\tSpeechInterruptOptions,\n\tSpeechPlayAudio,\n\tSpeechPlayEncodedAudio,\n\tSpeechPlayOptions,\n\tSpeechPlayPcmAudio,\n\tSpeechPlayUrlAudio,\n\tSpeechResult,\n\tSpeechSpeakOptions,\n\tSpeechUtterance\n} from './speech';\nexport {\n\tSPEECH_LIMITS,\n\tSpeechBufferTimeoutError,\n\tSpeechRuntimeError,\n\tSpeechUtteranceClosedError,\n\tUnsupportedSpeechOperationError\n} from './speech';\n\nexport type {\n\tExperienceEventEnvelope,\n\tExperienceEventName,\n\tExperienceEvents,\n\tFeedbackFailedEvent,\n\tFeedbackResult\n} from './experienceEvents';\n\ntype StartSessionShared = {\n\treadonly embedBaseUrl?: string;\n\treadonly debug?: boolean;\n\t/** ExperienceWidget warm embed chrome (`?ui=widget`). */\n\treadonly ui?: 'widget';\n\treadonly onStart?: (event: StartedEvent) => void | Promise<void>;\n\treadonly onUserTranscript?: (update: UserTranscriptUpdate) => void | Promise<void>;\n\treadonly conversationProcessor?: ConversationProcessorFn;\n\t/**\n\t * Whole-snapshot marketing attribution. `false` disables auto-capture.\n\t * When omitted, the SDK reads standard UTMs + document.referrer from the embedding page.\n\t */\n\treadonly attribution?: import('./api/captureAttribution').ExperienceAttribution | false;\n\t/**\n\t * Conversion keys this play is already ineligible for (for example `registration`).\n\t * Snapshot at mint. Do not fire `conversion(key)` for keys listed here.\n\t */\n\treadonly alreadyConverted?: readonly string[];\n};\n\nexport type StartSessionOptions =\n\t| (StartSessionShared & {\n\t\t\treadonly experienceId: string;\n\t\t\t/** BCP 47 locale (preferred). When omitted in the browser, defaults to `navigator.language`. */\n\t\t\treadonly locale?: string;\n\t\t\treadonly secondaryLocale?: string;\n\t\t\treadonly learningLocale?: string;\n\t\t\t/** @deprecated Prefer `locale`. */\n\t\t\treadonly language?: 'en' | 'es' | string;\n\t\t\treadonly backdropId?: string;\n\t\t\t/** @deprecated Prefer `backdropId`. */\n\t\t\treadonly locationId?: string;\n\t\t\treadonly avatarId?: string;\n\t\t\treadonly castSize?: 2 | 3 | 4;\n\t\t\treadonly mode?: ExperienceMode;\n\t\t\treadonly speechInputMode?: SpeechInputMode;\n\t\t\t/** Voice-only session: skip avatar renderer and location scene asset loading. */\n\t\t\treadonly speechOnly?: boolean;\n\t })\n\t| (StartSessionShared & {\n\t\t\treadonly experienceId: string;\n\t\t\treadonly sessionEndpoint: string;\n\t\t\t/** BCP 47 locale (preferred). When omitted in the browser, defaults to `navigator.language`. */\n\t\t\treadonly locale?: string;\n\t\t\treadonly secondaryLocale?: string;\n\t\t\treadonly learningLocale?: string;\n\t\t\t/** @deprecated Prefer `locale`. */\n\t\t\treadonly language?: 'en' | 'es' | string;\n\t\t\treadonly backdropId?: string;\n\t\t\t/** @deprecated Prefer `backdropId`. */\n\t\t\treadonly locationId?: string;\n\t\t\treadonly avatarId?: string;\n\t\t\treadonly castSize?: 2 | 3 | 4;\n\t\t\treadonly mode?: ExperienceMode;\n\t\t\treadonly speechInputMode?: SpeechInputMode;\n\t\t\t/** Voice-only session: skip avatar renderer and location scene asset loading. */\n\t\t\treadonly speechOnly?: boolean;\n\t })\n\t| (StartSessionShared & {\n\t\t\t/**\n\t\t\t * Opaque signed launch string from a prior Session Launch response.\n\t\t\t * Prefer `sessionEndpoint` so page JS does not hold launch when avoidable.\n\t\t\t */\n\t\t\treadonly launch: string;\n\t\t\treadonly session?: Session;\n\t\t\treadonly backdropId?: string;\n\t\t\t/** @deprecated Prefer `backdropId`. */\n\t\t\treadonly locationId?: string;\n\t\t\treadonly avatarId?: string;\n\t\t\t/** Voice-only session: skip avatar renderer and location scene asset loading. */\n\t\t\treadonly speechOnly?: boolean;\n\t });\n\nexport type AttachOptions = {\n\treadonly container: HTMLElement;\n\t/** Initial scene framing. Change later with {@link Experience.setFit}. */\n\treadonly fit?: ExperienceFit;\n\treadonly startButton?: StartButtonOptions;\n\t/**\n\t * Global player chrome theme (introduction, feedback, shared buttons, panels).\n\t * Distinct from {@link AttachOptions.startButton} CTA overrides. Presentation only — does not remint.\n\t */\n\treadonly theme?: PlayerTheme;\n\t/**\n\t * When true (default), the Liforma player shows end-of-session Feedback UI.\n\t * When false, hosts receive scores via `feedback` / `feedbackFailed` and render their own UX.\n\t * Presentation only — does not remint.\n\t */\n\treadonly showFeedback?: boolean;\n\t/** Nested interaction patch merged before first paint. Does not remint. */\n\treadonly interaction?: ExperienceInteractionPatch;\n\treadonly closeButton?: CloseButtonOptions | boolean;\n\treadonly returnUrl?: string;\n\treadonly onPlayerStatusChange?: (status: PlayerStatus) => void;\n\t/** @deprecated Prefer {@link AttachOptions.onPlayerStatusChange}. */\n\treadonly onStateUpdate?: (state: EmbedState) => void;\n\treadonly onWidgetReady?: () => void;\n\treadonly onWidgetExpand?: () => void;\n\treadonly onWidgetCollapse?: () => void;\n\treadonly onWidgetAudioSettings?: (open: boolean) => void;\n\t/** Docked shell: player surface drag → parent repositions the dock. */\n\treadonly onWidgetDragStart?: (event: { readonly pointerId: number }) => void;\n\treadonly onWidgetDragMove?: (event: {\n\t\treadonly pointerId: number;\n\t\treadonly dx: number;\n\t\treadonly dy: number;\n\t}) => void;\n\treadonly onWidgetDragEnd?: (event: { readonly pointerId: number }) => void;\n\t/**\n\t * Show the in-player close control. Set when the host provides `onClose`\n\t * and/or `returnUrl` / `closeButton`. Widget chrome keeps its own toolbar close separately.\n\t * @deprecated Prefer {@link AttachOptions.closeButton}.\n\t */\n\treadonly showClose?: boolean;\n};\n\nexport type { EmbedState };\n\nexport type ReadyEvent = {\n\treadonly session: Session;\n};\n\nexport type LiformaPlayer = {\n\tclose(): void;\n\tdestroy(): void;\n\ton(event: 'close', handler: (event: CloseEvent) => void): void;\n};\n\ntype SessionBootstrap =\n\t| {\n\t\t\treadonly kind: 'public';\n\t\t\treadonly experienceId: string;\n\t\t\treadonly locale?: string;\n\t\t\treadonly secondaryLocale?: string;\n\t\t\treadonly learningLocale?: string;\n\t\t\treadonly language?: string;\n\t\t\treadonly backdropId?: string;\n\t\t\treadonly locationId?: string;\n\t\t\treadonly avatarId?: string;\n\t\t\treadonly castSize?: 2 | 3 | 4;\n\t\t\treadonly embedBaseUrl?: string;\n\t\t\treadonly debug?: boolean;\n\t\t\treadonly mode?: ExperienceMode;\n\t\t\treadonly speechInputMode?: SpeechInputMode;\n\t\t\treadonly speechOnly?: boolean;\n\t\t\treadonly attribution?: import('./api/captureAttribution').ExperienceAttribution | false;\n\t\t\treadonly alreadyConverted?: readonly string[];\n\t\t\treadonly ui?: 'widget';\n\t\t\treadonly onStart?: (event: StartedEvent) => void | Promise<void>;\n\t\t\treadonly onUserTranscript?: (update: UserTranscriptUpdate) => void | Promise<void>;\n\t\t\treadonly conversationProcessor?: ConversationProcessorFn;\n\t }\n\t| {\n\t\t\treadonly kind: 'sessionEndpoint';\n\t\t\treadonly experienceId: string;\n\t\t\treadonly sessionEndpoint: string;\n\t\t\treadonly locale?: string;\n\t\t\treadonly secondaryLocale?: string;\n\t\t\treadonly learningLocale?: string;\n\t\t\treadonly language?: string;\n\t\t\treadonly backdropId?: string;\n\t\t\treadonly locationId?: string;\n\t\t\treadonly avatarId?: string;\n\t\t\treadonly castSize?: 2 | 3 | 4;\n\t\t\treadonly embedBaseUrl?: string;\n\t\t\treadonly debug?: boolean;\n\t\t\treadonly mode?: ExperienceMode;\n\t\t\treadonly speechInputMode?: SpeechInputMode;\n\t\t\treadonly speechOnly?: boolean;\n\t\t\treadonly attribution?: import('./api/captureAttribution').ExperienceAttribution | false;\n\t\t\treadonly alreadyConverted?: readonly string[];\n\t\t\treadonly ui?: 'widget';\n\t\t\treadonly onStart?: (event: StartedEvent) => void | Promise<void>;\n\t\t\treadonly onUserTranscript?: (update: UserTranscriptUpdate) => void | Promise<void>;\n\t\t\treadonly conversationProcessor?: ConversationProcessorFn;\n\t }\n\t| {\n\t\t\treadonly kind: 'launch';\n\t\t\treadonly launch: string;\n\t\t\treadonly session?: Session;\n\t\t\treadonly backdropId?: string;\n\t\t\treadonly locationId?: string;\n\t\t\treadonly avatarId?: string;\n\t\t\treadonly embedBaseUrl?: string;\n\t\t\treadonly debug?: boolean;\n\t\t\treadonly speechOnly?: boolean;\n\t\t\treadonly ui?: 'widget';\n\t\t\treadonly onStart?: (event: StartedEvent) => void | Promise<void>;\n\t\t\treadonly onUserTranscript?: (update: UserTranscriptUpdate) => void | Promise<void>;\n\t\t\treadonly conversationProcessor?: ConversationProcessorFn;\n\t };\n\nfunction resolveShowClose(options: AttachOptions): boolean {\n\tif (options.showClose === true) return true;\n\tif (options.returnUrl?.trim()) return true;\n\tif (options.closeButton === true) return true;\n\tif (\n\t\toptions.closeButton &&\n\t\ttypeof options.closeButton === 'object' &&\n\t\toptions.closeButton.visible !== false\n\t) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nexport class Experience {\n\tprivate readonly bootstrap: SessionBootstrap;\n\tprivate readonly conversationProcessor: ConversationProcessorFn | null;\n\tprivate iframeHost: IframeHost | null = null;\n\tprivate attachInFlight: Promise<LiformaPlayer> | null = null;\n\tprivate endpointAbortController: AbortController | null = null;\n\tprivate processorAbortController: AbortController | null = null;\n\tprivate processorChain: Promise<void> = Promise.resolve();\n\tprivate resolvedSession: Session | null;\n\tprivate launchToken: string | null;\n\tprivate attachReturnUrl: string | null = null;\n\tprivate closed = false;\n\tprivate attached = false;\n\tprivate pendingFit: ExperienceFit | null = null;\n\tprivate lastInteraction: ExperienceInteraction | null = null;\n\tprivate readonly closeHandlers: ((event: CloseEvent) => void)[] = [];\n\tprivate readonly eventRegistry = createExperienceEventRegistry();\n\tprivate readyEnvelope: ExperienceEvents['ready'] | null = null;\n\tprivate startedEnvelope: ExperienceEvents['started'] | null = null;\n\tprivate sessionMintedEnvelope: ExperienceEvents['sessionMinted'] | null = null;\n\tprivate conversationCache: readonly ConversationMessage[] = [];\n\t/** Public speech API — text TTS and BYO PCM (`speak` / `play` / `createUtterance` / `interrupt`). */\n\treadonly speech: SpeechController;\n\n\tprivate constructor(bootstrap: SessionBootstrap) {\n\t\tthis.bootstrap = bootstrap;\n\t\tthis.conversationProcessor = bootstrap.conversationProcessor ?? null;\n\t\tthis.resolvedSession = bootstrap.kind === 'launch' ? (bootstrap.session ?? null) : null;\n\t\tthis.launchToken = bootstrap.kind === 'launch' ? bootstrap.launch : null;\n\t\tthis.speech = createSpeechController({\n\t\t\tgetIframeHost: () => this.iframeHost,\n\t\t\tassertSessionStarted: () => this.assertSessionStarted(),\n\t\t\tgetCapabilities: () => resolveSpeechCapabilities(this.resolvedSession),\n\t\t\tgetActiveCharacterId: () => 'character_unknown',\n\t\t\tonProcessorInterrupt: () => {\n\t\t\t\tthis.processorAbortController?.abort();\n\t\t\t\tthis.processorAbortController = null;\n\t\t\t}\n\t\t});\n\t}\n\n\tstatic async startSession(options: StartSessionOptions): Promise<Experience> {\n\t\tif ('launch' in options && typeof options.launch === 'string') {\n\t\t\tconst launch = options.launch.trim();\n\t\t\tif (!launch) {\n\t\t\t\tthrow new Error('StartSessionOptions.launch must be a non-empty string.');\n\t\t\t}\n\t\t\treturn new Experience({\n\t\t\t\tkind: 'launch',\n\t\t\t\tlaunch,\n\t\t\t\tsession: options.session,\n\t\t\t\tbackdropId: options.backdropId,\n\t\t\t\tlocationId: options.locationId,\n\t\t\t\tavatarId: options.avatarId,\n\t\t\t\tembedBaseUrl: options.embedBaseUrl,\n\t\t\t\tdebug: options.debug,\n\t\t\t\tspeechOnly: options.speechOnly,\n\t\t\t\tui: options.ui,\n\t\t\t\tonStart: options.onStart,\n\t\t\t\tonUserTranscript: options.onUserTranscript,\n\t\t\t\tconversationProcessor: options.conversationProcessor\n\t\t\t});\n\t\t}\n\n\t\tif ('sessionEndpoint' in options) {\n\t\t\treturn new Experience({\n\t\t\t\tkind: 'sessionEndpoint',\n\t\t\t\texperienceId: options.experienceId,\n\t\t\t\tsessionEndpoint: options.sessionEndpoint,\n\t\t\t\tlocale: options.locale,\n\t\t\t\tsecondaryLocale: options.secondaryLocale,\n\t\t\t\tlearningLocale: options.learningLocale,\n\t\t\t\tlanguage: options.language,\n\t\t\t\tbackdropId: options.backdropId,\n\t\t\t\tlocationId: options.locationId,\n\t\t\t\tavatarId: options.avatarId,\n\t\t\t\tcastSize: options.castSize,\n\t\t\t\tembedBaseUrl: options.embedBaseUrl,\n\t\t\t\tdebug: options.debug,\n\t\t\t\tmode: options.mode,\n\t\t\t\tspeechInputMode: options.speechInputMode,\n\t\t\t\tspeechOnly: options.speechOnly,\n\t\t\t\tattribution: options.attribution,\n\t\t\t\talreadyConverted: options.alreadyConverted,\n\t\t\t\tui: options.ui,\n\t\t\t\tonStart: options.onStart,\n\t\t\t\tonUserTranscript: options.onUserTranscript,\n\t\t\t\tconversationProcessor: options.conversationProcessor\n\t\t\t});\n\t\t}\n\n\t\tif ('experienceId' in options) {\n\t\t\treturn new Experience({\n\t\t\t\tkind: 'public',\n\t\t\t\texperienceId: options.experienceId,\n\t\t\t\tlocale: options.locale,\n\t\t\t\tsecondaryLocale: options.secondaryLocale,\n\t\t\t\tlearningLocale: options.learningLocale,\n\t\t\t\tlanguage: options.language,\n\t\t\t\tbackdropId: options.backdropId,\n\t\t\t\tlocationId: options.locationId,\n\t\t\t\tavatarId: options.avatarId,\n\t\t\t\tcastSize: options.castSize,\n\t\t\t\tembedBaseUrl: options.embedBaseUrl,\n\t\t\t\tdebug: options.debug,\n\t\t\t\tmode: options.mode,\n\t\t\t\tspeechInputMode: options.speechInputMode,\n\t\t\t\tspeechOnly: options.speechOnly,\n\t\t\t\tattribution: options.attribution,\n\t\t\t\talreadyConverted: options.alreadyConverted,\n\t\t\t\tui: options.ui,\n\t\t\t\tonStart: options.onStart,\n\t\t\t\tonUserTranscript: options.onUserTranscript,\n\t\t\t\tconversationProcessor: options.conversationProcessor\n\t\t\t});\n\t\t}\n\n\t\tthrow new Error(\n\t\t\t'Experience.startSession requires experienceId, sessionEndpoint, or launch.'\n\t\t);\n\t}\n\n\tgetSession(): Session | null {\n\t\treturn this.resolvedSession;\n\t}\n\n\t/**\n\t * @deprecated Session Manifest is no longer a public SDK contract.\n\t * Use {@link Experience.getSession} for the public Session summary.\n\t */\n\tgetManifest(): SessionManifest | null {\n\t\treturn null;\n\t}\n\n\ton<K extends ExperienceEventName>(\n\t\tevent: K,\n\t\thandler: (event: ExperienceEvents[K]) => void\n\t): () => void {\n\t\tconst unsubscribe = subscribeExperienceEvent(this.eventRegistry, event, handler);\n\t\tif (event === 'ready' && this.readyEnvelope) {\n\t\t\tqueueMicrotask(() => handler(this.readyEnvelope as ExperienceEvents[K]));\n\t\t}\n\t\tif (event === 'started' && this.startedEnvelope) {\n\t\t\tqueueMicrotask(() => handler(this.startedEnvelope as ExperienceEvents[K]));\n\t\t}\n\t\tif (event === 'sessionMinted' && this.sessionMintedEnvelope) {\n\t\t\tqueueMicrotask(() => handler(this.sessionMintedEnvelope as ExperienceEvents[K]));\n\t\t}\n\t\treturn unsubscribe;\n\t}\n\n\tasync attach(options: AttachOptions): Promise<LiformaPlayer> {\n\t\tif (this.closed) {\n\t\t\tthrow new Error('Session has ended.');\n\t\t}\n\t\tif (!options.container) {\n\t\t\tthrow new Error('Experience.attach requires a DOM container element.');\n\t\t}\n\t\tif (this.attached && this.iframeHost) {\n\t\t\treturn this.createPlayerFacade();\n\t\t}\n\t\tif (this.attachInFlight) {\n\t\t\treturn this.attachInFlight;\n\t\t}\n\n\t\tthis.attachInFlight = this.attachInternal(options).finally(() => {\n\t\t\tthis.attachInFlight = null;\n\t\t});\n\t\treturn this.attachInFlight;\n\t}\n\n\tprivate async attachInternal(options: AttachOptions): Promise<LiformaPlayer> {\n\t\tif (this.closed) {\n\t\t\tthrow new Error('Session has ended.');\n\t\t}\n\t\tif (this.attached && this.iframeHost) {\n\t\t\treturn this.createPlayerFacade();\n\t\t}\n\t\tif (this.iframeHost) {\n\t\t\tthis.iframeHost.destroy();\n\t\t\tthis.iframeHost = null;\n\t\t}\n\n\t\tthis.attachReturnUrl = options.returnUrl?.trim() || null;\n\n\t\tconst embedBaseUrl = this.bootstrap.embedBaseUrl ?? resolvePublicPlayerEmbedUrl();\n\t\tconst debug = this.bootstrap.debug === true;\n\t\tconst speechOnly = this.bootstrap.speechOnly === true;\n\t\tconst locationId = speechOnly\n\t\t\t? undefined\n\t\t\t: resolveSceneHintId(this.bootstrap.backdropId, this.bootstrap.locationId);\n\t\tconst avatarId = speechOnly ? undefined : this.bootstrap.avatarId;\n\t\t// The SDK owns minting and posts the opaque launch. Do not put experienceId in the\n\t\t// iframe URL or the player will mint a second session before the parent launch arrives.\n\t\tconst iframeSrc = buildManifestEmbedUrl(\n\t\t\tembedBaseUrl,\n\t\t\tdebug,\n\t\t\tlocationId,\n\t\t\tavatarId,\n\t\t\toptions.fit,\n\t\t\tthis.bootstrap.ui,\n\t\t\tresolveShowClose(options),\n\t\t\tthis.bootstrap.kind === 'launch' ? undefined : this.bootstrap.castSize\n\t\t);\n\t\tconst playerOrigin = resolvePlayerOrigin(iframeSrc);\n\n\t\tlet resolveLoadingUi: (() => void) | null = null;\n\t\tconst loadingUiPromise = new Promise<void>((resolve) => {\n\t\t\tresolveLoadingUi = resolve;\n\t\t});\n\t\tlet resolveReadyUi: (() => void) | null = null;\n\t\tconst readyUiPromise = new Promise<void>((resolve) => {\n\t\t\tresolveReadyUi = resolve;\n\t\t});\n\t\tconst readyGate = createReadyGate<Session>((readySession) => {\n\t\t\tif (this.readyEnvelope) return;\n\t\t\tthis.resolvedSession = readySession;\n\t\t\tthis.readyEnvelope = this.emitWrapped('ready', { session: readySession });\n\t\t});\n\n\t\tconst onUserTranscript = this.bootstrap.onUserTranscript;\n\n\t\tconst onPlayerStatus = (status: PlayerStatus) => {\n\t\t\toptions.onPlayerStatusChange?.(status);\n\t\t\toptions.onStateUpdate?.(status);\n\t\t\tif (status === 'loading' && resolveLoadingUi) {\n\t\t\t\tresolveLoadingUi();\n\t\t\t\tresolveLoadingUi = null;\n\t\t\t}\n\t\t\tif (status === 'ready' && resolveReadyUi) {\n\t\t\t\tresolveReadyUi();\n\t\t\t\tresolveReadyUi = null;\n\t\t\t}\n\t\t\tif (status === 'ready') {\n\t\t\t\treadyGate.markReady();\n\t\t\t}\n\t\t};\n\n\t\tconst iframeHost = createIframeHost({\n\t\t\tcontainer: options.container,\n\t\t\tsrc: iframeSrc,\n\t\t\tplayerOrigin,\n\t\t\ttransparent: this.bootstrap.ui === 'widget',\n\t\t\tonClose: (event) => {\n\t\t\t\tconst enriched: CloseEvent =\n\t\t\t\t\tevent.returnUrl || !this.attachReturnUrl\n\t\t\t\t\t\t? event\n\t\t\t\t\t\t: { ...event, returnUrl: this.attachReturnUrl };\n\t\t\t\tfor (const handler of this.closeHandlers) {\n\t\t\t\t\thandler(enriched);\n\t\t\t\t}\n\t\t\t},\n\t\t\tonPlayerStatusChange: onPlayerStatus,\n\t\t\tonUserTranscript: (update) => {\n\t\t\t\tthis.emitWrapped('userTranscript', update);\n\t\t\t\tvoid onUserTranscript?.(update);\n\t\t\t\tthis.queueProcessorTurn(update);\n\t\t\t},\n\t\t\tonUserSpeechStarted: (event) => {\n\t\t\t\tthis.emitWrapped('userSpeechStarted', event);\n\t\t\t},\n\t\t\tonUserSpeechEnded: (event) => {\n\t\t\t\tthis.emitWrapped('userSpeechEnded', event);\n\t\t\t},\n\t\t\tonCharacterSpeechStarted: (event: CharacterSpeechEvent) => {\n\t\t\t\tthis.emitWrapped('characterSpeechStarted', event);\n\t\t\t},\n\t\t\tonCharacterSpeechEnded: (event: CharacterSpeechEvent) => {\n\t\t\t\tthis.emitWrapped('characterSpeechEnded', event);\n\t\t\t},\n\t\t\tonCharacterFocusChanged: (event) => {\n\t\t\t\tthis.emitWrapped('characterFocusChanged', event);\n\t\t\t},\n\t\t\tonListeningState: (listening) => {\n\t\t\t\tthis.emitWrapped('listeningState', listening);\n\t\t\t},\n\t\t\tonActivityChange: (activity: SessionActivity) => {\n\t\t\t\tthis.emitWrapped('activityChange', activity);\n\t\t\t},\n\t\t\tonInteractionChange: (interaction: ExperienceInteraction) => {\n\t\t\t\tthis.lastInteraction = interaction;\n\t\t\t\tthis.emitWrapped('interactionChange', interaction);\n\t\t\t},\n\t\t\tonFeedback: (result) => {\n\t\t\t\tthis.emitWrapped('feedback', result);\n\t\t\t},\n\t\t\tonFeedbackFailed: (event) => {\n\t\t\t\tthis.emitWrapped('feedbackFailed', event);\n\t\t\t},\n\t\t\tonMessage: (message) => {\n\t\t\t\tthis.emitWrapped('message', message);\n\t\t\t},\n\t\t\tonStarted: (event) => {\n\t\t\t\tif (!this.startedEnvelope) {\n\t\t\t\t\tthis.startedEnvelope = this.emitWrapped('started', event);\n\t\t\t\t\tvoid this.bootstrap.onStart?.(event);\n\t\t\t\t}\n\t\t\t},\n\t\t\tonConversationUpdate: (conversation) => {\n\t\t\t\tthis.conversationCache = conversation;\n\t\t\t\tthis.emitWrapped('conversationUpdate', conversation);\n\t\t\t},\n\t\t\tonWidgetReady: () => options.onWidgetReady?.(),\n\t\t\tonWidgetExpand: () => options.onWidgetExpand?.(),\n\t\t\tonWidgetCollapse: () => options.onWidgetCollapse?.(),\n\t\t\tonWidgetAudioSettings: (open) => options.onWidgetAudioSettings?.(open),\n\t\t\tonWidgetDragStart: (event) => options.onWidgetDragStart?.(event),\n\t\t\tonWidgetDragMove: (event) => options.onWidgetDragMove?.(event),\n\t\t\tonWidgetDragEnd: (event) => options.onWidgetDragEnd?.(event)\n\t\t});\n\t\tthis.iframeHost = iframeHost;\n\n\t\tconst mintInteraction = this.resolveMintInteraction();\n\n\t\tconst launchPromise: Promise<SessionLaunchResponse | null> =\n\t\t\tthis.bootstrap.kind === 'sessionEndpoint'\n\t\t\t\t? (() => {\n\t\t\t\t\t\tthis.endpointAbortController = new AbortController();\n\t\t\t\t\t\treturn fetchSessionLaunch(this.bootstrap.sessionEndpoint, {\n\t\t\t\t\t\t\texperienceId: this.bootstrap.experienceId,\n\t\t\t\t\t\t\tlocale: this.bootstrap.locale,\n\t\t\t\t\t\t\tsecondaryLocale: this.bootstrap.secondaryLocale,\n\t\t\t\t\t\t\tlearningLocale: this.bootstrap.learningLocale,\n\t\t\t\t\t\t\tlanguage: this.bootstrap.language,\n\t\t\t\t\t\t\tmode: mintInteraction.mode,\n\t\t\t\t\t\t\tspeechInputMode: mintInteraction.speechInputMode,\n\t\t\t\t\t\t\tspeechOnly: this.bootstrap.speechOnly,\n\t\t\t\t\t\t\tattribution: this.bootstrap.attribution,\n\t\t\t\t\t\t\talreadyConverted: this.bootstrap.alreadyConverted,\n\t\t\t\t\t\t\tsignal: this.endpointAbortController.signal\n\t\t\t\t\t\t});\n\t\t\t\t\t})()\n\t\t\t\t: this.bootstrap.kind === 'public'\n\t\t\t\t\t? mintBrowserSession(this.bootstrap.experienceId, {\n\t\t\t\t\t\t\tlocale: this.bootstrap.locale,\n\t\t\t\t\t\t\tsecondaryLocale: this.bootstrap.secondaryLocale,\n\t\t\t\t\t\t\tlearningLocale: this.bootstrap.learningLocale,\n\t\t\t\t\t\t\tlanguage: this.bootstrap.language,\n\t\t\t\t\t\t\tmode: mintInteraction.mode,\n\t\t\t\t\t\t\tspeechInputMode: mintInteraction.speechInputMode,\n\t\t\t\t\t\t\tspeechOnly: this.bootstrap.speechOnly,\n\t\t\t\t\t\t\tattribution: this.bootstrap.attribution,\n\t\t\t\t\t\t\talreadyConverted: this.bootstrap.alreadyConverted\n\t\t\t\t\t\t})\n\t\t\t\t\t: Promise.resolve(\n\t\t\t\t\t\t\tthis.bootstrap.session\n\t\t\t\t\t\t\t\t? { session: this.bootstrap.session, launch: this.bootstrap.launch }\n\t\t\t\t\t\t\t\t: null\n\t\t\t\t\t\t);\n\n\t\tlet launchResponse: SessionLaunchResponse | null;\n\t\ttry {\n\t\t\t[, launchResponse] = await Promise.all([iframeHost.waitForLoad(), launchPromise]);\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tvoid iframeHost.reportSdkError({\n\t\t\t\t\terrorCode: 'sdk.session.attach_failed',\n\t\t\t\t\tseverity: 'error',\n\t\t\t\t\toperation: 'attach',\n\t\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t\t\trelease: SDK_RELEASE\n\t\t\t\t});\n\t\t\t} catch {\n\t\t\t\t/* best-effort */\n\t\t\t}\n\t\t\tiframeHost.destroy();\n\t\t\tif (this.iframeHost === iframeHost) {\n\t\t\t\tthis.iframeHost = null;\n\t\t\t}\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tthis.endpointAbortController = null;\n\t\t}\n\t\tiframeHost.postParentHello();\n\n\t\tconst launchToken =\n\t\t\tlaunchResponse?.launch ??\n\t\t\t(this.bootstrap.kind === 'launch' ? this.bootstrap.launch : null);\n\t\tconst session =\n\t\t\tlaunchResponse?.session ??\n\t\t\t(this.bootstrap.kind === 'launch' ? this.bootstrap.session : undefined);\n\n\t\tif (!launchToken) {\n\t\t\tiframeHost.destroy();\n\t\t\tif (this.iframeHost === iframeHost) {\n\t\t\t\tthis.iframeHost = null;\n\t\t\t}\n\t\t\tthrow new Error('Session Launch response did not include a launch token.');\n\t\t}\n\n\t\tthis.launchToken = launchToken;\n\t\tconst mintedSession =\n\t\t\tsession ??\n\t\t\t(this.bootstrap.kind === 'launch' ? this.bootstrap.session : undefined);\n\t\tif (mintedSession && !this.sessionMintedEnvelope) {\n\t\t\tthis.resolvedSession = mintedSession;\n\t\t\tthis.sessionMintedEnvelope = this.emitWrapped('sessionMinted', {\n\t\t\t\tsession: mintedSession\n\t\t\t});\n\t\t}\n\t\tif (session) {\n\t\t\tthis.resolvedSession = session;\n\t\t\t// Mint/endpoint paths already warn inside parseSessionLaunchResponse.\n\t\t\tif (this.bootstrap.kind === 'launch') {\n\t\t\t\twarnLocaleVoiceFallbacks(session);\n\t\t\t}\n\t\t\tiframeHost.postLaunch(launchToken, session, {\n\t\t\t\tstartButton: options.startButton,\n\t\t\t\ttheme: options.theme,\n\t\t\t\tshowFeedback: options.showFeedback,\n\t\t\t\tinteraction: options.interaction\n\t\t\t});\n\t\t\treadyGate.setValue(session);\n\t\t} else {\n\t\t\tiframeHost.postLaunch(launchToken, undefined, {\n\t\t\t\tstartButton: options.startButton,\n\t\t\t\ttheme: options.theme,\n\t\t\t\tshowFeedback: options.showFeedback,\n\t\t\t\tinteraction: options.interaction\n\t\t\t});\n\t\t}\n\n\t\tawait Promise.race([\n\t\t\tloadingUiPromise,\n\t\t\tnew Promise<void>((_, reject) => {\n\t\t\t\tsetTimeout(\n\t\t\t\t\t() => reject(new Error('Timed out waiting for player loading UI.')),\n\t\t\t\t\t120_000\n\t\t\t\t);\n\t\t\t})\n\t\t]).catch((error) => {\n\t\t\ttry {\n\t\t\t\tvoid iframeHost.reportSdkError({\n\t\t\t\t\terrorCode: 'sdk.session.attach_failed',\n\t\t\t\t\tseverity: 'error',\n\t\t\t\t\toperation: 'attach',\n\t\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t\t\trelease: SDK_RELEASE\n\t\t\t\t});\n\t\t\t} catch {\n\t\t\t\t/* best-effort */\n\t\t\t}\n\t\t\tthrow error;\n\t\t});\n\n\t\tawait Promise.race([\n\t\t\treadyUiPromise,\n\t\t\tnew Promise<void>((_, reject) => {\n\t\t\t\tsetTimeout(\n\t\t\t\t\t() => reject(new Error('Timed out waiting for player ready state.')),\n\t\t\t\t\t120_000\n\t\t\t\t);\n\t\t\t})\n\t\t]).catch((error) => {\n\t\t\ttry {\n\t\t\t\tvoid iframeHost.reportSdkError({\n\t\t\t\t\terrorCode: 'sdk.session.attach_failed',\n\t\t\t\t\tseverity: 'error',\n\t\t\t\t\toperation: 'attach',\n\t\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t\t\trelease: SDK_RELEASE\n\t\t\t\t});\n\t\t\t} catch {\n\t\t\t\t/* best-effort */\n\t\t\t}\n\t\t\tthrow error;\n\t\t});\n\n\t\tthis.attached = true;\n\t\tif (this.pendingFit) {\n\t\t\tawait iframeHost.setFit(this.pendingFit);\n\t\t}\n\t\treturn this.createPlayerFacade();\n\t}\n\n\tasync startListening(): Promise<void> {\n\t\tthis.assertSessionStarted();\n\t\tawait this.iframeHost!.startListening();\n\t}\n\n\tasync stopListening(): Promise<UtteranceResult> {\n\t\tthis.assertSessionStarted();\n\t\treturn this.iframeHost!.stopListening();\n\t}\n\n\tasync listenOnce(options?: ListenOnceOptions): Promise<UtteranceResult> {\n\t\tthis.assertSessionStarted();\n\t\treturn this.iframeHost!.listenOnce({\n\t\t\ttimeoutMs: options?.timeoutMs\n\t\t});\n\t}\n\n\tgetConversation(): readonly ConversationMessage[] {\n\t\treturn this.conversationCache;\n\t}\n\n\t/** Parent → player chrome mode for ExperienceWidget warm/cold expand / dock. */\n\tsetWidgetChrome(mode: 'collapsed' | 'loading' | 'expanded' | 'docked'): void {\n\t\tthis.iframeHost?.postWidgetSetChrome(mode);\n\t}\n\n\t/** Parent → player toggle for mic/speaker settings (ExperienceWidget toolbar). */\n\ttoggleAudioSettings(): void {\n\t\tthis.iframeHost?.postWidgetToggleAudioSettings();\n\t}\n\n\t/** Presentation-only. No-op on single-Character nodes. */\n\tasync focusCharacter(characterId: string): Promise<void> {\n\t\tthis.assertSessionStarted();\n\t\tawait this.iframeHost!.focusCharacter(characterId);\n\t}\n\n\t/** Live scene framing. Does not remint or restart the session. Queues until `attach()` if needed. */\n\tasync setFit(fit: ExperienceFit): Promise<void> {\n\t\tconst parsed = parseExperienceFit(fit);\n\t\tif (!parsed) {\n\t\t\tthrow new Error('setFit requires \"full\", \"medium\", or \"face\".');\n\t\t}\n\t\tif (this.closed) {\n\t\t\tthrow new Error('Session has ended.');\n\t\t}\n\t\tthis.pendingFit = parsed;\n\t\tif (!this.attached || !this.iframeHost) return;\n\t\tawait this.iframeHost.setFit(parsed);\n\t}\n\n\t/**\n\t * Patch captions / mic / text / Edit allow + state after `attach()`.\n\t * Returns the player-resolved {@link ExperienceInteraction}.\n\t */\n\tasync setInteraction(patch: ExperienceInteractionPatch): Promise<ExperienceInteraction> {\n\t\tif (this.closed) {\n\t\t\tthrow new Error('Session has ended.');\n\t\t}\n\t\tif (!this.iframeHost) {\n\t\t\tthrow new Error('setInteraction() requires attach() first.');\n\t\t}\n\t\tconst result = await this.iframeHost.setInteraction(patch);\n\t\tthis.lastInteraction = result;\n\t\treturn result;\n\t}\n\n\t/** Fetch the resolved interaction settings from the player (updates local cache). */\n\tasync getInteraction(): Promise<ExperienceInteraction> {\n\t\tif (this.closed) {\n\t\t\tthrow new Error('Session has ended.');\n\t\t}\n\t\tif (!this.iframeHost) {\n\t\t\tthrow new Error('getInteraction() requires attach() first.');\n\t\t}\n\t\tconst result = await this.iframeHost.getInteraction();\n\t\tthis.lastInteraction = result;\n\t\treturn result;\n\t}\n\n\t/** Record a conversion milestone (once per session per key). Client-reported. */\n\tasync conversion(key: string): Promise<void> {\n\t\tif (this.closed) {\n\t\t\tthrow new Error('Session has ended.');\n\t\t}\n\t\tif (!this.iframeHost) {\n\t\t\tthrow new Error('conversion() requires attach() first.');\n\t\t}\n\t\tawait this.iframeHost.conversion(key);\n\t}\n\n\t/** Mark engagement from an authored choice / explicit interaction. Idempotent. */\n\tasync engage(): Promise<void> {\n\t\tif (this.closed) {\n\t\t\tthrow new Error('Session has ended.');\n\t\t}\n\t\tif (!this.iframeHost) {\n\t\t\tthrow new Error('engage() requires attach() first.');\n\t\t}\n\t\tawait this.iframeHost.engage();\n\t}\n\n\tgetLastTurn(): readonly ConversationMessage[] {\n\t\tif (this.conversationCache.length === 0) return [];\n\t\tconst lastTurnId = this.conversationCache[this.conversationCache.length - 1]!.turnId;\n\t\treturn this.conversationCache.filter((m) => m.turnId === lastTurnId);\n\t}\n\n\tasync end(): Promise<void> {\n\t\tthis.close();\n\t}\n\n\tdestroy(): void {\n\t\tif (this.closed) return;\n\t\tthis.closed = true;\n\t\tthis.processorAbortController?.abort();\n\t\tthis.processorAbortController = null;\n\t\tthis.endpointAbortController?.abort();\n\t\tthis.endpointAbortController = null;\n\t\tthis.attachInFlight = null;\n\t\tthis.iframeHost?.destroy();\n\t\tthis.iframeHost = null;\n\t\tclearExperienceEventRegistry(this.eventRegistry);\n\t\tthis.readyEnvelope = null;\n\t\tthis.startedEnvelope = null;\n\t\tthis.closeHandlers.length = 0;\n\t\tthis.lastInteraction = null;\n\t\tthis.attached = false;\n\t}\n\n\tprivate resolveMintInteraction(): {\n\t\treadonly mode?: ExperienceMode;\n\t\treadonly speechInputMode?: SpeechInputMode;\n\t} {\n\t\tif (this.bootstrap.kind === 'launch') {\n\t\t\treturn {};\n\t\t}\n\t\treturn {\n\t\t\tmode: this.bootstrap.mode,\n\t\t\tspeechInputMode: this.bootstrap.speechInputMode\n\t\t};\n\t}\n\n\tprivate getSessionId(): string {\n\t\treturn this.resolvedSession?.id ?? '';\n\t}\n\n\tprivate emitWrapped<K extends ExperienceEventName>(\n\t\tevent: K,\n\t\tdata: ExperienceEvents[K]['data']\n\t): ExperienceEvents[K] {\n\t\tconst envelope = createExperienceEventEnvelope(event, this.getSessionId(), data) as unknown as ExperienceEvents[K];\n\t\temitExperienceEvent(this.eventRegistry, event, envelope);\n\t\treturn envelope;\n\t}\n\n\tprivate queueProcessorTurn(update: UserTranscriptUpdate): void {\n\t\tif (!update.isFinal || !update.text.trim() || !this.conversationProcessor) return;\n\n\t\tconst processor = this.conversationProcessor;\n\t\tthis.processorAbortController?.abort();\n\t\tthis.processorAbortController = new AbortController();\n\t\tconst signal = this.processorAbortController.signal;\n\n\t\tthis.processorChain = this.processorChain.then(async () => {\n\t\t\tif (signal.aborted) return;\n\t\t\ttry {\n\t\t\t\tconst dispatch = await dispatchConversationProcessor(processor, {\n\t\t\t\t\tutteranceId: update.utteranceId,\n\t\t\t\t\ttext: update.text,\n\t\t\t\t\tconversation: this.conversationCache,\n\t\t\t\t\tsignal\n\t\t\t\t});\n\t\t\t\tif (signal.aborted) return;\n\t\t\t\tif (dispatch.kind === 'complete') {\n\t\t\t\t\tconst speech = dispatch.speech;\n\t\t\t\t\tawait this.speech.speak({\n\t\t\t\t\t\ttext: speech.text,\n\t\t\t\t\t\t...(speech.characterId ? { characterId: speech.characterId } : {}),\n\t\t\t\t\t\tqueue: speech.behavior === 'interrupt' ? 'replace-active' : 'append'\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tawait this.iframeHost!.speakProcessorStream(dispatch.stream, { signal });\n\t\t\t} catch (error) {\n\t\t\t\tif (signal.aborted) return;\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tthis.emitWrapped('conversationProcessorError', {\n\t\t\t\t\tutteranceId: update.utteranceId,\n\t\t\t\t\tmessage\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate assertAttached(): void {\n\t\tif (!this.attached || !this.iframeHost) {\n\t\t\tthrow new Error('Call Experience.attach() before using speech APIs.');\n\t\t}\n\t}\n\n\tprivate assertSessionStarted(): void {\n\t\tthis.assertAttached();\n\t\tif (!this.startedEnvelope) {\n\t\t\tthrow new Error(\n\t\t\t\t'Session has not started. Wait for the player start button and the started event before using speak() or listening APIs.'\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate close(): void {\n\t\tif (this.closed) return;\n\t\tthis.closed = true;\n\t\tthis.endpointAbortController?.abort();\n\t\tthis.endpointAbortController = null;\n\t\tthis.attachInFlight = null;\n\t\tthis.iframeHost?.destroy();\n\t\tthis.iframeHost = null;\n\t\tthis.attached = false;\n\t}\n\n\tprivate createPlayerFacade(): LiformaPlayer {\n\t\treturn {\n\t\t\tclose: () => {\n\t\t\t\tthis.close();\n\t\t\t},\n\t\t\tdestroy: () => {\n\t\t\t\tthis.destroy();\n\t\t\t},\n\t\t\ton: (event, handler) => {\n\t\t\t\tif (event === 'close') {\n\t\t\t\t\tthis.closeHandlers.push(handler);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n}\n\n/** Live session handle returned by {@link Experience.startSession}. */\nexport type ExperienceSession = Experience;\n\nfunction resolveSpeechCapabilities(session: Session | null): SpeechCapabilities {\n\tif (!session) {\n\t\treturn { textSpeech: true, externalSpeechAudio: true };\n\t}\n\treturn {\n\t\ttextSpeech: session.capabilities.speech.output,\n\t\texternalSpeechAudio: session.capabilities.speech.externalAudio\n\t};\n}\n","import './liforma-experience';\nimport './liforma-experience-thumbnail';\nimport './liforma-experience-widget';\n\nexport { Experience, type ExperienceSession } from './experience';\nexport { LiformaError, liformaErrorFromResponse } from './errors/LiformaError';\nexport type {\n\tAttachOptions,\n\tCloseEvent,\n\tEmbedState,\n\tLiformaPlayer,\n\tReadyEvent,\n\tStartSessionOptions\n} from './experience';\nexport type { SessionManifest, SessionManifestCharacter } from './types/sessionManifest';\nexport type {\n\tCloseButtonOptions,\n\tLocaleVoiceFallback,\n\tPlayerStatus,\n\tSession,\n\tSessionActivity,\n\tSessionCapabilities,\n\tSessionLaunchResponse,\n\tSessionMode\n} from './types/sessionLaunch';\nexport { warnLocaleVoiceFallbacks } from './types/sessionLaunch';\nexport type { ExperienceEventName, ExperienceEvents, ExperienceEventEnvelope, FeedbackResult, FeedbackFailedEvent } from './experienceEvents';\nexport type {\n\tCharacterSpeechEvent,\n\tCharacterSpeechSource,\n\tCharacterSpeechTerminalReason,\n\tConversationMessage,\n\tSpeakOptions,\n\tTextSpeakResult,\n\tSpeechResult as LegacySpeakResult,\n\tUserTranscriptUpdate,\n\tUtteranceResult,\n\tExperienceFit,\n\tExperienceInteraction,\n\tExperienceInteractionPatch,\n\tExperienceMode,\n\tResponseMode,\n\tSpeechInputMode,\n\tVisibleTurns,\n\tInteractionControls,\n\tStartButtonAppearance,\n\tStartButtonOptions,\n\tStartButtonPlacement,\n\tStartButtonShadow,\n\tStartButtonSize,\n\tStartButtonVariant,\n\tStartButtonIconPosition,\n\tPlayerTheme,\n\tPlayerThemeButton,\n\tPlayerThemeColors,\n\tPlayerThemeTypography,\n\tStartedEvent,\n} from './types/sessionInteraction';\nexport type {\n\tSpeechAudioFormat,\n\tSpeechController,\n\tSpeechCreateUtteranceOptions,\n\tSpeechInterruptOptions,\n\tSpeechPlayAudio,\n\tSpeechPlayEncodedAudio,\n\tSpeechPlayOptions,\n\tSpeechPlayPcmAudio,\n\tSpeechPlayUrlAudio,\n\tSpeechResult,\n\tSpeechSpeakOptions,\n\tSpeechUtterance\n} from './speech';\nexport {\n\tSPEECH_LIMITS,\n\tSpeechBufferTimeoutError,\n\tSpeechRuntimeError,\n\tSpeechUtteranceClosedError,\n\tUnsupportedSpeechOperationError\n} from './speech';\n\nimport { Experience } from './experience';\n\ndeclare global {\n\tinterface Window {\n\t\tLiforma?: {\n\t\t\tExperience: typeof Experience;\n\t\t\tsdkVersion: 'v2';\n\t\t\treadonly features: {\n\t\t\t\treadonly speakApi: boolean;\n\t\t\t\treadonly speechAudioApi: boolean;\n\t\t\t};\n\t\t};\n\t}\n}\n\nwindow.Liforma = {\n\tExperience,\n\tsdkVersion: 'v2',\n\tfeatures: {\n\t\tspeakApi: true,\n\t\tspeechAudioApi: true\n\t}\n};\n"],"mappings":"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"}
|