realtime-avatar 0.1.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.
Files changed (109) hide show
  1. package/AGENTS.md +132 -0
  2. package/CLAUDE.md +17 -0
  3. package/LICENSE +21 -0
  4. package/README.md +254 -0
  5. package/dist/api-keys.d.ts +26 -0
  6. package/dist/api-keys.d.ts.map +1 -0
  7. package/dist/api-keys.js +88 -0
  8. package/dist/api-keys.js.map +1 -0
  9. package/dist/browser/audio.d.ts +65 -0
  10. package/dist/browser/audio.d.ts.map +1 -0
  11. package/dist/browser/audio.js +154 -0
  12. package/dist/browser/audio.js.map +1 -0
  13. package/dist/browser/boomerang.d.ts +38 -0
  14. package/dist/browser/boomerang.d.ts.map +1 -0
  15. package/dist/browser/boomerang.js +85 -0
  16. package/dist/browser/boomerang.js.map +1 -0
  17. package/dist/browser/index.d.ts +8 -0
  18. package/dist/browser/index.d.ts.map +1 -0
  19. package/dist/browser/index.js +8 -0
  20. package/dist/browser/index.js.map +1 -0
  21. package/dist/browser/media-session.d.ts +43 -0
  22. package/dist/browser/media-session.d.ts.map +1 -0
  23. package/dist/browser/media-session.js +169 -0
  24. package/dist/browser/media-session.js.map +1 -0
  25. package/dist/browser/player.d.ts +162 -0
  26. package/dist/browser/player.d.ts.map +1 -0
  27. package/dist/browser/player.js +514 -0
  28. package/dist/browser/player.js.map +1 -0
  29. package/dist/browser/view.d.ts +47 -0
  30. package/dist/browser/view.d.ts.map +1 -0
  31. package/dist/browser/view.js +7 -0
  32. package/dist/browser/view.js.map +1 -0
  33. package/dist/browser/webrtc.d.ts +21 -0
  34. package/dist/browser/webrtc.d.ts.map +1 -0
  35. package/dist/browser/webrtc.js +149 -0
  36. package/dist/browser/webrtc.js.map +1 -0
  37. package/dist/browser/yuv-canvas.d.ts +13 -0
  38. package/dist/browser/yuv-canvas.d.ts.map +1 -0
  39. package/dist/browser/yuv-canvas.js +95 -0
  40. package/dist/browser/yuv-canvas.js.map +1 -0
  41. package/dist/client.d.ts +195 -0
  42. package/dist/client.d.ts.map +1 -0
  43. package/dist/client.js +440 -0
  44. package/dist/client.js.map +1 -0
  45. package/dist/errors.d.ts +33 -0
  46. package/dist/errors.d.ts.map +1 -0
  47. package/dist/errors.js +73 -0
  48. package/dist/errors.js.map +1 -0
  49. package/dist/generated/openapi.d.ts +1523 -0
  50. package/dist/generated/openapi.d.ts.map +1 -0
  51. package/dist/generated/openapi.js +6 -0
  52. package/dist/generated/openapi.js.map +1 -0
  53. package/dist/index.d.ts +14 -0
  54. package/dist/index.d.ts.map +1 -0
  55. package/dist/index.js +15 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/media.d.ts +40 -0
  58. package/dist/media.d.ts.map +1 -0
  59. package/dist/media.js +4 -0
  60. package/dist/media.js.map +1 -0
  61. package/dist/mux.d.ts +104 -0
  62. package/dist/mux.d.ts.map +1 -0
  63. package/dist/mux.js +290 -0
  64. package/dist/mux.js.map +1 -0
  65. package/dist/platform.d.ts +163 -0
  66. package/dist/platform.d.ts.map +1 -0
  67. package/dist/platform.js +5 -0
  68. package/dist/platform.js.map +1 -0
  69. package/dist/react/index.d.ts +5 -0
  70. package/dist/react/index.d.ts.map +1 -0
  71. package/dist/react/index.js +5 -0
  72. package/dist/react/index.js.map +1 -0
  73. package/dist/react/provider.d.ts +37 -0
  74. package/dist/react/provider.d.ts.map +1 -0
  75. package/dist/react/provider.js +33 -0
  76. package/dist/react/provider.js.map +1 -0
  77. package/dist/react/realtime.d.ts +74 -0
  78. package/dist/react/realtime.d.ts.map +1 -0
  79. package/dist/react/realtime.js +105 -0
  80. package/dist/react/realtime.js.map +1 -0
  81. package/dist/react/session.d.ts +91 -0
  82. package/dist/react/session.d.ts.map +1 -0
  83. package/dist/react/session.js +322 -0
  84. package/dist/react/session.js.map +1 -0
  85. package/dist/react/stage.d.ts +23 -0
  86. package/dist/react/stage.d.ts.map +1 -0
  87. package/dist/react/stage.js +62 -0
  88. package/dist/react/stage.js.map +1 -0
  89. package/dist/schemas.d.ts +59 -0
  90. package/dist/schemas.d.ts.map +1 -0
  91. package/dist/schemas.js +58 -0
  92. package/dist/schemas.js.map +1 -0
  93. package/dist/server.d.ts +2 -0
  94. package/dist/server.d.ts.map +1 -0
  95. package/dist/server.js +8 -0
  96. package/dist/server.js.map +1 -0
  97. package/dist/session-socket.d.ts +96 -0
  98. package/dist/session-socket.d.ts.map +1 -0
  99. package/dist/session-socket.js +299 -0
  100. package/dist/session-socket.js.map +1 -0
  101. package/dist/session.d.ts +107 -0
  102. package/dist/session.d.ts.map +1 -0
  103. package/dist/session.js +192 -0
  104. package/dist/session.js.map +1 -0
  105. package/dist/types.d.ts +24 -0
  106. package/dist/types.d.ts.map +1 -0
  107. package/dist/types.js +2 -0
  108. package/dist/types.js.map +1 -0
  109. package/package.json +94 -0
@@ -0,0 +1,322 @@
1
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
2
+ import { AvatarPlayer } from "../browser/player";
3
+ import { connectAvatarSessionMedia, } from "../browser/media-session";
4
+ const EMPTY_METRICS = {
5
+ frames: 0,
6
+ droppedFrames: 0,
7
+ firstAudioMs: null,
8
+ firstVideoMs: null,
9
+ firstFrameDrawnMs: null,
10
+ audioQueueMs: 0,
11
+ audioUnderrunMs: 0,
12
+ width: null,
13
+ height: null,
14
+ };
15
+ /**
16
+ * Drop-in realtime avatar session for React. Owns prepare lifecycle + audio-
17
+ * clocked playback; bind `canvasRef` to a `<canvas>` and call `send`.
18
+ *
19
+ * const avatar = useAvatarSession({ client, avatarId });
20
+ * return <>
21
+ * <canvas ref={avatar.canvasRef} />
22
+ * <button onClick={() => avatar.send("hi")} disabled={!avatar.ready}>Send</button>
23
+ * </>;
24
+ */
25
+ export function useAvatarSession(options) {
26
+ const { client, autoPrepare = true, transport: transportMode = "auto", media = "auto", whep, waitForMedia, waitForMediaMs, connectTimeoutMs = 5_000, playoutDelayMs, avatarId, sourceKind, portraitUrl, sourceVideoUrl, videoCacheId, voiceId, backgroundId, turnDefaults, } = options;
27
+ const canvasRef = useRef(null);
28
+ const videoElementRef = useRef(null);
29
+ const playerRef = useRef(null);
30
+ const mediaConnectionRef = useRef(null);
31
+ const abortRef = useRef(null);
32
+ const prepareSeqRef = useRef(0);
33
+ const [status, setStatus] = useState("idle");
34
+ const [error, setError] = useState(null);
35
+ const [lastError, setLastError] = useState(null);
36
+ const [text, setText] = useState("");
37
+ const [prepared, setPrepared] = useState(null);
38
+ const [metrics, setMetrics] = useState(EMPTY_METRICS);
39
+ const [lastSummary, setLastSummary] = useState(null);
40
+ const [transport, setTransport] = useState("http");
41
+ const [mediaPlan, setMediaPlan] = useState(null);
42
+ const [mediaState, setMediaState] = useState("disabled");
43
+ const [mediaError, setMediaError] = useState(null);
44
+ const session = useMemo(() => client.session({
45
+ avatarId,
46
+ sourceKind,
47
+ portraitUrl,
48
+ sourceVideoUrl,
49
+ videoCacheId,
50
+ voiceId,
51
+ backgroundId,
52
+ turnDefaults,
53
+ }), [client, avatarId, sourceKind, portraitUrl, sourceVideoUrl, videoCacheId, voiceId, backgroundId, turnDefaults]);
54
+ function getPlayer() {
55
+ playerRef.current ??= new AvatarPlayer(playoutDelayMs ? { playoutDelayMs } : {});
56
+ playerRef.current.attach(canvasRef.current);
57
+ return playerRef.current;
58
+ }
59
+ const attachWhepPlaybackToCurrentVideo = useCallback((playback) => {
60
+ const video = videoElementRef.current;
61
+ if (!video)
62
+ return;
63
+ if (video.srcObject !== playback.stream)
64
+ video.srcObject = playback.stream;
65
+ video.muted = true;
66
+ video.playsInline = true;
67
+ void video.play().catch(() => undefined);
68
+ if (video.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA)
69
+ setMediaState("playing");
70
+ }, []);
71
+ const videoRef = useCallback((node) => {
72
+ const previous = videoElementRef.current;
73
+ const playback = mediaConnectionRef.current?.mediaPlayback;
74
+ if (previous && previous !== node && playback && previous.srcObject === playback.stream) {
75
+ previous.srcObject = null;
76
+ }
77
+ videoElementRef.current = node;
78
+ if (node && playback)
79
+ attachWhepPlaybackToCurrentVideo(playback);
80
+ }, [attachWhepPlaybackToCurrentVideo]);
81
+ const closeMediaConnection = useCallback(async () => {
82
+ const connection = mediaConnectionRef.current;
83
+ mediaConnectionRef.current = null;
84
+ const playback = connection?.mediaPlayback;
85
+ const video = videoElementRef.current;
86
+ if (playback && video?.srcObject === playback.stream)
87
+ video.srcObject = null;
88
+ await connection?.close();
89
+ }, []);
90
+ const prepare = useCallback(async (prepareOptions = {}) => {
91
+ const seq = (prepareSeqRef.current += 1);
92
+ const isCurrent = () => seq === prepareSeqRef.current && !prepareOptions.signal?.aborted;
93
+ setStatus("preparing");
94
+ setError(null);
95
+ setLastError(null);
96
+ setMediaError(null);
97
+ setLastSummary(null);
98
+ setPrepared(null);
99
+ await closeMediaConnection();
100
+ try {
101
+ let preparedResponse;
102
+ if (transportMode === "auto") {
103
+ // Socket first (one GPU container for the whole session); HTTP turns
104
+ // remain the costless fallback when the socket cannot be established.
105
+ try {
106
+ const connection = await withAbortableDeadline((signal) => connectAvatarSessionMedia(session, {
107
+ video: videoElementRef.current,
108
+ media,
109
+ signal,
110
+ whep,
111
+ waitForMedia,
112
+ waitForMediaMs,
113
+ onMediaState: (event) => {
114
+ if (!isCurrent())
115
+ return;
116
+ setMediaState(event.state);
117
+ setMediaError(event.error?.message ?? null);
118
+ },
119
+ }), connectTimeoutMs, prepareOptions.signal);
120
+ if (!isCurrent()) {
121
+ await connection.close();
122
+ return;
123
+ }
124
+ mediaConnectionRef.current = connection;
125
+ preparedResponse = connection.prepared;
126
+ setMediaPlan(connection.media);
127
+ void connection.mediaReady
128
+ .then((playback) => {
129
+ if (isCurrent() && mediaConnectionRef.current === connection && playback) {
130
+ attachWhepPlaybackToCurrentVideo(playback);
131
+ }
132
+ })
133
+ .catch(() => undefined);
134
+ }
135
+ catch {
136
+ if (!isCurrent())
137
+ return;
138
+ session.disconnect();
139
+ preparedResponse = await session.prepare({ signal: prepareOptions.signal });
140
+ setMediaPlan(null);
141
+ setMediaState("disabled");
142
+ }
143
+ }
144
+ else {
145
+ preparedResponse = await session.prepare({ signal: prepareOptions.signal });
146
+ setMediaPlan(null);
147
+ setMediaState("disabled");
148
+ }
149
+ if (!isCurrent())
150
+ return;
151
+ setPrepared(preparedResponse);
152
+ setTransport(session.transport);
153
+ setStatus("ready");
154
+ }
155
+ catch (err) {
156
+ if (!isCurrent())
157
+ return;
158
+ setStatus("error");
159
+ setLastError(err);
160
+ setError(err instanceof Error ? err.message : "Avatar prepare failed");
161
+ }
162
+ }, [attachWhepPlaybackToCurrentVideo, closeMediaConnection, connectTimeoutMs, media, session, transportMode, waitForMedia, waitForMediaMs, whep]);
163
+ useEffect(() => {
164
+ if (!autoPrepare)
165
+ return;
166
+ void prepare();
167
+ return () => {
168
+ prepareSeqRef.current += 1;
169
+ void closeMediaConnection();
170
+ session.disconnect();
171
+ };
172
+ }, [autoPrepare, closeMediaConnection, prepare, session]);
173
+ useEffect(() => {
174
+ return () => {
175
+ prepareSeqRef.current += 1;
176
+ abortRef.current?.abort();
177
+ playerRef.current?.stop();
178
+ void closeMediaConnection();
179
+ };
180
+ }, [closeMediaConnection]);
181
+ const runTurn = useCallback(async (stream, signal) => {
182
+ setText("");
183
+ setMetrics(EMPTY_METRICS);
184
+ setLastSummary(null);
185
+ setStatus("thinking");
186
+ setError(null);
187
+ setLastError(null);
188
+ try {
189
+ const player = getPlayer();
190
+ const summary = await player.play(await stream, {
191
+ signal,
192
+ onText: (_delta, full) => setText(full),
193
+ onState: (state) => {
194
+ if (state === "speaking")
195
+ setStatus("speaking");
196
+ },
197
+ onMetrics: setMetrics,
198
+ });
199
+ if (!signal.aborted) {
200
+ setLastSummary(summary);
201
+ setMetrics(summary.metrics);
202
+ setStatus("ready");
203
+ return summary;
204
+ }
205
+ return null;
206
+ }
207
+ catch (err) {
208
+ if (signal.aborted)
209
+ return null;
210
+ setStatus("error");
211
+ setLastError(err);
212
+ setError(err instanceof Error ? err.message : "Realtime stream failed");
213
+ throw err;
214
+ }
215
+ finally {
216
+ setTransport(session.transport);
217
+ }
218
+ }, [session]);
219
+ const startTurn = useCallback((make) => {
220
+ abortRef.current?.abort();
221
+ const controller = new AbortController();
222
+ abortRef.current = controller;
223
+ return runTurn(make({ signal: controller.signal }), controller.signal);
224
+ }, [runTurn]);
225
+ const send = useCallback((message, turnOptions = {}) => startTurn((opts) => session.chat(message, {
226
+ ...opts,
227
+ history: turnOptions.history,
228
+ turn: turnOptions.turn,
229
+ })), [session, startTurn]);
230
+ const speak = useCallback((message, turnOptions = {}) => startTurn((opts) => session.speak(message, { ...opts, turn: turnOptions.turn })), [session, startTurn]);
231
+ const unlockAudio = useCallback(() => getPlayer().unlock(), []);
232
+ const captureAudioStream = useCallback(() => getPlayer().captureAudioStream(), []);
233
+ const stop = useCallback(() => {
234
+ abortRef.current?.abort();
235
+ abortRef.current = null;
236
+ // On the socket path this also tells the GPU to stop rendering frames
237
+ // nobody will play, while keeping the socket warm for the next turn.
238
+ void session.cancel();
239
+ playerRef.current?.stop();
240
+ setStatus((current) => (current === "thinking" || current === "speaking" ? "ready" : current));
241
+ }, [session]);
242
+ const disconnect = useCallback(() => {
243
+ prepareSeqRef.current += 1;
244
+ abortRef.current?.abort();
245
+ abortRef.current = null;
246
+ playerRef.current?.stop();
247
+ void closeMediaConnection();
248
+ session.disconnect();
249
+ setTransport("http");
250
+ setMediaState("disabled");
251
+ setPrepared(null);
252
+ setLastError(null);
253
+ setStatus("idle");
254
+ }, [closeMediaConnection, session]);
255
+ // A media provider may prewarm with black/silent frames so WHEP can finish
256
+ // SDP+ICE before the first turn. Do not let that idle media hide the poster:
257
+ // only consider WebRTC visually live once the mux/canvas path has drawn a
258
+ // real turn frame.
259
+ const webrtcLive = mediaState === "playing" && metrics.firstFrameDrawnMs !== null;
260
+ const canvasLive = metrics.firstFrameDrawnMs !== null && !webrtcLive;
261
+ return {
262
+ canvasRef,
263
+ videoRef,
264
+ videoElementRef,
265
+ status,
266
+ ready: status === "ready",
267
+ busy: status === "thinking" || status === "speaking",
268
+ error,
269
+ lastError,
270
+ text,
271
+ prepared,
272
+ metrics,
273
+ transport,
274
+ mediaPlan,
275
+ mediaState,
276
+ mediaError,
277
+ canvasLive,
278
+ webrtcLive,
279
+ lastSummary,
280
+ unlockAudio,
281
+ captureAudioStream,
282
+ send,
283
+ speak,
284
+ prepare,
285
+ stop,
286
+ disconnect,
287
+ };
288
+ }
289
+ function withAbortableDeadline(start, timeoutMs, parent) {
290
+ if (!timeoutMs || timeoutMs <= 0)
291
+ return start(parent ?? new AbortController().signal);
292
+ const controller = new AbortController();
293
+ const cleanupParent = linkAbort(parent, controller);
294
+ const work = start(controller.signal);
295
+ return new Promise((resolve, reject) => {
296
+ const timer = setTimeout(() => {
297
+ controller.abort();
298
+ cleanupParent();
299
+ reject(new Error("Realtime avatar session timed out"));
300
+ }, timeoutMs);
301
+ void work.then((value) => {
302
+ clearTimeout(timer);
303
+ cleanupParent();
304
+ resolve(value);
305
+ }, (error) => {
306
+ clearTimeout(timer);
307
+ cleanupParent();
308
+ reject(error);
309
+ });
310
+ });
311
+ }
312
+ function linkAbort(parent, child) {
313
+ if (!parent)
314
+ return () => undefined;
315
+ const abort = () => child.abort();
316
+ if (parent.aborted)
317
+ abort();
318
+ else
319
+ parent.addEventListener("abort", abort, { once: true });
320
+ return () => parent.removeEventListener("abort", abort);
321
+ }
322
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/react/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { CSSProperties, ReactElement, ReactNode } from "react";
2
+ import type { UseAvatarSessionResult } from "./session";
3
+ export type AvatarStageProps = {
4
+ session: UseAvatarSessionResult;
5
+ /** Idle loop shown until the first rendered frame (e.g. the FLF video). */
6
+ idleVideoUrl?: string | null;
7
+ /** Static poster shown when there is no idle video. */
8
+ portraitUrl?: string | null;
9
+ /** CSS object-fit for every visual layer. Default `cover`. */
10
+ fit?: CSSProperties["objectFit"];
11
+ objectPosition?: CSSProperties["objectPosition"];
12
+ className?: string;
13
+ style?: CSSProperties;
14
+ canvasStyle?: CSSProperties;
15
+ videoStyle?: CSSProperties;
16
+ posterStyle?: CSSProperties;
17
+ /** Quick transport/status chip while integrating; leave off in production UI. */
18
+ showDebugBadge?: boolean;
19
+ children?: ReactNode;
20
+ };
21
+ /** Minimal layered stage: idle video / portrait poster with live canvas + optional WHEP on top. */
22
+ export declare function AvatarStage(props: AvatarStageProps): ReactElement;
23
+ //# sourceMappingURL=stage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stage.d.ts","sourceRoot":"","sources":["../../src/react/stage.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACpE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAExD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,sBAAsB,CAAC;IAChC,2EAA2E;IAC3E,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,8DAA8D;IAC9D,GAAG,CAAC,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IACjC,cAAc,CAAC,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,WAAW,CAAC,EAAE,aAAa,CAAC;IAC5B,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,WAAW,CAAC,EAAE,aAAa,CAAC;IAC5B,iFAAiF;IACjF,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB,CAAC;AAEF,mGAAmG;AACnG,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,YAAY,CAiFjE"}
@@ -0,0 +1,62 @@
1
+ import { createElement } from "react";
2
+ /** Minimal layered stage: idle video / portrait poster with live canvas + optional WHEP on top. */
3
+ export function AvatarStage(props) {
4
+ const { session, idleVideoUrl, portraitUrl, fit = "cover", objectPosition = "center", className, style, canvasStyle, videoStyle, posterStyle, showDebugBadge, children, } = props;
5
+ const live = session.canvasLive || session.webrtcLive;
6
+ const layerStyle = {
7
+ position: "absolute",
8
+ inset: 0,
9
+ width: "100%",
10
+ height: "100%",
11
+ objectFit: fit,
12
+ objectPosition,
13
+ };
14
+ const nodes = [];
15
+ if (idleVideoUrl) {
16
+ nodes.push(createElement("video", {
17
+ key: "idle",
18
+ src: idleVideoUrl,
19
+ autoPlay: true,
20
+ muted: true,
21
+ loop: true,
22
+ playsInline: true,
23
+ style: { ...layerStyle, opacity: live ? 0 : 1, transition: "opacity 200ms", ...videoStyle },
24
+ }));
25
+ }
26
+ else if (portraitUrl) {
27
+ nodes.push(createElement("img", { key: "portrait", src: portraitUrl, alt: "", style: { ...layerStyle, opacity: live ? 0 : 1, ...posterStyle } }));
28
+ }
29
+ nodes.push(createElement("canvas", {
30
+ key: "canvas",
31
+ ref: session.canvasRef,
32
+ style: { ...layerStyle, zIndex: 1, opacity: session.canvasLive ? 1 : 0, ...canvasStyle },
33
+ }));
34
+ nodes.push(createElement("video", {
35
+ key: "webrtc",
36
+ ref: session.videoRef,
37
+ autoPlay: true,
38
+ muted: true,
39
+ playsInline: true,
40
+ style: { ...layerStyle, zIndex: 2, opacity: session.webrtcLive ? 1 : 0, pointerEvents: "none", ...videoStyle },
41
+ }));
42
+ if (showDebugBadge) {
43
+ nodes.push(createElement("div", {
44
+ key: "debug",
45
+ style: {
46
+ position: "absolute",
47
+ right: 8,
48
+ bottom: 8,
49
+ zIndex: 3,
50
+ borderRadius: 999,
51
+ padding: "4px 8px",
52
+ background: "rgba(0,0,0,0.65)",
53
+ color: "white",
54
+ font: "12px/1.2 ui-monospace, SFMono-Regular, Menlo, monospace",
55
+ },
56
+ }, `${session.status} · ${session.transport}${session.mediaState !== "disabled" ? ` · ${session.mediaState}` : ""}`));
57
+ }
58
+ if (children)
59
+ nodes.push(createElement("div", { key: "children", style: { position: "absolute", inset: 0, zIndex: 4 } }, children));
60
+ return createElement("div", { className, style: { position: "relative", overflow: "hidden", ...style } }, nodes);
61
+ }
62
+ //# sourceMappingURL=stage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stage.js","sourceRoot":"","sources":["../../src/react/stage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ import { z } from "zod";
2
+ export declare const videoAvatarCacheManifestSchema: z.ZodObject<{
3
+ cache_id: z.ZodString;
4
+ source_video_url: z.ZodString;
5
+ storage_path: z.ZodString;
6
+ status: z.ZodOptional<z.ZodEnum<{
7
+ queued: "queued";
8
+ failed: "failed";
9
+ ready: "ready";
10
+ registering: "registering";
11
+ stale: "stale";
12
+ }>>;
13
+ n_frames: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
14
+ width: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
15
+ height: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
16
+ duration_seconds: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
17
+ error: z.ZodOptional<z.ZodNullable<z.ZodString>>;
18
+ }, z.core.$loose>;
19
+ export declare const realtimePrepareResponseSchema: z.ZodObject<{
20
+ avatar_id: z.ZodString;
21
+ status: z.ZodOptional<z.ZodLiteral<"ready">>;
22
+ source_kind: z.ZodOptional<z.ZodEnum<{
23
+ portrait: "portrait";
24
+ source_video: "source_video";
25
+ }>>;
26
+ registered: z.ZodOptional<z.ZodBoolean>;
27
+ timings: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
28
+ video_cache: z.ZodOptional<z.ZodNullable<z.ZodObject<{
29
+ cache_id: z.ZodString;
30
+ source_video_url: z.ZodString;
31
+ storage_path: z.ZodString;
32
+ status: z.ZodOptional<z.ZodEnum<{
33
+ queued: "queued";
34
+ failed: "failed";
35
+ ready: "ready";
36
+ registering: "registering";
37
+ stale: "stale";
38
+ }>>;
39
+ n_frames: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
40
+ width: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
41
+ height: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
42
+ duration_seconds: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
43
+ error: z.ZodOptional<z.ZodNullable<z.ZodString>>;
44
+ }, z.core.$loose>>>;
45
+ runtime: z.ZodOptional<z.ZodNullable<z.ZodObject<{
46
+ cold_start: z.ZodOptional<z.ZodBoolean>;
47
+ container_age_seconds: z.ZodOptional<z.ZodNumber>;
48
+ engine_load_seconds: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
49
+ }, z.core.$loose>>>;
50
+ }, z.core.$loose>;
51
+ export declare const artifactStatusSchema: z.ZodObject<{
52
+ artifacts_ready: z.ZodBoolean;
53
+ engines_ready: z.ZodBoolean;
54
+ manifest_exists: z.ZodBoolean;
55
+ manifest_path: z.ZodString;
56
+ storage_root: z.ZodString;
57
+ }, z.core.$loose>;
58
+ export declare const videoCachePlanResponseSchema: z.ZodObject<{}, z.core.$loose>;
59
+ //# sourceMappingURL=schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AASxB,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;iBAY3B,CAAC;AAEjB,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkB1B,CAAC;AAEjB,eAAO,MAAM,oBAAoB;;;;;;iBAQjB,CAAC;AAEjB,eAAO,MAAM,4BAA4B,gCAA6B,CAAC"}
@@ -0,0 +1,58 @@
1
+ // Runtime boundary validators for the JSON responses the client returns.
2
+ //
3
+ // SSOT note: the *types* still come from the generated OpenAPI schema
4
+ // (`./generated/openapi`, derived from the Modal FastAPI/Pydantic app). These
5
+ // Zod schemas only add a runtime check at the network boundary so a
6
+ // contract-breaking response is caught instead of being blindly cast.
7
+ //
8
+ // To avoid re-creating a second source of truth, each schema:
9
+ // - validates only the *load-bearing* fields the client/consumers rely on,
10
+ // - `.passthrough()`es everything else so the full typed object flows through,
11
+ // - is pinned to the generated type via `assertConforms` below, so if the
12
+ // Pydantic contract changes a load-bearing field the TypeScript build breaks.
13
+ import { z } from "zod";
14
+ export const videoAvatarCacheManifestSchema = z
15
+ .object({
16
+ cache_id: z.string(),
17
+ source_video_url: z.string(),
18
+ storage_path: z.string(),
19
+ status: z.enum(["queued", "registering", "ready", "failed", "stale"]).optional(),
20
+ n_frames: z.number().nullable().optional(),
21
+ width: z.number().nullable().optional(),
22
+ height: z.number().nullable().optional(),
23
+ duration_seconds: z.number().nullable().optional(),
24
+ error: z.string().nullable().optional(),
25
+ })
26
+ .passthrough();
27
+ export const realtimePrepareResponseSchema = z
28
+ .object({
29
+ avatar_id: z.string(),
30
+ status: z.literal("ready").optional(),
31
+ source_kind: z.enum(["portrait", "source_video"]).optional(),
32
+ registered: z.boolean().optional(),
33
+ timings: z.record(z.string(), z.number()).optional(),
34
+ video_cache: videoAvatarCacheManifestSchema.nullable().optional(),
35
+ runtime: z
36
+ .object({
37
+ cold_start: z.boolean().optional(),
38
+ container_age_seconds: z.number().optional(),
39
+ engine_load_seconds: z.number().nullable().optional(),
40
+ })
41
+ .passthrough()
42
+ .nullable()
43
+ .optional(),
44
+ })
45
+ .passthrough();
46
+ export const artifactStatusSchema = z
47
+ .object({
48
+ artifacts_ready: z.boolean(),
49
+ engines_ready: z.boolean(),
50
+ manifest_exists: z.boolean(),
51
+ manifest_path: z.string(),
52
+ storage_root: z.string(),
53
+ })
54
+ .passthrough();
55
+ export const videoCachePlanResponseSchema = z.object({}).passthrough();
56
+ const _pins = { manifest: true, prepare: true, artifacts: true, plan: true };
57
+ void _pins;
58
+ //# sourceMappingURL=schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { RealtimeAvatarApiKeyError, assertRealtimeAvatarApiKeyActive, hashRealtimeAvatarApiKey, parseRealtimeAvatarApiKey, redactRealtimeAvatarApiKey, verifyRealtimeAvatarApiKeyHash, type ParsedRealtimeAvatarApiKey, type RealtimeAvatarApiKeyEnvironment, } from "./api-keys";
2
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,yBAAyB,EACzB,gCAAgC,EAChC,wBAAwB,EACxB,yBAAyB,EACzB,0BAA0B,EAC1B,8BAA8B,EAC9B,KAAK,0BAA0B,EAC/B,KAAK,+BAA+B,GACrC,MAAM,YAAY,CAAC"}
package/dist/server.js ADDED
@@ -0,0 +1,8 @@
1
+ // Server-only entry. These helpers hash/verify API keys with a secret pepper
2
+ // and are meant to run on YOUR backend (the platform), never shipped to a
3
+ // browser or handed to API consumers. They are deliberately kept out of the
4
+ // default client entry so the published SDK exposes no key-verification logic.
5
+ //
6
+ // import { hashRealtimeAvatarApiKey } from "realtime-avatar/server";
7
+ export { RealtimeAvatarApiKeyError, assertRealtimeAvatarApiKeyActive, hashRealtimeAvatarApiKey, parseRealtimeAvatarApiKey, redactRealtimeAvatarApiKey, verifyRealtimeAvatarApiKeyHash, } from "./api-keys";
8
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,0EAA0E;AAC1E,4EAA4E;AAC5E,+EAA+E;AAC/E,EAAE;AACF,uEAAuE;AACvE,OAAO,EACL,yBAAyB,EACzB,gCAAgC,EAChC,wBAAwB,EACxB,yBAAyB,EACzB,0BAA0B,EAC1B,8BAA8B,GAG/B,MAAM,YAAY,CAAC"}