@runwayml/avatars-react 0.5.0 → 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/dist/index.cjs CHANGED
@@ -27,44 +27,15 @@ async function consumeSession(options) {
27
27
  }
28
28
  return response.json();
29
29
  }
30
-
31
- // src/utils/suspense-resource.ts
32
- function createSuspenseResource(promise) {
33
- let status = "pending";
34
- let result;
35
- let error;
36
- const suspender = promise.then(
37
- (value) => {
38
- status = "fulfilled";
39
- result = value;
40
- },
41
- (err) => {
42
- status = "rejected";
43
- error = err;
44
- }
45
- );
46
- return {
47
- read() {
48
- switch (status) {
49
- case "pending":
50
- throw suspender;
51
- case "rejected":
52
- throw error;
53
- case "fulfilled":
54
- return result;
55
- }
56
- }
57
- };
30
+ function useLatest(value) {
31
+ const ref = react.useRef(value);
32
+ react.useEffect(() => {
33
+ ref.current = value;
34
+ }, [value]);
35
+ return ref;
58
36
  }
59
37
 
60
38
  // src/hooks/useCredentials.ts
61
- var resourceCache = /* @__PURE__ */ new Map();
62
- function computeKey(options) {
63
- if (options.credentials) return `direct:${options.credentials.sessionId}`;
64
- if (options.sessionId && options.sessionKey)
65
- return `session:${options.sessionId}`;
66
- return `connect:${options.avatarId}:${options.connectUrl ?? "custom"}`;
67
- }
68
39
  async function fetchCredentials(options) {
69
40
  const { avatarId, sessionId, sessionKey, connectUrl, connect, baseUrl } = options;
70
41
  if (sessionId && sessionKey) {
@@ -95,28 +66,105 @@ async function fetchCredentials(options) {
95
66
  );
96
67
  }
97
68
  function useCredentials(options) {
98
- const key = computeKey(options);
69
+ const {
70
+ credentials: directCredentials,
71
+ avatarId,
72
+ sessionId,
73
+ sessionKey,
74
+ connectUrl,
75
+ connect,
76
+ baseUrl,
77
+ onError
78
+ } = options;
79
+ const onErrorRef = useLatest(onError);
80
+ const connectRef = useLatest(connect);
81
+ const fetchedKeyRef = react.useRef(null);
82
+ const [state, setState] = react.useState(() => {
83
+ if (directCredentials) {
84
+ return { status: "ready", credentials: directCredentials, error: null };
85
+ }
86
+ return { status: "loading", credentials: null, error: null };
87
+ });
99
88
  react.useEffect(() => {
89
+ if (directCredentials) {
90
+ setState({
91
+ status: "ready",
92
+ credentials: directCredentials,
93
+ error: null
94
+ });
95
+ return;
96
+ }
97
+ const credentialKey = `${avatarId}:${sessionId}:${sessionKey}:${connectUrl}:${baseUrl}`;
98
+ if (fetchedKeyRef.current === credentialKey) return;
99
+ fetchedKeyRef.current = credentialKey;
100
+ let cancelled = false;
101
+ setState({ status: "loading", credentials: null, error: null });
102
+ async function load() {
103
+ try {
104
+ const fetchOptions = {
105
+ avatarId,
106
+ sessionId,
107
+ sessionKey,
108
+ connectUrl,
109
+ connect: connectRef.current ?? void 0,
110
+ baseUrl
111
+ };
112
+ const credentials = await fetchCredentials(fetchOptions);
113
+ if (!cancelled) {
114
+ setState({ status: "ready", credentials, error: null });
115
+ }
116
+ } catch (err) {
117
+ if (!cancelled) {
118
+ const error = err instanceof Error ? err : new Error(String(err));
119
+ setState({ status: "error", credentials: null, error });
120
+ onErrorRef.current?.(error);
121
+ }
122
+ }
123
+ }
124
+ load();
100
125
  return () => {
101
- resourceCache.delete(key);
126
+ cancelled = true;
102
127
  };
103
- }, [key]);
104
- if (options.credentials) {
105
- return options.credentials;
106
- }
107
- let resource = resourceCache.get(key);
108
- if (!resource) {
109
- resource = createSuspenseResource(fetchCredentials(options));
110
- resourceCache.set(key, resource);
128
+ }, [directCredentials, avatarId, sessionId, sessionKey, connectUrl, baseUrl]);
129
+ return state;
130
+ }
131
+ async function hasMediaDevice(kind, timeoutMs = 1e3) {
132
+ try {
133
+ const timeoutPromise = new Promise(
134
+ (resolve) => setTimeout(() => resolve(false), timeoutMs)
135
+ );
136
+ const checkPromise = navigator.mediaDevices.enumerateDevices().then((devices) => devices.some((device) => device.kind === kind));
137
+ return await Promise.race([checkPromise, timeoutPromise]);
138
+ } catch {
139
+ return false;
111
140
  }
112
- return resource.read();
113
141
  }
114
- function useLatest(value) {
115
- const ref = react.useRef(value);
142
+ function useDeviceAvailability(requestAudio, requestVideo) {
143
+ const [state, setState] = react.useState({
144
+ audio: requestAudio,
145
+ // Optimistically assume devices exist
146
+ video: requestVideo
147
+ });
116
148
  react.useEffect(() => {
117
- ref.current = value;
118
- }, [value]);
119
- return ref;
149
+ let cancelled = false;
150
+ async function checkDevices() {
151
+ const [hasAudio, hasVideo] = await Promise.all([
152
+ requestAudio ? hasMediaDevice("audioinput") : Promise.resolve(false),
153
+ requestVideo ? hasMediaDevice("videoinput") : Promise.resolve(false)
154
+ ]);
155
+ if (!cancelled) {
156
+ setState({
157
+ audio: requestAudio && hasAudio,
158
+ video: requestVideo && hasVideo
159
+ });
160
+ }
161
+ }
162
+ checkDevices();
163
+ return () => {
164
+ cancelled = true;
165
+ };
166
+ }, [requestAudio, requestVideo]);
167
+ return state;
120
168
  }
121
169
  var DEFAULT_ROOM_OPTIONS = {
122
170
  adaptiveStream: false,
@@ -142,13 +190,14 @@ var AvatarSessionContext = react.createContext(
142
190
  function AvatarSession({
143
191
  credentials,
144
192
  children,
145
- audio = true,
146
- video = true,
193
+ audio: requestAudio = true,
194
+ video: requestVideo = true,
147
195
  onEnd,
148
196
  onError,
149
197
  __unstable_roomOptions
150
198
  }) {
151
199
  const errorRef = react.useRef(null);
200
+ const deviceAvailability = useDeviceAvailability(requestAudio, requestVideo);
152
201
  const handleError = (error) => {
153
202
  errorRef.current = error;
154
203
  onError?.(error);
@@ -163,8 +212,8 @@ function AvatarSession({
163
212
  serverUrl: credentials.serverUrl,
164
213
  token: credentials.token,
165
214
  connect: true,
166
- audio,
167
- video,
215
+ audio: deviceAvailability.audio,
216
+ video: deviceAvailability.video,
168
217
  onDisconnected: () => onEnd?.(),
169
218
  onError: handleError,
170
219
  options: roomOptions,
@@ -228,7 +277,10 @@ function useAvatar() {
228
277
  const avatarParticipant = remoteParticipants[0] ?? null;
229
278
  const videoTracks = componentsReact.useTracks(
230
279
  [{ source: livekitClient.Track.Source.Camera, withPlaceholder: true }],
231
- { onlySubscribed: true, updateOnlyOn: [] }
280
+ {
281
+ onlySubscribed: true,
282
+ updateOnlyOn: []
283
+ }
232
284
  ).filter((ref) => !ref.participant.isLocal);
233
285
  const videoTrackRef = videoTracks[0] ?? null;
234
286
  const hasVideo = videoTrackRef !== null && componentsReact.isTrackReference(videoTrackRef);
@@ -286,23 +338,29 @@ function useLocalMedia() {
286
338
  const { localParticipant } = componentsReact.useLocalParticipant();
287
339
  const audioDevices = componentsReact.useMediaDevices({ kind: "audioinput" });
288
340
  const videoDevices = componentsReact.useMediaDevices({ kind: "videoinput" });
289
- const hasMic = audioDevices.length > 0;
290
- const hasCamera = videoDevices.length > 0;
341
+ const hasMic = audioDevices?.length > 0;
342
+ const hasCamera = videoDevices?.length > 0;
291
343
  const isMicEnabled = localParticipant?.isMicrophoneEnabled ?? false;
292
344
  const isCameraEnabled = localParticipant?.isCameraEnabled ?? false;
293
345
  const isScreenShareEnabled = localParticipant?.isScreenShareEnabled ?? false;
294
346
  const isMicEnabledRef = useLatest(isMicEnabled);
295
347
  const isCameraEnabledRef = useLatest(isCameraEnabled);
296
348
  const isScreenShareEnabledRef = useLatest(isScreenShareEnabled);
349
+ const hasMicRef = useLatest(hasMic);
350
+ const hasCameraRef = useLatest(hasCamera);
297
351
  const toggleMic = react.useCallback(() => {
298
- localParticipant?.setMicrophoneEnabled(!isMicEnabledRef.current);
299
- }, [localParticipant, isMicEnabledRef]);
352
+ if (hasMicRef.current || isMicEnabledRef.current) {
353
+ localParticipant?.setMicrophoneEnabled(!isMicEnabledRef.current);
354
+ }
355
+ }, [localParticipant]);
300
356
  const toggleCamera = react.useCallback(() => {
301
- localParticipant?.setCameraEnabled(!isCameraEnabledRef.current);
302
- }, [localParticipant, isCameraEnabledRef]);
357
+ if (hasCameraRef.current || isCameraEnabledRef.current) {
358
+ localParticipant?.setCameraEnabled(!isCameraEnabledRef.current);
359
+ }
360
+ }, [localParticipant]);
303
361
  const toggleScreenShare = react.useCallback(() => {
304
362
  localParticipant?.setScreenShareEnabled(!isScreenShareEnabledRef.current);
305
- }, [localParticipant, isScreenShareEnabledRef]);
363
+ }, [localParticipant]);
306
364
  const tracks = componentsReact.useTracks(
307
365
  [{ source: livekitClient.Track.Source.Camera, withPlaceholder: true }],
308
366
  {
@@ -517,19 +575,38 @@ function AvatarCall({
517
575
  ...props
518
576
  }) {
519
577
  const onErrorRef = useLatest(onError);
520
- const credentials = useCredentials({
578
+ const credentialsState = useCredentials({
521
579
  avatarId,
522
580
  sessionId,
523
581
  sessionKey,
524
582
  credentials: directCredentials,
525
583
  connectUrl,
526
584
  connect,
527
- baseUrl
585
+ baseUrl,
586
+ onError: (err) => onErrorRef.current?.(err)
528
587
  });
529
588
  const handleSessionError = (err) => {
530
589
  onErrorRef.current?.(err);
531
590
  };
532
591
  const backgroundStyle = avatarImageUrl ? { "--avatar-image": `url(${avatarImageUrl})` } : void 0;
592
+ const defaultChildren = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
593
+ /* @__PURE__ */ jsxRuntime.jsx(AvatarVideo, {}),
594
+ /* @__PURE__ */ jsxRuntime.jsx(UserVideo, {}),
595
+ /* @__PURE__ */ jsxRuntime.jsx(ControlBar, {})
596
+ ] });
597
+ if (credentialsState.status !== "ready") {
598
+ const status = credentialsState.status === "error" ? "error" : "connecting";
599
+ return /* @__PURE__ */ jsxRuntime.jsx(
600
+ "div",
601
+ {
602
+ ...props,
603
+ "data-avatar-call": "",
604
+ "data-avatar-id": avatarId,
605
+ style: { ...props.style, ...backgroundStyle },
606
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { "data-avatar-video": "", "data-avatar-status": status })
607
+ }
608
+ );
609
+ }
533
610
  return /* @__PURE__ */ jsxRuntime.jsx(
534
611
  "div",
535
612
  {
@@ -540,15 +617,11 @@ function AvatarCall({
540
617
  children: /* @__PURE__ */ jsxRuntime.jsx(
541
618
  AvatarSession,
542
619
  {
543
- credentials,
620
+ credentials: credentialsState.credentials,
544
621
  onEnd,
545
622
  onError: handleSessionError,
546
623
  __unstable_roomOptions,
547
- children: children ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
548
- /* @__PURE__ */ jsxRuntime.jsx(AvatarVideo, {}),
549
- /* @__PURE__ */ jsxRuntime.jsx(UserVideo, {}),
550
- /* @__PURE__ */ jsxRuntime.jsx(ControlBar, {})
551
- ] })
624
+ children: children ?? defaultChildren
552
625
  }
553
626
  )
554
627
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api/config.ts","../src/api/consume.ts","../src/utils/suspense-resource.ts","../src/hooks/useCredentials.ts","../src/hooks/useLatest.ts","../src/components/AvatarSession.tsx","../src/hooks/useAvatar.ts","../src/hooks/useAvatarSession.ts","../src/hooks/useAvatarStatus.ts","../src/components/AvatarVideo.tsx","../src/hooks/useLocalMedia.ts","../src/components/ControlBar.tsx","../src/components/UserVideo.tsx","../src/components/AvatarCall.tsx","../src/components/ScreenShareVideo.tsx"],"names":["useEffect","useRef","ConnectionState","createContext","jsxs","LiveKitRoom","jsx","RoomAudioRenderer","useRoomContext","useConnectionState","useCallback","useContext","useRemoteParticipants","useTracks","Track","isTrackReference","Fragment","VideoTrack","useLocalParticipant","useMediaDevices","TrackToggle"],"mappings":"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","file":"index.cjs","sourcesContent":["export const DEFAULT_BASE_URL = 'https://api.dev.runwayml.com';\n","import type { ConsumeSessionOptions, ConsumeSessionResponse } from '../types';\nimport { DEFAULT_BASE_URL } from './config';\n\nexport async function consumeSession(\n options: ConsumeSessionOptions,\n): Promise<ConsumeSessionResponse> {\n const { sessionId, sessionKey, baseUrl = DEFAULT_BASE_URL } = options;\n\n const url = `${baseUrl}/v1/realtime_sessions/${sessionId}/consume`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${sessionKey}`,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to consume session: ${response.status} ${errorText}`,\n );\n }\n\n return response.json();\n}\n","export interface SuspenseResource<T> {\n read(): T;\n}\n\nexport function createSuspenseResource<T>(\n promise: Promise<T>,\n): SuspenseResource<T> {\n let status: 'pending' | 'fulfilled' | 'rejected' = 'pending';\n let result: T;\n let error: unknown;\n\n const suspender = promise.then(\n (value) => {\n status = 'fulfilled';\n result = value;\n },\n (err) => {\n status = 'rejected';\n error = err;\n },\n );\n\n return {\n read() {\n switch (status) {\n case 'pending':\n throw suspender;\n case 'rejected':\n throw error;\n case 'fulfilled':\n return result;\n }\n },\n };\n}\n","'use client';\n\nimport { useEffect } from 'react';\nimport { consumeSession } from '../api/consume';\nimport type { SessionCredentials } from '../types';\nimport {\n createSuspenseResource,\n type SuspenseResource,\n} from '../utils/suspense-resource';\n\nexport interface UseCredentialsOptions {\n avatarId: string;\n sessionId?: string;\n sessionKey?: string;\n credentials?: SessionCredentials;\n connectUrl?: string;\n connect?: (avatarId: string) => Promise<SessionCredentials>;\n baseUrl?: string;\n}\n\nconst resourceCache = new Map<string, SuspenseResource<SessionCredentials>>();\n\nfunction computeKey(options: UseCredentialsOptions): string {\n if (options.credentials) return `direct:${options.credentials.sessionId}`;\n if (options.sessionId && options.sessionKey)\n return `session:${options.sessionId}`;\n return `connect:${options.avatarId}:${options.connectUrl ?? 'custom'}`;\n}\n\nasync function fetchCredentials(\n options: UseCredentialsOptions,\n): Promise<SessionCredentials> {\n const { avatarId, sessionId, sessionKey, connectUrl, connect, baseUrl } =\n options;\n\n if (sessionId && sessionKey) {\n const { url, token, roomName } = await consumeSession({\n sessionId,\n sessionKey,\n baseUrl,\n });\n return { sessionId, serverUrl: url, token, roomName };\n }\n\n if (connect) {\n return connect(avatarId);\n }\n\n if (connectUrl) {\n const response = await fetch(connectUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ avatarId }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to connect: ${response.status} ${errorText}`);\n }\n\n return response.json();\n }\n\n throw new Error(\n 'AvatarCall requires one of: credentials, sessionId+sessionKey, connectUrl, or connect',\n );\n}\n\nexport function useCredentials(\n options: UseCredentialsOptions,\n): SessionCredentials {\n const key = computeKey(options);\n\n useEffect(() => {\n return () => {\n resourceCache.delete(key);\n };\n }, [key]);\n\n if (options.credentials) {\n return options.credentials;\n }\n\n let resource = resourceCache.get(key);\n if (!resource) {\n resource = createSuspenseResource(fetchCredentials(options));\n resourceCache.set(key, resource);\n }\n\n return resource.read();\n}\n","'use client';\n\nimport { useEffect, useRef } from 'react';\n\nexport function useLatest<T>(value: T): React.RefObject<T> {\n const ref = useRef(value);\n\n useEffect(() => {\n ref.current = value;\n }, [value]);\n\n return ref;\n}\n","'use client';\n\n/**\n * AvatarSession Component\n *\n * Provides the session context for avatar interactions.\n * Manages the WebRTC connection and exposes a clean API for child components.\n *\n * @example\n * ```tsx\n * <AvatarSession credentials={credentials} onEnd={handleEnd}>\n * <AvatarVideo />\n * <ControlBar />\n * </AvatarSession>\n * ```\n */\n\nimport {\n LiveKitRoom,\n RoomAudioRenderer,\n useConnectionState,\n useRoomContext,\n} from '@livekit/components-react';\nimport type { RoomOptions } from 'livekit-client';\nimport { ConnectionState } from 'livekit-client';\nimport {\n createContext,\n type ReactNode,\n useCallback,\n useContext,\n useRef,\n} from 'react';\nimport type {\n AvatarSessionContextValue,\n AvatarSessionProps,\n SessionState,\n} from '../types';\n\nconst DEFAULT_ROOM_OPTIONS: RoomOptions = {\n adaptiveStream: false,\n dynacast: false,\n};\n\n/**\n * Maps WebRTC connection state to session state\n */\nfunction mapConnectionState(connectionState: ConnectionState): SessionState {\n switch (connectionState) {\n case ConnectionState.Connecting:\n return 'connecting';\n case ConnectionState.Connected:\n return 'active';\n case ConnectionState.Reconnecting:\n return 'connecting';\n case ConnectionState.Disconnected:\n return 'ended';\n default:\n return 'ended';\n }\n}\n\nconst AvatarSessionContext = createContext<AvatarSessionContextValue | null>(\n null,\n);\n\n/**\n * AvatarSession component - the main entry point for avatar sessions\n *\n * Establishes a WebRTC connection and provides session state to children.\n * This is a headless component that renders minimal DOM.\n */\nexport function AvatarSession({\n credentials,\n children,\n audio = true,\n video = true,\n onEnd,\n onError,\n __unstable_roomOptions,\n}: AvatarSessionProps) {\n const errorRef = useRef<Error | null>(null);\n\n const handleError = (error: Error) => {\n errorRef.current = error;\n onError?.(error);\n };\n\n const roomOptions = {\n ...DEFAULT_ROOM_OPTIONS,\n ...__unstable_roomOptions,\n };\n\n return (\n <LiveKitRoom\n serverUrl={credentials.serverUrl}\n token={credentials.token}\n connect={true}\n audio={audio}\n video={video}\n onDisconnected={() => onEnd?.()}\n onError={handleError}\n options={roomOptions}\n connectOptions={{\n autoSubscribe: true,\n }}\n >\n <AvatarSessionContextInner\n sessionId={credentials.sessionId}\n onEnd={onEnd}\n errorRef={errorRef}\n >\n {children}\n </AvatarSessionContextInner>\n <RoomAudioRenderer />\n </LiveKitRoom>\n );\n}\n\n/**\n * Inner context provider that has access to the room context\n */\nfunction AvatarSessionContextInner({\n sessionId,\n onEnd,\n errorRef,\n children,\n}: {\n sessionId: string;\n onEnd?: () => void;\n errorRef: React.RefObject<Error | null>;\n children: ReactNode;\n}) {\n const room = useRoomContext();\n const connectionState = useConnectionState();\n const onEndRef = useRef(onEnd);\n onEndRef.current = onEnd;\n\n const end = useCallback(async () => {\n try {\n // Send END_CALL message to the avatar\n const encoder = new TextEncoder();\n const data = encoder.encode(JSON.stringify({ type: 'END_CALL' }));\n await room.localParticipant.publishData(data, { reliable: true });\n } catch {\n // Ignore errors when sending end message\n }\n\n await room.disconnect();\n onEndRef.current?.();\n }, [room]);\n\n const contextValue: AvatarSessionContextValue = {\n state: mapConnectionState(connectionState),\n sessionId,\n error: errorRef.current,\n end,\n };\n\n return (\n <AvatarSessionContext.Provider value={contextValue}>\n {children}\n </AvatarSessionContext.Provider>\n );\n}\n\n/**\n * Hook to access the avatar session context\n * Must be used within an AvatarSession component\n */\nexport function useAvatarSessionContext(): AvatarSessionContextValue {\n const context = useContext(AvatarSessionContext);\n if (!context) {\n throw new Error(\n 'useAvatarSessionContext must be used within an AvatarSession',\n );\n }\n return context;\n}\n\n/**\n * Hook to optionally access the avatar session context\n * Returns null if not within an AvatarSession\n */\nexport function useMaybeAvatarSessionContext(): AvatarSessionContextValue | null {\n return useContext(AvatarSessionContext);\n}\n","'use client';\n\n/**\n * useAvatar Hook\n *\n * Provides access to the remote avatar participant's video track.\n * Audio is handled automatically by the session.\n *\n * @example\n * ```tsx\n * function AvatarDisplay() {\n * const { videoTrackRef, hasVideo } = useAvatar();\n *\n * if (!hasVideo) {\n * return <Placeholder />;\n * }\n *\n * return <VideoTrack trackRef={videoTrackRef} />;\n * }\n * ```\n */\n\nimport {\n isTrackReference,\n useRemoteParticipants,\n useTracks,\n} from '@livekit/components-react';\nimport { Track } from 'livekit-client';\nimport type { UseAvatarReturn } from '../types';\n\n/**\n * Hook to access the remote avatar participant's video track\n *\n * @returns Avatar participant info and video track reference\n */\nexport function useAvatar(): UseAvatarReturn {\n const remoteParticipants = useRemoteParticipants();\n const avatarParticipant = remoteParticipants[0] ?? null;\n\n // Only subscribe to video - audio is handled automatically by the session\n const videoTracks = useTracks(\n [{ source: Track.Source.Camera, withPlaceholder: true }],\n { onlySubscribed: true, updateOnlyOn: [] },\n ).filter((ref) => !ref.participant.isLocal);\n\n const videoTrackRef = videoTracks[0] ?? null;\n const hasVideo = videoTrackRef !== null && isTrackReference(videoTrackRef);\n\n return {\n participant: avatarParticipant,\n videoTrackRef,\n hasVideo,\n };\n}\n","'use client';\n\n/**\n * useAvatarSession Hook\n *\n * Provides access to the current avatar session state.\n * Returns a discriminated union based on session state for type-safe UI rendering.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const session = useAvatarSession();\n *\n * if (session.state === 'connecting') {\n * return <Loading />;\n * }\n *\n * if (session.state === 'error') {\n * return <Error message={session.error.message} />;\n * }\n *\n * return <ActiveSession onEnd={session.end} />;\n * }\n * ```\n */\n\nimport { useAvatarSessionContext } from '../components/AvatarSession';\nimport type { AvatarSessionContextValue } from '../types';\n\n/**\n * Discriminated union types for type-safe session state handling\n */\nexport type UseAvatarSessionReturn =\n | { state: 'idle'; sessionId: string; error: null; end: () => Promise<void> }\n | { state: 'connecting'; sessionId: string; error: null; end: () => Promise<void> }\n | { state: 'active'; sessionId: string; error: null; end: () => Promise<void> }\n | { state: 'ending'; sessionId: string; error: null; end: () => Promise<void> }\n | { state: 'ended'; sessionId: string; error: null; end: () => Promise<void> }\n | { state: 'error'; sessionId: string; error: Error; end: () => Promise<void> };\n\n/**\n * Hook to access the current avatar session state\n *\n * @returns Session state as a discriminated union\n */\nexport function useAvatarSession(): UseAvatarSessionReturn {\n const context = useAvatarSessionContext();\n return context as UseAvatarSessionReturn;\n}\n\nexport type { AvatarSessionContextValue };\n","'use client';\n\n/**\n * useAvatarStatus Hook\n *\n * Returns a single discriminated union representing the full avatar lifecycle\n * inside an AvatarSession. Combines session connection state and video\n * track availability into one status value.\n *\n * Must be used within <AvatarCall> or <AvatarSession>.\n *\n * @example\n * ```tsx\n * function MyAvatar() {\n * const avatar = useAvatarStatus();\n *\n * switch (avatar.status) {\n * case 'connecting':\n * return <Spinner />;\n * case 'waiting':\n * return <p>Waiting for video...</p>;\n * case 'ready':\n * return <VideoTrack trackRef={avatar.videoTrackRef} />;\n * case 'error':\n * return <p>{avatar.error.message}</p>;\n * case 'ended':\n * return <p>Call ended</p>;\n * }\n * }\n * ```\n */\n\nimport type { TrackReferenceOrPlaceholder } from '@livekit/components-react';\nimport { useAvatar } from './useAvatar';\nimport { useAvatarSession } from './useAvatarSession';\n\nexport type AvatarStatus =\n | { status: 'connecting' }\n | { status: 'waiting' }\n | { status: 'ready'; videoTrackRef: TrackReferenceOrPlaceholder }\n | { status: 'ending' }\n | { status: 'ended' }\n | { status: 'error'; error: Error };\n\nexport function useAvatarStatus(): AvatarStatus {\n const session = useAvatarSession();\n const { videoTrackRef, hasVideo } = useAvatar();\n\n switch (session.state) {\n case 'connecting':\n case 'idle':\n return { status: 'connecting' };\n\n case 'active':\n if (hasVideo && videoTrackRef) {\n return { status: 'ready', videoTrackRef };\n }\n return { status: 'waiting' };\n\n case 'ending':\n return { status: 'ending' };\n\n case 'ended':\n return { status: 'ended' };\n\n case 'error':\n return { status: 'error', error: session.error };\n }\n}\n","'use client';\n\nimport { isTrackReference, VideoTrack } from '@livekit/components-react';\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react';\nimport { type AvatarStatus, useAvatarStatus } from '../hooks/useAvatarStatus';\n\n/** Subset of AvatarStatus relevant to the video display */\nexport type AvatarVideoStatus = Extract<\n AvatarStatus,\n { status: 'connecting' } | { status: 'waiting' } | { status: 'ready' }\n>;\n\nexport interface AvatarVideoProps\n extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {\n children?: (status: AvatarVideoStatus) => ReactNode;\n}\n\nexport function AvatarVideo({ children, ...props }: AvatarVideoProps) {\n const avatar = useAvatarStatus();\n\n const videoStatus: AvatarVideoStatus =\n avatar.status === 'ready'\n ? avatar\n : avatar.status === 'connecting'\n ? { status: 'connecting' }\n : { status: 'waiting' };\n\n if (children) {\n return <>{children(videoStatus)}</>;\n }\n\n return (\n <div\n {...props}\n data-avatar-video=\"\"\n data-avatar-status={videoStatus.status}\n >\n {videoStatus.status === 'ready' &&\n isTrackReference(videoStatus.videoTrackRef) && (\n <VideoTrack trackRef={videoStatus.videoTrackRef} />\n )}\n </div>\n );\n}\n","'use client';\n\nimport {\n useLocalParticipant,\n useMediaDevices,\n useTracks,\n} from '@livekit/components-react';\nimport { Track } from 'livekit-client';\nimport { useCallback } from 'react';\nimport type { UseLocalMediaReturn } from '../types';\nimport { useLatest } from './useLatest';\n\nexport function useLocalMedia(): UseLocalMediaReturn {\n const { localParticipant } = useLocalParticipant();\n\n const audioDevices = useMediaDevices({ kind: 'audioinput' });\n const videoDevices = useMediaDevices({ kind: 'videoinput' });\n\n const hasMic = audioDevices.length > 0;\n const hasCamera = videoDevices.length > 0;\n\n const isMicEnabled = localParticipant?.isMicrophoneEnabled ?? false;\n const isCameraEnabled = localParticipant?.isCameraEnabled ?? false;\n const isScreenShareEnabled = localParticipant?.isScreenShareEnabled ?? false;\n\n const isMicEnabledRef = useLatest(isMicEnabled);\n const isCameraEnabledRef = useLatest(isCameraEnabled);\n const isScreenShareEnabledRef = useLatest(isScreenShareEnabled);\n\n const toggleMic = useCallback(() => {\n localParticipant?.setMicrophoneEnabled(!isMicEnabledRef.current);\n }, [localParticipant, isMicEnabledRef]);\n\n const toggleCamera = useCallback(() => {\n localParticipant?.setCameraEnabled(!isCameraEnabledRef.current);\n }, [localParticipant, isCameraEnabledRef]);\n\n const toggleScreenShare = useCallback(() => {\n localParticipant?.setScreenShareEnabled(!isScreenShareEnabledRef.current);\n }, [localParticipant, isScreenShareEnabledRef]);\n\n const tracks = useTracks(\n [{ source: Track.Source.Camera, withPlaceholder: true }],\n {\n onlySubscribed: false,\n updateOnlyOn: [],\n },\n );\n\n const localIdentity = localParticipant?.identity;\n\n const localVideoTrackRef =\n tracks.find(\n (trackRef) =>\n trackRef.participant.identity === localIdentity &&\n trackRef.source === Track.Source.Camera,\n ) ?? null;\n\n return {\n hasMic,\n hasCamera,\n isMicEnabled,\n isCameraEnabled,\n isScreenShareEnabled,\n toggleMic,\n toggleCamera,\n toggleScreenShare,\n localVideoTrackRef,\n };\n}\n","'use client';\n\nimport { TrackToggle } from '@livekit/components-react';\nimport { Track } from 'livekit-client';\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react';\nimport { useAvatarSession } from '../hooks/useAvatarSession';\nimport { useLocalMedia } from '../hooks/useLocalMedia';\n\nexport interface ControlBarState {\n isMicEnabled: boolean;\n isCameraEnabled: boolean;\n isScreenShareEnabled: boolean;\n toggleMic: () => void;\n toggleCamera: () => void;\n toggleScreenShare: () => void;\n endCall: () => Promise<void>;\n isActive: boolean;\n}\n\nexport interface ControlBarProps\n extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {\n showMicrophone?: boolean;\n showCamera?: boolean;\n showScreenShare?: boolean;\n showEndCall?: boolean;\n children?: (state: ControlBarState) => ReactNode;\n}\n\nexport function ControlBar({\n children,\n showMicrophone = true,\n showCamera = true,\n showScreenShare = false,\n showEndCall = true,\n ...props\n}: ControlBarProps) {\n const session = useAvatarSession();\n const {\n isMicEnabled,\n isCameraEnabled,\n isScreenShareEnabled,\n toggleMic,\n toggleCamera,\n toggleScreenShare,\n } = useLocalMedia();\n\n const isActive = session.state === 'active';\n\n const state: ControlBarState = {\n isMicEnabled,\n isCameraEnabled,\n isScreenShareEnabled,\n toggleMic,\n toggleCamera,\n toggleScreenShare,\n endCall: session.end,\n isActive,\n };\n\n if (children) {\n return <>{children(state)}</>;\n }\n\n if (!isActive) {\n return null;\n }\n\n return (\n <div {...props} data-avatar-control-bar=\"\" data-avatar-active={isActive}>\n {showMicrophone && (\n <button\n type=\"button\"\n onClick={toggleMic}\n data-avatar-control=\"microphone\"\n data-avatar-enabled={isMicEnabled}\n aria-label={isMicEnabled ? 'Mute microphone' : 'Unmute microphone'}\n >\n {microphoneIcon}\n </button>\n )}\n {showCamera && (\n <button\n type=\"button\"\n onClick={toggleCamera}\n data-avatar-control=\"camera\"\n data-avatar-enabled={isCameraEnabled}\n aria-label={isCameraEnabled ? 'Turn off camera' : 'Turn on camera'}\n >\n {cameraIcon}\n </button>\n )}\n {showScreenShare && (\n <TrackToggle\n source={Track.Source.ScreenShare}\n showIcon={false}\n data-avatar-control=\"screen-share\"\n data-avatar-enabled={isScreenShareEnabled}\n aria-label=\"Toggle screen share\"\n >\n {screenShareIcon}\n </TrackToggle>\n )}\n {showEndCall && (\n <button\n type=\"button\"\n onClick={session.end}\n data-avatar-control=\"end-call\"\n data-avatar-enabled={true}\n aria-label=\"End call\"\n >\n {phoneIcon}\n </button>\n )}\n </div>\n );\n}\n\n// Lucide icons (https://lucide.dev) - MIT License\nconst microphoneIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\" />\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" />\n <line x1=\"12\" x2=\"12\" y1=\"19\" y2=\"22\" />\n </svg>\n);\n\nconst cameraIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\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\nconst screenShareIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <rect width=\"20\" height=\"14\" x=\"2\" y=\"3\" rx=\"2\" />\n <line x1=\"8\" x2=\"16\" y1=\"21\" y2=\"21\" />\n <line x1=\"12\" x2=\"12\" y1=\"17\" y2=\"21\" />\n </svg>\n);\n\nconst phoneIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"8 14 24 12\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path d=\"M12.8429 22.5693L11.4018 21.0986C11.2675 20.9626 11.1625 20.7995 11.0935 20.6197C11.0245 20.4399 10.9931 20.2474 11.0013 20.0545C11.0094 19.8616 11.0569 19.6726 11.1408 19.4995C11.2247 19.3265 11.343 19.1732 11.4883 19.0495C13.127 17.7049 15.0519 16.7714 17.1083 16.3239C19.0064 15.892 20.9744 15.892 22.8725 16.3239C24.9374 16.7743 26.8693 17.7147 28.5117 19.0691C28.6565 19.1924 28.7746 19.3451 28.8585 19.5176C28.9423 19.69 28.99 19.8784 28.9986 20.0707C29.0072 20.263 28.9764 20.455 28.9083 20.6345C28.8402 20.814 28.7362 20.9771 28.603 21.1133L27.1619 22.584C26.9311 22.8242 26.6226 22.9706 26.2938 22.9959C25.9651 23.0211 25.6385 22.9235 25.3751 22.7212C24.8531 22.3127 24.2875 21.9657 23.689 21.6869C23.4525 21.5774 23.2517 21.4009 23.1103 21.1785C22.969 20.9561 22.8931 20.697 22.8917 20.4319V19.1867C21.0053 18.6573 19.0139 18.6573 17.1275 19.1867V20.4319C17.1261 20.697 17.0502 20.9561 16.9089 21.1785C16.7676 21.4009 16.5667 21.5774 16.3302 21.6869C15.7317 21.9657 15.1661 22.3127 14.6442 22.7212C14.3779 22.9258 14.0473 23.0233 13.7152 22.9953C13.383 22.9673 13.0726 22.8156 12.8429 22.5693Z\" />\n </svg>\n);\n","'use client';\n\nimport { isTrackReference, VideoTrack } from '@livekit/components-react';\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react';\nimport { useLocalMedia } from '../hooks/useLocalMedia';\nimport type { UseLocalMediaReturn } from '../types';\n\nexport interface UserVideoState {\n hasVideo: boolean;\n isCameraEnabled: boolean;\n trackRef: UseLocalMediaReturn['localVideoTrackRef'];\n}\n\nexport interface UserVideoProps\n extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {\n mirror?: boolean;\n children?: (state: UserVideoState) => ReactNode;\n}\n\nexport function UserVideo({\n children,\n mirror = true,\n ...props\n}: UserVideoProps) {\n const { localVideoTrackRef, isCameraEnabled } = useLocalMedia();\n\n const hasVideo =\n localVideoTrackRef !== null && isTrackReference(localVideoTrackRef);\n\n const state: UserVideoState = {\n hasVideo,\n isCameraEnabled,\n trackRef: localVideoTrackRef,\n };\n\n if (children) {\n return <>{children(state)}</>;\n }\n\n return (\n <div\n {...props}\n data-avatar-user-video=\"\"\n data-avatar-has-video={hasVideo}\n data-avatar-camera-enabled={isCameraEnabled}\n data-avatar-mirror={mirror}\n >\n {hasVideo &&\n localVideoTrackRef &&\n isTrackReference(localVideoTrackRef) && (\n <VideoTrack trackRef={localVideoTrackRef} />\n )}\n </div>\n );\n}\n","'use client';\n\n/**\n * AvatarCall Component\n *\n * High-level component that handles the complete session lifecycle.\n * Suspends during credential fetching (Phase 1) — wrap in <Suspense> to\n * show loading UI while the server creates the session.\n *\n * @example\n * ```tsx\n * <Suspense fallback={<Loading />}>\n * <AvatarCall avatarId=\"game-host\" connectUrl=\"/api/avatar/connect\">\n * <AvatarVideo />\n * <ControlBar />\n * </AvatarCall>\n * </Suspense>\n * ```\n */\n\nimport { useCredentials } from '../hooks/useCredentials';\nimport { useLatest } from '../hooks/useLatest';\nimport type { AvatarCallProps } from '../types';\nimport { AvatarSession } from './AvatarSession';\nimport { AvatarVideo } from './AvatarVideo';\nimport { ControlBar } from './ControlBar';\nimport { UserVideo } from './UserVideo';\n\nexport function AvatarCall({\n avatarId,\n sessionId,\n sessionKey,\n credentials: directCredentials,\n connectUrl,\n connect,\n baseUrl,\n avatarImageUrl,\n onEnd,\n onError,\n children,\n __unstable_roomOptions,\n ...props\n}: AvatarCallProps) {\n const onErrorRef = useLatest(onError);\n\n const credentials = useCredentials({\n avatarId,\n sessionId,\n sessionKey,\n credentials: directCredentials,\n connectUrl,\n connect,\n baseUrl,\n });\n\n const handleSessionError = (err: Error) => {\n onErrorRef.current?.(err);\n };\n\n const backgroundStyle = avatarImageUrl\n ? ({ '--avatar-image': `url(${avatarImageUrl})` } as React.CSSProperties)\n : undefined;\n\n return (\n <div\n {...props}\n data-avatar-call=\"\"\n data-avatar-id={avatarId}\n style={{ ...props.style, ...backgroundStyle }}\n >\n <AvatarSession\n credentials={credentials}\n onEnd={onEnd}\n onError={handleSessionError}\n __unstable_roomOptions={__unstable_roomOptions}\n >\n {children ?? (\n <>\n <AvatarVideo />\n <UserVideo />\n <ControlBar />\n </>\n )}\n </AvatarSession>\n </div>\n );\n}\n","'use client';\n\nimport {\n isTrackReference,\n type TrackReferenceOrPlaceholder,\n useLocalParticipant,\n useTracks,\n VideoTrack,\n} from '@livekit/components-react';\nimport { Track } from 'livekit-client';\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react';\n\nexport interface ScreenShareVideoState {\n isSharing: boolean;\n trackRef: TrackReferenceOrPlaceholder | null;\n}\n\nexport interface ScreenShareVideoProps\n extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {\n children?: (state: ScreenShareVideoState) => ReactNode;\n}\n\nexport function ScreenShareVideo({\n children,\n ...props\n}: ScreenShareVideoProps) {\n const { localParticipant } = useLocalParticipant();\n\n const tracks = useTracks(\n [{ source: Track.Source.ScreenShare, withPlaceholder: false }],\n { onlySubscribed: false },\n );\n\n const localIdentity = localParticipant?.identity;\n\n const screenShareTrackRef =\n tracks.find(\n (trackRef) =>\n trackRef.participant.identity === localIdentity &&\n trackRef.source === Track.Source.ScreenShare,\n ) ?? null;\n\n const isSharing =\n screenShareTrackRef !== null && isTrackReference(screenShareTrackRef);\n\n const state: ScreenShareVideoState = {\n isSharing,\n trackRef: screenShareTrackRef,\n };\n\n if (children) {\n return <>{children(state)}</>;\n }\n\n if (!isSharing) {\n return null;\n }\n\n return (\n <div {...props} data-avatar-screen-share=\"\" data-avatar-sharing={isSharing}>\n {screenShareTrackRef && isTrackReference(screenShareTrackRef) && (\n <VideoTrack trackRef={screenShareTrackRef} />\n )}\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/api/config.ts","../src/api/consume.ts","../src/hooks/useLatest.ts","../src/hooks/useCredentials.ts","../src/components/AvatarSession.tsx","../src/hooks/useAvatar.ts","../src/hooks/useAvatarSession.ts","../src/hooks/useAvatarStatus.ts","../src/components/AvatarVideo.tsx","../src/hooks/useLocalMedia.ts","../src/components/ControlBar.tsx","../src/components/UserVideo.tsx","../src/components/AvatarCall.tsx","../src/components/ScreenShareVideo.tsx"],"names":["useRef","useEffect","useState","ConnectionState","createContext","jsxs","LiveKitRoom","jsx","RoomAudioRenderer","useRoomContext","useConnectionState","useCallback","useContext","useRemoteParticipants","useTracks","Track","isTrackReference","Fragment","VideoTrack","useLocalParticipant","useMediaDevices","TrackToggle"],"mappings":"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","file":"index.cjs","sourcesContent":["export const DEFAULT_BASE_URL = 'https://api.dev.runwayml.com';\n","import type { ConsumeSessionOptions, ConsumeSessionResponse } from '../types';\nimport { DEFAULT_BASE_URL } from './config';\n\nexport async function consumeSession(\n options: ConsumeSessionOptions,\n): Promise<ConsumeSessionResponse> {\n const { sessionId, sessionKey, baseUrl = DEFAULT_BASE_URL } = options;\n\n const url = `${baseUrl}/v1/realtime_sessions/${sessionId}/consume`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${sessionKey}`,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to consume session: ${response.status} ${errorText}`,\n );\n }\n\n return response.json();\n}\n","'use client';\n\nimport { useEffect, useRef } from 'react';\n\nexport function useLatest<T>(value: T): React.RefObject<T> {\n const ref = useRef(value);\n\n useEffect(() => {\n ref.current = value;\n }, [value]);\n\n return ref;\n}\n","'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport { consumeSession } from '../api/consume';\nimport type { SessionCredentials } from '../types';\nimport { useLatest } from './useLatest';\n\nexport interface UseCredentialsOptions {\n avatarId: string;\n sessionId?: string;\n sessionKey?: string;\n credentials?: SessionCredentials;\n connectUrl?: string;\n connect?: (avatarId: string) => Promise<SessionCredentials>;\n baseUrl?: string;\n onError?: (error: Error) => void;\n}\n\nexport type CredentialsState =\n | { status: 'loading'; credentials: null; error: null }\n | { status: 'ready'; credentials: SessionCredentials; error: null }\n | { status: 'error'; credentials: null; error: Error };\n\nasync function fetchCredentials(\n options: UseCredentialsOptions,\n): Promise<SessionCredentials> {\n const { avatarId, sessionId, sessionKey, connectUrl, connect, baseUrl } =\n options;\n\n if (sessionId && sessionKey) {\n const { url, token, roomName } = await consumeSession({\n sessionId,\n sessionKey,\n baseUrl,\n });\n return { sessionId, serverUrl: url, token, roomName };\n }\n\n if (connect) {\n return connect(avatarId);\n }\n\n if (connectUrl) {\n const response = await fetch(connectUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ avatarId }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to connect: ${response.status} ${errorText}`);\n }\n\n return response.json();\n }\n\n throw new Error(\n 'AvatarCall requires one of: credentials, sessionId+sessionKey, connectUrl, or connect',\n );\n}\n\nexport function useCredentials(\n options: UseCredentialsOptions,\n): CredentialsState {\n const {\n credentials: directCredentials,\n avatarId,\n sessionId,\n sessionKey,\n connectUrl,\n connect,\n baseUrl,\n onError,\n } = options;\n\n const onErrorRef = useLatest(onError);\n const connectRef = useLatest(connect);\n\n const fetchedKeyRef = useRef<string | null>(null);\n\n const [state, setState] = useState<CredentialsState>(() => {\n if (directCredentials) {\n return { status: 'ready', credentials: directCredentials, error: null };\n }\n return { status: 'loading', credentials: null, error: null };\n });\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: refs are stable - we read .current at call time\n useEffect(() => {\n if (directCredentials) {\n setState({\n status: 'ready',\n credentials: directCredentials,\n error: null,\n });\n return;\n }\n\n const credentialKey = `${avatarId}:${sessionId}:${sessionKey}:${connectUrl}:${baseUrl}`;\n\n if (fetchedKeyRef.current === credentialKey) return;\n fetchedKeyRef.current = credentialKey;\n\n let cancelled = false;\n setState({ status: 'loading', credentials: null, error: null });\n\n async function load() {\n try {\n const fetchOptions: UseCredentialsOptions = {\n avatarId,\n sessionId,\n sessionKey,\n connectUrl,\n connect: connectRef.current ?? undefined,\n baseUrl,\n };\n const credentials = await fetchCredentials(fetchOptions);\n if (!cancelled) {\n setState({ status: 'ready', credentials, error: null });\n }\n } catch (err) {\n if (!cancelled) {\n const error = err instanceof Error ? err : new Error(String(err));\n setState({ status: 'error', credentials: null, error });\n onErrorRef.current?.(error);\n }\n }\n }\n\n load();\n\n return () => {\n cancelled = true;\n };\n }, [directCredentials, avatarId, sessionId, sessionKey, connectUrl, baseUrl]);\n\n return state;\n}\n","'use client';\n\n/**\n * AvatarSession Component\n *\n * Provides the session context for avatar interactions.\n * Manages the WebRTC connection and exposes a clean API for child components.\n *\n * @example\n * ```tsx\n * <AvatarSession credentials={credentials} onEnd={handleEnd}>\n * <AvatarVideo />\n * <ControlBar />\n * </AvatarSession>\n * ```\n */\n\nimport {\n LiveKitRoom,\n RoomAudioRenderer,\n useConnectionState,\n useRoomContext,\n} from '@livekit/components-react';\nimport type { RoomOptions } from 'livekit-client';\nimport { ConnectionState } from 'livekit-client';\nimport {\n createContext,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport type {\n AvatarSessionContextValue,\n AvatarSessionProps,\n SessionState,\n} from '../types';\n\n/**\n * Check if a media device of the given kind is available\n * Returns within timeout to avoid blocking the connection\n */\nasync function hasMediaDevice(\n kind: 'audioinput' | 'videoinput',\n timeoutMs = 1000,\n): Promise<boolean> {\n try {\n const timeoutPromise = new Promise<boolean>((resolve) =>\n setTimeout(() => resolve(false), timeoutMs),\n );\n const checkPromise = navigator.mediaDevices\n .enumerateDevices()\n .then((devices) => devices.some((device) => device.kind === kind));\n\n return await Promise.race([checkPromise, timeoutPromise]);\n } catch {\n return false;\n }\n}\n\n/**\n * Hook to check device availability before connecting.\n * Completes quickly to avoid blocking the connection.\n */\nfunction useDeviceAvailability(\n requestAudio: boolean,\n requestVideo: boolean,\n): { audio: boolean; video: boolean } {\n const [state, setState] = useState({\n audio: requestAudio, // Optimistically assume devices exist\n video: requestVideo,\n });\n\n useEffect(() => {\n let cancelled = false;\n\n async function checkDevices() {\n const [hasAudio, hasVideo] = await Promise.all([\n requestAudio ? hasMediaDevice('audioinput') : Promise.resolve(false),\n requestVideo ? hasMediaDevice('videoinput') : Promise.resolve(false),\n ]);\n\n if (!cancelled) {\n setState({\n audio: requestAudio && hasAudio,\n video: requestVideo && hasVideo,\n });\n }\n }\n\n checkDevices();\n\n return () => {\n cancelled = true;\n };\n }, [requestAudio, requestVideo]);\n\n return state;\n}\n\nconst DEFAULT_ROOM_OPTIONS: RoomOptions = {\n adaptiveStream: false,\n dynacast: false,\n};\n\n/**\n * Maps WebRTC connection state to session state\n */\nfunction mapConnectionState(connectionState: ConnectionState): SessionState {\n switch (connectionState) {\n case ConnectionState.Connecting:\n return 'connecting';\n case ConnectionState.Connected:\n return 'active';\n case ConnectionState.Reconnecting:\n return 'connecting';\n case ConnectionState.Disconnected:\n return 'ended';\n default:\n return 'ended';\n }\n}\n\nconst AvatarSessionContext = createContext<AvatarSessionContextValue | null>(\n null,\n);\n\n/**\n * AvatarSession component - the main entry point for avatar sessions\n *\n * Establishes a WebRTC connection and provides session state to children.\n * This is a headless component that renders minimal DOM.\n */\nexport function AvatarSession({\n credentials,\n children,\n audio: requestAudio = true,\n video: requestVideo = true,\n onEnd,\n onError,\n __unstable_roomOptions,\n}: AvatarSessionProps) {\n const errorRef = useRef<Error | null>(null);\n\n const deviceAvailability = useDeviceAvailability(requestAudio, requestVideo);\n\n const handleError = (error: Error) => {\n errorRef.current = error;\n onError?.(error);\n };\n\n const roomOptions = {\n ...DEFAULT_ROOM_OPTIONS,\n ...__unstable_roomOptions,\n };\n\n return (\n <LiveKitRoom\n serverUrl={credentials.serverUrl}\n token={credentials.token}\n connect={true}\n audio={deviceAvailability.audio}\n video={deviceAvailability.video}\n onDisconnected={() => onEnd?.()}\n onError={handleError}\n options={roomOptions}\n connectOptions={{\n autoSubscribe: true,\n }}\n >\n <AvatarSessionContextInner\n sessionId={credentials.sessionId}\n onEnd={onEnd}\n errorRef={errorRef}\n >\n {children}\n </AvatarSessionContextInner>\n <RoomAudioRenderer />\n </LiveKitRoom>\n );\n}\n\n/**\n * Inner context provider that has access to the room context\n */\nfunction AvatarSessionContextInner({\n sessionId,\n onEnd,\n errorRef,\n children,\n}: {\n sessionId: string;\n onEnd?: () => void;\n errorRef: React.RefObject<Error | null>;\n children: ReactNode;\n}) {\n const room = useRoomContext();\n const connectionState = useConnectionState();\n const onEndRef = useRef(onEnd);\n onEndRef.current = onEnd;\n\n const end = useCallback(async () => {\n try {\n // Send END_CALL message to the avatar\n const encoder = new TextEncoder();\n const data = encoder.encode(JSON.stringify({ type: 'END_CALL' }));\n await room.localParticipant.publishData(data, { reliable: true });\n } catch {\n // Ignore errors when sending end message\n }\n\n await room.disconnect();\n onEndRef.current?.();\n }, [room]);\n\n const contextValue: AvatarSessionContextValue = {\n state: mapConnectionState(connectionState),\n sessionId,\n error: errorRef.current,\n end,\n };\n\n return (\n <AvatarSessionContext.Provider value={contextValue}>\n {children}\n </AvatarSessionContext.Provider>\n );\n}\n\n/**\n * Hook to access the avatar session context\n * Must be used within an AvatarSession component\n */\nexport function useAvatarSessionContext(): AvatarSessionContextValue {\n const context = useContext(AvatarSessionContext);\n if (!context) {\n throw new Error(\n 'useAvatarSessionContext must be used within an AvatarSession',\n );\n }\n return context;\n}\n\n/**\n * Hook to optionally access the avatar session context\n * Returns null if not within an AvatarSession\n */\nexport function useMaybeAvatarSessionContext(): AvatarSessionContextValue | null {\n return useContext(AvatarSessionContext);\n}\n","'use client';\n\n/**\n * useAvatar Hook\n *\n * Provides access to the remote avatar participant's video track.\n * Audio is handled automatically by the session.\n *\n * Must be used within an AvatarSession or AvatarCall component.\n *\n * @example\n * ```tsx\n * function AvatarDisplay() {\n * const { videoTrackRef, hasVideo } = useAvatar();\n *\n * if (!hasVideo) {\n * return <Placeholder />;\n * }\n *\n * return <VideoTrack trackRef={videoTrackRef} />;\n * }\n * ```\n */\n\nimport {\n isTrackReference,\n useRemoteParticipants,\n useTracks,\n} from '@livekit/components-react';\nimport { Track } from 'livekit-client';\nimport type { UseAvatarReturn } from '../types';\n\n/**\n * Hook to access the remote avatar participant's video track\n *\n * @returns Avatar participant info and video track reference\n */\nexport function useAvatar(): UseAvatarReturn {\n const remoteParticipants = useRemoteParticipants();\n const avatarParticipant = remoteParticipants[0] ?? null;\n\n // Only subscribe to video - audio is handled automatically by the session\n const videoTracks = useTracks(\n [{ source: Track.Source.Camera, withPlaceholder: true }],\n {\n onlySubscribed: true,\n updateOnlyOn: [],\n },\n ).filter((ref) => !ref.participant.isLocal);\n\n const videoTrackRef = videoTracks[0] ?? null;\n const hasVideo = videoTrackRef !== null && isTrackReference(videoTrackRef);\n\n return {\n participant: avatarParticipant,\n videoTrackRef,\n hasVideo,\n };\n}\n","'use client';\n\n/**\n * useAvatarSession Hook\n *\n * Provides access to the current avatar session state.\n * Returns a discriminated union based on session state for type-safe UI rendering.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const session = useAvatarSession();\n *\n * if (session.state === 'connecting') {\n * return <Loading />;\n * }\n *\n * if (session.state === 'error') {\n * return <Error message={session.error.message} />;\n * }\n *\n * return <ActiveSession onEnd={session.end} />;\n * }\n * ```\n */\n\nimport { useAvatarSessionContext } from '../components/AvatarSession';\nimport type { AvatarSessionContextValue } from '../types';\n\n/**\n * Discriminated union types for type-safe session state handling\n */\nexport type UseAvatarSessionReturn =\n | { state: 'idle'; sessionId: string; error: null; end: () => Promise<void> }\n | { state: 'connecting'; sessionId: string; error: null; end: () => Promise<void> }\n | { state: 'active'; sessionId: string; error: null; end: () => Promise<void> }\n | { state: 'ending'; sessionId: string; error: null; end: () => Promise<void> }\n | { state: 'ended'; sessionId: string; error: null; end: () => Promise<void> }\n | { state: 'error'; sessionId: string; error: Error; end: () => Promise<void> };\n\n/**\n * Hook to access the current avatar session state\n *\n * @returns Session state as a discriminated union\n */\nexport function useAvatarSession(): UseAvatarSessionReturn {\n const context = useAvatarSessionContext();\n return context as UseAvatarSessionReturn;\n}\n\nexport type { AvatarSessionContextValue };\n","'use client';\n\n/**\n * useAvatarStatus Hook\n *\n * Returns a single discriminated union representing the full avatar lifecycle\n * inside an AvatarSession. Combines session connection state and video\n * track availability into one status value.\n *\n * Must be used within <AvatarCall> or <AvatarSession>.\n *\n * @example\n * ```tsx\n * function MyAvatar() {\n * const avatar = useAvatarStatus();\n *\n * switch (avatar.status) {\n * case 'connecting':\n * return <Spinner />;\n * case 'waiting':\n * return <p>Waiting for video...</p>;\n * case 'ready':\n * return <VideoTrack trackRef={avatar.videoTrackRef} />;\n * case 'error':\n * return <p>{avatar.error.message}</p>;\n * case 'ended':\n * return <p>Call ended</p>;\n * }\n * }\n * ```\n */\n\nimport type { TrackReferenceOrPlaceholder } from '@livekit/components-react';\nimport { useAvatar } from './useAvatar';\nimport { useAvatarSession } from './useAvatarSession';\n\nexport type AvatarStatus =\n | { status: 'connecting' }\n | { status: 'waiting' }\n | { status: 'ready'; videoTrackRef: TrackReferenceOrPlaceholder }\n | { status: 'ending' }\n | { status: 'ended' }\n | { status: 'error'; error: Error };\n\nexport function useAvatarStatus(): AvatarStatus {\n const session = useAvatarSession();\n const { videoTrackRef, hasVideo } = useAvatar();\n\n switch (session.state) {\n case 'connecting':\n case 'idle':\n return { status: 'connecting' };\n\n case 'active':\n if (hasVideo && videoTrackRef) {\n return { status: 'ready', videoTrackRef };\n }\n return { status: 'waiting' };\n\n case 'ending':\n return { status: 'ending' };\n\n case 'ended':\n return { status: 'ended' };\n\n case 'error':\n return { status: 'error', error: session.error };\n }\n}\n","'use client';\n\nimport { isTrackReference, VideoTrack } from '@livekit/components-react';\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react';\nimport { type AvatarStatus, useAvatarStatus } from '../hooks/useAvatarStatus';\n\n/** Subset of AvatarStatus relevant to the video display */\nexport type AvatarVideoStatus = Extract<\n AvatarStatus,\n { status: 'connecting' } | { status: 'waiting' } | { status: 'ready' }\n>;\n\nexport interface AvatarVideoProps\n extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {\n children?: (status: AvatarVideoStatus) => ReactNode;\n}\n\nexport function AvatarVideo({ children, ...props }: AvatarVideoProps) {\n const avatar = useAvatarStatus();\n\n const videoStatus: AvatarVideoStatus =\n avatar.status === 'ready'\n ? avatar\n : avatar.status === 'connecting'\n ? { status: 'connecting' }\n : { status: 'waiting' };\n\n if (children) {\n return <>{children(videoStatus)}</>;\n }\n\n return (\n <div\n {...props}\n data-avatar-video=\"\"\n data-avatar-status={videoStatus.status}\n >\n {videoStatus.status === 'ready' &&\n isTrackReference(videoStatus.videoTrackRef) && (\n <VideoTrack trackRef={videoStatus.videoTrackRef} />\n )}\n </div>\n );\n}\n","'use client';\n\nimport {\n useLocalParticipant,\n useMediaDevices,\n useTracks,\n} from '@livekit/components-react';\nimport { Track } from 'livekit-client';\nimport { useCallback } from 'react';\nimport type { UseLocalMediaReturn } from '../types';\nimport { useLatest } from './useLatest';\n\n/**\n * Hook for local media controls (mic, camera, screen share).\n *\n * Must be used within an AvatarSession or AvatarCall component.\n * For use outside the session context, use AvatarSession directly\n * and manage your own loading states.\n */\nexport function useLocalMedia(): UseLocalMediaReturn {\n const { localParticipant } = useLocalParticipant();\n\n const audioDevices = useMediaDevices({ kind: 'audioinput' });\n const videoDevices = useMediaDevices({ kind: 'videoinput' });\n\n const hasMic = audioDevices?.length > 0;\n const hasCamera = videoDevices?.length > 0;\n\n const isMicEnabled = localParticipant?.isMicrophoneEnabled ?? false;\n const isCameraEnabled = localParticipant?.isCameraEnabled ?? false;\n const isScreenShareEnabled = localParticipant?.isScreenShareEnabled ?? false;\n\n const isMicEnabledRef = useLatest(isMicEnabled);\n const isCameraEnabledRef = useLatest(isCameraEnabled);\n const isScreenShareEnabledRef = useLatest(isScreenShareEnabled);\n\n const hasMicRef = useLatest(hasMic);\n const hasCameraRef = useLatest(hasCamera);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: refs from useLatest are stable\n const toggleMic = useCallback(() => {\n if (hasMicRef.current || isMicEnabledRef.current) {\n localParticipant?.setMicrophoneEnabled(!isMicEnabledRef.current);\n }\n }, [localParticipant]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: refs from useLatest are stable\n const toggleCamera = useCallback(() => {\n if (hasCameraRef.current || isCameraEnabledRef.current) {\n localParticipant?.setCameraEnabled(!isCameraEnabledRef.current);\n }\n }, [localParticipant]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: refs from useLatest are stable\n const toggleScreenShare = useCallback(() => {\n localParticipant?.setScreenShareEnabled(!isScreenShareEnabledRef.current);\n }, [localParticipant]);\n\n const tracks = useTracks(\n [{ source: Track.Source.Camera, withPlaceholder: true }],\n {\n onlySubscribed: false,\n updateOnlyOn: [],\n },\n );\n\n const localIdentity = localParticipant?.identity;\n\n const localVideoTrackRef =\n tracks.find(\n (trackRef) =>\n trackRef.participant.identity === localIdentity &&\n trackRef.source === Track.Source.Camera,\n ) ?? null;\n\n return {\n hasMic,\n hasCamera,\n isMicEnabled,\n isCameraEnabled,\n isScreenShareEnabled,\n toggleMic,\n toggleCamera,\n toggleScreenShare,\n localVideoTrackRef,\n };\n}\n","'use client';\n\nimport { TrackToggle } from '@livekit/components-react';\nimport { Track } from 'livekit-client';\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react';\nimport { useAvatarSession } from '../hooks/useAvatarSession';\nimport { useLocalMedia } from '../hooks/useLocalMedia';\n\nexport interface ControlBarState {\n isMicEnabled: boolean;\n isCameraEnabled: boolean;\n isScreenShareEnabled: boolean;\n toggleMic: () => void;\n toggleCamera: () => void;\n toggleScreenShare: () => void;\n endCall: () => Promise<void>;\n isActive: boolean;\n}\n\nexport interface ControlBarProps\n extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {\n showMicrophone?: boolean;\n showCamera?: boolean;\n showScreenShare?: boolean;\n showEndCall?: boolean;\n children?: (state: ControlBarState) => ReactNode;\n}\n\nexport function ControlBar({\n children,\n showMicrophone = true,\n showCamera = true,\n showScreenShare = false,\n showEndCall = true,\n ...props\n}: ControlBarProps) {\n const session = useAvatarSession();\n const {\n isMicEnabled,\n isCameraEnabled,\n isScreenShareEnabled,\n toggleMic,\n toggleCamera,\n toggleScreenShare,\n } = useLocalMedia();\n\n const isActive = session.state === 'active';\n\n const state: ControlBarState = {\n isMicEnabled,\n isCameraEnabled,\n isScreenShareEnabled,\n toggleMic,\n toggleCamera,\n toggleScreenShare,\n endCall: session.end,\n isActive,\n };\n\n if (children) {\n return <>{children(state)}</>;\n }\n\n if (!isActive) {\n return null;\n }\n\n return (\n <div {...props} data-avatar-control-bar=\"\" data-avatar-active={isActive}>\n {showMicrophone && (\n <button\n type=\"button\"\n onClick={toggleMic}\n data-avatar-control=\"microphone\"\n data-avatar-enabled={isMicEnabled}\n aria-label={isMicEnabled ? 'Mute microphone' : 'Unmute microphone'}\n >\n {microphoneIcon}\n </button>\n )}\n {showCamera && (\n <button\n type=\"button\"\n onClick={toggleCamera}\n data-avatar-control=\"camera\"\n data-avatar-enabled={isCameraEnabled}\n aria-label={isCameraEnabled ? 'Turn off camera' : 'Turn on camera'}\n >\n {cameraIcon}\n </button>\n )}\n {showScreenShare && (\n <TrackToggle\n source={Track.Source.ScreenShare}\n showIcon={false}\n data-avatar-control=\"screen-share\"\n data-avatar-enabled={isScreenShareEnabled}\n aria-label=\"Toggle screen share\"\n >\n {screenShareIcon}\n </TrackToggle>\n )}\n {showEndCall && (\n <button\n type=\"button\"\n onClick={session.end}\n data-avatar-control=\"end-call\"\n data-avatar-enabled={true}\n aria-label=\"End call\"\n >\n {phoneIcon}\n </button>\n )}\n </div>\n );\n}\n\n// Lucide icons (https://lucide.dev) - MIT License\nconst microphoneIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\" />\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" />\n <line x1=\"12\" x2=\"12\" y1=\"19\" y2=\"22\" />\n </svg>\n);\n\nconst cameraIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\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\nconst screenShareIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <rect width=\"20\" height=\"14\" x=\"2\" y=\"3\" rx=\"2\" />\n <line x1=\"8\" x2=\"16\" y1=\"21\" y2=\"21\" />\n <line x1=\"12\" x2=\"12\" y1=\"17\" y2=\"21\" />\n </svg>\n);\n\nconst phoneIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"8 14 24 12\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path d=\"M12.8429 22.5693L11.4018 21.0986C11.2675 20.9626 11.1625 20.7995 11.0935 20.6197C11.0245 20.4399 10.9931 20.2474 11.0013 20.0545C11.0094 19.8616 11.0569 19.6726 11.1408 19.4995C11.2247 19.3265 11.343 19.1732 11.4883 19.0495C13.127 17.7049 15.0519 16.7714 17.1083 16.3239C19.0064 15.892 20.9744 15.892 22.8725 16.3239C24.9374 16.7743 26.8693 17.7147 28.5117 19.0691C28.6565 19.1924 28.7746 19.3451 28.8585 19.5176C28.9423 19.69 28.99 19.8784 28.9986 20.0707C29.0072 20.263 28.9764 20.455 28.9083 20.6345C28.8402 20.814 28.7362 20.9771 28.603 21.1133L27.1619 22.584C26.9311 22.8242 26.6226 22.9706 26.2938 22.9959C25.9651 23.0211 25.6385 22.9235 25.3751 22.7212C24.8531 22.3127 24.2875 21.9657 23.689 21.6869C23.4525 21.5774 23.2517 21.4009 23.1103 21.1785C22.969 20.9561 22.8931 20.697 22.8917 20.4319V19.1867C21.0053 18.6573 19.0139 18.6573 17.1275 19.1867V20.4319C17.1261 20.697 17.0502 20.9561 16.9089 21.1785C16.7676 21.4009 16.5667 21.5774 16.3302 21.6869C15.7317 21.9657 15.1661 22.3127 14.6442 22.7212C14.3779 22.9258 14.0473 23.0233 13.7152 22.9953C13.383 22.9673 13.0726 22.8156 12.8429 22.5693Z\" />\n </svg>\n);\n","'use client';\n\nimport { isTrackReference, VideoTrack } from '@livekit/components-react';\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react';\nimport { useLocalMedia } from '../hooks/useLocalMedia';\nimport type { UseLocalMediaReturn } from '../types';\n\nexport interface UserVideoState {\n hasVideo: boolean;\n isCameraEnabled: boolean;\n trackRef: UseLocalMediaReturn['localVideoTrackRef'];\n}\n\nexport interface UserVideoProps\n extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {\n mirror?: boolean;\n children?: (state: UserVideoState) => ReactNode;\n}\n\nexport function UserVideo({\n children,\n mirror = true,\n ...props\n}: UserVideoProps) {\n const { localVideoTrackRef, isCameraEnabled } = useLocalMedia();\n\n const hasVideo =\n localVideoTrackRef !== null && isTrackReference(localVideoTrackRef);\n\n const state: UserVideoState = {\n hasVideo,\n isCameraEnabled,\n trackRef: localVideoTrackRef,\n };\n\n if (children) {\n return <>{children(state)}</>;\n }\n\n return (\n <div\n {...props}\n data-avatar-user-video=\"\"\n data-avatar-has-video={hasVideo}\n data-avatar-camera-enabled={isCameraEnabled}\n data-avatar-mirror={mirror}\n >\n {hasVideo &&\n localVideoTrackRef &&\n isTrackReference(localVideoTrackRef) && (\n <VideoTrack trackRef={localVideoTrackRef} />\n )}\n </div>\n );\n}\n","'use client';\n\n/**\n * AvatarCall Component\n *\n * High-level component that handles the complete session lifecycle.\n * Manages credential fetching, connection, and video display internally\n * with a seamless loading experience.\n *\n * During credential loading, shows a loading state with the avatar image.\n * Once connected, renders children inside the session context.\n *\n * For more control over the loading UI, use AvatarSession directly.\n *\n * @example\n * ```tsx\n * // Simple usage - handles everything automatically\n * <AvatarCall avatarId=\"game-host\" connectUrl=\"/api/avatar/connect\" />\n *\n * // Custom children - rendered once connected\n * <AvatarCall avatarId=\"game-host\" connectUrl=\"/api/avatar/connect\">\n * <AvatarVideo />\n * <ControlBar />\n * </AvatarCall>\n * ```\n */\n\nimport { useCredentials } from '../hooks/useCredentials';\nimport { useLatest } from '../hooks/useLatest';\nimport type { AvatarCallProps } from '../types';\nimport { AvatarSession } from './AvatarSession';\nimport { AvatarVideo } from './AvatarVideo';\nimport { ControlBar } from './ControlBar';\nimport { UserVideo } from './UserVideo';\n\nexport function AvatarCall({\n avatarId,\n sessionId,\n sessionKey,\n credentials: directCredentials,\n connectUrl,\n connect,\n baseUrl,\n avatarImageUrl,\n onEnd,\n onError,\n children,\n __unstable_roomOptions,\n ...props\n}: AvatarCallProps) {\n const onErrorRef = useLatest(onError);\n\n const credentialsState = useCredentials({\n avatarId,\n sessionId,\n sessionKey,\n credentials: directCredentials,\n connectUrl,\n connect,\n baseUrl,\n onError: (err) => onErrorRef.current?.(err),\n });\n\n const handleSessionError = (err: Error) => {\n onErrorRef.current?.(err);\n };\n\n const backgroundStyle = avatarImageUrl\n ? ({ '--avatar-image': `url(${avatarImageUrl})` } as React.CSSProperties)\n : undefined;\n\n const defaultChildren = (\n <>\n <AvatarVideo />\n <UserVideo />\n <ControlBar />\n </>\n );\n\n // During credential loading/error, show a simple loading state\n // Children are NOT rendered here because they may use hooks that require LiveKitRoom context\n if (credentialsState.status !== 'ready') {\n const status =\n credentialsState.status === 'error' ? 'error' : 'connecting';\n\n return (\n <div\n {...props}\n data-avatar-call=\"\"\n data-avatar-id={avatarId}\n style={{ ...props.style, ...backgroundStyle }}\n >\n <div data-avatar-video=\"\" data-avatar-status={status} />\n </div>\n );\n }\n\n // Once credentials are ready, render children inside the session context\n // This ensures all hooks have access to the LiveKitRoom context\n return (\n <div\n {...props}\n data-avatar-call=\"\"\n data-avatar-id={avatarId}\n style={{ ...props.style, ...backgroundStyle }}\n >\n <AvatarSession\n credentials={credentialsState.credentials}\n onEnd={onEnd}\n onError={handleSessionError}\n __unstable_roomOptions={__unstable_roomOptions}\n >\n {children ?? defaultChildren}\n </AvatarSession>\n </div>\n );\n}\n","'use client';\n\nimport {\n isTrackReference,\n type TrackReferenceOrPlaceholder,\n useLocalParticipant,\n useTracks,\n VideoTrack,\n} from '@livekit/components-react';\nimport { Track } from 'livekit-client';\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react';\n\nexport interface ScreenShareVideoState {\n isSharing: boolean;\n trackRef: TrackReferenceOrPlaceholder | null;\n}\n\nexport interface ScreenShareVideoProps\n extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {\n children?: (state: ScreenShareVideoState) => ReactNode;\n}\n\n/**\n * Component for displaying local screen share video.\n *\n * Must be used within an AvatarSession or AvatarCall component.\n */\nexport function ScreenShareVideo({\n children,\n ...props\n}: ScreenShareVideoProps) {\n const { localParticipant } = useLocalParticipant();\n\n const tracks = useTracks(\n [{ source: Track.Source.ScreenShare, withPlaceholder: false }],\n { onlySubscribed: false },\n );\n\n const localIdentity = localParticipant?.identity;\n\n const screenShareTrackRef =\n tracks.find(\n (trackRef) =>\n trackRef.participant.identity === localIdentity &&\n trackRef.source === Track.Source.ScreenShare,\n ) ?? null;\n\n const isSharing =\n screenShareTrackRef !== null && isTrackReference(screenShareTrackRef);\n\n const state: ScreenShareVideoState = {\n isSharing,\n trackRef: screenShareTrackRef,\n };\n\n if (children) {\n return <>{children(state)}</>;\n }\n\n if (!isSharing) {\n return null;\n }\n\n return (\n <div {...props} data-avatar-screen-share=\"\" data-avatar-sharing={isSharing}>\n {screenShareTrackRef && isTrackReference(screenShareTrackRef) && (\n <VideoTrack trackRef={screenShareTrackRef} />\n )}\n </div>\n );\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -124,7 +124,7 @@ declare function AvatarCall({ avatarId, sessionId, sessionKey, credentials: dire
124
124
  * Establishes a WebRTC connection and provides session state to children.
125
125
  * This is a headless component that renders minimal DOM.
126
126
  */
127
- declare function AvatarSession({ credentials, children, audio, video, onEnd, onError, __unstable_roomOptions, }: AvatarSessionProps): react_jsx_runtime.JSX.Element;
127
+ declare function AvatarSession({ credentials, children, audio: requestAudio, video: requestVideo, onEnd, onError, __unstable_roomOptions, }: AvatarSessionProps): react_jsx_runtime.JSX.Element;
128
128
 
129
129
  /**
130
130
  * useAvatarStatus Hook
@@ -212,6 +212,11 @@ interface ScreenShareVideoState {
212
212
  interface ScreenShareVideoProps extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {
213
213
  children?: (state: ScreenShareVideoState) => ReactNode;
214
214
  }
215
+ /**
216
+ * Component for displaying local screen share video.
217
+ *
218
+ * Must be used within an AvatarSession or AvatarCall component.
219
+ */
215
220
  declare function ScreenShareVideo({ children, ...props }: ScreenShareVideoProps): react_jsx_runtime.JSX.Element | null;
216
221
 
217
222
  interface UserVideoState {
@@ -273,6 +278,13 @@ type UseAvatarSessionReturn = {
273
278
  */
274
279
  declare function useAvatarSession(): UseAvatarSessionReturn;
275
280
 
281
+ /**
282
+ * Hook for local media controls (mic, camera, screen share).
283
+ *
284
+ * Must be used within an AvatarSession or AvatarCall component.
285
+ * For use outside the session context, use AvatarSession directly
286
+ * and manage your own loading states.
287
+ */
276
288
  declare function useLocalMedia(): UseLocalMediaReturn;
277
289
 
278
290
  export { AvatarCall, type AvatarCallProps, AvatarSession, type AvatarStatus, AvatarVideo, type AvatarVideoStatus, ControlBar, ScreenShareVideo, type SessionCredentials, type SessionState, UserVideo, useAvatar, useAvatarSession, useAvatarStatus, useLocalMedia };
package/dist/index.d.ts CHANGED
@@ -124,7 +124,7 @@ declare function AvatarCall({ avatarId, sessionId, sessionKey, credentials: dire
124
124
  * Establishes a WebRTC connection and provides session state to children.
125
125
  * This is a headless component that renders minimal DOM.
126
126
  */
127
- declare function AvatarSession({ credentials, children, audio, video, onEnd, onError, __unstable_roomOptions, }: AvatarSessionProps): react_jsx_runtime.JSX.Element;
127
+ declare function AvatarSession({ credentials, children, audio: requestAudio, video: requestVideo, onEnd, onError, __unstable_roomOptions, }: AvatarSessionProps): react_jsx_runtime.JSX.Element;
128
128
 
129
129
  /**
130
130
  * useAvatarStatus Hook
@@ -212,6 +212,11 @@ interface ScreenShareVideoState {
212
212
  interface ScreenShareVideoProps extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {
213
213
  children?: (state: ScreenShareVideoState) => ReactNode;
214
214
  }
215
+ /**
216
+ * Component for displaying local screen share video.
217
+ *
218
+ * Must be used within an AvatarSession or AvatarCall component.
219
+ */
215
220
  declare function ScreenShareVideo({ children, ...props }: ScreenShareVideoProps): react_jsx_runtime.JSX.Element | null;
216
221
 
217
222
  interface UserVideoState {
@@ -273,6 +278,13 @@ type UseAvatarSessionReturn = {
273
278
  */
274
279
  declare function useAvatarSession(): UseAvatarSessionReturn;
275
280
 
281
+ /**
282
+ * Hook for local media controls (mic, camera, screen share).
283
+ *
284
+ * Must be used within an AvatarSession or AvatarCall component.
285
+ * For use outside the session context, use AvatarSession directly
286
+ * and manage your own loading states.
287
+ */
276
288
  declare function useLocalMedia(): UseLocalMediaReturn;
277
289
 
278
290
  export { AvatarCall, type AvatarCallProps, AvatarSession, type AvatarStatus, AvatarVideo, type AvatarVideoStatus, ControlBar, ScreenShareVideo, type SessionCredentials, type SessionState, UserVideo, useAvatar, useAvatarSession, useAvatarStatus, useLocalMedia };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { LiveKitRoom, RoomAudioRenderer, useRoomContext, useConnectionState, useRemoteParticipants, useTracks, isTrackReference, VideoTrack, useLocalParticipant, useMediaDevices, TrackToggle } from '@livekit/components-react';
2
2
  export { RoomAudioRenderer as AudioRenderer, VideoTrack } from '@livekit/components-react';
3
- import { createContext, useRef, useCallback, useContext, useEffect } from 'react';
3
+ import { createContext, useRef, useCallback, useState, useEffect, useContext } from 'react';
4
4
  import { Track, ConnectionState } from 'livekit-client';
5
5
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
6
 
@@ -26,44 +26,15 @@ async function consumeSession(options) {
26
26
  }
27
27
  return response.json();
28
28
  }
29
-
30
- // src/utils/suspense-resource.ts
31
- function createSuspenseResource(promise) {
32
- let status = "pending";
33
- let result;
34
- let error;
35
- const suspender = promise.then(
36
- (value) => {
37
- status = "fulfilled";
38
- result = value;
39
- },
40
- (err) => {
41
- status = "rejected";
42
- error = err;
43
- }
44
- );
45
- return {
46
- read() {
47
- switch (status) {
48
- case "pending":
49
- throw suspender;
50
- case "rejected":
51
- throw error;
52
- case "fulfilled":
53
- return result;
54
- }
55
- }
56
- };
29
+ function useLatest(value) {
30
+ const ref = useRef(value);
31
+ useEffect(() => {
32
+ ref.current = value;
33
+ }, [value]);
34
+ return ref;
57
35
  }
58
36
 
59
37
  // src/hooks/useCredentials.ts
60
- var resourceCache = /* @__PURE__ */ new Map();
61
- function computeKey(options) {
62
- if (options.credentials) return `direct:${options.credentials.sessionId}`;
63
- if (options.sessionId && options.sessionKey)
64
- return `session:${options.sessionId}`;
65
- return `connect:${options.avatarId}:${options.connectUrl ?? "custom"}`;
66
- }
67
38
  async function fetchCredentials(options) {
68
39
  const { avatarId, sessionId, sessionKey, connectUrl, connect, baseUrl } = options;
69
40
  if (sessionId && sessionKey) {
@@ -94,28 +65,105 @@ async function fetchCredentials(options) {
94
65
  );
95
66
  }
96
67
  function useCredentials(options) {
97
- const key = computeKey(options);
68
+ const {
69
+ credentials: directCredentials,
70
+ avatarId,
71
+ sessionId,
72
+ sessionKey,
73
+ connectUrl,
74
+ connect,
75
+ baseUrl,
76
+ onError
77
+ } = options;
78
+ const onErrorRef = useLatest(onError);
79
+ const connectRef = useLatest(connect);
80
+ const fetchedKeyRef = useRef(null);
81
+ const [state, setState] = useState(() => {
82
+ if (directCredentials) {
83
+ return { status: "ready", credentials: directCredentials, error: null };
84
+ }
85
+ return { status: "loading", credentials: null, error: null };
86
+ });
98
87
  useEffect(() => {
88
+ if (directCredentials) {
89
+ setState({
90
+ status: "ready",
91
+ credentials: directCredentials,
92
+ error: null
93
+ });
94
+ return;
95
+ }
96
+ const credentialKey = `${avatarId}:${sessionId}:${sessionKey}:${connectUrl}:${baseUrl}`;
97
+ if (fetchedKeyRef.current === credentialKey) return;
98
+ fetchedKeyRef.current = credentialKey;
99
+ let cancelled = false;
100
+ setState({ status: "loading", credentials: null, error: null });
101
+ async function load() {
102
+ try {
103
+ const fetchOptions = {
104
+ avatarId,
105
+ sessionId,
106
+ sessionKey,
107
+ connectUrl,
108
+ connect: connectRef.current ?? void 0,
109
+ baseUrl
110
+ };
111
+ const credentials = await fetchCredentials(fetchOptions);
112
+ if (!cancelled) {
113
+ setState({ status: "ready", credentials, error: null });
114
+ }
115
+ } catch (err) {
116
+ if (!cancelled) {
117
+ const error = err instanceof Error ? err : new Error(String(err));
118
+ setState({ status: "error", credentials: null, error });
119
+ onErrorRef.current?.(error);
120
+ }
121
+ }
122
+ }
123
+ load();
99
124
  return () => {
100
- resourceCache.delete(key);
125
+ cancelled = true;
101
126
  };
102
- }, [key]);
103
- if (options.credentials) {
104
- return options.credentials;
105
- }
106
- let resource = resourceCache.get(key);
107
- if (!resource) {
108
- resource = createSuspenseResource(fetchCredentials(options));
109
- resourceCache.set(key, resource);
127
+ }, [directCredentials, avatarId, sessionId, sessionKey, connectUrl, baseUrl]);
128
+ return state;
129
+ }
130
+ async function hasMediaDevice(kind, timeoutMs = 1e3) {
131
+ try {
132
+ const timeoutPromise = new Promise(
133
+ (resolve) => setTimeout(() => resolve(false), timeoutMs)
134
+ );
135
+ const checkPromise = navigator.mediaDevices.enumerateDevices().then((devices) => devices.some((device) => device.kind === kind));
136
+ return await Promise.race([checkPromise, timeoutPromise]);
137
+ } catch {
138
+ return false;
110
139
  }
111
- return resource.read();
112
140
  }
113
- function useLatest(value) {
114
- const ref = useRef(value);
141
+ function useDeviceAvailability(requestAudio, requestVideo) {
142
+ const [state, setState] = useState({
143
+ audio: requestAudio,
144
+ // Optimistically assume devices exist
145
+ video: requestVideo
146
+ });
115
147
  useEffect(() => {
116
- ref.current = value;
117
- }, [value]);
118
- return ref;
148
+ let cancelled = false;
149
+ async function checkDevices() {
150
+ const [hasAudio, hasVideo] = await Promise.all([
151
+ requestAudio ? hasMediaDevice("audioinput") : Promise.resolve(false),
152
+ requestVideo ? hasMediaDevice("videoinput") : Promise.resolve(false)
153
+ ]);
154
+ if (!cancelled) {
155
+ setState({
156
+ audio: requestAudio && hasAudio,
157
+ video: requestVideo && hasVideo
158
+ });
159
+ }
160
+ }
161
+ checkDevices();
162
+ return () => {
163
+ cancelled = true;
164
+ };
165
+ }, [requestAudio, requestVideo]);
166
+ return state;
119
167
  }
120
168
  var DEFAULT_ROOM_OPTIONS = {
121
169
  adaptiveStream: false,
@@ -141,13 +189,14 @@ var AvatarSessionContext = createContext(
141
189
  function AvatarSession({
142
190
  credentials,
143
191
  children,
144
- audio = true,
145
- video = true,
192
+ audio: requestAudio = true,
193
+ video: requestVideo = true,
146
194
  onEnd,
147
195
  onError,
148
196
  __unstable_roomOptions
149
197
  }) {
150
198
  const errorRef = useRef(null);
199
+ const deviceAvailability = useDeviceAvailability(requestAudio, requestVideo);
151
200
  const handleError = (error) => {
152
201
  errorRef.current = error;
153
202
  onError?.(error);
@@ -162,8 +211,8 @@ function AvatarSession({
162
211
  serverUrl: credentials.serverUrl,
163
212
  token: credentials.token,
164
213
  connect: true,
165
- audio,
166
- video,
214
+ audio: deviceAvailability.audio,
215
+ video: deviceAvailability.video,
167
216
  onDisconnected: () => onEnd?.(),
168
217
  onError: handleError,
169
218
  options: roomOptions,
@@ -227,7 +276,10 @@ function useAvatar() {
227
276
  const avatarParticipant = remoteParticipants[0] ?? null;
228
277
  const videoTracks = useTracks(
229
278
  [{ source: Track.Source.Camera, withPlaceholder: true }],
230
- { onlySubscribed: true, updateOnlyOn: [] }
279
+ {
280
+ onlySubscribed: true,
281
+ updateOnlyOn: []
282
+ }
231
283
  ).filter((ref) => !ref.participant.isLocal);
232
284
  const videoTrackRef = videoTracks[0] ?? null;
233
285
  const hasVideo = videoTrackRef !== null && isTrackReference(videoTrackRef);
@@ -285,23 +337,29 @@ function useLocalMedia() {
285
337
  const { localParticipant } = useLocalParticipant();
286
338
  const audioDevices = useMediaDevices({ kind: "audioinput" });
287
339
  const videoDevices = useMediaDevices({ kind: "videoinput" });
288
- const hasMic = audioDevices.length > 0;
289
- const hasCamera = videoDevices.length > 0;
340
+ const hasMic = audioDevices?.length > 0;
341
+ const hasCamera = videoDevices?.length > 0;
290
342
  const isMicEnabled = localParticipant?.isMicrophoneEnabled ?? false;
291
343
  const isCameraEnabled = localParticipant?.isCameraEnabled ?? false;
292
344
  const isScreenShareEnabled = localParticipant?.isScreenShareEnabled ?? false;
293
345
  const isMicEnabledRef = useLatest(isMicEnabled);
294
346
  const isCameraEnabledRef = useLatest(isCameraEnabled);
295
347
  const isScreenShareEnabledRef = useLatest(isScreenShareEnabled);
348
+ const hasMicRef = useLatest(hasMic);
349
+ const hasCameraRef = useLatest(hasCamera);
296
350
  const toggleMic = useCallback(() => {
297
- localParticipant?.setMicrophoneEnabled(!isMicEnabledRef.current);
298
- }, [localParticipant, isMicEnabledRef]);
351
+ if (hasMicRef.current || isMicEnabledRef.current) {
352
+ localParticipant?.setMicrophoneEnabled(!isMicEnabledRef.current);
353
+ }
354
+ }, [localParticipant]);
299
355
  const toggleCamera = useCallback(() => {
300
- localParticipant?.setCameraEnabled(!isCameraEnabledRef.current);
301
- }, [localParticipant, isCameraEnabledRef]);
356
+ if (hasCameraRef.current || isCameraEnabledRef.current) {
357
+ localParticipant?.setCameraEnabled(!isCameraEnabledRef.current);
358
+ }
359
+ }, [localParticipant]);
302
360
  const toggleScreenShare = useCallback(() => {
303
361
  localParticipant?.setScreenShareEnabled(!isScreenShareEnabledRef.current);
304
- }, [localParticipant, isScreenShareEnabledRef]);
362
+ }, [localParticipant]);
305
363
  const tracks = useTracks(
306
364
  [{ source: Track.Source.Camera, withPlaceholder: true }],
307
365
  {
@@ -516,19 +574,38 @@ function AvatarCall({
516
574
  ...props
517
575
  }) {
518
576
  const onErrorRef = useLatest(onError);
519
- const credentials = useCredentials({
577
+ const credentialsState = useCredentials({
520
578
  avatarId,
521
579
  sessionId,
522
580
  sessionKey,
523
581
  credentials: directCredentials,
524
582
  connectUrl,
525
583
  connect,
526
- baseUrl
584
+ baseUrl,
585
+ onError: (err) => onErrorRef.current?.(err)
527
586
  });
528
587
  const handleSessionError = (err) => {
529
588
  onErrorRef.current?.(err);
530
589
  };
531
590
  const backgroundStyle = avatarImageUrl ? { "--avatar-image": `url(${avatarImageUrl})` } : void 0;
591
+ const defaultChildren = /* @__PURE__ */ jsxs(Fragment, { children: [
592
+ /* @__PURE__ */ jsx(AvatarVideo, {}),
593
+ /* @__PURE__ */ jsx(UserVideo, {}),
594
+ /* @__PURE__ */ jsx(ControlBar, {})
595
+ ] });
596
+ if (credentialsState.status !== "ready") {
597
+ const status = credentialsState.status === "error" ? "error" : "connecting";
598
+ return /* @__PURE__ */ jsx(
599
+ "div",
600
+ {
601
+ ...props,
602
+ "data-avatar-call": "",
603
+ "data-avatar-id": avatarId,
604
+ style: { ...props.style, ...backgroundStyle },
605
+ children: /* @__PURE__ */ jsx("div", { "data-avatar-video": "", "data-avatar-status": status })
606
+ }
607
+ );
608
+ }
532
609
  return /* @__PURE__ */ jsx(
533
610
  "div",
534
611
  {
@@ -539,15 +616,11 @@ function AvatarCall({
539
616
  children: /* @__PURE__ */ jsx(
540
617
  AvatarSession,
541
618
  {
542
- credentials,
619
+ credentials: credentialsState.credentials,
543
620
  onEnd,
544
621
  onError: handleSessionError,
545
622
  __unstable_roomOptions,
546
- children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
547
- /* @__PURE__ */ jsx(AvatarVideo, {}),
548
- /* @__PURE__ */ jsx(UserVideo, {}),
549
- /* @__PURE__ */ jsx(ControlBar, {})
550
- ] })
623
+ children: children ?? defaultChildren
551
624
  }
552
625
  )
553
626
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api/config.ts","../src/api/consume.ts","../src/utils/suspense-resource.ts","../src/hooks/useCredentials.ts","../src/hooks/useLatest.ts","../src/components/AvatarSession.tsx","../src/hooks/useAvatar.ts","../src/hooks/useAvatarSession.ts","../src/hooks/useAvatarStatus.ts","../src/components/AvatarVideo.tsx","../src/hooks/useLocalMedia.ts","../src/components/ControlBar.tsx","../src/components/UserVideo.tsx","../src/components/AvatarCall.tsx","../src/components/ScreenShareVideo.tsx"],"names":["useEffect","useRef","RoomAudioRenderer","jsx","isTrackReference","useCallback","useTracks","Track","Fragment","jsxs","VideoTrack","useLocalParticipant"],"mappings":"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","file":"index.js","sourcesContent":["export const DEFAULT_BASE_URL = 'https://api.dev.runwayml.com';\n","import type { ConsumeSessionOptions, ConsumeSessionResponse } from '../types';\nimport { DEFAULT_BASE_URL } from './config';\n\nexport async function consumeSession(\n options: ConsumeSessionOptions,\n): Promise<ConsumeSessionResponse> {\n const { sessionId, sessionKey, baseUrl = DEFAULT_BASE_URL } = options;\n\n const url = `${baseUrl}/v1/realtime_sessions/${sessionId}/consume`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${sessionKey}`,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to consume session: ${response.status} ${errorText}`,\n );\n }\n\n return response.json();\n}\n","export interface SuspenseResource<T> {\n read(): T;\n}\n\nexport function createSuspenseResource<T>(\n promise: Promise<T>,\n): SuspenseResource<T> {\n let status: 'pending' | 'fulfilled' | 'rejected' = 'pending';\n let result: T;\n let error: unknown;\n\n const suspender = promise.then(\n (value) => {\n status = 'fulfilled';\n result = value;\n },\n (err) => {\n status = 'rejected';\n error = err;\n },\n );\n\n return {\n read() {\n switch (status) {\n case 'pending':\n throw suspender;\n case 'rejected':\n throw error;\n case 'fulfilled':\n return result;\n }\n },\n };\n}\n","'use client';\n\nimport { useEffect } from 'react';\nimport { consumeSession } from '../api/consume';\nimport type { SessionCredentials } from '../types';\nimport {\n createSuspenseResource,\n type SuspenseResource,\n} from '../utils/suspense-resource';\n\nexport interface UseCredentialsOptions {\n avatarId: string;\n sessionId?: string;\n sessionKey?: string;\n credentials?: SessionCredentials;\n connectUrl?: string;\n connect?: (avatarId: string) => Promise<SessionCredentials>;\n baseUrl?: string;\n}\n\nconst resourceCache = new Map<string, SuspenseResource<SessionCredentials>>();\n\nfunction computeKey(options: UseCredentialsOptions): string {\n if (options.credentials) return `direct:${options.credentials.sessionId}`;\n if (options.sessionId && options.sessionKey)\n return `session:${options.sessionId}`;\n return `connect:${options.avatarId}:${options.connectUrl ?? 'custom'}`;\n}\n\nasync function fetchCredentials(\n options: UseCredentialsOptions,\n): Promise<SessionCredentials> {\n const { avatarId, sessionId, sessionKey, connectUrl, connect, baseUrl } =\n options;\n\n if (sessionId && sessionKey) {\n const { url, token, roomName } = await consumeSession({\n sessionId,\n sessionKey,\n baseUrl,\n });\n return { sessionId, serverUrl: url, token, roomName };\n }\n\n if (connect) {\n return connect(avatarId);\n }\n\n if (connectUrl) {\n const response = await fetch(connectUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ avatarId }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to connect: ${response.status} ${errorText}`);\n }\n\n return response.json();\n }\n\n throw new Error(\n 'AvatarCall requires one of: credentials, sessionId+sessionKey, connectUrl, or connect',\n );\n}\n\nexport function useCredentials(\n options: UseCredentialsOptions,\n): SessionCredentials {\n const key = computeKey(options);\n\n useEffect(() => {\n return () => {\n resourceCache.delete(key);\n };\n }, [key]);\n\n if (options.credentials) {\n return options.credentials;\n }\n\n let resource = resourceCache.get(key);\n if (!resource) {\n resource = createSuspenseResource(fetchCredentials(options));\n resourceCache.set(key, resource);\n }\n\n return resource.read();\n}\n","'use client';\n\nimport { useEffect, useRef } from 'react';\n\nexport function useLatest<T>(value: T): React.RefObject<T> {\n const ref = useRef(value);\n\n useEffect(() => {\n ref.current = value;\n }, [value]);\n\n return ref;\n}\n","'use client';\n\n/**\n * AvatarSession Component\n *\n * Provides the session context for avatar interactions.\n * Manages the WebRTC connection and exposes a clean API for child components.\n *\n * @example\n * ```tsx\n * <AvatarSession credentials={credentials} onEnd={handleEnd}>\n * <AvatarVideo />\n * <ControlBar />\n * </AvatarSession>\n * ```\n */\n\nimport {\n LiveKitRoom,\n RoomAudioRenderer,\n useConnectionState,\n useRoomContext,\n} from '@livekit/components-react';\nimport type { RoomOptions } from 'livekit-client';\nimport { ConnectionState } from 'livekit-client';\nimport {\n createContext,\n type ReactNode,\n useCallback,\n useContext,\n useRef,\n} from 'react';\nimport type {\n AvatarSessionContextValue,\n AvatarSessionProps,\n SessionState,\n} from '../types';\n\nconst DEFAULT_ROOM_OPTIONS: RoomOptions = {\n adaptiveStream: false,\n dynacast: false,\n};\n\n/**\n * Maps WebRTC connection state to session state\n */\nfunction mapConnectionState(connectionState: ConnectionState): SessionState {\n switch (connectionState) {\n case ConnectionState.Connecting:\n return 'connecting';\n case ConnectionState.Connected:\n return 'active';\n case ConnectionState.Reconnecting:\n return 'connecting';\n case ConnectionState.Disconnected:\n return 'ended';\n default:\n return 'ended';\n }\n}\n\nconst AvatarSessionContext = createContext<AvatarSessionContextValue | null>(\n null,\n);\n\n/**\n * AvatarSession component - the main entry point for avatar sessions\n *\n * Establishes a WebRTC connection and provides session state to children.\n * This is a headless component that renders minimal DOM.\n */\nexport function AvatarSession({\n credentials,\n children,\n audio = true,\n video = true,\n onEnd,\n onError,\n __unstable_roomOptions,\n}: AvatarSessionProps) {\n const errorRef = useRef<Error | null>(null);\n\n const handleError = (error: Error) => {\n errorRef.current = error;\n onError?.(error);\n };\n\n const roomOptions = {\n ...DEFAULT_ROOM_OPTIONS,\n ...__unstable_roomOptions,\n };\n\n return (\n <LiveKitRoom\n serverUrl={credentials.serverUrl}\n token={credentials.token}\n connect={true}\n audio={audio}\n video={video}\n onDisconnected={() => onEnd?.()}\n onError={handleError}\n options={roomOptions}\n connectOptions={{\n autoSubscribe: true,\n }}\n >\n <AvatarSessionContextInner\n sessionId={credentials.sessionId}\n onEnd={onEnd}\n errorRef={errorRef}\n >\n {children}\n </AvatarSessionContextInner>\n <RoomAudioRenderer />\n </LiveKitRoom>\n );\n}\n\n/**\n * Inner context provider that has access to the room context\n */\nfunction AvatarSessionContextInner({\n sessionId,\n onEnd,\n errorRef,\n children,\n}: {\n sessionId: string;\n onEnd?: () => void;\n errorRef: React.RefObject<Error | null>;\n children: ReactNode;\n}) {\n const room = useRoomContext();\n const connectionState = useConnectionState();\n const onEndRef = useRef(onEnd);\n onEndRef.current = onEnd;\n\n const end = useCallback(async () => {\n try {\n // Send END_CALL message to the avatar\n const encoder = new TextEncoder();\n const data = encoder.encode(JSON.stringify({ type: 'END_CALL' }));\n await room.localParticipant.publishData(data, { reliable: true });\n } catch {\n // Ignore errors when sending end message\n }\n\n await room.disconnect();\n onEndRef.current?.();\n }, [room]);\n\n const contextValue: AvatarSessionContextValue = {\n state: mapConnectionState(connectionState),\n sessionId,\n error: errorRef.current,\n end,\n };\n\n return (\n <AvatarSessionContext.Provider value={contextValue}>\n {children}\n </AvatarSessionContext.Provider>\n );\n}\n\n/**\n * Hook to access the avatar session context\n * Must be used within an AvatarSession component\n */\nexport function useAvatarSessionContext(): AvatarSessionContextValue {\n const context = useContext(AvatarSessionContext);\n if (!context) {\n throw new Error(\n 'useAvatarSessionContext must be used within an AvatarSession',\n );\n }\n return context;\n}\n\n/**\n * Hook to optionally access the avatar session context\n * Returns null if not within an AvatarSession\n */\nexport function useMaybeAvatarSessionContext(): AvatarSessionContextValue | null {\n return useContext(AvatarSessionContext);\n}\n","'use client';\n\n/**\n * useAvatar Hook\n *\n * Provides access to the remote avatar participant's video track.\n * Audio is handled automatically by the session.\n *\n * @example\n * ```tsx\n * function AvatarDisplay() {\n * const { videoTrackRef, hasVideo } = useAvatar();\n *\n * if (!hasVideo) {\n * return <Placeholder />;\n * }\n *\n * return <VideoTrack trackRef={videoTrackRef} />;\n * }\n * ```\n */\n\nimport {\n isTrackReference,\n useRemoteParticipants,\n useTracks,\n} from '@livekit/components-react';\nimport { Track } from 'livekit-client';\nimport type { UseAvatarReturn } from '../types';\n\n/**\n * Hook to access the remote avatar participant's video track\n *\n * @returns Avatar participant info and video track reference\n */\nexport function useAvatar(): UseAvatarReturn {\n const remoteParticipants = useRemoteParticipants();\n const avatarParticipant = remoteParticipants[0] ?? null;\n\n // Only subscribe to video - audio is handled automatically by the session\n const videoTracks = useTracks(\n [{ source: Track.Source.Camera, withPlaceholder: true }],\n { onlySubscribed: true, updateOnlyOn: [] },\n ).filter((ref) => !ref.participant.isLocal);\n\n const videoTrackRef = videoTracks[0] ?? null;\n const hasVideo = videoTrackRef !== null && isTrackReference(videoTrackRef);\n\n return {\n participant: avatarParticipant,\n videoTrackRef,\n hasVideo,\n };\n}\n","'use client';\n\n/**\n * useAvatarSession Hook\n *\n * Provides access to the current avatar session state.\n * Returns a discriminated union based on session state for type-safe UI rendering.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const session = useAvatarSession();\n *\n * if (session.state === 'connecting') {\n * return <Loading />;\n * }\n *\n * if (session.state === 'error') {\n * return <Error message={session.error.message} />;\n * }\n *\n * return <ActiveSession onEnd={session.end} />;\n * }\n * ```\n */\n\nimport { useAvatarSessionContext } from '../components/AvatarSession';\nimport type { AvatarSessionContextValue } from '../types';\n\n/**\n * Discriminated union types for type-safe session state handling\n */\nexport type UseAvatarSessionReturn =\n | { state: 'idle'; sessionId: string; error: null; end: () => Promise<void> }\n | { state: 'connecting'; sessionId: string; error: null; end: () => Promise<void> }\n | { state: 'active'; sessionId: string; error: null; end: () => Promise<void> }\n | { state: 'ending'; sessionId: string; error: null; end: () => Promise<void> }\n | { state: 'ended'; sessionId: string; error: null; end: () => Promise<void> }\n | { state: 'error'; sessionId: string; error: Error; end: () => Promise<void> };\n\n/**\n * Hook to access the current avatar session state\n *\n * @returns Session state as a discriminated union\n */\nexport function useAvatarSession(): UseAvatarSessionReturn {\n const context = useAvatarSessionContext();\n return context as UseAvatarSessionReturn;\n}\n\nexport type { AvatarSessionContextValue };\n","'use client';\n\n/**\n * useAvatarStatus Hook\n *\n * Returns a single discriminated union representing the full avatar lifecycle\n * inside an AvatarSession. Combines session connection state and video\n * track availability into one status value.\n *\n * Must be used within <AvatarCall> or <AvatarSession>.\n *\n * @example\n * ```tsx\n * function MyAvatar() {\n * const avatar = useAvatarStatus();\n *\n * switch (avatar.status) {\n * case 'connecting':\n * return <Spinner />;\n * case 'waiting':\n * return <p>Waiting for video...</p>;\n * case 'ready':\n * return <VideoTrack trackRef={avatar.videoTrackRef} />;\n * case 'error':\n * return <p>{avatar.error.message}</p>;\n * case 'ended':\n * return <p>Call ended</p>;\n * }\n * }\n * ```\n */\n\nimport type { TrackReferenceOrPlaceholder } from '@livekit/components-react';\nimport { useAvatar } from './useAvatar';\nimport { useAvatarSession } from './useAvatarSession';\n\nexport type AvatarStatus =\n | { status: 'connecting' }\n | { status: 'waiting' }\n | { status: 'ready'; videoTrackRef: TrackReferenceOrPlaceholder }\n | { status: 'ending' }\n | { status: 'ended' }\n | { status: 'error'; error: Error };\n\nexport function useAvatarStatus(): AvatarStatus {\n const session = useAvatarSession();\n const { videoTrackRef, hasVideo } = useAvatar();\n\n switch (session.state) {\n case 'connecting':\n case 'idle':\n return { status: 'connecting' };\n\n case 'active':\n if (hasVideo && videoTrackRef) {\n return { status: 'ready', videoTrackRef };\n }\n return { status: 'waiting' };\n\n case 'ending':\n return { status: 'ending' };\n\n case 'ended':\n return { status: 'ended' };\n\n case 'error':\n return { status: 'error', error: session.error };\n }\n}\n","'use client';\n\nimport { isTrackReference, VideoTrack } from '@livekit/components-react';\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react';\nimport { type AvatarStatus, useAvatarStatus } from '../hooks/useAvatarStatus';\n\n/** Subset of AvatarStatus relevant to the video display */\nexport type AvatarVideoStatus = Extract<\n AvatarStatus,\n { status: 'connecting' } | { status: 'waiting' } | { status: 'ready' }\n>;\n\nexport interface AvatarVideoProps\n extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {\n children?: (status: AvatarVideoStatus) => ReactNode;\n}\n\nexport function AvatarVideo({ children, ...props }: AvatarVideoProps) {\n const avatar = useAvatarStatus();\n\n const videoStatus: AvatarVideoStatus =\n avatar.status === 'ready'\n ? avatar\n : avatar.status === 'connecting'\n ? { status: 'connecting' }\n : { status: 'waiting' };\n\n if (children) {\n return <>{children(videoStatus)}</>;\n }\n\n return (\n <div\n {...props}\n data-avatar-video=\"\"\n data-avatar-status={videoStatus.status}\n >\n {videoStatus.status === 'ready' &&\n isTrackReference(videoStatus.videoTrackRef) && (\n <VideoTrack trackRef={videoStatus.videoTrackRef} />\n )}\n </div>\n );\n}\n","'use client';\n\nimport {\n useLocalParticipant,\n useMediaDevices,\n useTracks,\n} from '@livekit/components-react';\nimport { Track } from 'livekit-client';\nimport { useCallback } from 'react';\nimport type { UseLocalMediaReturn } from '../types';\nimport { useLatest } from './useLatest';\n\nexport function useLocalMedia(): UseLocalMediaReturn {\n const { localParticipant } = useLocalParticipant();\n\n const audioDevices = useMediaDevices({ kind: 'audioinput' });\n const videoDevices = useMediaDevices({ kind: 'videoinput' });\n\n const hasMic = audioDevices.length > 0;\n const hasCamera = videoDevices.length > 0;\n\n const isMicEnabled = localParticipant?.isMicrophoneEnabled ?? false;\n const isCameraEnabled = localParticipant?.isCameraEnabled ?? false;\n const isScreenShareEnabled = localParticipant?.isScreenShareEnabled ?? false;\n\n const isMicEnabledRef = useLatest(isMicEnabled);\n const isCameraEnabledRef = useLatest(isCameraEnabled);\n const isScreenShareEnabledRef = useLatest(isScreenShareEnabled);\n\n const toggleMic = useCallback(() => {\n localParticipant?.setMicrophoneEnabled(!isMicEnabledRef.current);\n }, [localParticipant, isMicEnabledRef]);\n\n const toggleCamera = useCallback(() => {\n localParticipant?.setCameraEnabled(!isCameraEnabledRef.current);\n }, [localParticipant, isCameraEnabledRef]);\n\n const toggleScreenShare = useCallback(() => {\n localParticipant?.setScreenShareEnabled(!isScreenShareEnabledRef.current);\n }, [localParticipant, isScreenShareEnabledRef]);\n\n const tracks = useTracks(\n [{ source: Track.Source.Camera, withPlaceholder: true }],\n {\n onlySubscribed: false,\n updateOnlyOn: [],\n },\n );\n\n const localIdentity = localParticipant?.identity;\n\n const localVideoTrackRef =\n tracks.find(\n (trackRef) =>\n trackRef.participant.identity === localIdentity &&\n trackRef.source === Track.Source.Camera,\n ) ?? null;\n\n return {\n hasMic,\n hasCamera,\n isMicEnabled,\n isCameraEnabled,\n isScreenShareEnabled,\n toggleMic,\n toggleCamera,\n toggleScreenShare,\n localVideoTrackRef,\n };\n}\n","'use client';\n\nimport { TrackToggle } from '@livekit/components-react';\nimport { Track } from 'livekit-client';\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react';\nimport { useAvatarSession } from '../hooks/useAvatarSession';\nimport { useLocalMedia } from '../hooks/useLocalMedia';\n\nexport interface ControlBarState {\n isMicEnabled: boolean;\n isCameraEnabled: boolean;\n isScreenShareEnabled: boolean;\n toggleMic: () => void;\n toggleCamera: () => void;\n toggleScreenShare: () => void;\n endCall: () => Promise<void>;\n isActive: boolean;\n}\n\nexport interface ControlBarProps\n extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {\n showMicrophone?: boolean;\n showCamera?: boolean;\n showScreenShare?: boolean;\n showEndCall?: boolean;\n children?: (state: ControlBarState) => ReactNode;\n}\n\nexport function ControlBar({\n children,\n showMicrophone = true,\n showCamera = true,\n showScreenShare = false,\n showEndCall = true,\n ...props\n}: ControlBarProps) {\n const session = useAvatarSession();\n const {\n isMicEnabled,\n isCameraEnabled,\n isScreenShareEnabled,\n toggleMic,\n toggleCamera,\n toggleScreenShare,\n } = useLocalMedia();\n\n const isActive = session.state === 'active';\n\n const state: ControlBarState = {\n isMicEnabled,\n isCameraEnabled,\n isScreenShareEnabled,\n toggleMic,\n toggleCamera,\n toggleScreenShare,\n endCall: session.end,\n isActive,\n };\n\n if (children) {\n return <>{children(state)}</>;\n }\n\n if (!isActive) {\n return null;\n }\n\n return (\n <div {...props} data-avatar-control-bar=\"\" data-avatar-active={isActive}>\n {showMicrophone && (\n <button\n type=\"button\"\n onClick={toggleMic}\n data-avatar-control=\"microphone\"\n data-avatar-enabled={isMicEnabled}\n aria-label={isMicEnabled ? 'Mute microphone' : 'Unmute microphone'}\n >\n {microphoneIcon}\n </button>\n )}\n {showCamera && (\n <button\n type=\"button\"\n onClick={toggleCamera}\n data-avatar-control=\"camera\"\n data-avatar-enabled={isCameraEnabled}\n aria-label={isCameraEnabled ? 'Turn off camera' : 'Turn on camera'}\n >\n {cameraIcon}\n </button>\n )}\n {showScreenShare && (\n <TrackToggle\n source={Track.Source.ScreenShare}\n showIcon={false}\n data-avatar-control=\"screen-share\"\n data-avatar-enabled={isScreenShareEnabled}\n aria-label=\"Toggle screen share\"\n >\n {screenShareIcon}\n </TrackToggle>\n )}\n {showEndCall && (\n <button\n type=\"button\"\n onClick={session.end}\n data-avatar-control=\"end-call\"\n data-avatar-enabled={true}\n aria-label=\"End call\"\n >\n {phoneIcon}\n </button>\n )}\n </div>\n );\n}\n\n// Lucide icons (https://lucide.dev) - MIT License\nconst microphoneIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\" />\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" />\n <line x1=\"12\" x2=\"12\" y1=\"19\" y2=\"22\" />\n </svg>\n);\n\nconst cameraIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\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\nconst screenShareIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <rect width=\"20\" height=\"14\" x=\"2\" y=\"3\" rx=\"2\" />\n <line x1=\"8\" x2=\"16\" y1=\"21\" y2=\"21\" />\n <line x1=\"12\" x2=\"12\" y1=\"17\" y2=\"21\" />\n </svg>\n);\n\nconst phoneIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"8 14 24 12\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path d=\"M12.8429 22.5693L11.4018 21.0986C11.2675 20.9626 11.1625 20.7995 11.0935 20.6197C11.0245 20.4399 10.9931 20.2474 11.0013 20.0545C11.0094 19.8616 11.0569 19.6726 11.1408 19.4995C11.2247 19.3265 11.343 19.1732 11.4883 19.0495C13.127 17.7049 15.0519 16.7714 17.1083 16.3239C19.0064 15.892 20.9744 15.892 22.8725 16.3239C24.9374 16.7743 26.8693 17.7147 28.5117 19.0691C28.6565 19.1924 28.7746 19.3451 28.8585 19.5176C28.9423 19.69 28.99 19.8784 28.9986 20.0707C29.0072 20.263 28.9764 20.455 28.9083 20.6345C28.8402 20.814 28.7362 20.9771 28.603 21.1133L27.1619 22.584C26.9311 22.8242 26.6226 22.9706 26.2938 22.9959C25.9651 23.0211 25.6385 22.9235 25.3751 22.7212C24.8531 22.3127 24.2875 21.9657 23.689 21.6869C23.4525 21.5774 23.2517 21.4009 23.1103 21.1785C22.969 20.9561 22.8931 20.697 22.8917 20.4319V19.1867C21.0053 18.6573 19.0139 18.6573 17.1275 19.1867V20.4319C17.1261 20.697 17.0502 20.9561 16.9089 21.1785C16.7676 21.4009 16.5667 21.5774 16.3302 21.6869C15.7317 21.9657 15.1661 22.3127 14.6442 22.7212C14.3779 22.9258 14.0473 23.0233 13.7152 22.9953C13.383 22.9673 13.0726 22.8156 12.8429 22.5693Z\" />\n </svg>\n);\n","'use client';\n\nimport { isTrackReference, VideoTrack } from '@livekit/components-react';\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react';\nimport { useLocalMedia } from '../hooks/useLocalMedia';\nimport type { UseLocalMediaReturn } from '../types';\n\nexport interface UserVideoState {\n hasVideo: boolean;\n isCameraEnabled: boolean;\n trackRef: UseLocalMediaReturn['localVideoTrackRef'];\n}\n\nexport interface UserVideoProps\n extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {\n mirror?: boolean;\n children?: (state: UserVideoState) => ReactNode;\n}\n\nexport function UserVideo({\n children,\n mirror = true,\n ...props\n}: UserVideoProps) {\n const { localVideoTrackRef, isCameraEnabled } = useLocalMedia();\n\n const hasVideo =\n localVideoTrackRef !== null && isTrackReference(localVideoTrackRef);\n\n const state: UserVideoState = {\n hasVideo,\n isCameraEnabled,\n trackRef: localVideoTrackRef,\n };\n\n if (children) {\n return <>{children(state)}</>;\n }\n\n return (\n <div\n {...props}\n data-avatar-user-video=\"\"\n data-avatar-has-video={hasVideo}\n data-avatar-camera-enabled={isCameraEnabled}\n data-avatar-mirror={mirror}\n >\n {hasVideo &&\n localVideoTrackRef &&\n isTrackReference(localVideoTrackRef) && (\n <VideoTrack trackRef={localVideoTrackRef} />\n )}\n </div>\n );\n}\n","'use client';\n\n/**\n * AvatarCall Component\n *\n * High-level component that handles the complete session lifecycle.\n * Suspends during credential fetching (Phase 1) — wrap in <Suspense> to\n * show loading UI while the server creates the session.\n *\n * @example\n * ```tsx\n * <Suspense fallback={<Loading />}>\n * <AvatarCall avatarId=\"game-host\" connectUrl=\"/api/avatar/connect\">\n * <AvatarVideo />\n * <ControlBar />\n * </AvatarCall>\n * </Suspense>\n * ```\n */\n\nimport { useCredentials } from '../hooks/useCredentials';\nimport { useLatest } from '../hooks/useLatest';\nimport type { AvatarCallProps } from '../types';\nimport { AvatarSession } from './AvatarSession';\nimport { AvatarVideo } from './AvatarVideo';\nimport { ControlBar } from './ControlBar';\nimport { UserVideo } from './UserVideo';\n\nexport function AvatarCall({\n avatarId,\n sessionId,\n sessionKey,\n credentials: directCredentials,\n connectUrl,\n connect,\n baseUrl,\n avatarImageUrl,\n onEnd,\n onError,\n children,\n __unstable_roomOptions,\n ...props\n}: AvatarCallProps) {\n const onErrorRef = useLatest(onError);\n\n const credentials = useCredentials({\n avatarId,\n sessionId,\n sessionKey,\n credentials: directCredentials,\n connectUrl,\n connect,\n baseUrl,\n });\n\n const handleSessionError = (err: Error) => {\n onErrorRef.current?.(err);\n };\n\n const backgroundStyle = avatarImageUrl\n ? ({ '--avatar-image': `url(${avatarImageUrl})` } as React.CSSProperties)\n : undefined;\n\n return (\n <div\n {...props}\n data-avatar-call=\"\"\n data-avatar-id={avatarId}\n style={{ ...props.style, ...backgroundStyle }}\n >\n <AvatarSession\n credentials={credentials}\n onEnd={onEnd}\n onError={handleSessionError}\n __unstable_roomOptions={__unstable_roomOptions}\n >\n {children ?? (\n <>\n <AvatarVideo />\n <UserVideo />\n <ControlBar />\n </>\n )}\n </AvatarSession>\n </div>\n );\n}\n","'use client';\n\nimport {\n isTrackReference,\n type TrackReferenceOrPlaceholder,\n useLocalParticipant,\n useTracks,\n VideoTrack,\n} from '@livekit/components-react';\nimport { Track } from 'livekit-client';\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react';\n\nexport interface ScreenShareVideoState {\n isSharing: boolean;\n trackRef: TrackReferenceOrPlaceholder | null;\n}\n\nexport interface ScreenShareVideoProps\n extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {\n children?: (state: ScreenShareVideoState) => ReactNode;\n}\n\nexport function ScreenShareVideo({\n children,\n ...props\n}: ScreenShareVideoProps) {\n const { localParticipant } = useLocalParticipant();\n\n const tracks = useTracks(\n [{ source: Track.Source.ScreenShare, withPlaceholder: false }],\n { onlySubscribed: false },\n );\n\n const localIdentity = localParticipant?.identity;\n\n const screenShareTrackRef =\n tracks.find(\n (trackRef) =>\n trackRef.participant.identity === localIdentity &&\n trackRef.source === Track.Source.ScreenShare,\n ) ?? null;\n\n const isSharing =\n screenShareTrackRef !== null && isTrackReference(screenShareTrackRef);\n\n const state: ScreenShareVideoState = {\n isSharing,\n trackRef: screenShareTrackRef,\n };\n\n if (children) {\n return <>{children(state)}</>;\n }\n\n if (!isSharing) {\n return null;\n }\n\n return (\n <div {...props} data-avatar-screen-share=\"\" data-avatar-sharing={isSharing}>\n {screenShareTrackRef && isTrackReference(screenShareTrackRef) && (\n <VideoTrack trackRef={screenShareTrackRef} />\n )}\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/api/config.ts","../src/api/consume.ts","../src/hooks/useLatest.ts","../src/hooks/useCredentials.ts","../src/components/AvatarSession.tsx","../src/hooks/useAvatar.ts","../src/hooks/useAvatarSession.ts","../src/hooks/useAvatarStatus.ts","../src/components/AvatarVideo.tsx","../src/hooks/useLocalMedia.ts","../src/components/ControlBar.tsx","../src/components/UserVideo.tsx","../src/components/AvatarCall.tsx","../src/components/ScreenShareVideo.tsx"],"names":["useRef","useEffect","useState","RoomAudioRenderer","jsx","isTrackReference","useCallback","useTracks","Track","Fragment","jsxs","VideoTrack","useLocalParticipant"],"mappings":"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","file":"index.js","sourcesContent":["export const DEFAULT_BASE_URL = 'https://api.dev.runwayml.com';\n","import type { ConsumeSessionOptions, ConsumeSessionResponse } from '../types';\nimport { DEFAULT_BASE_URL } from './config';\n\nexport async function consumeSession(\n options: ConsumeSessionOptions,\n): Promise<ConsumeSessionResponse> {\n const { sessionId, sessionKey, baseUrl = DEFAULT_BASE_URL } = options;\n\n const url = `${baseUrl}/v1/realtime_sessions/${sessionId}/consume`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${sessionKey}`,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to consume session: ${response.status} ${errorText}`,\n );\n }\n\n return response.json();\n}\n","'use client';\n\nimport { useEffect, useRef } from 'react';\n\nexport function useLatest<T>(value: T): React.RefObject<T> {\n const ref = useRef(value);\n\n useEffect(() => {\n ref.current = value;\n }, [value]);\n\n return ref;\n}\n","'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport { consumeSession } from '../api/consume';\nimport type { SessionCredentials } from '../types';\nimport { useLatest } from './useLatest';\n\nexport interface UseCredentialsOptions {\n avatarId: string;\n sessionId?: string;\n sessionKey?: string;\n credentials?: SessionCredentials;\n connectUrl?: string;\n connect?: (avatarId: string) => Promise<SessionCredentials>;\n baseUrl?: string;\n onError?: (error: Error) => void;\n}\n\nexport type CredentialsState =\n | { status: 'loading'; credentials: null; error: null }\n | { status: 'ready'; credentials: SessionCredentials; error: null }\n | { status: 'error'; credentials: null; error: Error };\n\nasync function fetchCredentials(\n options: UseCredentialsOptions,\n): Promise<SessionCredentials> {\n const { avatarId, sessionId, sessionKey, connectUrl, connect, baseUrl } =\n options;\n\n if (sessionId && sessionKey) {\n const { url, token, roomName } = await consumeSession({\n sessionId,\n sessionKey,\n baseUrl,\n });\n return { sessionId, serverUrl: url, token, roomName };\n }\n\n if (connect) {\n return connect(avatarId);\n }\n\n if (connectUrl) {\n const response = await fetch(connectUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ avatarId }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to connect: ${response.status} ${errorText}`);\n }\n\n return response.json();\n }\n\n throw new Error(\n 'AvatarCall requires one of: credentials, sessionId+sessionKey, connectUrl, or connect',\n );\n}\n\nexport function useCredentials(\n options: UseCredentialsOptions,\n): CredentialsState {\n const {\n credentials: directCredentials,\n avatarId,\n sessionId,\n sessionKey,\n connectUrl,\n connect,\n baseUrl,\n onError,\n } = options;\n\n const onErrorRef = useLatest(onError);\n const connectRef = useLatest(connect);\n\n const fetchedKeyRef = useRef<string | null>(null);\n\n const [state, setState] = useState<CredentialsState>(() => {\n if (directCredentials) {\n return { status: 'ready', credentials: directCredentials, error: null };\n }\n return { status: 'loading', credentials: null, error: null };\n });\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: refs are stable - we read .current at call time\n useEffect(() => {\n if (directCredentials) {\n setState({\n status: 'ready',\n credentials: directCredentials,\n error: null,\n });\n return;\n }\n\n const credentialKey = `${avatarId}:${sessionId}:${sessionKey}:${connectUrl}:${baseUrl}`;\n\n if (fetchedKeyRef.current === credentialKey) return;\n fetchedKeyRef.current = credentialKey;\n\n let cancelled = false;\n setState({ status: 'loading', credentials: null, error: null });\n\n async function load() {\n try {\n const fetchOptions: UseCredentialsOptions = {\n avatarId,\n sessionId,\n sessionKey,\n connectUrl,\n connect: connectRef.current ?? undefined,\n baseUrl,\n };\n const credentials = await fetchCredentials(fetchOptions);\n if (!cancelled) {\n setState({ status: 'ready', credentials, error: null });\n }\n } catch (err) {\n if (!cancelled) {\n const error = err instanceof Error ? err : new Error(String(err));\n setState({ status: 'error', credentials: null, error });\n onErrorRef.current?.(error);\n }\n }\n }\n\n load();\n\n return () => {\n cancelled = true;\n };\n }, [directCredentials, avatarId, sessionId, sessionKey, connectUrl, baseUrl]);\n\n return state;\n}\n","'use client';\n\n/**\n * AvatarSession Component\n *\n * Provides the session context for avatar interactions.\n * Manages the WebRTC connection and exposes a clean API for child components.\n *\n * @example\n * ```tsx\n * <AvatarSession credentials={credentials} onEnd={handleEnd}>\n * <AvatarVideo />\n * <ControlBar />\n * </AvatarSession>\n * ```\n */\n\nimport {\n LiveKitRoom,\n RoomAudioRenderer,\n useConnectionState,\n useRoomContext,\n} from '@livekit/components-react';\nimport type { RoomOptions } from 'livekit-client';\nimport { ConnectionState } from 'livekit-client';\nimport {\n createContext,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport type {\n AvatarSessionContextValue,\n AvatarSessionProps,\n SessionState,\n} from '../types';\n\n/**\n * Check if a media device of the given kind is available\n * Returns within timeout to avoid blocking the connection\n */\nasync function hasMediaDevice(\n kind: 'audioinput' | 'videoinput',\n timeoutMs = 1000,\n): Promise<boolean> {\n try {\n const timeoutPromise = new Promise<boolean>((resolve) =>\n setTimeout(() => resolve(false), timeoutMs),\n );\n const checkPromise = navigator.mediaDevices\n .enumerateDevices()\n .then((devices) => devices.some((device) => device.kind === kind));\n\n return await Promise.race([checkPromise, timeoutPromise]);\n } catch {\n return false;\n }\n}\n\n/**\n * Hook to check device availability before connecting.\n * Completes quickly to avoid blocking the connection.\n */\nfunction useDeviceAvailability(\n requestAudio: boolean,\n requestVideo: boolean,\n): { audio: boolean; video: boolean } {\n const [state, setState] = useState({\n audio: requestAudio, // Optimistically assume devices exist\n video: requestVideo,\n });\n\n useEffect(() => {\n let cancelled = false;\n\n async function checkDevices() {\n const [hasAudio, hasVideo] = await Promise.all([\n requestAudio ? hasMediaDevice('audioinput') : Promise.resolve(false),\n requestVideo ? hasMediaDevice('videoinput') : Promise.resolve(false),\n ]);\n\n if (!cancelled) {\n setState({\n audio: requestAudio && hasAudio,\n video: requestVideo && hasVideo,\n });\n }\n }\n\n checkDevices();\n\n return () => {\n cancelled = true;\n };\n }, [requestAudio, requestVideo]);\n\n return state;\n}\n\nconst DEFAULT_ROOM_OPTIONS: RoomOptions = {\n adaptiveStream: false,\n dynacast: false,\n};\n\n/**\n * Maps WebRTC connection state to session state\n */\nfunction mapConnectionState(connectionState: ConnectionState): SessionState {\n switch (connectionState) {\n case ConnectionState.Connecting:\n return 'connecting';\n case ConnectionState.Connected:\n return 'active';\n case ConnectionState.Reconnecting:\n return 'connecting';\n case ConnectionState.Disconnected:\n return 'ended';\n default:\n return 'ended';\n }\n}\n\nconst AvatarSessionContext = createContext<AvatarSessionContextValue | null>(\n null,\n);\n\n/**\n * AvatarSession component - the main entry point for avatar sessions\n *\n * Establishes a WebRTC connection and provides session state to children.\n * This is a headless component that renders minimal DOM.\n */\nexport function AvatarSession({\n credentials,\n children,\n audio: requestAudio = true,\n video: requestVideo = true,\n onEnd,\n onError,\n __unstable_roomOptions,\n}: AvatarSessionProps) {\n const errorRef = useRef<Error | null>(null);\n\n const deviceAvailability = useDeviceAvailability(requestAudio, requestVideo);\n\n const handleError = (error: Error) => {\n errorRef.current = error;\n onError?.(error);\n };\n\n const roomOptions = {\n ...DEFAULT_ROOM_OPTIONS,\n ...__unstable_roomOptions,\n };\n\n return (\n <LiveKitRoom\n serverUrl={credentials.serverUrl}\n token={credentials.token}\n connect={true}\n audio={deviceAvailability.audio}\n video={deviceAvailability.video}\n onDisconnected={() => onEnd?.()}\n onError={handleError}\n options={roomOptions}\n connectOptions={{\n autoSubscribe: true,\n }}\n >\n <AvatarSessionContextInner\n sessionId={credentials.sessionId}\n onEnd={onEnd}\n errorRef={errorRef}\n >\n {children}\n </AvatarSessionContextInner>\n <RoomAudioRenderer />\n </LiveKitRoom>\n );\n}\n\n/**\n * Inner context provider that has access to the room context\n */\nfunction AvatarSessionContextInner({\n sessionId,\n onEnd,\n errorRef,\n children,\n}: {\n sessionId: string;\n onEnd?: () => void;\n errorRef: React.RefObject<Error | null>;\n children: ReactNode;\n}) {\n const room = useRoomContext();\n const connectionState = useConnectionState();\n const onEndRef = useRef(onEnd);\n onEndRef.current = onEnd;\n\n const end = useCallback(async () => {\n try {\n // Send END_CALL message to the avatar\n const encoder = new TextEncoder();\n const data = encoder.encode(JSON.stringify({ type: 'END_CALL' }));\n await room.localParticipant.publishData(data, { reliable: true });\n } catch {\n // Ignore errors when sending end message\n }\n\n await room.disconnect();\n onEndRef.current?.();\n }, [room]);\n\n const contextValue: AvatarSessionContextValue = {\n state: mapConnectionState(connectionState),\n sessionId,\n error: errorRef.current,\n end,\n };\n\n return (\n <AvatarSessionContext.Provider value={contextValue}>\n {children}\n </AvatarSessionContext.Provider>\n );\n}\n\n/**\n * Hook to access the avatar session context\n * Must be used within an AvatarSession component\n */\nexport function useAvatarSessionContext(): AvatarSessionContextValue {\n const context = useContext(AvatarSessionContext);\n if (!context) {\n throw new Error(\n 'useAvatarSessionContext must be used within an AvatarSession',\n );\n }\n return context;\n}\n\n/**\n * Hook to optionally access the avatar session context\n * Returns null if not within an AvatarSession\n */\nexport function useMaybeAvatarSessionContext(): AvatarSessionContextValue | null {\n return useContext(AvatarSessionContext);\n}\n","'use client';\n\n/**\n * useAvatar Hook\n *\n * Provides access to the remote avatar participant's video track.\n * Audio is handled automatically by the session.\n *\n * Must be used within an AvatarSession or AvatarCall component.\n *\n * @example\n * ```tsx\n * function AvatarDisplay() {\n * const { videoTrackRef, hasVideo } = useAvatar();\n *\n * if (!hasVideo) {\n * return <Placeholder />;\n * }\n *\n * return <VideoTrack trackRef={videoTrackRef} />;\n * }\n * ```\n */\n\nimport {\n isTrackReference,\n useRemoteParticipants,\n useTracks,\n} from '@livekit/components-react';\nimport { Track } from 'livekit-client';\nimport type { UseAvatarReturn } from '../types';\n\n/**\n * Hook to access the remote avatar participant's video track\n *\n * @returns Avatar participant info and video track reference\n */\nexport function useAvatar(): UseAvatarReturn {\n const remoteParticipants = useRemoteParticipants();\n const avatarParticipant = remoteParticipants[0] ?? null;\n\n // Only subscribe to video - audio is handled automatically by the session\n const videoTracks = useTracks(\n [{ source: Track.Source.Camera, withPlaceholder: true }],\n {\n onlySubscribed: true,\n updateOnlyOn: [],\n },\n ).filter((ref) => !ref.participant.isLocal);\n\n const videoTrackRef = videoTracks[0] ?? null;\n const hasVideo = videoTrackRef !== null && isTrackReference(videoTrackRef);\n\n return {\n participant: avatarParticipant,\n videoTrackRef,\n hasVideo,\n };\n}\n","'use client';\n\n/**\n * useAvatarSession Hook\n *\n * Provides access to the current avatar session state.\n * Returns a discriminated union based on session state for type-safe UI rendering.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const session = useAvatarSession();\n *\n * if (session.state === 'connecting') {\n * return <Loading />;\n * }\n *\n * if (session.state === 'error') {\n * return <Error message={session.error.message} />;\n * }\n *\n * return <ActiveSession onEnd={session.end} />;\n * }\n * ```\n */\n\nimport { useAvatarSessionContext } from '../components/AvatarSession';\nimport type { AvatarSessionContextValue } from '../types';\n\n/**\n * Discriminated union types for type-safe session state handling\n */\nexport type UseAvatarSessionReturn =\n | { state: 'idle'; sessionId: string; error: null; end: () => Promise<void> }\n | { state: 'connecting'; sessionId: string; error: null; end: () => Promise<void> }\n | { state: 'active'; sessionId: string; error: null; end: () => Promise<void> }\n | { state: 'ending'; sessionId: string; error: null; end: () => Promise<void> }\n | { state: 'ended'; sessionId: string; error: null; end: () => Promise<void> }\n | { state: 'error'; sessionId: string; error: Error; end: () => Promise<void> };\n\n/**\n * Hook to access the current avatar session state\n *\n * @returns Session state as a discriminated union\n */\nexport function useAvatarSession(): UseAvatarSessionReturn {\n const context = useAvatarSessionContext();\n return context as UseAvatarSessionReturn;\n}\n\nexport type { AvatarSessionContextValue };\n","'use client';\n\n/**\n * useAvatarStatus Hook\n *\n * Returns a single discriminated union representing the full avatar lifecycle\n * inside an AvatarSession. Combines session connection state and video\n * track availability into one status value.\n *\n * Must be used within <AvatarCall> or <AvatarSession>.\n *\n * @example\n * ```tsx\n * function MyAvatar() {\n * const avatar = useAvatarStatus();\n *\n * switch (avatar.status) {\n * case 'connecting':\n * return <Spinner />;\n * case 'waiting':\n * return <p>Waiting for video...</p>;\n * case 'ready':\n * return <VideoTrack trackRef={avatar.videoTrackRef} />;\n * case 'error':\n * return <p>{avatar.error.message}</p>;\n * case 'ended':\n * return <p>Call ended</p>;\n * }\n * }\n * ```\n */\n\nimport type { TrackReferenceOrPlaceholder } from '@livekit/components-react';\nimport { useAvatar } from './useAvatar';\nimport { useAvatarSession } from './useAvatarSession';\n\nexport type AvatarStatus =\n | { status: 'connecting' }\n | { status: 'waiting' }\n | { status: 'ready'; videoTrackRef: TrackReferenceOrPlaceholder }\n | { status: 'ending' }\n | { status: 'ended' }\n | { status: 'error'; error: Error };\n\nexport function useAvatarStatus(): AvatarStatus {\n const session = useAvatarSession();\n const { videoTrackRef, hasVideo } = useAvatar();\n\n switch (session.state) {\n case 'connecting':\n case 'idle':\n return { status: 'connecting' };\n\n case 'active':\n if (hasVideo && videoTrackRef) {\n return { status: 'ready', videoTrackRef };\n }\n return { status: 'waiting' };\n\n case 'ending':\n return { status: 'ending' };\n\n case 'ended':\n return { status: 'ended' };\n\n case 'error':\n return { status: 'error', error: session.error };\n }\n}\n","'use client';\n\nimport { isTrackReference, VideoTrack } from '@livekit/components-react';\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react';\nimport { type AvatarStatus, useAvatarStatus } from '../hooks/useAvatarStatus';\n\n/** Subset of AvatarStatus relevant to the video display */\nexport type AvatarVideoStatus = Extract<\n AvatarStatus,\n { status: 'connecting' } | { status: 'waiting' } | { status: 'ready' }\n>;\n\nexport interface AvatarVideoProps\n extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {\n children?: (status: AvatarVideoStatus) => ReactNode;\n}\n\nexport function AvatarVideo({ children, ...props }: AvatarVideoProps) {\n const avatar = useAvatarStatus();\n\n const videoStatus: AvatarVideoStatus =\n avatar.status === 'ready'\n ? avatar\n : avatar.status === 'connecting'\n ? { status: 'connecting' }\n : { status: 'waiting' };\n\n if (children) {\n return <>{children(videoStatus)}</>;\n }\n\n return (\n <div\n {...props}\n data-avatar-video=\"\"\n data-avatar-status={videoStatus.status}\n >\n {videoStatus.status === 'ready' &&\n isTrackReference(videoStatus.videoTrackRef) && (\n <VideoTrack trackRef={videoStatus.videoTrackRef} />\n )}\n </div>\n );\n}\n","'use client';\n\nimport {\n useLocalParticipant,\n useMediaDevices,\n useTracks,\n} from '@livekit/components-react';\nimport { Track } from 'livekit-client';\nimport { useCallback } from 'react';\nimport type { UseLocalMediaReturn } from '../types';\nimport { useLatest } from './useLatest';\n\n/**\n * Hook for local media controls (mic, camera, screen share).\n *\n * Must be used within an AvatarSession or AvatarCall component.\n * For use outside the session context, use AvatarSession directly\n * and manage your own loading states.\n */\nexport function useLocalMedia(): UseLocalMediaReturn {\n const { localParticipant } = useLocalParticipant();\n\n const audioDevices = useMediaDevices({ kind: 'audioinput' });\n const videoDevices = useMediaDevices({ kind: 'videoinput' });\n\n const hasMic = audioDevices?.length > 0;\n const hasCamera = videoDevices?.length > 0;\n\n const isMicEnabled = localParticipant?.isMicrophoneEnabled ?? false;\n const isCameraEnabled = localParticipant?.isCameraEnabled ?? false;\n const isScreenShareEnabled = localParticipant?.isScreenShareEnabled ?? false;\n\n const isMicEnabledRef = useLatest(isMicEnabled);\n const isCameraEnabledRef = useLatest(isCameraEnabled);\n const isScreenShareEnabledRef = useLatest(isScreenShareEnabled);\n\n const hasMicRef = useLatest(hasMic);\n const hasCameraRef = useLatest(hasCamera);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: refs from useLatest are stable\n const toggleMic = useCallback(() => {\n if (hasMicRef.current || isMicEnabledRef.current) {\n localParticipant?.setMicrophoneEnabled(!isMicEnabledRef.current);\n }\n }, [localParticipant]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: refs from useLatest are stable\n const toggleCamera = useCallback(() => {\n if (hasCameraRef.current || isCameraEnabledRef.current) {\n localParticipant?.setCameraEnabled(!isCameraEnabledRef.current);\n }\n }, [localParticipant]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: refs from useLatest are stable\n const toggleScreenShare = useCallback(() => {\n localParticipant?.setScreenShareEnabled(!isScreenShareEnabledRef.current);\n }, [localParticipant]);\n\n const tracks = useTracks(\n [{ source: Track.Source.Camera, withPlaceholder: true }],\n {\n onlySubscribed: false,\n updateOnlyOn: [],\n },\n );\n\n const localIdentity = localParticipant?.identity;\n\n const localVideoTrackRef =\n tracks.find(\n (trackRef) =>\n trackRef.participant.identity === localIdentity &&\n trackRef.source === Track.Source.Camera,\n ) ?? null;\n\n return {\n hasMic,\n hasCamera,\n isMicEnabled,\n isCameraEnabled,\n isScreenShareEnabled,\n toggleMic,\n toggleCamera,\n toggleScreenShare,\n localVideoTrackRef,\n };\n}\n","'use client';\n\nimport { TrackToggle } from '@livekit/components-react';\nimport { Track } from 'livekit-client';\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react';\nimport { useAvatarSession } from '../hooks/useAvatarSession';\nimport { useLocalMedia } from '../hooks/useLocalMedia';\n\nexport interface ControlBarState {\n isMicEnabled: boolean;\n isCameraEnabled: boolean;\n isScreenShareEnabled: boolean;\n toggleMic: () => void;\n toggleCamera: () => void;\n toggleScreenShare: () => void;\n endCall: () => Promise<void>;\n isActive: boolean;\n}\n\nexport interface ControlBarProps\n extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {\n showMicrophone?: boolean;\n showCamera?: boolean;\n showScreenShare?: boolean;\n showEndCall?: boolean;\n children?: (state: ControlBarState) => ReactNode;\n}\n\nexport function ControlBar({\n children,\n showMicrophone = true,\n showCamera = true,\n showScreenShare = false,\n showEndCall = true,\n ...props\n}: ControlBarProps) {\n const session = useAvatarSession();\n const {\n isMicEnabled,\n isCameraEnabled,\n isScreenShareEnabled,\n toggleMic,\n toggleCamera,\n toggleScreenShare,\n } = useLocalMedia();\n\n const isActive = session.state === 'active';\n\n const state: ControlBarState = {\n isMicEnabled,\n isCameraEnabled,\n isScreenShareEnabled,\n toggleMic,\n toggleCamera,\n toggleScreenShare,\n endCall: session.end,\n isActive,\n };\n\n if (children) {\n return <>{children(state)}</>;\n }\n\n if (!isActive) {\n return null;\n }\n\n return (\n <div {...props} data-avatar-control-bar=\"\" data-avatar-active={isActive}>\n {showMicrophone && (\n <button\n type=\"button\"\n onClick={toggleMic}\n data-avatar-control=\"microphone\"\n data-avatar-enabled={isMicEnabled}\n aria-label={isMicEnabled ? 'Mute microphone' : 'Unmute microphone'}\n >\n {microphoneIcon}\n </button>\n )}\n {showCamera && (\n <button\n type=\"button\"\n onClick={toggleCamera}\n data-avatar-control=\"camera\"\n data-avatar-enabled={isCameraEnabled}\n aria-label={isCameraEnabled ? 'Turn off camera' : 'Turn on camera'}\n >\n {cameraIcon}\n </button>\n )}\n {showScreenShare && (\n <TrackToggle\n source={Track.Source.ScreenShare}\n showIcon={false}\n data-avatar-control=\"screen-share\"\n data-avatar-enabled={isScreenShareEnabled}\n aria-label=\"Toggle screen share\"\n >\n {screenShareIcon}\n </TrackToggle>\n )}\n {showEndCall && (\n <button\n type=\"button\"\n onClick={session.end}\n data-avatar-control=\"end-call\"\n data-avatar-enabled={true}\n aria-label=\"End call\"\n >\n {phoneIcon}\n </button>\n )}\n </div>\n );\n}\n\n// Lucide icons (https://lucide.dev) - MIT License\nconst microphoneIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\" />\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" />\n <line x1=\"12\" x2=\"12\" y1=\"19\" y2=\"22\" />\n </svg>\n);\n\nconst cameraIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\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\nconst screenShareIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <rect width=\"20\" height=\"14\" x=\"2\" y=\"3\" rx=\"2\" />\n <line x1=\"8\" x2=\"16\" y1=\"21\" y2=\"21\" />\n <line x1=\"12\" x2=\"12\" y1=\"17\" y2=\"21\" />\n </svg>\n);\n\nconst phoneIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"8 14 24 12\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path d=\"M12.8429 22.5693L11.4018 21.0986C11.2675 20.9626 11.1625 20.7995 11.0935 20.6197C11.0245 20.4399 10.9931 20.2474 11.0013 20.0545C11.0094 19.8616 11.0569 19.6726 11.1408 19.4995C11.2247 19.3265 11.343 19.1732 11.4883 19.0495C13.127 17.7049 15.0519 16.7714 17.1083 16.3239C19.0064 15.892 20.9744 15.892 22.8725 16.3239C24.9374 16.7743 26.8693 17.7147 28.5117 19.0691C28.6565 19.1924 28.7746 19.3451 28.8585 19.5176C28.9423 19.69 28.99 19.8784 28.9986 20.0707C29.0072 20.263 28.9764 20.455 28.9083 20.6345C28.8402 20.814 28.7362 20.9771 28.603 21.1133L27.1619 22.584C26.9311 22.8242 26.6226 22.9706 26.2938 22.9959C25.9651 23.0211 25.6385 22.9235 25.3751 22.7212C24.8531 22.3127 24.2875 21.9657 23.689 21.6869C23.4525 21.5774 23.2517 21.4009 23.1103 21.1785C22.969 20.9561 22.8931 20.697 22.8917 20.4319V19.1867C21.0053 18.6573 19.0139 18.6573 17.1275 19.1867V20.4319C17.1261 20.697 17.0502 20.9561 16.9089 21.1785C16.7676 21.4009 16.5667 21.5774 16.3302 21.6869C15.7317 21.9657 15.1661 22.3127 14.6442 22.7212C14.3779 22.9258 14.0473 23.0233 13.7152 22.9953C13.383 22.9673 13.0726 22.8156 12.8429 22.5693Z\" />\n </svg>\n);\n","'use client';\n\nimport { isTrackReference, VideoTrack } from '@livekit/components-react';\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react';\nimport { useLocalMedia } from '../hooks/useLocalMedia';\nimport type { UseLocalMediaReturn } from '../types';\n\nexport interface UserVideoState {\n hasVideo: boolean;\n isCameraEnabled: boolean;\n trackRef: UseLocalMediaReturn['localVideoTrackRef'];\n}\n\nexport interface UserVideoProps\n extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {\n mirror?: boolean;\n children?: (state: UserVideoState) => ReactNode;\n}\n\nexport function UserVideo({\n children,\n mirror = true,\n ...props\n}: UserVideoProps) {\n const { localVideoTrackRef, isCameraEnabled } = useLocalMedia();\n\n const hasVideo =\n localVideoTrackRef !== null && isTrackReference(localVideoTrackRef);\n\n const state: UserVideoState = {\n hasVideo,\n isCameraEnabled,\n trackRef: localVideoTrackRef,\n };\n\n if (children) {\n return <>{children(state)}</>;\n }\n\n return (\n <div\n {...props}\n data-avatar-user-video=\"\"\n data-avatar-has-video={hasVideo}\n data-avatar-camera-enabled={isCameraEnabled}\n data-avatar-mirror={mirror}\n >\n {hasVideo &&\n localVideoTrackRef &&\n isTrackReference(localVideoTrackRef) && (\n <VideoTrack trackRef={localVideoTrackRef} />\n )}\n </div>\n );\n}\n","'use client';\n\n/**\n * AvatarCall Component\n *\n * High-level component that handles the complete session lifecycle.\n * Manages credential fetching, connection, and video display internally\n * with a seamless loading experience.\n *\n * During credential loading, shows a loading state with the avatar image.\n * Once connected, renders children inside the session context.\n *\n * For more control over the loading UI, use AvatarSession directly.\n *\n * @example\n * ```tsx\n * // Simple usage - handles everything automatically\n * <AvatarCall avatarId=\"game-host\" connectUrl=\"/api/avatar/connect\" />\n *\n * // Custom children - rendered once connected\n * <AvatarCall avatarId=\"game-host\" connectUrl=\"/api/avatar/connect\">\n * <AvatarVideo />\n * <ControlBar />\n * </AvatarCall>\n * ```\n */\n\nimport { useCredentials } from '../hooks/useCredentials';\nimport { useLatest } from '../hooks/useLatest';\nimport type { AvatarCallProps } from '../types';\nimport { AvatarSession } from './AvatarSession';\nimport { AvatarVideo } from './AvatarVideo';\nimport { ControlBar } from './ControlBar';\nimport { UserVideo } from './UserVideo';\n\nexport function AvatarCall({\n avatarId,\n sessionId,\n sessionKey,\n credentials: directCredentials,\n connectUrl,\n connect,\n baseUrl,\n avatarImageUrl,\n onEnd,\n onError,\n children,\n __unstable_roomOptions,\n ...props\n}: AvatarCallProps) {\n const onErrorRef = useLatest(onError);\n\n const credentialsState = useCredentials({\n avatarId,\n sessionId,\n sessionKey,\n credentials: directCredentials,\n connectUrl,\n connect,\n baseUrl,\n onError: (err) => onErrorRef.current?.(err),\n });\n\n const handleSessionError = (err: Error) => {\n onErrorRef.current?.(err);\n };\n\n const backgroundStyle = avatarImageUrl\n ? ({ '--avatar-image': `url(${avatarImageUrl})` } as React.CSSProperties)\n : undefined;\n\n const defaultChildren = (\n <>\n <AvatarVideo />\n <UserVideo />\n <ControlBar />\n </>\n );\n\n // During credential loading/error, show a simple loading state\n // Children are NOT rendered here because they may use hooks that require LiveKitRoom context\n if (credentialsState.status !== 'ready') {\n const status =\n credentialsState.status === 'error' ? 'error' : 'connecting';\n\n return (\n <div\n {...props}\n data-avatar-call=\"\"\n data-avatar-id={avatarId}\n style={{ ...props.style, ...backgroundStyle }}\n >\n <div data-avatar-video=\"\" data-avatar-status={status} />\n </div>\n );\n }\n\n // Once credentials are ready, render children inside the session context\n // This ensures all hooks have access to the LiveKitRoom context\n return (\n <div\n {...props}\n data-avatar-call=\"\"\n data-avatar-id={avatarId}\n style={{ ...props.style, ...backgroundStyle }}\n >\n <AvatarSession\n credentials={credentialsState.credentials}\n onEnd={onEnd}\n onError={handleSessionError}\n __unstable_roomOptions={__unstable_roomOptions}\n >\n {children ?? defaultChildren}\n </AvatarSession>\n </div>\n );\n}\n","'use client';\n\nimport {\n isTrackReference,\n type TrackReferenceOrPlaceholder,\n useLocalParticipant,\n useTracks,\n VideoTrack,\n} from '@livekit/components-react';\nimport { Track } from 'livekit-client';\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react';\n\nexport interface ScreenShareVideoState {\n isSharing: boolean;\n trackRef: TrackReferenceOrPlaceholder | null;\n}\n\nexport interface ScreenShareVideoProps\n extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {\n children?: (state: ScreenShareVideoState) => ReactNode;\n}\n\n/**\n * Component for displaying local screen share video.\n *\n * Must be used within an AvatarSession or AvatarCall component.\n */\nexport function ScreenShareVideo({\n children,\n ...props\n}: ScreenShareVideoProps) {\n const { localParticipant } = useLocalParticipant();\n\n const tracks = useTracks(\n [{ source: Track.Source.ScreenShare, withPlaceholder: false }],\n { onlySubscribed: false },\n );\n\n const localIdentity = localParticipant?.identity;\n\n const screenShareTrackRef =\n tracks.find(\n (trackRef) =>\n trackRef.participant.identity === localIdentity &&\n trackRef.source === Track.Source.ScreenShare,\n ) ?? null;\n\n const isSharing =\n screenShareTrackRef !== null && isTrackReference(screenShareTrackRef);\n\n const state: ScreenShareVideoState = {\n isSharing,\n trackRef: screenShareTrackRef,\n };\n\n if (children) {\n return <>{children(state)}</>;\n }\n\n if (!isSharing) {\n return null;\n }\n\n return (\n <div {...props} data-avatar-screen-share=\"\" data-avatar-sharing={isSharing}>\n {screenShareTrackRef && isTrackReference(screenShareTrackRef) && (\n <VideoTrack trackRef={screenShareTrackRef} />\n )}\n </div>\n );\n}\n"]}
package/dist/styles.css CHANGED
@@ -31,9 +31,16 @@
31
31
  filter: blur(20px) brightness(0.5);
32
32
  transform: scale(1.1);
33
33
  z-index: -1;
34
+ transition: opacity 0.3s ease;
35
+ }
36
+ [data-avatar-call]:has([data-avatar-video][data-avatar-status=ready])::before {
37
+ opacity: 0;
38
+ pointer-events: none;
34
39
  }
35
40
  [data-avatar-video] {
36
41
  flex: 1;
42
+ width: 100%;
43
+ min-height: 0;
37
44
  display: flex;
38
45
  align-items: center;
39
46
  justify-content: center;
@@ -139,6 +146,27 @@
139
146
  [data-avatar-user-video][data-avatar-mirror=true] video {
140
147
  transform: scaleX(-1);
141
148
  }
149
+ [data-avatar-user-video][data-avatar-has-video=false]::before {
150
+ content: "";
151
+ position: absolute;
152
+ top: 50%;
153
+ left: 50%;
154
+ transform: translate(-50%, -50%);
155
+ width: 40%;
156
+ height: 40%;
157
+ background-color: var(--avatar-text-secondary);
158
+ mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3E%3Cpath d='M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z'/%3E%3C/svg%3E");
159
+ mask-size: contain;
160
+ mask-repeat: no-repeat;
161
+ mask-position: center;
162
+ -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3E%3Cpath d='M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z'/%3E%3C/svg%3E");
163
+ -webkit-mask-size: contain;
164
+ -webkit-mask-repeat: no-repeat;
165
+ -webkit-mask-position: center;
166
+ }
167
+ [data-avatar-user-video][data-avatar-camera-enabled=false] {
168
+ display: none;
169
+ }
142
170
  [data-avatar-screen-share] {
143
171
  position: absolute;
144
172
  inset: 0;
@@ -158,6 +186,30 @@
158
186
  opacity: 0.5;
159
187
  }
160
188
  }
189
+ [data-avatar-call]:has([data-avatar-video][data-avatar-status=connecting])::after,
190
+ [data-avatar-call]:has([data-avatar-video][data-avatar-status=waiting])::after {
191
+ content: "";
192
+ position: absolute;
193
+ top: 50%;
194
+ left: 50%;
195
+ transform: translate(-50%, -50%);
196
+ width: 48px;
197
+ height: 48px;
198
+ border: 3px solid rgba(255, 255, 255, 0.2);
199
+ border-top-color: rgba(255, 255, 255, 0.8);
200
+ border-radius: 50%;
201
+ animation: avatar-spin 0.8s linear infinite;
202
+ z-index: 3;
203
+ pointer-events: none;
204
+ }
205
+ @keyframes avatar-spin {
206
+ from {
207
+ transform: translate(-50%, -50%) rotate(0deg);
208
+ }
209
+ to {
210
+ transform: translate(-50%, -50%) rotate(360deg);
211
+ }
212
+ }
161
213
  [data-avatar-video][data-avatar-status=connecting]::after,
162
214
  [data-avatar-video][data-avatar-status=waiting]::after {
163
215
  content: "";
@@ -167,12 +219,14 @@
167
219
  linear-gradient(
168
220
  90deg,
169
221
  transparent,
170
- rgba(255, 255, 255, 0.05),
222
+ rgba(255, 255, 255, 0.03),
171
223
  transparent);
172
224
  background-size: 200% 100%;
173
225
  animation: avatar-pulse 2s ease-in-out infinite;
174
226
  }
175
227
  @media (prefers-reduced-motion: reduce) {
228
+ [data-avatar-call]:has([data-avatar-video][data-avatar-status=connecting])::after,
229
+ [data-avatar-call]:has([data-avatar-video][data-avatar-status=waiting])::after,
176
230
  [data-avatar-video][data-avatar-status=connecting]::after,
177
231
  [data-avatar-video][data-avatar-status=waiting]::after {
178
232
  animation: none;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runwayml/avatars-react",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "React SDK for real-time AI avatar interactions with GWM-1",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -53,7 +53,9 @@
53
53
  "lint:fix": "biome lint --write src/",
54
54
  "format": "biome format --write src/",
55
55
  "check": "biome check src/",
56
- "typecheck": "tsc --noEmit"
56
+ "typecheck": "tsc --noEmit",
57
+ "example:link": "bun run build && bun link && cd examples/react-router && bun link @runwayml/avatars-react",
58
+ "example:dev": "bun run example:link && cd examples/react-router && bun run dev"
57
59
  },
58
60
  "keywords": [
59
61
  "runwayml",