@reactor-team/js-sdk 2.3.2 → 2.5.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.d.mts CHANGED
@@ -9,6 +9,81 @@ type ReactorStatus = "disconnected" | "connecting" | "waiting" | "ready";
9
9
  * - "runtime": platform-level control messages (e.g., capabilities exchange).
10
10
  */
11
11
  type MessageScope = "application" | "runtime";
12
+ /**
13
+ * Describes a single named media track for SDP negotiation.
14
+ *
15
+ * Track names must exactly match the class attribute names defined on the
16
+ * model's Python code. The name is encoded as the SDP MID so both sides
17
+ * can route media by name rather than by positional index.
18
+ *
19
+ * Use the {@link video} and {@link audio} helper functions to create
20
+ * instances instead of constructing this interface directly.
21
+ */
22
+ interface TrackConfig {
23
+ name: string;
24
+ kind: "audio" | "video";
25
+ }
26
+ /**
27
+ * Optional configuration for a video track (reserved for future use).
28
+ */
29
+ interface VideoTrackOptions {
30
+ /** Maximum framerate constraint for the video track. */
31
+ maxFramerate?: number;
32
+ }
33
+ /**
34
+ * Optional configuration for an audio track (reserved for future use).
35
+ */
36
+ interface AudioTrackOptions {
37
+ /** Sample rate constraint for the audio track. */
38
+ sampleRate?: number;
39
+ }
40
+ /**
41
+ * Creates a **video** {@link TrackConfig}.
42
+ *
43
+ * A track declared in the **`receive`** array means the client will
44
+ * **RECEIVE** video frames **from the model** (model → client).
45
+ *
46
+ * A track declared in the **`send`** array means the client will
47
+ * **SEND** video frames **to the model** (client → model).
48
+ *
49
+ * Track names must be unique across both arrays — the same name cannot
50
+ * appear in `receive` and `send`.
51
+ *
52
+ * @param name - The track name. Must match the model's declared track attribute name.
53
+ * @param options - Reserved for future constraints (e.g. `maxFramerate`).
54
+ *
55
+ * When no `receive` array is provided to the Reactor constructor, a single
56
+ * `video("main_video")` track is used by default.
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * receive: [video("main_video")] // receive video from the model
61
+ * send: [video("webcam")] // send webcam video to the model
62
+ * ```
63
+ */
64
+ declare function video(name: string, _options?: VideoTrackOptions): TrackConfig;
65
+ /**
66
+ * Creates an **audio** {@link TrackConfig}.
67
+ *
68
+ * A track declared in the **`receive`** array means the client will
69
+ * **RECEIVE** audio samples **from the model** (model → client).
70
+ *
71
+ * A track declared in the **`send`** array means the client will
72
+ * **SEND** audio samples **to the model** (client → model).
73
+ *
74
+ * Track names must be unique across both arrays — the same name cannot
75
+ * appear in `receive` and `send`.
76
+ *
77
+ * @param name - The track name. Must match the model's declared track attribute name.
78
+ * @param options - Reserved for future constraints (e.g. `sampleRate`).
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * receive: [audio("main_audio")] // receive audio from the model
83
+ * send: [audio("mic")] // send microphone audio to the model
84
+ * ```
85
+ */
86
+ declare function audio(name: string, _options?: AudioTrackOptions): TrackConfig;
12
87
  interface ReactorError {
13
88
  code: string;
14
89
  message: string;
@@ -31,13 +106,42 @@ interface ConnectOptions {
31
106
  /** Maximum number of SDP polling attempts before giving up. Default: 6. */
32
107
  maxAttempts?: number;
33
108
  }
34
- type ReactorEvent = "statusChanged" | "sessionIdChanged" | "newMessage" | "streamChanged" | "error" | "sessionExpirationChanged";
109
+ interface ConnectionStats {
110
+ /** ICE candidate-pair round-trip time in milliseconds */
111
+ rtt?: number;
112
+ /** ICE candidate type: "host", "srflx", "prflx", or "relay" (TURN) */
113
+ candidateType?: string;
114
+ /** Estimated available outgoing bitrate in bits/second */
115
+ availableOutgoingBitrate?: number;
116
+ /** Received video frames per second */
117
+ framesPerSecond?: number;
118
+ /** Ratio of packets lost (0-1) */
119
+ packetLossRatio?: number;
120
+ /** Network jitter in seconds (from inbound-rtp) */
121
+ jitter?: number;
122
+ timestamp: number;
123
+ }
124
+ type ReactorEvent = "statusChanged" | "sessionIdChanged" | "message" | "runtimeMessage" | "trackReceived" | "error" | "sessionExpirationChanged" | "statsUpdate";
35
125
 
36
126
  declare const PROD_COORDINATOR_URL = "https://api.reactor.inc";
37
127
  declare const OptionsSchema: z.ZodObject<{
38
128
  coordinatorUrl: z.ZodDefault<z.ZodString>;
39
129
  modelName: z.ZodString;
40
130
  local: z.ZodDefault<z.ZodBoolean>;
131
+ receive: z.ZodDefault<z.ZodArray<z.ZodObject<{
132
+ name: z.ZodString;
133
+ kind: z.ZodEnum<{
134
+ audio: "audio";
135
+ video: "video";
136
+ }>;
137
+ }, z.core.$strip>>>;
138
+ send: z.ZodDefault<z.ZodArray<z.ZodObject<{
139
+ name: z.ZodString;
140
+ kind: z.ZodEnum<{
141
+ audio: "audio";
142
+ video: "video";
143
+ }>;
144
+ }, z.core.$strip>>>;
41
145
  }, z.core.$strip>;
42
146
  type Options = z.input<typeof OptionsSchema>;
43
147
  type EventHandler = (...args: any[]) => void;
@@ -50,6 +154,10 @@ declare class Reactor {
50
154
  private model;
51
155
  private sessionExpiration?;
52
156
  private local;
157
+ /** Tracks the client RECEIVES from the model (model → client). */
158
+ private receive;
159
+ /** Tracks the client SENDS to the model (client → model). */
160
+ private send;
53
161
  private sessionId?;
54
162
  constructor(options: Options);
55
163
  private eventListeners;
@@ -57,24 +165,26 @@ declare class Reactor {
57
165
  off(event: ReactorEvent, handler: EventHandler): void;
58
166
  emit(event: ReactorEvent, ...args: any[]): void;
59
167
  /**
60
- * Public method to send a message to the machine.
61
- * Wraps the message in the specified channel envelope (defaults to "application").
62
- * @param command The command name to send.
168
+ * Sends a command to the model via the data channel.
169
+ *
170
+ * @param command The command name.
63
171
  * @param data The command payload.
64
- * @param scope The envelope scope – "application" (default) for model commands,
65
- * "runtime" for platform-level messages (e.g. requestCapabilities).
66
- * @throws Error if not in ready state
172
+ * @param scope "application" (default) for model commands, "runtime" for platform messages.
67
173
  */
68
174
  sendCommand(command: string, data: any, scope?: MessageScope): Promise<void>;
69
175
  /**
70
- * Public method to publish a track to the machine.
71
- * @param track The track to send to the machine.
176
+ * Publishes a MediaStreamTrack to a named send track.
177
+ *
178
+ * @param name The declared send track name (e.g. "webcam").
179
+ * @param track The MediaStreamTrack to publish.
72
180
  */
73
- publishTrack(track: MediaStreamTrack): Promise<void>;
181
+ publishTrack(name: string, track: MediaStreamTrack): Promise<void>;
74
182
  /**
75
- * Public method to unpublish the currently published track.
183
+ * Unpublishes the track with the given name.
184
+ *
185
+ * @param name The declared send track name to unpublish.
76
186
  */
77
- unpublishTrack(): Promise<void>;
187
+ unpublishTrack(name: string): Promise<void>;
78
188
  /**
79
189
  * Public method for reconnecting to an existing session, that may have been interrupted but can be recovered.
80
190
  * @param options Optional connect options (e.g. maxAttempts for SDP polling)
@@ -114,6 +224,7 @@ declare class Reactor {
114
224
  * Get the last error that occurred
115
225
  */
116
226
  getLastError(): ReactorError | undefined;
227
+ getStats(): ConnectionStats | undefined;
117
228
  /**
118
229
  * Create and store an error
119
230
  */
@@ -122,19 +233,24 @@ declare class Reactor {
122
233
 
123
234
  interface ReactorState {
124
235
  status: ReactorStatus;
125
- videoTrack: MediaStreamTrack | null;
236
+ /**
237
+ * Media tracks received from the model, keyed by track name.
238
+ *
239
+ * Each entry maps a declared **receive** track name (e.g. `"main_video"`,
240
+ * `"main_audio"`) to the live `MediaStreamTrack` delivered by the model.
241
+ */
242
+ tracks: Record<string, MediaStreamTrack>;
126
243
  lastError?: ReactorError;
127
244
  sessionId?: string;
128
245
  sessionExpiration?: number;
129
- insecureApiKey?: string;
130
246
  jwtToken?: string;
131
247
  }
132
248
  interface ReactorActions {
133
249
  sendCommand(command: string, data: any, scope?: MessageScope): Promise<void>;
134
250
  connect(jwtToken?: string, options?: ConnectOptions): Promise<void>;
135
251
  disconnect(recoverable?: boolean): Promise<void>;
136
- publishVideoStream(stream: MediaStream): Promise<void>;
137
- unpublishVideoStream(): Promise<void>;
252
+ publish(name: string, track: MediaStreamTrack): Promise<void>;
253
+ unpublish(name: string): Promise<void>;
138
254
  reconnect(options?: ConnectOptions): Promise<void>;
139
255
  }
140
256
  interface ReactorInternalState {
@@ -164,13 +280,26 @@ declare function ReactorProvider({ children, connectOptions, jwtToken, ...props
164
280
  declare function useReactorStore<T = ReactorStore>(selector: (state: ReactorStore) => T): T;
165
281
 
166
282
  interface ReactorViewProps {
283
+ /**
284
+ * The name of the **receive** track to render.
285
+ * Must match a track name declared in the `receive` array (model → client).
286
+ * Defaults to `"main_video"`.
287
+ */
288
+ track?: string;
289
+ /**
290
+ * Optional name of a **receive** audio track to play alongside the video
291
+ * (e.g. `"main_audio"`). The audio is mixed into the same `<video>` element.
292
+ */
293
+ audioTrack?: string;
167
294
  width?: number;
168
295
  height?: number;
169
296
  className?: string;
170
297
  style?: React.CSSProperties;
171
298
  videoObjectFit?: NonNullable<React.VideoHTMLAttributes<HTMLVideoElement>["style"]>["objectFit"];
299
+ /** Controls whether inbound audio plays. Default true (muted) to satisfy browser autoplay policies. */
300
+ muted?: boolean;
172
301
  }
173
- declare function ReactorView({ width, height, className, style, videoObjectFit, }: ReactorViewProps): react_jsx_runtime.JSX.Element;
302
+ declare function ReactorView({ track, audioTrack, width, height, className, style, videoObjectFit, muted, }: ReactorViewProps): react_jsx_runtime.JSX.Element;
174
303
 
175
304
  interface ReactorControllerProps {
176
305
  className?: string;
@@ -178,14 +307,19 @@ interface ReactorControllerProps {
178
307
  }
179
308
  declare function ReactorController({ className, style, }: ReactorControllerProps): react_jsx_runtime.JSX.Element;
180
309
 
181
- interface Props {
310
+ interface WebcamStreamProps {
311
+ /**
312
+ * The name of the **send** track to publish the webcam to.
313
+ * Must match a track name declared in the `send` array (client → model).
314
+ */
315
+ track: string;
182
316
  className?: string;
183
317
  style?: React.CSSProperties;
184
318
  videoConstraints?: MediaTrackConstraints;
185
319
  showWebcam?: boolean;
186
320
  videoObjectFit?: NonNullable<React.VideoHTMLAttributes<HTMLVideoElement>["style"]>["objectFit"];
187
321
  }
188
- declare function WebcamStream({ className, style, videoConstraints, showWebcam, videoObjectFit, }: Props): react_jsx_runtime.JSX.Element;
322
+ declare function WebcamStream({ track, className, style, videoConstraints, showWebcam, videoObjectFit, }: WebcamStreamProps): react_jsx_runtime.JSX.Element;
189
323
 
190
324
  /**
191
325
  * Generic hook for accessing selected parts of the Reactor store.
@@ -195,15 +329,30 @@ declare function WebcamStream({ className, style, videoConstraints, showWebcam,
195
329
  */
196
330
  declare function useReactor<T>(selector: (state: ReactorStore) => T): T;
197
331
  /**
198
- * Hook for handling message subscriptions with proper React lifecycle management.
332
+ * Hook for receiving model application messages.
333
+ *
334
+ * Only fires for messages sent by the model via `get_ctx().send()`.
335
+ * Internal platform-level messages (e.g. capabilities) are NOT delivered here.
336
+ *
337
+ * @param handler - Callback invoked with each application message payload.
338
+ */
339
+ declare function useReactorMessage(handler: (message: any) => void): void;
340
+ /**
341
+ * Hook for receiving internal platform-level (runtime) messages.
199
342
  *
200
- * The handler receives the message payload and the scope it arrived on:
201
- * - "application" for model-defined messages (via get_ctx().send())
202
- * - "runtime" for platform-level messages (e.g., capabilities response)
343
+ * This is intended for advanced use cases that need access to the runtime
344
+ * control layer, such as capabilities negotiation. Model application messages
345
+ * sent via `get_ctx().send()` are NOT delivered through this hook — use
346
+ * {@link useReactorMessage} for those.
203
347
  *
204
- * @param handler - The message handler function (message, scope)
348
+ * @param handler - Callback invoked with each runtime message payload.
349
+ */
350
+ declare function useReactorInternalMessage(handler: (message: any) => void): void;
351
+ /**
352
+ * Hook that returns the current connection stats (RTT, etc.).
353
+ * Updates every ~2s while connected. Returns undefined when disconnected.
205
354
  */
206
- declare function useReactorMessage(handler: (message: any, scope: MessageScope) => void): void;
355
+ declare function useStats(): ConnectionStats | undefined;
207
356
 
208
357
  /**
209
358
  * ⚠️ INSECURE: Fetches a JWT token directly from the client.
@@ -218,4 +367,4 @@ declare function useReactorMessage(handler: (message: any, scope: MessageScope)
218
367
  */
219
368
  declare function fetchInsecureJwtToken(apiKey: string, coordinatorUrl?: string): Promise<string>;
220
369
 
221
- export { ConflictError, type ConnectOptions, type MessageScope, type Options, PROD_COORDINATOR_URL, Reactor, type ReactorConnectOptions, ReactorController, type ReactorControllerProps, type ReactorError, type ReactorEvent, ReactorProvider, type ReactorState$1 as ReactorState, type ReactorStatus, ReactorView, type ReactorViewProps, WebcamStream, fetchInsecureJwtToken, useReactor, useReactorMessage, useReactorStore };
370
+ export { type AudioTrackOptions, ConflictError, type ConnectOptions, type ConnectionStats, type MessageScope, type Options, PROD_COORDINATOR_URL, Reactor, type ReactorConnectOptions, ReactorController, type ReactorControllerProps, type ReactorError, type ReactorEvent, ReactorProvider, type ReactorState$1 as ReactorState, type ReactorStatus, ReactorView, type ReactorViewProps, type TrackConfig, type VideoTrackOptions, WebcamStream, type WebcamStreamProps, audio, fetchInsecureJwtToken, useReactor, useReactorInternalMessage, useReactorMessage, useReactorStore, useStats, video };
package/dist/index.d.ts CHANGED
@@ -9,6 +9,81 @@ type ReactorStatus = "disconnected" | "connecting" | "waiting" | "ready";
9
9
  * - "runtime": platform-level control messages (e.g., capabilities exchange).
10
10
  */
11
11
  type MessageScope = "application" | "runtime";
12
+ /**
13
+ * Describes a single named media track for SDP negotiation.
14
+ *
15
+ * Track names must exactly match the class attribute names defined on the
16
+ * model's Python code. The name is encoded as the SDP MID so both sides
17
+ * can route media by name rather than by positional index.
18
+ *
19
+ * Use the {@link video} and {@link audio} helper functions to create
20
+ * instances instead of constructing this interface directly.
21
+ */
22
+ interface TrackConfig {
23
+ name: string;
24
+ kind: "audio" | "video";
25
+ }
26
+ /**
27
+ * Optional configuration for a video track (reserved for future use).
28
+ */
29
+ interface VideoTrackOptions {
30
+ /** Maximum framerate constraint for the video track. */
31
+ maxFramerate?: number;
32
+ }
33
+ /**
34
+ * Optional configuration for an audio track (reserved for future use).
35
+ */
36
+ interface AudioTrackOptions {
37
+ /** Sample rate constraint for the audio track. */
38
+ sampleRate?: number;
39
+ }
40
+ /**
41
+ * Creates a **video** {@link TrackConfig}.
42
+ *
43
+ * A track declared in the **`receive`** array means the client will
44
+ * **RECEIVE** video frames **from the model** (model → client).
45
+ *
46
+ * A track declared in the **`send`** array means the client will
47
+ * **SEND** video frames **to the model** (client → model).
48
+ *
49
+ * Track names must be unique across both arrays — the same name cannot
50
+ * appear in `receive` and `send`.
51
+ *
52
+ * @param name - The track name. Must match the model's declared track attribute name.
53
+ * @param options - Reserved for future constraints (e.g. `maxFramerate`).
54
+ *
55
+ * When no `receive` array is provided to the Reactor constructor, a single
56
+ * `video("main_video")` track is used by default.
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * receive: [video("main_video")] // receive video from the model
61
+ * send: [video("webcam")] // send webcam video to the model
62
+ * ```
63
+ */
64
+ declare function video(name: string, _options?: VideoTrackOptions): TrackConfig;
65
+ /**
66
+ * Creates an **audio** {@link TrackConfig}.
67
+ *
68
+ * A track declared in the **`receive`** array means the client will
69
+ * **RECEIVE** audio samples **from the model** (model → client).
70
+ *
71
+ * A track declared in the **`send`** array means the client will
72
+ * **SEND** audio samples **to the model** (client → model).
73
+ *
74
+ * Track names must be unique across both arrays — the same name cannot
75
+ * appear in `receive` and `send`.
76
+ *
77
+ * @param name - The track name. Must match the model's declared track attribute name.
78
+ * @param options - Reserved for future constraints (e.g. `sampleRate`).
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * receive: [audio("main_audio")] // receive audio from the model
83
+ * send: [audio("mic")] // send microphone audio to the model
84
+ * ```
85
+ */
86
+ declare function audio(name: string, _options?: AudioTrackOptions): TrackConfig;
12
87
  interface ReactorError {
13
88
  code: string;
14
89
  message: string;
@@ -31,13 +106,42 @@ interface ConnectOptions {
31
106
  /** Maximum number of SDP polling attempts before giving up. Default: 6. */
32
107
  maxAttempts?: number;
33
108
  }
34
- type ReactorEvent = "statusChanged" | "sessionIdChanged" | "newMessage" | "streamChanged" | "error" | "sessionExpirationChanged";
109
+ interface ConnectionStats {
110
+ /** ICE candidate-pair round-trip time in milliseconds */
111
+ rtt?: number;
112
+ /** ICE candidate type: "host", "srflx", "prflx", or "relay" (TURN) */
113
+ candidateType?: string;
114
+ /** Estimated available outgoing bitrate in bits/second */
115
+ availableOutgoingBitrate?: number;
116
+ /** Received video frames per second */
117
+ framesPerSecond?: number;
118
+ /** Ratio of packets lost (0-1) */
119
+ packetLossRatio?: number;
120
+ /** Network jitter in seconds (from inbound-rtp) */
121
+ jitter?: number;
122
+ timestamp: number;
123
+ }
124
+ type ReactorEvent = "statusChanged" | "sessionIdChanged" | "message" | "runtimeMessage" | "trackReceived" | "error" | "sessionExpirationChanged" | "statsUpdate";
35
125
 
36
126
  declare const PROD_COORDINATOR_URL = "https://api.reactor.inc";
37
127
  declare const OptionsSchema: z.ZodObject<{
38
128
  coordinatorUrl: z.ZodDefault<z.ZodString>;
39
129
  modelName: z.ZodString;
40
130
  local: z.ZodDefault<z.ZodBoolean>;
131
+ receive: z.ZodDefault<z.ZodArray<z.ZodObject<{
132
+ name: z.ZodString;
133
+ kind: z.ZodEnum<{
134
+ audio: "audio";
135
+ video: "video";
136
+ }>;
137
+ }, z.core.$strip>>>;
138
+ send: z.ZodDefault<z.ZodArray<z.ZodObject<{
139
+ name: z.ZodString;
140
+ kind: z.ZodEnum<{
141
+ audio: "audio";
142
+ video: "video";
143
+ }>;
144
+ }, z.core.$strip>>>;
41
145
  }, z.core.$strip>;
42
146
  type Options = z.input<typeof OptionsSchema>;
43
147
  type EventHandler = (...args: any[]) => void;
@@ -50,6 +154,10 @@ declare class Reactor {
50
154
  private model;
51
155
  private sessionExpiration?;
52
156
  private local;
157
+ /** Tracks the client RECEIVES from the model (model → client). */
158
+ private receive;
159
+ /** Tracks the client SENDS to the model (client → model). */
160
+ private send;
53
161
  private sessionId?;
54
162
  constructor(options: Options);
55
163
  private eventListeners;
@@ -57,24 +165,26 @@ declare class Reactor {
57
165
  off(event: ReactorEvent, handler: EventHandler): void;
58
166
  emit(event: ReactorEvent, ...args: any[]): void;
59
167
  /**
60
- * Public method to send a message to the machine.
61
- * Wraps the message in the specified channel envelope (defaults to "application").
62
- * @param command The command name to send.
168
+ * Sends a command to the model via the data channel.
169
+ *
170
+ * @param command The command name.
63
171
  * @param data The command payload.
64
- * @param scope The envelope scope – "application" (default) for model commands,
65
- * "runtime" for platform-level messages (e.g. requestCapabilities).
66
- * @throws Error if not in ready state
172
+ * @param scope "application" (default) for model commands, "runtime" for platform messages.
67
173
  */
68
174
  sendCommand(command: string, data: any, scope?: MessageScope): Promise<void>;
69
175
  /**
70
- * Public method to publish a track to the machine.
71
- * @param track The track to send to the machine.
176
+ * Publishes a MediaStreamTrack to a named send track.
177
+ *
178
+ * @param name The declared send track name (e.g. "webcam").
179
+ * @param track The MediaStreamTrack to publish.
72
180
  */
73
- publishTrack(track: MediaStreamTrack): Promise<void>;
181
+ publishTrack(name: string, track: MediaStreamTrack): Promise<void>;
74
182
  /**
75
- * Public method to unpublish the currently published track.
183
+ * Unpublishes the track with the given name.
184
+ *
185
+ * @param name The declared send track name to unpublish.
76
186
  */
77
- unpublishTrack(): Promise<void>;
187
+ unpublishTrack(name: string): Promise<void>;
78
188
  /**
79
189
  * Public method for reconnecting to an existing session, that may have been interrupted but can be recovered.
80
190
  * @param options Optional connect options (e.g. maxAttempts for SDP polling)
@@ -114,6 +224,7 @@ declare class Reactor {
114
224
  * Get the last error that occurred
115
225
  */
116
226
  getLastError(): ReactorError | undefined;
227
+ getStats(): ConnectionStats | undefined;
117
228
  /**
118
229
  * Create and store an error
119
230
  */
@@ -122,19 +233,24 @@ declare class Reactor {
122
233
 
123
234
  interface ReactorState {
124
235
  status: ReactorStatus;
125
- videoTrack: MediaStreamTrack | null;
236
+ /**
237
+ * Media tracks received from the model, keyed by track name.
238
+ *
239
+ * Each entry maps a declared **receive** track name (e.g. `"main_video"`,
240
+ * `"main_audio"`) to the live `MediaStreamTrack` delivered by the model.
241
+ */
242
+ tracks: Record<string, MediaStreamTrack>;
126
243
  lastError?: ReactorError;
127
244
  sessionId?: string;
128
245
  sessionExpiration?: number;
129
- insecureApiKey?: string;
130
246
  jwtToken?: string;
131
247
  }
132
248
  interface ReactorActions {
133
249
  sendCommand(command: string, data: any, scope?: MessageScope): Promise<void>;
134
250
  connect(jwtToken?: string, options?: ConnectOptions): Promise<void>;
135
251
  disconnect(recoverable?: boolean): Promise<void>;
136
- publishVideoStream(stream: MediaStream): Promise<void>;
137
- unpublishVideoStream(): Promise<void>;
252
+ publish(name: string, track: MediaStreamTrack): Promise<void>;
253
+ unpublish(name: string): Promise<void>;
138
254
  reconnect(options?: ConnectOptions): Promise<void>;
139
255
  }
140
256
  interface ReactorInternalState {
@@ -164,13 +280,26 @@ declare function ReactorProvider({ children, connectOptions, jwtToken, ...props
164
280
  declare function useReactorStore<T = ReactorStore>(selector: (state: ReactorStore) => T): T;
165
281
 
166
282
  interface ReactorViewProps {
283
+ /**
284
+ * The name of the **receive** track to render.
285
+ * Must match a track name declared in the `receive` array (model → client).
286
+ * Defaults to `"main_video"`.
287
+ */
288
+ track?: string;
289
+ /**
290
+ * Optional name of a **receive** audio track to play alongside the video
291
+ * (e.g. `"main_audio"`). The audio is mixed into the same `<video>` element.
292
+ */
293
+ audioTrack?: string;
167
294
  width?: number;
168
295
  height?: number;
169
296
  className?: string;
170
297
  style?: React.CSSProperties;
171
298
  videoObjectFit?: NonNullable<React.VideoHTMLAttributes<HTMLVideoElement>["style"]>["objectFit"];
299
+ /** Controls whether inbound audio plays. Default true (muted) to satisfy browser autoplay policies. */
300
+ muted?: boolean;
172
301
  }
173
- declare function ReactorView({ width, height, className, style, videoObjectFit, }: ReactorViewProps): react_jsx_runtime.JSX.Element;
302
+ declare function ReactorView({ track, audioTrack, width, height, className, style, videoObjectFit, muted, }: ReactorViewProps): react_jsx_runtime.JSX.Element;
174
303
 
175
304
  interface ReactorControllerProps {
176
305
  className?: string;
@@ -178,14 +307,19 @@ interface ReactorControllerProps {
178
307
  }
179
308
  declare function ReactorController({ className, style, }: ReactorControllerProps): react_jsx_runtime.JSX.Element;
180
309
 
181
- interface Props {
310
+ interface WebcamStreamProps {
311
+ /**
312
+ * The name of the **send** track to publish the webcam to.
313
+ * Must match a track name declared in the `send` array (client → model).
314
+ */
315
+ track: string;
182
316
  className?: string;
183
317
  style?: React.CSSProperties;
184
318
  videoConstraints?: MediaTrackConstraints;
185
319
  showWebcam?: boolean;
186
320
  videoObjectFit?: NonNullable<React.VideoHTMLAttributes<HTMLVideoElement>["style"]>["objectFit"];
187
321
  }
188
- declare function WebcamStream({ className, style, videoConstraints, showWebcam, videoObjectFit, }: Props): react_jsx_runtime.JSX.Element;
322
+ declare function WebcamStream({ track, className, style, videoConstraints, showWebcam, videoObjectFit, }: WebcamStreamProps): react_jsx_runtime.JSX.Element;
189
323
 
190
324
  /**
191
325
  * Generic hook for accessing selected parts of the Reactor store.
@@ -195,15 +329,30 @@ declare function WebcamStream({ className, style, videoConstraints, showWebcam,
195
329
  */
196
330
  declare function useReactor<T>(selector: (state: ReactorStore) => T): T;
197
331
  /**
198
- * Hook for handling message subscriptions with proper React lifecycle management.
332
+ * Hook for receiving model application messages.
333
+ *
334
+ * Only fires for messages sent by the model via `get_ctx().send()`.
335
+ * Internal platform-level messages (e.g. capabilities) are NOT delivered here.
336
+ *
337
+ * @param handler - Callback invoked with each application message payload.
338
+ */
339
+ declare function useReactorMessage(handler: (message: any) => void): void;
340
+ /**
341
+ * Hook for receiving internal platform-level (runtime) messages.
199
342
  *
200
- * The handler receives the message payload and the scope it arrived on:
201
- * - "application" for model-defined messages (via get_ctx().send())
202
- * - "runtime" for platform-level messages (e.g., capabilities response)
343
+ * This is intended for advanced use cases that need access to the runtime
344
+ * control layer, such as capabilities negotiation. Model application messages
345
+ * sent via `get_ctx().send()` are NOT delivered through this hook — use
346
+ * {@link useReactorMessage} for those.
203
347
  *
204
- * @param handler - The message handler function (message, scope)
348
+ * @param handler - Callback invoked with each runtime message payload.
349
+ */
350
+ declare function useReactorInternalMessage(handler: (message: any) => void): void;
351
+ /**
352
+ * Hook that returns the current connection stats (RTT, etc.).
353
+ * Updates every ~2s while connected. Returns undefined when disconnected.
205
354
  */
206
- declare function useReactorMessage(handler: (message: any, scope: MessageScope) => void): void;
355
+ declare function useStats(): ConnectionStats | undefined;
207
356
 
208
357
  /**
209
358
  * ⚠️ INSECURE: Fetches a JWT token directly from the client.
@@ -218,4 +367,4 @@ declare function useReactorMessage(handler: (message: any, scope: MessageScope)
218
367
  */
219
368
  declare function fetchInsecureJwtToken(apiKey: string, coordinatorUrl?: string): Promise<string>;
220
369
 
221
- export { ConflictError, type ConnectOptions, type MessageScope, type Options, PROD_COORDINATOR_URL, Reactor, type ReactorConnectOptions, ReactorController, type ReactorControllerProps, type ReactorError, type ReactorEvent, ReactorProvider, type ReactorState$1 as ReactorState, type ReactorStatus, ReactorView, type ReactorViewProps, WebcamStream, fetchInsecureJwtToken, useReactor, useReactorMessage, useReactorStore };
370
+ export { type AudioTrackOptions, ConflictError, type ConnectOptions, type ConnectionStats, type MessageScope, type Options, PROD_COORDINATOR_URL, Reactor, type ReactorConnectOptions, ReactorController, type ReactorControllerProps, type ReactorError, type ReactorEvent, ReactorProvider, type ReactorState$1 as ReactorState, type ReactorStatus, ReactorView, type ReactorViewProps, type TrackConfig, type VideoTrackOptions, WebcamStream, type WebcamStreamProps, audio, fetchInsecureJwtToken, useReactor, useReactorInternalMessage, useReactorMessage, useReactorStore, useStats, video };