@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/dist/index.mjs
CHANGED
|
@@ -50,6 +50,13 @@ var __async = (__this, __arguments, generator) => {
|
|
|
50
50
|
});
|
|
51
51
|
};
|
|
52
52
|
|
|
53
|
+
// src/types.ts
|
|
54
|
+
var ConflictError = class extends Error {
|
|
55
|
+
constructor(message) {
|
|
56
|
+
super(message);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
53
60
|
// src/core/CoordinatorClient.ts
|
|
54
61
|
var INITIAL_BACKOFF_MS = 500;
|
|
55
62
|
var MAX_BACKOFF_MS = 3e4;
|
|
@@ -68,6 +75,11 @@ var CoordinatorClient = class {
|
|
|
68
75
|
Authorization: `Bearer ${this.jwtToken}`
|
|
69
76
|
};
|
|
70
77
|
}
|
|
78
|
+
getIceServers() {
|
|
79
|
+
return __async(this, null, function* () {
|
|
80
|
+
return [{ urls: "stun:stun.l.google.com:19302" }];
|
|
81
|
+
});
|
|
82
|
+
}
|
|
71
83
|
/**
|
|
72
84
|
* Creates a new session with the coordinator.
|
|
73
85
|
* Expects a 200 response and stores the session ID.
|
|
@@ -304,6 +316,27 @@ var LocalCoordinatorClient = class extends CoordinatorClient {
|
|
|
304
316
|
});
|
|
305
317
|
this.localBaseUrl = baseUrl;
|
|
306
318
|
}
|
|
319
|
+
/**
|
|
320
|
+
* Gets ICE servers from the local HTTP runtime.
|
|
321
|
+
* @returns The ICE server configuration
|
|
322
|
+
*/
|
|
323
|
+
getIceServers() {
|
|
324
|
+
return __async(this, null, function* () {
|
|
325
|
+
console.debug("[LocalCoordinatorClient] Fetching ICE servers...");
|
|
326
|
+
const response = yield fetch(`${this.localBaseUrl}/ice_servers`, {
|
|
327
|
+
method: "GET"
|
|
328
|
+
});
|
|
329
|
+
if (!response.ok) {
|
|
330
|
+
throw new Error("Failed to get ICE servers from local coordinator.");
|
|
331
|
+
}
|
|
332
|
+
const data = yield response.json();
|
|
333
|
+
console.debug(
|
|
334
|
+
"[LocalCoordinatorClient] Received ICE servers:",
|
|
335
|
+
data.ice_servers
|
|
336
|
+
);
|
|
337
|
+
return data.ice_servers;
|
|
338
|
+
});
|
|
339
|
+
}
|
|
307
340
|
/**
|
|
308
341
|
* Creates a local session by posting to /start_session.
|
|
309
342
|
* @returns always "local"
|
|
@@ -344,6 +377,9 @@ var LocalCoordinatorClient = class extends CoordinatorClient {
|
|
|
344
377
|
body: JSON.stringify(sdpBody)
|
|
345
378
|
});
|
|
346
379
|
if (!response.ok) {
|
|
380
|
+
if (response.status === 409) {
|
|
381
|
+
throw new ConflictError("Connection superseded by newer request");
|
|
382
|
+
}
|
|
347
383
|
throw new Error("Failed to get SDP answer from local coordinator.");
|
|
348
384
|
}
|
|
349
385
|
const sdpAnswer = yield response.json();
|
|
@@ -362,15 +398,12 @@ var LocalCoordinatorClient = class extends CoordinatorClient {
|
|
|
362
398
|
};
|
|
363
399
|
|
|
364
400
|
// src/utils/webrtc.ts
|
|
365
|
-
var DEFAULT_ICE_SERVERS = [
|
|
366
|
-
{ urls: "stun:stun.l.google.com:19302" },
|
|
367
|
-
{ urls: "stun:stun1.l.google.com:19302" }
|
|
368
|
-
];
|
|
369
401
|
var DEFAULT_DATA_CHANNEL_LABEL = "data";
|
|
402
|
+
var FORCE_RELAY_MODE = false;
|
|
370
403
|
function createPeerConnection(config) {
|
|
371
|
-
var _a;
|
|
372
404
|
return new RTCPeerConnection({
|
|
373
|
-
iceServers:
|
|
405
|
+
iceServers: config.iceServers,
|
|
406
|
+
iceTransportPolicy: FORCE_RELAY_MODE ? "relay" : "all"
|
|
374
407
|
});
|
|
375
408
|
}
|
|
376
409
|
function createDataChannel(pc, label) {
|
|
@@ -451,7 +484,7 @@ var GPUMachineClient = class {
|
|
|
451
484
|
constructor(config) {
|
|
452
485
|
this.eventListeners = /* @__PURE__ */ new Map();
|
|
453
486
|
this.status = "disconnected";
|
|
454
|
-
this.config = config
|
|
487
|
+
this.config = config;
|
|
455
488
|
}
|
|
456
489
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
457
490
|
// Event Emitter API
|
|
@@ -848,9 +881,14 @@ var Reactor = class {
|
|
|
848
881
|
console.warn("[Reactor] No active session to reconnect to.");
|
|
849
882
|
return;
|
|
850
883
|
}
|
|
884
|
+
if (this.status === "ready") {
|
|
885
|
+
console.warn("[Reactor] Already connected, no need to reconnect.");
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
851
888
|
this.setStatus("connecting");
|
|
852
889
|
if (!this.machineClient) {
|
|
853
|
-
|
|
890
|
+
const iceServers = yield this.coordinatorClient.getIceServers();
|
|
891
|
+
this.machineClient = new GPUMachineClient({ iceServers });
|
|
854
892
|
this.setupMachineClientHandlers();
|
|
855
893
|
}
|
|
856
894
|
const sdpOffer = yield this.machineClient.createOffer();
|
|
@@ -862,8 +900,12 @@ var Reactor = class {
|
|
|
862
900
|
yield this.machineClient.connect(sdpAnswer);
|
|
863
901
|
this.setStatus("ready");
|
|
864
902
|
} catch (error) {
|
|
903
|
+
let recoverable = false;
|
|
904
|
+
if (error instanceof ConflictError) {
|
|
905
|
+
recoverable = true;
|
|
906
|
+
}
|
|
865
907
|
console.error("[Reactor] Failed to reconnect:", error);
|
|
866
|
-
this.disconnect(
|
|
908
|
+
this.disconnect(recoverable);
|
|
867
909
|
this.createError(
|
|
868
910
|
"RECONNECTION_FAILED",
|
|
869
911
|
`Failed to reconnect: ${error}`,
|
|
@@ -898,7 +940,8 @@ var Reactor = class {
|
|
|
898
940
|
// Safe: validated on line 186-188
|
|
899
941
|
model: this.model
|
|
900
942
|
});
|
|
901
|
-
|
|
943
|
+
const iceServers = yield this.coordinatorClient.getIceServers();
|
|
944
|
+
this.machineClient = new GPUMachineClient({ iceServers });
|
|
902
945
|
this.setupMachineClientHandlers();
|
|
903
946
|
const sdpOffer = yield this.machineClient.createOffer();
|
|
904
947
|
const sessionId = yield this.coordinatorClient.createSession(sdpOffer);
|
|
@@ -2087,13 +2130,36 @@ function WebcamStream({
|
|
|
2087
2130
|
}
|
|
2088
2131
|
);
|
|
2089
2132
|
}
|
|
2133
|
+
|
|
2134
|
+
// src/utils/tokens.ts
|
|
2135
|
+
function fetchInsecureJwtToken(_0) {
|
|
2136
|
+
return __async(this, arguments, function* (apiKey, coordinatorUrl = PROD_COORDINATOR_URL) {
|
|
2137
|
+
console.warn(
|
|
2138
|
+
"[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."
|
|
2139
|
+
);
|
|
2140
|
+
const response = yield fetch(`${coordinatorUrl}/tokens`, {
|
|
2141
|
+
method: "GET",
|
|
2142
|
+
headers: {
|
|
2143
|
+
"X-API-Key": apiKey
|
|
2144
|
+
}
|
|
2145
|
+
});
|
|
2146
|
+
if (!response.ok) {
|
|
2147
|
+
const error = yield response.text();
|
|
2148
|
+
throw new Error(`Failed to create token: ${response.status} ${error}`);
|
|
2149
|
+
}
|
|
2150
|
+
const { jwt } = yield response.json();
|
|
2151
|
+
return jwt;
|
|
2152
|
+
});
|
|
2153
|
+
}
|
|
2090
2154
|
export {
|
|
2155
|
+
ConflictError,
|
|
2091
2156
|
PROD_COORDINATOR_URL,
|
|
2092
2157
|
Reactor,
|
|
2093
2158
|
ReactorController,
|
|
2094
2159
|
ReactorProvider,
|
|
2095
2160
|
ReactorView,
|
|
2096
2161
|
WebcamStream,
|
|
2162
|
+
fetchInsecureJwtToken,
|
|
2097
2163
|
useReactor,
|
|
2098
2164
|
useReactorMessage,
|
|
2099
2165
|
useReactorStore
|