@reactor-team/js-sdk 2.6.0 → 2.8.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
@@ -2,6 +2,90 @@ import { z } from 'zod';
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
3
  import React, { ReactNode } from 'react';
4
4
 
5
+ /**
6
+ * Internal types for the Reactor SDK.
7
+ *
8
+ * All Zod schemas and derived TypeScript types live here.
9
+ * Version constants are sourced from package.json via resolveJsonModule.
10
+ */
11
+
12
+ declare const TrackCapabilitySchema: z.ZodObject<{
13
+ name: z.ZodString;
14
+ kind: z.ZodEnum<{
15
+ video: "video";
16
+ audio: "audio";
17
+ }>;
18
+ direction: z.ZodEnum<{
19
+ recvonly: "recvonly";
20
+ sendonly: "sendonly";
21
+ }>;
22
+ }, z.core.$strip>;
23
+ declare const CommandCapabilitySchema: z.ZodObject<{
24
+ name: z.ZodString;
25
+ description: z.ZodString;
26
+ schema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
27
+ }, z.core.$strip>;
28
+ declare const CapabilitiesSchema: z.ZodObject<{
29
+ protocol_version: z.ZodString;
30
+ tracks: z.ZodArray<z.ZodObject<{
31
+ name: z.ZodString;
32
+ kind: z.ZodEnum<{
33
+ video: "video";
34
+ audio: "audio";
35
+ }>;
36
+ direction: z.ZodEnum<{
37
+ recvonly: "recvonly";
38
+ sendonly: "sendonly";
39
+ }>;
40
+ }, z.core.$strip>>;
41
+ commands: z.ZodOptional<z.ZodArray<z.ZodObject<{
42
+ name: z.ZodString;
43
+ description: z.ZodString;
44
+ schema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
45
+ }, z.core.$strip>>>;
46
+ emission_fps: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
47
+ }, z.core.$strip>;
48
+ declare const SessionResponseSchema: z.ZodObject<{
49
+ session_id: z.ZodString;
50
+ state: z.ZodString;
51
+ cluster: z.ZodString;
52
+ model: z.ZodObject<{
53
+ name: z.ZodString;
54
+ version: z.ZodOptional<z.ZodString>;
55
+ }, z.core.$strip>;
56
+ server_info: z.ZodObject<{
57
+ server_version: z.ZodString;
58
+ }, z.core.$strip>;
59
+ selected_transport: z.ZodOptional<z.ZodObject<{
60
+ protocol: z.ZodString;
61
+ version: z.ZodString;
62
+ }, z.core.$strip>>;
63
+ capabilities: z.ZodOptional<z.ZodObject<{
64
+ protocol_version: z.ZodString;
65
+ tracks: z.ZodArray<z.ZodObject<{
66
+ name: z.ZodString;
67
+ kind: z.ZodEnum<{
68
+ video: "video";
69
+ audio: "audio";
70
+ }>;
71
+ direction: z.ZodEnum<{
72
+ recvonly: "recvonly";
73
+ sendonly: "sendonly";
74
+ }>;
75
+ }, z.core.$strip>>;
76
+ commands: z.ZodOptional<z.ZodArray<z.ZodObject<{
77
+ name: z.ZodString;
78
+ description: z.ZodString;
79
+ schema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
80
+ }, z.core.$strip>>>;
81
+ emission_fps: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
82
+ }, z.core.$strip>>;
83
+ }, z.core.$strip>;
84
+ type TrackCapability = z.infer<typeof TrackCapabilitySchema>;
85
+ type CommandCapability = z.infer<typeof CommandCapabilitySchema>;
86
+ type SessionResponse = z.infer<typeof SessionResponseSchema>;
87
+ type Capabilities = z.infer<typeof CapabilitiesSchema>;
88
+
5
89
  type ReactorStatus = "disconnected" | "connecting" | "waiting" | "ready";
6
90
  /**
7
91
  * The message scope identifies the envelope layer a data channel message belongs to.
@@ -9,81 +93,7 @@ type ReactorStatus = "disconnected" | "connecting" | "waiting" | "ready";
9
93
  * - "runtime": platform-level control messages (e.g., capabilities exchange).
10
94
  */
11
95
  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;
96
+
87
97
  interface ReactorError {
88
98
  code: string;
89
99
  message: string;
@@ -112,21 +122,18 @@ interface ConnectOptions {
112
122
  maxAttempts?: number;
113
123
  }
114
124
  /**
115
- * One-shot timing breakdown of the connect() handshake, recorded once per
116
- * connection and included in every subsequent {@link ConnectionStats} update.
117
- * All durations are in milliseconds (from `performance.now()`).
125
+ * Transport-agnostic timing breakdown of the connect() handshake, recorded
126
+ * once per connection and included in every subsequent {@link ConnectionStats}
127
+ * update. All durations are in milliseconds (from `performance.now()`).
128
+ *
129
+ * For transport-specific timings (e.g. ICE negotiation, data channel open),
130
+ * see the relevant transport stats type (e.g. {@link WebRTCTransportTimings}).
118
131
  */
119
132
  interface ConnectionTimings {
120
133
  /** POST /sessions round-trip time */
121
134
  sessionCreationMs: number;
122
- /** Total time spent polling for the SDP answer */
123
- sdpPollingMs: number;
124
- /** Number of SDP poll requests made (1 = answered on first try) */
125
- sdpPollingAttempts: number;
126
- /** setRemoteDescription → RTCPeerConnection connectionState "connected" */
127
- iceNegotiationMs: number;
128
- /** setRemoteDescription → RTCDataChannel "open" */
129
- dataChannelMs: number;
135
+ /** Total time spent in transport.connect() (signaling, negotiation, etc.) */
136
+ transportConnectingMs: number;
130
137
  /** End-to-end: connect() invocation → status "ready" */
131
138
  totalMs: number;
132
139
  }
@@ -147,46 +154,31 @@ interface ConnectionStats {
147
154
  connectionTimings?: ConnectionTimings;
148
155
  timestamp: number;
149
156
  }
150
- type ReactorEvent = "statusChanged" | "sessionIdChanged" | "message" | "runtimeMessage" | "trackReceived" | "error" | "sessionExpirationChanged" | "statsUpdate";
157
+ type ReactorEvent = "statusChanged" | "sessionIdChanged" | "message" | "runtimeMessage" | "trackReceived" | "error" | "sessionExpirationChanged" | "capabilitiesReceived" | "statsUpdate";
151
158
 
152
159
  declare const DEFAULT_BASE_URL = "https://api.reactor.inc";
153
160
  declare const OptionsSchema: z.ZodObject<{
154
161
  apiUrl: z.ZodDefault<z.ZodString>;
155
162
  modelName: z.ZodString;
156
163
  local: z.ZodDefault<z.ZodBoolean>;
157
- receive: z.ZodDefault<z.ZodArray<z.ZodObject<{
158
- name: z.ZodString;
159
- kind: z.ZodEnum<{
160
- audio: "audio";
161
- video: "video";
162
- }>;
163
- }, z.core.$strip>>>;
164
- send: z.ZodDefault<z.ZodArray<z.ZodObject<{
165
- name: z.ZodString;
166
- kind: z.ZodEnum<{
167
- audio: "audio";
168
- video: "video";
169
- }>;
170
- }, z.core.$strip>>>;
171
164
  }, z.core.$strip>;
172
165
  type Options = z.input<typeof OptionsSchema>;
173
166
  type EventHandler = (...args: any[]) => void;
174
167
  declare class Reactor {
175
168
  private coordinatorClient;
176
- private machineClient;
169
+ private transportClient;
177
170
  private status;
178
171
  private coordinatorUrl;
179
172
  private lastError?;
180
173
  private model;
181
174
  private sessionExpiration?;
182
175
  private local;
183
- /** Tracks the client RECEIVES from the model (model → client). */
184
- private receive;
185
- /** Tracks the client SENDS to the model (client → model). */
186
- private send;
187
176
  private sessionId?;
188
177
  private connectStartTime?;
189
178
  private connectionTimings?;
179
+ private capabilities?;
180
+ private tracks;
181
+ private sessionResponse?;
190
182
  constructor(options: Options);
191
183
  private eventListeners;
192
184
  on(event: ReactorEvent, handler: EventHandler): void;
@@ -194,75 +186,45 @@ declare class Reactor {
194
186
  emit(event: ReactorEvent, ...args: any[]): void;
195
187
  /**
196
188
  * Sends a command to the model via the data channel.
197
- *
198
- * @param command The command name.
199
- * @param data The command payload.
200
- * @param scope "application" (default) for model commands, "runtime" for platform messages.
201
189
  */
202
190
  sendCommand(command: string, data: any, scope?: MessageScope): Promise<void>;
203
191
  /**
204
- * Publishes a MediaStreamTrack to a named send track.
205
- *
206
- * @param name The declared send track name (e.g. "webcam").
207
- * @param track The MediaStreamTrack to publish.
192
+ * Publishes a MediaStreamTrack to a named sendonly track.
193
+ * The transceiver is already set up from capabilities — this just
194
+ * calls replaceTrack() on the sender.
208
195
  */
209
196
  publishTrack(name: string, track: MediaStreamTrack): Promise<void>;
210
- /**
211
- * Unpublishes the track with the given name.
212
- *
213
- * @param name The declared send track name to unpublish.
214
- */
215
197
  unpublishTrack(name: string): Promise<void>;
216
198
  /**
217
- * Public method for reconnecting to an existing session, that may have been interrupted but can be recovered.
218
- * @param options Optional connect options (e.g. maxAttempts for SDP polling)
199
+ * Reconnects to an existing session with a fresh transport.
219
200
  */
220
201
  reconnect(options?: ConnectOptions): Promise<void>;
221
202
  /**
222
- * Connects to the coordinator and waits for a GPU to be assigned.
223
- * Once a GPU is assigned, the Reactor will connect to the gpu machine via WebRTC.
224
- * If no authentication is provided and not in local mode, an error is thrown.
225
- * @param jwtToken Optional JWT token for authentication
226
- * @param options Optional connect options (e.g. maxAttempts for SDP polling)
203
+ * Connects to the coordinator, creates a session, then establishes
204
+ * the transport using server-declared capabilities.
227
205
  */
228
206
  connect(jwtToken?: string, options?: ConnectOptions): Promise<void>;
229
207
  /**
230
- * Sets up event handlers for the machine client.
231
- *
232
- * Each handler captures the client reference at registration time and
233
- * ignores events if this.machineClient has since changed (e.g. after
234
- * disconnect + reconnect), preventing stale WebRTC teardown events from
235
- * interfering with a new connection.
208
+ * Sets up event handlers for the transport client.
209
+ * Each handler captures the client reference to ignore stale events.
236
210
  */
237
- private setupMachineClientHandlers;
211
+ private setupTransportHandlers;
238
212
  /**
239
- * Disconnects from the coordinator and the gpu machine.
240
- * Ensures cleanup completes even if individual disconnections fail.
213
+ * Disconnects from both the transport and the coordinator.
241
214
  */
242
215
  disconnect(recoverable?: boolean): Promise<void>;
243
- private setSessionId;
244
216
  getSessionId(): string | undefined;
245
- private setStatus;
246
217
  getStatus(): ReactorStatus;
247
- /**
248
- * Set the session expiration time.
249
- * @param newSessionExpiration The new session expiration time in seconds.
250
- */
251
- private setSessionExpiration;
252
- /**
253
- * Get the current state including status, error, and waiting info
254
- */
255
218
  getState(): ReactorState$1;
256
- /**
257
- * Get the last error that occurred
258
- */
259
219
  getLastError(): ReactorError | undefined;
220
+ getCapabilities(): Capabilities | undefined;
221
+ getSessionInfo(): SessionResponse | undefined;
260
222
  getStats(): ConnectionStats | undefined;
223
+ private setSessionId;
224
+ private setStatus;
225
+ private setSessionExpiration;
261
226
  private resetConnectionTimings;
262
227
  private finalizeConnectionTimings;
263
- /**
264
- * Create and store an error
265
- */
266
228
  private createError;
267
229
  }
268
230
 
@@ -271,7 +233,7 @@ interface ReactorState {
271
233
  /**
272
234
  * Media tracks received from the model, keyed by track name.
273
235
  *
274
- * Each entry maps a declared **receive** track name (e.g. `"main_video"`,
236
+ * Each entry maps a recvonly track name (e.g. `"main_video"`,
275
237
  * `"main_audio"`) to the live `MediaStreamTrack` delivered by the model.
276
238
  */
277
239
  tracks: Record<string, MediaStreamTrack>;
@@ -316,14 +278,16 @@ declare function useReactorStore<T = ReactorStore>(selector: (state: ReactorStor
316
278
 
317
279
  interface ReactorViewProps {
318
280
  /**
319
- * The name of the **receive** track to render.
320
- * Must match a track name declared in the `receive` array (model → client).
281
+ * The name of the recvonly track to render.
282
+ * Must match a track name declared in the server capabilities.
283
+ * Check the model's documentation for available track names.
321
284
  * Defaults to `"main_video"`.
322
285
  */
323
286
  track?: string;
324
287
  /**
325
- * Optional name of a **receive** audio track to play alongside the video
326
- * (e.g. `"main_audio"`). The audio is mixed into the same `<video>` element.
288
+ * Optional name of a recvonly audio track to play alongside the video
289
+ * (e.g. `"main_audio"`). The audio is mixed into the same `<video>` element.
290
+ * Check the model's documentation for available track names.
327
291
  */
328
292
  audioTrack?: string;
329
293
  width?: number;
@@ -344,8 +308,9 @@ declare function ReactorController({ className, style, }: ReactorControllerProps
344
308
 
345
309
  interface WebcamStreamProps {
346
310
  /**
347
- * The name of the **send** track to publish the webcam to.
348
- * Must match a track name declared in the `send` array (client → model).
311
+ * The name of the sendonly track to publish the webcam to.
312
+ * Must match a track name declared in the server capabilities.
313
+ * Check the model's documentation for available track names.
349
314
  */
350
315
  track: string;
351
316
  className?: string;
@@ -389,17 +354,4 @@ declare function useReactorInternalMessage(handler: (message: any) => void): voi
389
354
  */
390
355
  declare function useStats(): ConnectionStats | undefined;
391
356
 
392
- /**
393
- * ⚠️ INSECURE: Fetches a JWT token directly from the client.
394
- *
395
- * WARNING: This function exposes your API key in client-side code.
396
- * Only use this for local development or testing purposes.
397
- * In production, call /tokens from your server and pass the JWT to your frontend.
398
- *
399
- * @param apiKey - Your Reactor API key (will be exposed in client code!)
400
- * @param apiUrl - Optional API URL, defaults to production
401
- * @returns string containing the JWT token
402
- */
403
- declare function fetchInsecureToken(apiKey: string, apiUrl?: string): Promise<string>;
404
-
405
- export { AbortError, type AudioTrackOptions, ConflictError, type ConnectOptions, type ConnectionStats, type ConnectionTimings, DEFAULT_BASE_URL, type MessageScope, type Options, 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, fetchInsecureToken, isAbortError, useReactor, useReactorInternalMessage, useReactorMessage, useReactorStore, useStats, video };
357
+ export { AbortError, type Capabilities, type CommandCapability, ConflictError, type ConnectOptions, type ConnectionStats, type ConnectionTimings, DEFAULT_BASE_URL, type MessageScope, type Options, Reactor, type ReactorConnectOptions, ReactorController, type ReactorControllerProps, type ReactorError, type ReactorEvent, ReactorProvider, type ReactorState$1 as ReactorState, type ReactorStatus, type ReactorStore, ReactorView, type ReactorViewProps, type SessionResponse, type TrackCapability, WebcamStream, type WebcamStreamProps, isAbortError, useReactor, useReactorInternalMessage, useReactorMessage, useReactorStore, useStats };