@ai-matrx/media 0.6.66 → 0.7.0
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 +23 -0
- package/dist/live-audio-react.cjs +873 -0
- package/dist/live-audio-react.cjs.map +1 -0
- package/dist/live-audio-react.d.cts +36 -0
- package/dist/live-audio-react.d.ts +36 -0
- package/dist/live-audio-react.js +851 -0
- package/dist/live-audio-react.js.map +1 -0
- package/dist/live-audio.cjs +697 -0
- package/dist/live-audio.cjs.map +1 -0
- package/dist/live-audio.d.cts +212 -0
- package/dist/live-audio.d.ts +212 -0
- package/dist/live-audio.js +674 -0
- package/dist/live-audio.js.map +1 -0
- package/dist/react.cjs +11 -0
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +3 -1
- package/dist/react.d.ts +3 -1
- package/dist/react.js +11 -0
- package/dist/react.js.map +1 -1
- package/dist/share.cjs.map +1 -1
- package/dist/share.js.map +1 -1
- package/dist/viewers.cjs.map +1 -1
- package/dist/viewers.js.map +1 -1
- package/package.json +25 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/live-audio/react/use-live-audio.ts","../src/live-audio/mp3-player.ts","../src/live-audio/pcm-player.ts","../src/live-audio/controller.ts","../src/live-audio/react/use-live-audio-player.ts","../src/live-audio/react/live-audio-player.tsx","../src/react/cn.ts","../src/react/icons.tsx","../src/live-audio/registry.ts","../src/live-audio/media-frames.ts"],"sourcesContent":["/**\n * `useLiveAudio` — the React binding of the live-audio controller: one\n * controller per mount, the current player in state (re-renders only when\n * the player appears/disappears, never per chunk), torn down on unmount.\n */\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport {\n createLiveAudioController,\n type LiveAudioController,\n type LiveAudioControllerOptions,\n type LiveAudioEndEvent,\n} from \"../controller\";\nimport type { StreamingAudioPlayer } from \"../pcm-player\";\n\nexport interface UseLiveAudioOptions\n extends Omit<LiveAudioControllerOptions, \"onPlayer\" | \"onEnd\"> {\n /** The stream finished — the saved file is ready (persist `cdn_url`, swap players). */\n onEnd?: (event: LiveAudioEndEvent) => void;\n}\n\nexport interface UseLiveAudio {\n /** The live player while audio is streaming; null before the first chunk / after a drop. */\n player: StreamingAudioPlayer | null;\n /** Feed every `data` payload; true when it was a live-audio event (consumed). */\n handle: (data: unknown) => boolean;\n /** A fresh stream (new run, resume, rejoin): seq restarts at 0. */\n reset: () => void;\n}\n\nexport function useLiveAudio(options: UseLiveAudioOptions = {}): UseLiveAudio {\n const [player, setPlayer] = useState<StreamingAudioPlayer | null>(null);\n const optionsRef = useRef(options);\n optionsRef.current = options;\n const controllerRef = useRef<LiveAudioController | null>(null);\n\n const controller = useCallback((): LiveAudioController => {\n if (!controllerRef.current) {\n const current = optionsRef.current;\n controllerRef.current = createLiveAudioController({\n onPlayer: setPlayer,\n onEnd: (event) => optionsRef.current.onEnd?.(event),\n onDrop: (reason) =>\n optionsRef.current.onDrop\n ? optionsRef.current.onDrop(reason)\n : console.warn(`[live-audio] ${reason}`),\n ...(current.createPcmPlayer ? { createPcmPlayer: current.createPcmPlayer } : {}),\n ...(current.createMp3Player ? { createMp3Player: current.createMp3Player } : {}),\n });\n }\n return controllerRef.current;\n }, []);\n\n useEffect(\n () => () => {\n controllerRef.current?.destroy();\n controllerRef.current = null;\n },\n [],\n );\n\n const handle = useCallback((data: unknown) => controller().handle(data), [controller]);\n const reset = useCallback(() => controller().reset(), [controller]);\n\n return { player, handle, reset };\n}\n","// @ai-matrx/media/live-audio — mp3-player.ts\n//\n// Moved verbatim from matrx-frontend features/audio/streamingMp3Player.ts\n// (2026-10-01).\n//\n// Progressive MP3 player for encoded `audio_stream_chunk` events. ElevenLabs\n// returns one continuous MP3 byte stream in provider-sized chunks; MediaSource\n// lets the browser decode and play those bytes while later chunks are still\n// arriving. The interface intentionally matches StreamingAudioPlayer so the\n// podcast UI can swap PCM/Web Audio and MP3/MediaSource by event metadata.\n\nimport type { StreamingAudioPlayer } from \"./pcm-player\";\n\nexport interface StreamingMp3PlayerOptions {\n mimeType?: string;\n onError?: (error: Error) => void;\n}\n\nfunction base64ToArrayBuffer(b64: string): ArrayBuffer {\n const binary = atob(b64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer;\n}\n\nexport function createStreamingMp3Player(\n options: StreamingMp3PlayerOptions = {},\n): StreamingAudioPlayer | null {\n if (typeof window === \"undefined\" || typeof MediaSource === \"undefined\") {\n console.info(\n \"[streaming-mp3] MediaSource is unavailable — live MP3 playback disabled; waiting for the canonical audio file\",\n );\n return null;\n }\n\n const mimeType = options.mimeType || \"audio/mpeg\";\n if (!MediaSource.isTypeSupported(mimeType)) {\n console.info(\n `[streaming-mp3] browser does not support MediaSource ${mimeType} — live playback disabled; waiting for the canonical audio file`,\n );\n return null;\n }\n\n const mediaSource = new MediaSource();\n const objectUrl = URL.createObjectURL(mediaSource);\n const audio = document.createElement(\"audio\");\n audio.preload = \"auto\";\n audio.hidden = true;\n audio.setAttribute(\"aria-hidden\", \"true\");\n audio.src = objectUrl;\n // Keep the media element attached. Chromium will play a detached element,\n // but WebKit's MediaSource implementation is not reliable unless the\n // element belongs to the document. The visible transport remains the\n // LiveAudioPlayer component; this element is only the decoder/output sink.\n document.body.appendChild(audio);\n\n const pending: ArrayBuffer[] = [];\n const callbacks = new Set<() => void>();\n let sourceBuffer: SourceBuffer | null = null;\n let streamEnded = false;\n let destroyed = false;\n let failed = false;\n\n function notify(): void {\n for (const callback of callbacks) callback();\n }\n\n function fail(message: string, cause?: unknown): void {\n if (failed || destroyed) return;\n failed = true;\n const error =\n cause instanceof Error\n ? new Error(message, { cause })\n : new Error(message);\n console.error(`[streaming-mp3] ${message}`, cause ?? \"\");\n options.onError?.(error);\n notify();\n }\n\n function finishIfReady(): void {\n if (\n !destroyed &&\n !failed &&\n streamEnded &&\n pending.length === 0 &&\n sourceBuffer &&\n !sourceBuffer.updating &&\n mediaSource.readyState === \"open\"\n ) {\n try {\n mediaSource.endOfStream();\n } catch (error) {\n fail(\"could not finalize the MediaSource stream\", error);\n }\n }\n }\n\n function appendNext(): void {\n if (\n destroyed ||\n failed ||\n !sourceBuffer ||\n sourceBuffer.updating ||\n mediaSource.readyState !== \"open\"\n ) {\n return;\n }\n const next = pending.shift();\n if (!next) {\n finishIfReady();\n return;\n }\n try {\n sourceBuffer.appendBuffer(next);\n } catch (error) {\n fail(\"could not append an MP3 stream chunk\", error);\n }\n }\n\n mediaSource.addEventListener(\n \"sourceopen\",\n () => {\n if (destroyed || failed || sourceBuffer) return;\n try {\n sourceBuffer = mediaSource.addSourceBuffer(mimeType);\n sourceBuffer.mode = \"sequence\";\n sourceBuffer.addEventListener(\"updateend\", () => {\n notify();\n appendNext();\n });\n sourceBuffer.addEventListener(\"error\", () => {\n fail(\"MediaSource rejected the MP3 stream\");\n });\n appendNext();\n } catch (error) {\n fail(\"could not initialize an MP3 SourceBuffer\", error);\n }\n },\n { once: true },\n );\n\n for (const event of [\"timeupdate\", \"progress\", \"play\", \"pause\", \"ended\"]) {\n audio.addEventListener(event, notify);\n }\n audio.addEventListener(\"error\", () => {\n fail(\n `browser could not decode the live MP3 stream${audio.error?.message ? `: ${audio.error.message}` : \"\"}`,\n );\n });\n\n function getBufferedMs(): number {\n try {\n const ranges = audio.buffered;\n return ranges.length > 0 ? ranges.end(ranges.length - 1) * 1000 : 0;\n } catch {\n return 0;\n }\n }\n\n return {\n enqueueBase64: (b64) => {\n if (destroyed || failed || streamEnded) return;\n try {\n const bytes = base64ToArrayBuffer(b64);\n if (bytes.byteLength === 0) return;\n pending.push(bytes);\n appendNext();\n notify();\n } catch (error) {\n fail(\"received a malformed base64 MP3 chunk\", error);\n }\n },\n end: () => {\n if (destroyed || failed) return;\n streamEnded = true;\n finishIfReady();\n notify();\n },\n play: () => {\n if (destroyed || failed) return;\n void audio.play().catch((error) => {\n fail(\"browser refused live MP3 playback\", error);\n });\n },\n pause: () => audio.pause(),\n seekMs: (ms) => {\n if (destroyed || failed) return;\n const clampedMs = Math.max(0, Math.min(ms, getBufferedMs()));\n audio.currentTime = clampedMs / 1000;\n notify();\n },\n getPositionMs: () =>\n Number.isFinite(audio.currentTime) ? audio.currentTime * 1000 : 0,\n getBufferedMs,\n isPlaying: () => !audio.paused && !audio.ended,\n hasEnded: () => streamEnded,\n onUpdate: (callback) => {\n callbacks.add(callback);\n return () => callbacks.delete(callback);\n },\n destroy: () => {\n if (destroyed) return;\n destroyed = true;\n audio.pause();\n pending.length = 0;\n callbacks.clear();\n if (sourceBuffer?.updating) {\n try {\n sourceBuffer.abort();\n } catch {\n // The MediaSource may already have closed between the state check and abort.\n }\n }\n audio.removeAttribute(\"src\");\n audio.load();\n audio.remove();\n URL.revokeObjectURL(objectUrl);\n sourceBuffer = null;\n },\n };\n}\n","// @ai-matrx/media/live-audio — pcm-player.ts\n//\n// Moved verbatim from matrx-frontend features/audio/streamingPcmPlayer.ts\n// (2026-10-01) so every client plays live TTS identically.\n//\n// Generic progressive PCM stream player — the client half of the server's\n// `audio_stream_chunk` / `audio_stream_end` events (matrx_connect\n// AudioStreamChunkData: base64 signed 16-bit little-endian PCM segments).\n//\n// Unlike the conversational playback in features/voice-agent (turn-based,\n// interrupt-driven, fire-and-forget), this player BUFFERS every chunk so a\n// long render (a podcast episode arriving over minutes) supports the full\n// listen-while-it-renders UX: play/pause, seek within what has buffered,\n// position tracking, and graceful underrun (playback catches up with the\n// buffer, then resumes as the next chunk lands).\n//\n// Memory: chunks are kept as Int16 (half the size of Float32) and converted\n// per-chunk at schedule time. 24 kHz mono ≈ 2.9 MB/min — fine for the\n// transient live-preview window; callers destroy() once the canonical file\n// URL takes over.\n//\n// AudioContext is created lazily inside play() so the browser's user-gesture\n// requirement is satisfied by the user's own click.\n\nexport interface StreamingPcmFormat {\n sampleRate: number;\n /** Interleaved channel count. The podcast/TTS streams are mono (1). */\n channels: number;\n}\n\nexport interface StreamingAudioPlayer {\n /** Buffer one base64 chunk of s16le PCM. Safe to call before play(). */\n enqueueBase64: (b64: string) => void;\n /** No more chunks are coming — playback may drain to the true end. */\n end: () => void;\n play: () => void;\n pause: () => void;\n /** Seek within the buffered range (clamped). Keeps playing if playing. */\n seekMs: (ms: number) => void;\n getPositionMs: () => number;\n getBufferedMs: () => number;\n isPlaying: () => boolean;\n hasEnded: () => boolean;\n /** Subscribe to position/buffer changes. Returns unsubscribe. */\n onUpdate: (cb: () => void) => () => void;\n /** Tear down: stop audio, close the context, release buffers. */\n destroy: () => void;\n}\n\n/** Backward-compatible name for PCM-specific callers. */\nexport type StreamingPcmPlayer = StreamingAudioPlayer;\n\nfunction base64ToInt16(b64: string): Int16Array {\n const binary = atob(b64);\n const len = binary.length;\n const bytes = new Uint8Array(len);\n for (let i = 0; i < len; i++) bytes[i] = binary.charCodeAt(i);\n return new Int16Array(bytes.buffer, 0, len >> 1);\n}\n\nexport function createStreamingPcmPlayer(\n format: StreamingPcmFormat,\n): StreamingAudioPlayer {\n const sampleRate = format.sampleRate > 0 ? format.sampleRate : 24000;\n const channels = format.channels > 0 ? format.channels : 1;\n\n /** Buffered PCM, one Int16Array per received chunk (interleaved frames). */\n const chunks: Int16Array[] = [];\n /** Cumulative frame count at the END of each chunk — for offset lookup. */\n const chunkEndFrames: number[] = [];\n let totalFrames = 0;\n\n let ctx: AudioContext | null = null;\n const scheduled: AudioBufferSourceNode[] = [];\n /** Index of the next buffered chunk to schedule while playing. */\n let nextChunkIndex = 0;\n /** ctx time at which the next scheduled buffer should start (gapless chain). */\n let nextPlayTime = 0;\n\n let playing = false;\n let ended = false;\n let destroyed = false;\n /** Playhead when paused; while playing it's derived from the ctx clock. */\n let pausedAtFrame = 0;\n /** Anchors mapping ctx.currentTime → stream frame while playing. */\n let anchorCtxTime = 0;\n let anchorFrame = 0;\n\n let updateTimer: ReturnType<typeof setInterval> | null = null;\n const updateCallbacks = new Set<() => void>();\n\n function notify(): void {\n for (const cb of updateCallbacks) {\n try {\n cb();\n } catch {\n // subscriber errors must never break playback\n }\n }\n }\n\n function startUpdateLoop(): void {\n if (updateTimer !== null) return;\n updateTimer = setInterval(() => {\n notify();\n if (!playing && updateTimer !== null) {\n clearInterval(updateTimer);\n updateTimer = null;\n }\n }, 250);\n }\n\n function framesToMs(frames: number): number {\n return (frames / sampleRate) * 1000;\n }\n\n function getPositionFrames(): number {\n if (!playing || !ctx) return pausedAtFrame;\n const elapsed = Math.max(0, ctx.currentTime - anchorCtxTime);\n return Math.min(\n anchorFrame + Math.round(elapsed * sampleRate),\n totalFrames,\n );\n }\n\n function ensureContext(): AudioContext | null {\n if (typeof window === \"undefined\") return null;\n if (!ctx) {\n const Ctor: typeof AudioContext =\n window.AudioContext ||\n (window as unknown as { webkitAudioContext: typeof AudioContext })\n .webkitAudioContext;\n if (!Ctor) return null;\n ctx = new Ctor({ sampleRate });\n }\n if (ctx.state === \"suspended\") void ctx.resume();\n return ctx;\n }\n\n function int16ToBuffer(\n c: AudioContext,\n pcm: Int16Array,\n fromFrame: number,\n ): AudioBuffer | null {\n const frames = pcm.length / channels - fromFrame;\n if (frames <= 0) return null;\n const buf = c.createBuffer(channels, frames, sampleRate);\n for (let ch = 0; ch < channels; ch++) {\n const data = buf.getChannelData(ch);\n for (let i = 0; i < frames; i++) {\n data[i] = (pcm[(fromFrame + i) * channels + ch] ?? 0) / 0x8000;\n }\n }\n return buf;\n }\n\n function scheduleChunk(index: number, fromFrame: number): void {\n const pcm = chunks[index];\n if (!ctx || !pcm) return;\n const buf = int16ToBuffer(ctx, pcm, fromFrame);\n if (!buf) return;\n const src = ctx.createBufferSource();\n src.buffer = buf;\n src.connect(ctx.destination);\n\n const now = ctx.currentTime;\n const startAt = Math.max(now, nextPlayTime);\n // An underrun gap (playback drained before this chunk arrived) must not\n // count toward the playhead — shift the anchor by the silent gap.\n if (startAt > nextPlayTime && nextPlayTime > 0) {\n anchorCtxTime += startAt - nextPlayTime;\n }\n src.start(startAt);\n nextPlayTime = startAt + buf.duration;\n scheduled.push(src);\n src.onended = () => {\n const i = scheduled.indexOf(src);\n if (i !== -1) scheduled.splice(i, 1);\n try {\n src.disconnect();\n } catch {\n // already disconnected\n }\n if (\n playing &&\n scheduled.length === 0 &&\n ended &&\n nextChunkIndex >= chunks.length\n ) {\n // True end of the stream — settle as paused at the end.\n pausedAtFrame = totalFrames;\n playing = false;\n notify();\n }\n };\n }\n\n function scheduleFrom(frame: number): void {\n if (!ctx) return;\n // Locate the chunk containing `frame`.\n let index = chunkEndFrames.findIndex((end) => frame < end);\n if (index === -1) index = chunks.length; // at/past the buffered end\n const chunkStart = index === 0 ? 0 : (chunkEndFrames[index - 1] ?? 0);\n\n nextPlayTime = ctx.currentTime;\n anchorCtxTime = ctx.currentTime;\n anchorFrame = frame;\n if (index < chunks.length) {\n scheduleChunk(index, frame - chunkStart);\n for (let i = index + 1; i < chunks.length; i++) scheduleChunk(i, 0);\n }\n nextChunkIndex = chunks.length;\n }\n\n function stopScheduled(): void {\n for (const src of scheduled) {\n try {\n src.onended = null;\n src.stop(0);\n src.disconnect();\n } catch {\n // already stopped\n }\n }\n scheduled.length = 0;\n }\n\n function enqueueBase64(b64: string): void {\n if (destroyed || ended) return;\n let pcm: Int16Array;\n try {\n pcm = base64ToInt16(b64);\n } catch {\n return; // a malformed chunk is dropped, never fatal\n }\n if (pcm.length === 0) return;\n chunks.push(pcm);\n totalFrames += pcm.length / channels;\n chunkEndFrames.push(totalFrames);\n if (playing && ctx) {\n // Chain the new chunk onto the live schedule.\n scheduleChunk(chunks.length - 1, 0);\n nextChunkIndex = chunks.length;\n }\n notify();\n }\n\n function play(): void {\n if (destroyed || playing) return;\n const c = ensureContext();\n if (!c) return;\n if (ended && pausedAtFrame >= totalFrames) pausedAtFrame = 0; // replay\n playing = true;\n scheduleFrom(pausedAtFrame);\n startUpdateLoop();\n notify();\n }\n\n function pause(): void {\n if (!playing) return;\n pausedAtFrame = getPositionFrames();\n playing = false;\n stopScheduled();\n notify();\n }\n\n function seekMs(ms: number): void {\n const frame = Math.max(\n 0,\n Math.min(Math.round((ms / 1000) * sampleRate), totalFrames),\n );\n if (playing) {\n stopScheduled();\n scheduleFrom(frame);\n } else {\n pausedAtFrame = frame;\n }\n notify();\n }\n\n function end(): void {\n ended = true;\n notify();\n }\n\n function destroy(): void {\n if (destroyed) return;\n destroyed = true;\n playing = false;\n stopScheduled();\n if (updateTimer !== null) {\n clearInterval(updateTimer);\n updateTimer = null;\n }\n updateCallbacks.clear();\n chunks.length = 0;\n chunkEndFrames.length = 0;\n if (ctx) {\n void ctx.close().catch(() => undefined);\n ctx = null;\n }\n }\n\n return {\n enqueueBase64,\n end,\n play,\n pause,\n seekMs,\n getPositionMs: () => framesToMs(getPositionFrames()),\n getBufferedMs: () => framesToMs(totalFrames),\n isPlaying: () => playing,\n hasEnded: () => ended,\n onUpdate: (cb) => {\n updateCallbacks.add(cb);\n return () => updateCallbacks.delete(cb);\n },\n destroy,\n };\n}\n","/**\n * The live-audio controller — the ONE client interpretation of the server's\n * `audio_stream_chunk` / `audio_stream_end` data events\n * (matrx_connect AudioStreamChunkData / AudioStreamEndData):\n *\n * chunk: { stream_id, seq, audio_base64, mime_type,\n * encoding: \"pcm_s16le\" | \"mp3\", sample_rate, bits_per_sample,\n * channels } — frames ≤32 KiB raw, contiguous `seq` from 0\n * end: { stream_id, total_chunks, url, file_id, cdn_url, … }\n *\n * Framework-agnostic: feed it every `data` payload; it picks the codec player\n * (PCM → Web Audio, MP3 → MediaSource) from the chunk metadata, enforces one\n * stream identity and a gap-free `seq`, and hands the player to the host via\n * `onPlayer`. Any violation DROPS live playback loudly (the saved file takes\n * over when the end event lands) — playing a reordered or spliced stream is\n * worse than waiting. Behavior moved verbatim from matrx-frontend's podcast\n * studio (`useStudioRun`) so every client plays live TTS identically.\n */\n\nimport { createStreamingMp3Player } from \"./mp3-player\";\nimport {\n createStreamingPcmPlayer,\n type StreamingAudioPlayer,\n type StreamingPcmFormat,\n} from \"./pcm-player\";\n\nexport type LiveAudioEncoding = \"pcm_s16le\" | \"mp3\";\n\n/** `data` payload `{ type: \"audio_stream_chunk\", … }`. */\nexport interface LiveAudioChunkEvent {\n type: \"audio_stream_chunk\";\n stream_id: string;\n seq: number;\n audio_base64: string;\n mime_type: string;\n encoding?: string | null;\n sample_rate?: number | null;\n bits_per_sample?: number | null;\n channels?: number | null;\n}\n\n/** `data` payload `{ type: \"audio_stream_end\", … }` — the saved file's identity. */\nexport interface LiveAudioEndEvent {\n type: \"audio_stream_end\";\n stream_id: string;\n total_chunks?: number | null;\n url?: string | null;\n file_id?: string | null;\n cdn_url?: string | null;\n mime_type?: string | null;\n duration_ms?: number | null;\n}\n\nexport const LIVE_AUDIO_CHUNK = \"audio_stream_chunk\";\nexport const LIVE_AUDIO_END = \"audio_stream_end\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** True for a `data` payload of either live-audio event type. */\nexport function isLiveAudioEvent(\n data: unknown,\n): data is LiveAudioChunkEvent | LiveAudioEndEvent {\n return (\n isRecord(data) && (data.type === LIVE_AUDIO_CHUNK || data.type === LIVE_AUDIO_END)\n );\n}\n\n/** The codec of a chunk, from `encoding` first, else its MIME type. Null = unsupported. */\nexport function liveAudioEncodingOf(\n chunk: Pick<LiveAudioChunkEvent, \"encoding\" | \"mime_type\">,\n): LiveAudioEncoding | null {\n const mime = chunk.mime_type ?? \"\";\n if (chunk.encoding === \"mp3\" || /(?:mpeg|mp3)/i.test(mime)) return \"mp3\";\n if (chunk.encoding === \"pcm_s16le\" || /(?:l16|pcm)/i.test(mime)) return \"pcm_s16le\";\n return null;\n}\n\nexport interface LiveAudioControllerOptions {\n /** The current player (null after a drop/reset) — e.g. a React state setter. */\n onPlayer: (player: StreamingAudioPlayer | null) => void;\n /** The stream finished; the saved file (`url` / `cdn_url` / `file_id`) is ready. */\n onEnd?: (event: LiveAudioEndEvent) => void;\n /** Live playback was dropped. Default: `console.warn` — never silent. */\n onDrop?: (reason: string) => void;\n /** Codec player factories (tests, non-DOM hosts). Defaults: the package players. */\n createPcmPlayer?: (format: StreamingPcmFormat) => StreamingAudioPlayer | null;\n createMp3Player?: (options: {\n mimeType: string;\n onError: (error: Error) => void;\n }) => StreamingAudioPlayer | null;\n}\n\nexport interface LiveAudioController {\n /**\n * Feed one `data` payload. Returns true when it was a live-audio event\n * (consumed here — never put base64 chunks into UI state); false otherwise.\n */\n handle(data: unknown): boolean;\n /** A fresh stream (new run, resume, rejoin replay from frame one): seq restarts at 0. */\n reset(): void;\n /** Tear down the player for good. */\n destroy(): void;\n readonly player: StreamingAudioPlayer | null;\n}\n\nexport function createLiveAudioController(\n options: LiveAudioControllerOptions,\n): LiveAudioController {\n const makePcm = options.createPcmPlayer ?? createStreamingPcmPlayer;\n const makeMp3 = options.createMp3Player ?? createStreamingMp3Player;\n\n let player: StreamingAudioPlayer | null = null;\n let expectedSeq = 0;\n let streamId: string | null = null;\n let encoding: LiveAudioEncoding | null = null;\n let broken = false;\n\n function clearPlayer(): void {\n player?.destroy();\n player = null;\n options.onPlayer(null);\n }\n\n function drop(reason: string): void {\n const message = `${reason} — dropping live playback; the saved file takes over when rendering finishes`;\n if (options.onDrop) options.onDrop(message);\n else console.warn(`[live-audio] ${message}`);\n broken = true;\n clearPlayer();\n }\n\n function onChunk(e: LiveAudioChunkEvent): void {\n if (broken) return;\n const codec = liveAudioEncodingOf(e);\n if (!codec) {\n drop(`unsupported audio stream format ${e.encoding || e.mime_type}`);\n return;\n }\n if (streamId !== null && (streamId !== e.stream_id || encoding !== codec)) {\n drop(\n `audio stream identity/format changed mid-render (${streamId}/${encoding} → ${e.stream_id}/${codec})`,\n );\n return;\n }\n if (e.seq !== expectedSeq) {\n drop(`audio stream gap (expected seq ${expectedSeq}, got ${e.seq})`);\n return;\n }\n streamId = e.stream_id;\n encoding = codec;\n expectedSeq = e.seq + 1;\n if (!player) {\n const created =\n codec === \"mp3\"\n ? makeMp3({\n mimeType: e.mime_type || \"audio/mpeg\",\n onError: (error) => drop(error.message),\n })\n : makePcm({\n sampleRate: e.sample_rate || 24000,\n channels: e.channels || 1,\n });\n if (!created) {\n drop(`no browser player is available for ${codec}`);\n return;\n }\n player = created;\n options.onPlayer(created);\n }\n player.enqueueBase64(e.audio_base64);\n }\n\n return {\n handle(data: unknown): boolean {\n if (!isLiveAudioEvent(data)) return false;\n if (data.type === LIVE_AUDIO_CHUNK) {\n onChunk(data);\n return true;\n }\n player?.end();\n options.onEnd?.(data);\n return true;\n },\n reset(): void {\n expectedSeq = 0;\n streamId = null;\n encoding = null;\n broken = false;\n if (player) clearPlayer();\n },\n destroy(): void {\n player?.destroy();\n player = null;\n },\n get player() {\n return player;\n },\n };\n}\n\n/**\n * Hand a live player over to the saved file: pause it (never two audio\n * sources at once) and return where the listener was, so the full player can\n * pick up at the same moment. Null when nothing has been heard yet.\n */\nexport function takeLiveAudioHandoff(\n player: StreamingAudioPlayer,\n): { timeSec: number; resume: boolean } | null {\n const resume = player.isPlaying();\n const timeSec = player.getPositionMs() / 1000;\n player.pause();\n return timeSec > 0 ? { timeSec, resume } : null;\n}\n","/** `useLiveAudioPlayer(registry, key)` — the live player for one key, re-rendering only when it appears/goes away. */\n\nimport { useCallback, useSyncExternalStore } from \"react\";\n\nimport type { StreamingAudioPlayer } from \"../pcm-player\";\nimport type { LiveAudioRegistry } from \"../registry\";\n\nexport function useLiveAudioPlayer(\n registry: LiveAudioRegistry | null | undefined,\n key: string | null | undefined,\n): StreamingAudioPlayer | null {\n const subscribe = useCallback(\n (listener: () => void) => (registry ? registry.subscribe(listener) : () => undefined),\n [registry],\n );\n const read = useCallback(\n () => (registry && key ? registry.player(key) : null),\n [registry, key],\n );\n return useSyncExternalStore(subscribe, read, () => null);\n}\n","/**\n * `LiveAudioPlayer` — the listen-while-it-renders transport: play/pause, live\n * position over the buffered duration, seek within what has rendered so far.\n * The buffered edge keeps growing as the TTS streams; when the saved file\n * lands the host swaps this for its full player (`takeLiveAudioHandoff`\n * carries the position over). Moved from matrx-frontend's podcast generator\n * so every client renders live audio identically.\n */\n\nimport { useEffect, useState } from \"react\";\nimport { formatDurationMs } from \"@ai-matrx/kit/format\";\n\nimport { cn } from \"../../react/cn\";\nimport { PauseIcon, PlayIcon } from \"../../react/icons\";\nimport type { StreamingAudioPlayer } from \"../pcm-player\";\n\nexport interface LiveAudioPlayerProps {\n player: StreamingAudioPlayer;\n title?: string;\n className?: string;\n}\n\nfunction readPlayer(player: StreamingAudioPlayer) {\n return {\n positionMs: player.getPositionMs(),\n bufferedMs: player.getBufferedMs(),\n playing: player.isPlaying(),\n ended: player.hasEnded(),\n };\n}\n\nexport function LiveAudioPlayer({ player, title, className }: LiveAudioPlayerProps) {\n const [snapshot, setSnapshot] = useState(() => readPlayer(player));\n useEffect(() => {\n const update = () => setSnapshot(readPlayer(player));\n update();\n const unsubscribe = player.onUpdate(update);\n // MediaSource can append a burst of provider chunks before this component's\n // effect subscribes, and WebKit does not reliably emit `progress` for every\n // SourceBuffer update. Poll only while the transient live player is mounted\n // so its transport never displays a stale position or Play/Pause state.\n const timer = window.setInterval(update, 250);\n return () => {\n window.clearInterval(timer);\n unsubscribe();\n };\n }, [player]);\n\n const { positionMs, bufferedMs, playing, ended } = snapshot;\n const progress = bufferedMs > 0 ? (positionMs / bufferedMs) * 100 : 0;\n\n return (\n <div className={cn(\"rounded-2xl border border-border bg-card p-5 shadow-sm\", className)}>\n <div className=\"mb-3 flex items-center justify-between gap-2\">\n <span className=\"inline-flex items-center gap-1.5 rounded-full bg-primary/10 px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-primary\">\n <span className=\"relative flex h-1.5 w-1.5\">\n <span className=\"absolute inline-flex h-full w-full animate-ping rounded-full bg-primary/60\" />\n <span className=\"relative inline-flex h-1.5 w-1.5 rounded-full bg-primary\" />\n </span>\n Listen live\n </span>\n <span className=\"text-xs text-muted-foreground\">\n You're hearing the audio as it's rendered\n </span>\n </div>\n\n {title && (\n <p className=\"mb-3 truncate text-sm font-semibold text-foreground\">{title}</p>\n )}\n\n <div className=\"flex items-center gap-4\">\n <button\n type=\"button\"\n onClick={() => (playing ? player.pause() : player.play())}\n className=\"flex h-12 w-12 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground shadow-lg transition-colors hover:bg-primary/90 active:scale-95\"\n aria-label={playing ? \"Pause\" : \"Play\"}\n >\n {playing ? (\n <PauseIcon className=\"h-5 w-5\" />\n ) : (\n <PlayIcon className=\"ml-0.5 h-5 w-5\" />\n )}\n </button>\n\n <div className=\"min-w-0 flex-1\">\n {/* Progress over the buffered range. The right edge keeps growing as\n chunks land — seeking is allowed anywhere inside it. */}\n <div\n className=\"relative h-2 w-full cursor-pointer overflow-hidden rounded-full bg-muted\"\n onClick={(e) => {\n if (!bufferedMs) return;\n const rect = e.currentTarget.getBoundingClientRect();\n const ratio = (e.clientX - rect.left) / rect.width;\n player.seekMs(ratio * bufferedMs);\n }}\n role=\"progressbar\"\n aria-valuenow={Math.round(progress)}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label=\"Live audio position\"\n >\n <div\n className=\"absolute inset-y-0 left-0 rounded-full bg-primary transition-[width] duration-200\"\n style={{ width: `${progress}%` }}\n />\n {/* Soft pulse at the buffered edge while the stream is open. */}\n {!ended && (\n <div className=\"absolute inset-y-0 right-0 w-4 animate-pulse rounded-r-full bg-primary/20\" />\n )}\n </div>\n <div className=\"mt-1.5 flex justify-between text-xs tabular-nums text-muted-foreground\">\n <span>{formatDurationMs(positionMs, { style: \"clock\" })}</span>\n <span>\n {formatDurationMs(bufferedMs, { style: \"clock\" })}\n {!ended && <span className=\"ml-1 text-muted-foreground/60\">rendered</span>}\n </span>\n </div>\n </div>\n </div>\n </div>\n );\n}\n","/**\n * src/react/cn.ts — conditional class join with last-wins Tailwind conflict\n * merging. The originals used the app's `cn` (clsx + tailwind-merge); public\n * `className` overrides depend on last-wins class-conflict merging, so a\n * naive join would be a behavior divergence (the kit `./confirm` precedent —\n * this is why `tailwind-merge` is a sanctioned runtime dep of `/react`).\n */\n\nimport { twMerge } from \"tailwind-merge\";\n\nexport type ClassValue = string | false | null | undefined | 0;\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(inputs.filter(Boolean).join(\" \"));\n}\n","/**\n * src/react/icons.tsx — the package's OWN inlined SVG icons.\n *\n * Per campaign ruling C19 (2026-08-29): no icon-library dependency, ever.\n * Every glyph below is copied from lucide-react v1.22.0 (ISC license) exactly,\n * following the @ai-matrx/tap-target precedent. Add a new icon by copying the\n * lucide __iconNode data — never by adding a lucide peer.\n *\n * Internal module: icons are exported for the package's own components and for\n * hosts that want visual parity in slots, but they are not the product.\n */\n\nimport type { SVGProps } from \"react\";\n\nexport type MediaIconProps = SVGProps<SVGSVGElement>;\n\nfunction svgProps(props: MediaIconProps): MediaIconProps {\n return {\n xmlns: \"http://www.w3.org/2000/svg\",\n viewBox: \"0 0 24 24\",\n width: 24,\n height: 24,\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 2,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n \"aria-hidden\": true,\n ...props,\n };\n}\n\n// lucide: archive\nexport function ArchiveIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <rect width=\"20\" height=\"5\" x=\"2\" y=\"3\" rx=\"1\" />\n <path d=\"M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8\" />\n <path d=\"M10 12h4\" />\n </svg>\n );\n}\n\n// lucide: braces\nexport function BracesIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5c0 1.1.9 2 2 2h1\" />\n <path d=\"M16 21h1a2 2 0 0 0 2-2v-5c0-1.1.9-2 2-2a2 2 0 0 1-2-2V5a2 2 0 0 0-2-2h-1\" />\n </svg>\n );\n}\n\n// lucide: check\nexport function CheckIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n );\n}\n\n// lucide: code\nexport function CodeIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"m16 18 6-6-6-6\" />\n <path d=\"m8 6-6 6 6 6\" />\n </svg>\n );\n}\n\n// lucide: copy\nexport function CopyIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\" />\n <path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" />\n </svg>\n );\n}\n\n// lucide: database\nexport function DatabaseIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <ellipse cx=\"12\" cy=\"5\" rx=\"9\" ry=\"3\" />\n <path d=\"M3 5V19A9 3 0 0 0 21 19V5\" />\n <path d=\"M3 12A9 3 0 0 0 21 12\" />\n </svg>\n );\n}\n\n// lucide: download\nexport function DownloadIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M12 15V3\" />\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <path d=\"m7 10 5 5 5-5\" />\n </svg>\n );\n}\n\n// lucide: externalLink\nexport function ExternalLinkIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M15 3h6v6\" />\n <path d=\"M10 14 21 3\" />\n <path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\" />\n </svg>\n );\n}\n\n// lucide: file\nexport function FileIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\" />\n <path d=\"M14 2v5a1 1 0 0 0 1 1h5\" />\n </svg>\n );\n}\n\n// lucide: fileAudio\nexport function FileAudioIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M4 6.835V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.706.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2h-.343\" />\n <path d=\"M14 2v5a1 1 0 0 0 1 1h5\" />\n <path d=\"M2 19a2 2 0 0 1 4 0v1a2 2 0 0 1-4 0v-4a6 6 0 0 1 12 0v4a2 2 0 0 1-4 0v-1a2 2 0 0 1 4 0\" />\n </svg>\n );\n}\n\n// lucide: fileCode\nexport function FileCodeIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\" />\n <path d=\"M14 2v5a1 1 0 0 0 1 1h5\" />\n <path d=\"M10 12.5 8 15l2 2.5\" />\n <path d=\"m14 12.5 2 2.5-2 2.5\" />\n </svg>\n );\n}\n\n// lucide: fileJson\nexport function FileJsonIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\" />\n <path d=\"M14 2v5a1 1 0 0 0 1 1h5\" />\n <path d=\"M10 12a1 1 0 0 0-1 1v1a1 1 0 0 1-1 1 1 1 0 0 1 1 1v1a1 1 0 0 0 1 1\" />\n <path d=\"M14 18a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1 1 1 0 0 1-1-1v-1a1 1 0 0 0-1-1\" />\n </svg>\n );\n}\n\n// lucide: fileSpreadsheet\nexport function FileSpreadsheetIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\" />\n <path d=\"M14 2v5a1 1 0 0 0 1 1h5\" />\n <path d=\"M8 13h2\" />\n <path d=\"M14 13h2\" />\n <path d=\"M8 17h2\" />\n <path d=\"M14 17h2\" />\n </svg>\n );\n}\n\n// lucide: fileText\nexport function FileTextIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\" />\n <path d=\"M14 2v5a1 1 0 0 0 1 1h5\" />\n <path d=\"M10 9H8\" />\n <path d=\"M16 13H8\" />\n <path d=\"M16 17H8\" />\n </svg>\n );\n}\n\n// lucide: fileType\nexport function FileTypeIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\" />\n <path d=\"M14 2v5a1 1 0 0 0 1 1h5\" />\n <path d=\"M11 18h2\" />\n <path d=\"M12 12v6\" />\n <path d=\"M9 13v-.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 .5.5v.5\" />\n </svg>\n );\n}\n\n// lucide: fileVideo\nexport function FileVideoIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\" />\n <path d=\"M14 2v5a1 1 0 0 0 1 1h5\" />\n <path d=\"M15.033 13.44a.647.647 0 0 1 0 1.12l-4.065 2.352a.645.645 0 0 1-.968-.56v-4.704a.645.645 0 0 1 .967-.56z\" />\n </svg>\n );\n}\n\n// lucide: folder\nexport function FolderIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z\" />\n </svg>\n );\n}\n\n// lucide: folderOpen\nexport function FolderOpenIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2\" />\n </svg>\n );\n}\n\n// lucide: image\nexport function ImageIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" ry=\"2\" />\n <circle cx=\"9\" cy=\"9\" r=\"2\" />\n <path d=\"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21\" />\n </svg>\n );\n}\n\n// lucide: imageOff\nexport function ImageOffIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <line x1=\"2\" x2=\"22\" y1=\"2\" y2=\"22\" />\n <path d=\"M10.41 10.41a2 2 0 1 1-2.83-2.83\" />\n <line x1=\"13.5\" x2=\"6\" y1=\"13.5\" y2=\"21\" />\n <line x1=\"18\" x2=\"21\" y1=\"12\" y2=\"15\" />\n <path d=\"M3.59 3.59A1.99 1.99 0 0 0 3 5v14a2 2 0 0 0 2 2h14c.55 0 1.052-.22 1.41-.59\" />\n <path d=\"M21 15V5a2 2 0 0 0-2-2H9\" />\n </svg>\n );\n}\n\n// lucide: music\nexport function MusicIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M9 18V5l12-2v13\" />\n <circle cx=\"6\" cy=\"18\" r=\"3\" />\n <circle cx=\"18\" cy=\"16\" r=\"3\" />\n </svg>\n );\n}\n\n// lucide: packageBox\nexport function PackageBoxIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z\" />\n <path d=\"M12 22V12\" />\n <polyline points=\"3.29 7 12 12 20.71 7\" />\n <path d=\"m7.5 4.27 9 5.15\" />\n </svg>\n );\n}\n\n// lucide: penTool\nexport function PenToolIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M15.707 21.293a1 1 0 0 1-1.414 0l-1.586-1.586a1 1 0 0 1 0-1.414l5.586-5.586a1 1 0 0 1 1.414 0l1.586 1.586a1 1 0 0 1 0 1.414z\" />\n <path d=\"m18 13-1.375-6.874a1 1 0 0 0-.746-.776L3.235 2.028a1 1 0 0 0-1.207 1.207L5.35 15.879a1 1 0 0 0 .776.746L13 18\" />\n <path d=\"m2.3 2.3 7.286 7.286\" />\n <circle cx=\"11\" cy=\"11\" r=\"2\" />\n </svg>\n );\n}\n\n// lucide: share2\nexport function Share2Icon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <circle cx=\"18\" cy=\"5\" r=\"3\" />\n <circle cx=\"6\" cy=\"12\" r=\"3\" />\n <circle cx=\"18\" cy=\"19\" r=\"3\" />\n <line x1=\"8.59\" x2=\"15.42\" y1=\"13.51\" y2=\"17.49\" />\n <line x1=\"15.41\" x2=\"8.59\" y1=\"6.51\" y2=\"10.49\" />\n </svg>\n );\n}\n\n// lucide: subtitles\nexport function SubtitlesIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <rect width=\"18\" height=\"14\" x=\"3\" y=\"5\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 15h4M15 15h2M7 11h2M13 11h4\" />\n </svg>\n );\n}\n\n// lucide: upload\nexport function UploadIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M12 3v12\" />\n <path d=\"m17 8-5-5-5 5\" />\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n </svg>\n );\n}\n\n// lucide: video\nexport function VideoIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"m16 13 5.223 3.482a.5.5 0 0 0 .777-.416V7.87a.5.5 0 0 0-.752-.432L16 10.5\" />\n <rect x=\"2\" y=\"6\" width=\"14\" height=\"12\" rx=\"2\" />\n </svg>\n );\n}\n\n// lucide: videoOff\nexport function VideoOffIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M10.66 6H14a2 2 0 0 1 2 2v2.5l5.248-3.062A.5.5 0 0 1 22 7.87v8.196\" />\n <path d=\"M16 16a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h2\" />\n <path d=\"m2 2 20 20\" />\n </svg>\n );\n}\n\n// lucide: volumeX\nexport function VolumeXIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z\" />\n <line x1=\"22\" x2=\"16\" y1=\"9\" y2=\"15\" />\n <line x1=\"16\" x2=\"22\" y1=\"9\" y2=\"15\" />\n </svg>\n );\n}\n\n// lucide: x\nexport function XIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n );\n}\n\n// lucide: alertCircle\nexport function AlertCircleIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" x2=\"12\" y1=\"8\" y2=\"12\" />\n <line x1=\"12\" x2=\"12.01\" y1=\"16\" y2=\"16\" />\n </svg>\n );\n}\n\n// lucide: checkCircle2\nexport function CheckCircle2Icon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M21.801 10A10 10 0 1 1 17 3.335\" />\n <path d=\"m9 11 3 3L22 4\" />\n </svg>\n );\n}\n\n// lucide: globe\nexport function GlobeIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20\" />\n <path d=\"M2 12h20\" />\n </svg>\n );\n}\n\n// lucide: link-2\nexport function Link2Icon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M9 17H7A5 5 0 0 1 7 7h2\" />\n <path d=\"M15 7h2a5 5 0 1 1 0 10h-2\" />\n <line x1=\"8\" x2=\"16\" y1=\"12\" y2=\"12\" />\n </svg>\n );\n}\n\n// lucide: settings-2\nexport function Settings2Icon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M20 7h-9\" />\n <path d=\"M14 17H5\" />\n <circle cx=\"17\" cy=\"17\" r=\"3\" />\n <circle cx=\"7\" cy=\"7\" r=\"3\" />\n </svg>\n );\n}\n\n// lucide: loader-circle (a.k.a. Loader2)\nexport function SpinnerIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n </svg>\n );\n}\n\n// lucide: plus\nexport function PlusIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M5 12h14\" />\n <path d=\"M12 5v14\" />\n </svg>\n );\n}\n\n// lucide: search\nexport function SearchIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n </svg>\n );\n}\n\n// lucide: pause (lucide-react v1.48.0)\nexport function PauseIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <rect x=\"14\" y=\"3\" width=\"5\" height=\"18\" rx=\"1\" />\n <rect x=\"5\" y=\"3\" width=\"5\" height=\"18\" rx=\"1\" />\n </svg>\n );\n}\n\n// lucide: play (lucide-react v1.48.0)\nexport function PlayIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z\" />\n </svg>\n );\n}\n","/**\n * Many live streams at once — one live-audio controller per key (a workflow\n * run's `(node_id, dispatch_id, item_index)`, a chat request id, …) with a\n * change subscription, so a viewer can render the player for the step it\n * shows. Framework-agnostic; React reads it through `useLiveAudioPlayer`.\n */\n\nimport {\n createLiveAudioController,\n isLiveAudioEvent,\n type LiveAudioController,\n type LiveAudioControllerOptions,\n type LiveAudioEndEvent,\n} from \"./controller\";\nimport type { StreamingAudioPlayer } from \"./pcm-player\";\n\nexport interface LiveAudioRegistryOptions\n extends Omit<LiveAudioControllerOptions, \"onPlayer\" | \"onEnd\" | \"onDrop\"> {\n onEnd?: (key: string, event: LiveAudioEndEvent) => void;\n onDrop?: (key: string, reason: string) => void;\n}\n\nexport interface LiveAudioRegistry {\n /** Feed one `data` payload for `key`. True when it was a live-audio event (consumed). */\n handle(key: string, payload: unknown): boolean;\n /** The live player for `key`, or null. */\n player(key: string): StreamingAudioPlayer | null;\n /** Called whenever any key's player appears or goes away. */\n subscribe(listener: () => void): () => void;\n /** Start `key` over (a fresh stream for that step). */\n reset(key: string): void;\n /** Tear down every player. */\n destroy(): void;\n}\n\nexport function createLiveAudioRegistry(\n options: LiveAudioRegistryOptions = {},\n): LiveAudioRegistry {\n const controllers = new Map<string, LiveAudioController>();\n const players = new Map<string, StreamingAudioPlayer>();\n const listeners = new Set<() => void>();\n\n const notify = (): void => {\n for (const listener of listeners) {\n try {\n listener();\n } catch {\n // a subscriber error never breaks playback\n }\n }\n };\n\n const controllerFor = (key: string): LiveAudioController => {\n let controller = controllers.get(key);\n if (!controller) {\n controller = createLiveAudioController({\n onPlayer: (player) => {\n if (player) players.set(key, player);\n else players.delete(key);\n notify();\n },\n onEnd: (event) => options.onEnd?.(key, event),\n onDrop: (reason) =>\n options.onDrop\n ? options.onDrop(key, reason)\n : console.warn(`[live-audio] ${key}: ${reason}`),\n ...(options.createPcmPlayer ? { createPcmPlayer: options.createPcmPlayer } : {}),\n ...(options.createMp3Player ? { createMp3Player: options.createMp3Player } : {}),\n });\n controllers.set(key, controller);\n }\n return controller;\n };\n\n return {\n handle(key, payload) {\n if (!isLiveAudioEvent(payload)) return false;\n return controllerFor(key).handle(payload);\n },\n player: (key) => players.get(key) ?? null,\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n reset(key) {\n controllers.get(key)?.reset();\n },\n destroy() {\n for (const controller of controllers.values()) controller.destroy();\n controllers.clear();\n const had = players.size > 0;\n players.clear();\n if (had) notify();\n },\n };\n}\n","/**\n * Reassemble a workflow run's live-media `node_stream` frames into the exact\n * `data` payloads `/chat` streams (`audio_stream_chunk`, `audio_stream_end`,\n * `partial_image`, `media_block`).\n *\n * Wire contract (aidream `services/runtime/FEATURE.md` — \"Live media reaches a\n * workflow run as node_stream kind=media frames\", producer `_publish_framed`):\n *\n * {\"event\":\"node_stream\",\"run_id\",\"node_id\",\"dispatch_id\",\"item_index\",\n * \"kind\":\"media\",\"delta\":\"<slice of the payload JSON>\",\"stream_seq\",\"ts\",\n * \"frame_id\":\"media:<hex>\",\"frame_index\":i,\"frame_count\":n,…}\n *\n * Group by `frame_id`, join `delta` in `frame_index` order once all\n * `frame_count` slices are held, `JSON.parse`. Payload order = the\n * `stream_seq` of each set's first frame; an incomplete set is dropped (the\n * channel is ephemeral — a late attach or a lost frame never hands half a\n * payload, or a reordered audio chunk, to a player).\n *\n * `stream_seq` is counted PER EMITTER (one step's `ProgressTrackingEmitter`),\n * and one emitter publishes its sets in order through one wire queue — so\n * ordering and abandonment are judged per source `(node_id, dispatch_id,\n * item_index)`; parallel steps interleave freely.\n */\n\n/** The fields of one `node_stream` frame this assembler reads. */\nexport interface MediaNodeStreamFrame {\n kind?: string | null;\n delta: string;\n node_id?: string | null;\n dispatch_id?: string | null;\n item_index?: number | null;\n stream_seq?: number | null;\n frame_id?: string | null;\n frame_index?: number | null;\n frame_count?: number | null;\n}\n\n/** Which step produced a payload: `(node_id, dispatch_id, item_index)`. */\nexport interface MediaFrameSource {\n nodeId: string | null;\n dispatchId: string | null;\n itemIndex: number | null;\n}\n\nexport interface ReassembledMediaPayload {\n /** The parsed `data` payload — route it by `type` exactly as the chat stream does. */\n payload: Record<string, unknown>;\n source: MediaFrameSource;\n /** `stream_seq` of the set's first frame (the ordering key). */\n streamSeq: number;\n}\n\n/** Stable key for a step's media (one live player per key). */\nexport function mediaFrameSourceKey(source: MediaFrameSource): string {\n return `${source.nodeId ?? \"\"}|${source.dispatchId ?? \"\"}|${source.itemIndex ?? \"\"}`;\n}\n\n/** Frame sets held open at once before the oldest is abandoned. */\nexport const MAX_OPEN_MEDIA_FRAME_SETS = 32;\n\ninterface OpenSet {\n key: string;\n count: number;\n slices: Map<number, string>;\n firstSeq: number;\n source: MediaFrameSource;\n}\n\nexport interface MediaFrameAssemblerOptions {\n /** Payloads in `stream_seq` order. */\n onPayload: (payload: ReassembledMediaPayload) => void;\n /** An incomplete or unparseable set was dropped. Default: `console.warn`. */\n onDrop?: (frameId: string, reason: string) => void;\n}\n\nexport interface MediaFrameAssembler {\n /** Feed one `node_stream` frame. Returns true when it was a media frame (consumed). */\n push(frame: MediaNodeStreamFrame): boolean;\n /** The stream ended: drop every incomplete set, release what is complete. */\n flush(): void;\n readonly openCount: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function createMediaFrameAssembler(\n options: MediaFrameAssemblerOptions,\n): MediaFrameAssembler {\n const open = new Map<string, OpenSet>();\n const ready: ReassembledMediaPayload[] = [];\n let arrival = 0;\n\n const drop = (frameId: string, reason: string): void => {\n open.delete(frameId);\n if (options.onDrop) options.onDrop(frameId, reason);\n else console.warn(`[media-frames] dropped ${frameId}: ${reason}`);\n };\n\n /** Release every ready payload no still-open, earlier-started set of the SAME source must precede. */\n const release = (): void => {\n if (ready.length === 0) return;\n ready.sort((a, b) => a.streamSeq - b.streamSeq);\n const blocking = new Map<string, number>();\n for (const set of open.values()) {\n blocking.set(set.key, Math.min(blocking.get(set.key) ?? Infinity, set.firstSeq));\n }\n for (let i = 0; i < ready.length; ) {\n const item = ready[i]!;\n const key = mediaFrameSourceKey(item.source);\n if (item.streamSeq < (blocking.get(key) ?? Infinity)) {\n ready.splice(i, 1);\n options.onPayload(item);\n } else {\n i += 1;\n }\n }\n };\n\n return {\n push(frame: MediaNodeStreamFrame): boolean {\n if (frame.kind !== \"media\") return false;\n const frameId = frame.frame_id;\n const count = frame.frame_count ?? 1;\n const index = frame.frame_index ?? 0;\n if (\n !frameId ||\n !Number.isInteger(count) ||\n count < 1 ||\n !Number.isInteger(index) ||\n index < 0 ||\n index >= count\n ) {\n if (options.onDrop) options.onDrop(frameId ?? \"?\", \"malformed frame\");\n else console.warn(\"[media-frames] malformed media frame dropped\");\n return true;\n }\n arrival += 1;\n const seq =\n typeof frame.stream_seq === \"number\" && Number.isFinite(frame.stream_seq)\n ? frame.stream_seq\n : arrival;\n\n let set = open.get(frameId);\n if (!set) {\n if (open.size >= MAX_OPEN_MEDIA_FRAME_SETS) {\n const oldest = open.keys().next();\n if (!oldest.done) drop(oldest.value, \"abandoned (too many open sets)\");\n }\n const source: MediaFrameSource = {\n nodeId: frame.node_id ?? null,\n dispatchId: frame.dispatch_id ?? null,\n itemIndex: frame.item_index ?? null,\n };\n set = {\n key: mediaFrameSourceKey(source),\n count,\n slices: new Map(),\n firstSeq: seq,\n source,\n };\n open.set(frameId, set);\n }\n set.slices.set(index, frame.delta);\n if (index === 0) set.firstSeq = Math.min(set.firstSeq, seq);\n if (set.slices.size < set.count) {\n release();\n return true;\n }\n\n open.delete(frameId);\n let body = \"\";\n for (let i = 0; i < set.count; i++) body += set.slices.get(i) ?? \"\";\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n if (options.onDrop) options.onDrop(frameId, \"unparseable payload\");\n else console.warn(`[media-frames] dropped ${frameId}: unparseable payload`);\n release();\n return true;\n }\n if (!isRecord(parsed) || typeof parsed.type !== \"string\") {\n if (options.onDrop) options.onDrop(frameId, \"payload has no type\");\n else console.warn(`[media-frames] dropped ${frameId}: payload has no type`);\n release();\n return true;\n }\n // One emitter publishes its sets contiguously, so an earlier-started set\n // of the SAME source that is still open will never complete — drop it so\n // it cannot hold that source's later payloads hostage.\n for (const [id, other] of [...open.entries()]) {\n if (other.key === set.key && other.firstSeq < set.firstSeq) {\n drop(id, \"incomplete set\");\n }\n }\n ready.push({ payload: parsed, source: set.source, streamSeq: set.firstSeq });\n release();\n return true;\n },\n flush(): void {\n for (const id of [...open.keys()]) drop(id, \"incomplete at stream end\");\n release();\n },\n get openCount() {\n return open.size;\n },\n };\n}\n"],"mappings":"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","names":["end","useCallback","useEffect","useState","jsx","jsxs","useState","useEffect","isRecord"]}
|