@reactor-team/js-sdk 2.0.0 → 2.0.2
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/README.md +2 -16
- package/dist/index.d.mts +17 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.js +78 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +76 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,24 +11,10 @@ There are two main ways to use the frontend SDK:
|
|
|
11
11
|
|
|
12
12
|
## Building the SDK
|
|
13
13
|
|
|
14
|
-
Set up the environment variables:
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
cp .env.example .env
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
Then add your NPM_TOKEN to the .env file.
|
|
21
|
-
|
|
22
|
-
Build the SDK:
|
|
23
|
-
|
|
24
14
|
```bash
|
|
25
15
|
pnpm build
|
|
26
16
|
```
|
|
27
17
|
|
|
28
|
-
##
|
|
29
|
-
|
|
30
|
-
To publish the SDK:
|
|
18
|
+
## Documentation
|
|
31
19
|
|
|
32
|
-
|
|
33
|
-
./publish_package.sh
|
|
34
|
-
```
|
|
20
|
+
- [Getting Started](https://docs.reactor.inc)
|
package/dist/index.d.mts
CHANGED
|
@@ -11,6 +11,9 @@ interface ReactorError {
|
|
|
11
11
|
component: "coordinator" | "gpu" | "livekit";
|
|
12
12
|
retryAfter?: number;
|
|
13
13
|
}
|
|
14
|
+
declare class ConflictError extends Error {
|
|
15
|
+
constructor(message: string);
|
|
16
|
+
}
|
|
14
17
|
interface ReactorState$1 {
|
|
15
18
|
status: ReactorStatus;
|
|
16
19
|
lastError?: ReactorError;
|
|
@@ -171,4 +174,17 @@ declare function useReactor<T>(selector: (state: ReactorStore) => T): T;
|
|
|
171
174
|
*/
|
|
172
175
|
declare function useReactorMessage(handler: (message: any) => void): void;
|
|
173
176
|
|
|
174
|
-
|
|
177
|
+
/**
|
|
178
|
+
* ⚠️ INSECURE: Fetches a JWT token directly from the client.
|
|
179
|
+
*
|
|
180
|
+
* WARNING: This function exposes your API key in client-side code.
|
|
181
|
+
* Only use this for local development or testing purposes.
|
|
182
|
+
* In production, call /tokens from your server and pass the JWT to your frontend.
|
|
183
|
+
*
|
|
184
|
+
* @param apiKey - Your Reactor API key (will be exposed in client code!)
|
|
185
|
+
* @param coordinatorUrl - Optional coordinator URL, defaults to production
|
|
186
|
+
* @returns string containing the JWT token
|
|
187
|
+
*/
|
|
188
|
+
declare function fetchInsecureJwtToken(apiKey: string, coordinatorUrl?: string): Promise<string>;
|
|
189
|
+
|
|
190
|
+
export { ConflictError, type Options, PROD_COORDINATOR_URL, Reactor, ReactorController, type ReactorControllerProps, type ReactorError, type ReactorEvent, ReactorProvider, type ReactorState$1 as ReactorState, type ReactorStatus, ReactorView, type ReactorViewProps, WebcamStream, fetchInsecureJwtToken, useReactor, useReactorMessage, useReactorStore };
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,9 @@ interface ReactorError {
|
|
|
11
11
|
component: "coordinator" | "gpu" | "livekit";
|
|
12
12
|
retryAfter?: number;
|
|
13
13
|
}
|
|
14
|
+
declare class ConflictError extends Error {
|
|
15
|
+
constructor(message: string);
|
|
16
|
+
}
|
|
14
17
|
interface ReactorState$1 {
|
|
15
18
|
status: ReactorStatus;
|
|
16
19
|
lastError?: ReactorError;
|
|
@@ -171,4 +174,17 @@ declare function useReactor<T>(selector: (state: ReactorStore) => T): T;
|
|
|
171
174
|
*/
|
|
172
175
|
declare function useReactorMessage(handler: (message: any) => void): void;
|
|
173
176
|
|
|
174
|
-
|
|
177
|
+
/**
|
|
178
|
+
* ⚠️ INSECURE: Fetches a JWT token directly from the client.
|
|
179
|
+
*
|
|
180
|
+
* WARNING: This function exposes your API key in client-side code.
|
|
181
|
+
* Only use this for local development or testing purposes.
|
|
182
|
+
* In production, call /tokens from your server and pass the JWT to your frontend.
|
|
183
|
+
*
|
|
184
|
+
* @param apiKey - Your Reactor API key (will be exposed in client code!)
|
|
185
|
+
* @param coordinatorUrl - Optional coordinator URL, defaults to production
|
|
186
|
+
* @returns string containing the JWT token
|
|
187
|
+
*/
|
|
188
|
+
declare function fetchInsecureJwtToken(apiKey: string, coordinatorUrl?: string): Promise<string>;
|
|
189
|
+
|
|
190
|
+
export { ConflictError, type Options, PROD_COORDINATOR_URL, Reactor, ReactorController, type ReactorControllerProps, type ReactorError, type ReactorEvent, ReactorProvider, type ReactorState$1 as ReactorState, type ReactorStatus, ReactorView, type ReactorViewProps, WebcamStream, fetchInsecureJwtToken, useReactor, useReactorMessage, useReactorStore };
|
package/dist/index.js
CHANGED
|
@@ -79,18 +79,27 @@ var __async = (__this, __arguments, generator) => {
|
|
|
79
79
|
// src/index.ts
|
|
80
80
|
var index_exports = {};
|
|
81
81
|
__export(index_exports, {
|
|
82
|
+
ConflictError: () => ConflictError,
|
|
82
83
|
PROD_COORDINATOR_URL: () => PROD_COORDINATOR_URL,
|
|
83
84
|
Reactor: () => Reactor,
|
|
84
85
|
ReactorController: () => ReactorController,
|
|
85
86
|
ReactorProvider: () => ReactorProvider,
|
|
86
87
|
ReactorView: () => ReactorView,
|
|
87
88
|
WebcamStream: () => WebcamStream,
|
|
89
|
+
fetchInsecureJwtToken: () => fetchInsecureJwtToken,
|
|
88
90
|
useReactor: () => useReactor,
|
|
89
91
|
useReactorMessage: () => useReactorMessage,
|
|
90
92
|
useReactorStore: () => useReactorStore
|
|
91
93
|
});
|
|
92
94
|
module.exports = __toCommonJS(index_exports);
|
|
93
95
|
|
|
96
|
+
// src/types.ts
|
|
97
|
+
var ConflictError = class extends Error {
|
|
98
|
+
constructor(message) {
|
|
99
|
+
super(message);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
94
103
|
// src/core/CoordinatorClient.ts
|
|
95
104
|
var INITIAL_BACKOFF_MS = 500;
|
|
96
105
|
var MAX_BACKOFF_MS = 3e4;
|
|
@@ -109,6 +118,11 @@ var CoordinatorClient = class {
|
|
|
109
118
|
Authorization: `Bearer ${this.jwtToken}`
|
|
110
119
|
};
|
|
111
120
|
}
|
|
121
|
+
getIceServers() {
|
|
122
|
+
return __async(this, null, function* () {
|
|
123
|
+
return [{ urls: "stun:stun.l.google.com:19302" }];
|
|
124
|
+
});
|
|
125
|
+
}
|
|
112
126
|
/**
|
|
113
127
|
* Creates a new session with the coordinator.
|
|
114
128
|
* Expects a 200 response and stores the session ID.
|
|
@@ -345,6 +359,27 @@ var LocalCoordinatorClient = class extends CoordinatorClient {
|
|
|
345
359
|
});
|
|
346
360
|
this.localBaseUrl = baseUrl;
|
|
347
361
|
}
|
|
362
|
+
/**
|
|
363
|
+
* Gets ICE servers from the local HTTP runtime.
|
|
364
|
+
* @returns The ICE server configuration
|
|
365
|
+
*/
|
|
366
|
+
getIceServers() {
|
|
367
|
+
return __async(this, null, function* () {
|
|
368
|
+
console.debug("[LocalCoordinatorClient] Fetching ICE servers...");
|
|
369
|
+
const response = yield fetch(`${this.localBaseUrl}/ice_servers`, {
|
|
370
|
+
method: "GET"
|
|
371
|
+
});
|
|
372
|
+
if (!response.ok) {
|
|
373
|
+
throw new Error("Failed to get ICE servers from local coordinator.");
|
|
374
|
+
}
|
|
375
|
+
const data = yield response.json();
|
|
376
|
+
console.debug(
|
|
377
|
+
"[LocalCoordinatorClient] Received ICE servers:",
|
|
378
|
+
data.ice_servers
|
|
379
|
+
);
|
|
380
|
+
return data.ice_servers;
|
|
381
|
+
});
|
|
382
|
+
}
|
|
348
383
|
/**
|
|
349
384
|
* Creates a local session by posting to /start_session.
|
|
350
385
|
* @returns always "local"
|
|
@@ -385,6 +420,9 @@ var LocalCoordinatorClient = class extends CoordinatorClient {
|
|
|
385
420
|
body: JSON.stringify(sdpBody)
|
|
386
421
|
});
|
|
387
422
|
if (!response.ok) {
|
|
423
|
+
if (response.status === 409) {
|
|
424
|
+
throw new ConflictError("Connection superseded by newer request");
|
|
425
|
+
}
|
|
388
426
|
throw new Error("Failed to get SDP answer from local coordinator.");
|
|
389
427
|
}
|
|
390
428
|
const sdpAnswer = yield response.json();
|
|
@@ -403,15 +441,12 @@ var LocalCoordinatorClient = class extends CoordinatorClient {
|
|
|
403
441
|
};
|
|
404
442
|
|
|
405
443
|
// src/utils/webrtc.ts
|
|
406
|
-
var DEFAULT_ICE_SERVERS = [
|
|
407
|
-
{ urls: "stun:stun.l.google.com:19302" },
|
|
408
|
-
{ urls: "stun:stun1.l.google.com:19302" }
|
|
409
|
-
];
|
|
410
444
|
var DEFAULT_DATA_CHANNEL_LABEL = "data";
|
|
445
|
+
var FORCE_RELAY_MODE = false;
|
|
411
446
|
function createPeerConnection(config) {
|
|
412
|
-
var _a;
|
|
413
447
|
return new RTCPeerConnection({
|
|
414
|
-
iceServers:
|
|
448
|
+
iceServers: config.iceServers,
|
|
449
|
+
iceTransportPolicy: FORCE_RELAY_MODE ? "relay" : "all"
|
|
415
450
|
});
|
|
416
451
|
}
|
|
417
452
|
function createDataChannel(pc, label) {
|
|
@@ -492,7 +527,7 @@ var GPUMachineClient = class {
|
|
|
492
527
|
constructor(config) {
|
|
493
528
|
this.eventListeners = /* @__PURE__ */ new Map();
|
|
494
529
|
this.status = "disconnected";
|
|
495
|
-
this.config = config
|
|
530
|
+
this.config = config;
|
|
496
531
|
}
|
|
497
532
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
498
533
|
// Event Emitter API
|
|
@@ -889,9 +924,14 @@ var Reactor = class {
|
|
|
889
924
|
console.warn("[Reactor] No active session to reconnect to.");
|
|
890
925
|
return;
|
|
891
926
|
}
|
|
927
|
+
if (this.status === "ready") {
|
|
928
|
+
console.warn("[Reactor] Already connected, no need to reconnect.");
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
892
931
|
this.setStatus("connecting");
|
|
893
932
|
if (!this.machineClient) {
|
|
894
|
-
|
|
933
|
+
const iceServers = yield this.coordinatorClient.getIceServers();
|
|
934
|
+
this.machineClient = new GPUMachineClient({ iceServers });
|
|
895
935
|
this.setupMachineClientHandlers();
|
|
896
936
|
}
|
|
897
937
|
const sdpOffer = yield this.machineClient.createOffer();
|
|
@@ -903,8 +943,12 @@ var Reactor = class {
|
|
|
903
943
|
yield this.machineClient.connect(sdpAnswer);
|
|
904
944
|
this.setStatus("ready");
|
|
905
945
|
} catch (error) {
|
|
946
|
+
let recoverable = false;
|
|
947
|
+
if (error instanceof ConflictError) {
|
|
948
|
+
recoverable = true;
|
|
949
|
+
}
|
|
906
950
|
console.error("[Reactor] Failed to reconnect:", error);
|
|
907
|
-
this.disconnect(
|
|
951
|
+
this.disconnect(recoverable);
|
|
908
952
|
this.createError(
|
|
909
953
|
"RECONNECTION_FAILED",
|
|
910
954
|
`Failed to reconnect: ${error}`,
|
|
@@ -939,7 +983,8 @@ var Reactor = class {
|
|
|
939
983
|
// Safe: validated on line 186-188
|
|
940
984
|
model: this.model
|
|
941
985
|
});
|
|
942
|
-
|
|
986
|
+
const iceServers = yield this.coordinatorClient.getIceServers();
|
|
987
|
+
this.machineClient = new GPUMachineClient({ iceServers });
|
|
943
988
|
this.setupMachineClientHandlers();
|
|
944
989
|
const sdpOffer = yield this.machineClient.createOffer();
|
|
945
990
|
const sessionId = yield this.coordinatorClient.createSession(sdpOffer);
|
|
@@ -2128,14 +2173,37 @@ function WebcamStream({
|
|
|
2128
2173
|
}
|
|
2129
2174
|
);
|
|
2130
2175
|
}
|
|
2176
|
+
|
|
2177
|
+
// src/utils/tokens.ts
|
|
2178
|
+
function fetchInsecureJwtToken(_0) {
|
|
2179
|
+
return __async(this, arguments, function* (apiKey, coordinatorUrl = PROD_COORDINATOR_URL) {
|
|
2180
|
+
console.warn(
|
|
2181
|
+
"[Reactor] \u26A0\uFE0F SECURITY WARNING: fetchInsecureJwtToken() exposes your API key in client-side code. This should ONLY be used for local development or testing. In production, fetch tokens from your server instead."
|
|
2182
|
+
);
|
|
2183
|
+
const response = yield fetch(`${coordinatorUrl}/tokens`, {
|
|
2184
|
+
method: "GET",
|
|
2185
|
+
headers: {
|
|
2186
|
+
"X-API-Key": apiKey
|
|
2187
|
+
}
|
|
2188
|
+
});
|
|
2189
|
+
if (!response.ok) {
|
|
2190
|
+
const error = yield response.text();
|
|
2191
|
+
throw new Error(`Failed to create token: ${response.status} ${error}`);
|
|
2192
|
+
}
|
|
2193
|
+
const { jwt } = yield response.json();
|
|
2194
|
+
return jwt;
|
|
2195
|
+
});
|
|
2196
|
+
}
|
|
2131
2197
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2132
2198
|
0 && (module.exports = {
|
|
2199
|
+
ConflictError,
|
|
2133
2200
|
PROD_COORDINATOR_URL,
|
|
2134
2201
|
Reactor,
|
|
2135
2202
|
ReactorController,
|
|
2136
2203
|
ReactorProvider,
|
|
2137
2204
|
ReactorView,
|
|
2138
2205
|
WebcamStream,
|
|
2206
|
+
fetchInsecureJwtToken,
|
|
2139
2207
|
useReactor,
|
|
2140
2208
|
useReactorMessage,
|
|
2141
2209
|
useReactorStore
|