@reactor-team/js-sdk 2.3.1 → 2.3.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/dist/index.d.mts +25 -7
- package/dist/index.d.ts +25 -7
- package/dist/index.js +49 -24
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +49 -24
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -209,8 +209,9 @@ function closePeerConnection(pc) {
|
|
|
209
209
|
|
|
210
210
|
// src/core/CoordinatorClient.ts
|
|
211
211
|
var INITIAL_BACKOFF_MS = 500;
|
|
212
|
-
var MAX_BACKOFF_MS =
|
|
212
|
+
var MAX_BACKOFF_MS = 15e3;
|
|
213
213
|
var BACKOFF_MULTIPLIER = 2;
|
|
214
|
+
var DEFAULT_MAX_ATTEMPTS = 6;
|
|
214
215
|
var CoordinatorClient = class {
|
|
215
216
|
constructor(options) {
|
|
216
217
|
this.baseUrl = options.baseUrl;
|
|
@@ -403,13 +404,14 @@ var CoordinatorClient = class {
|
|
|
403
404
|
});
|
|
404
405
|
}
|
|
405
406
|
/**
|
|
406
|
-
* Polls for the SDP answer with
|
|
407
|
+
* Polls for the SDP answer with exponential backoff.
|
|
407
408
|
* Used for async reconnection when the answer is not immediately available.
|
|
408
409
|
* @param sessionId - The session ID to poll for
|
|
410
|
+
* @param maxAttempts - Optional maximum number of polling attempts before giving up
|
|
409
411
|
* @returns The SDP answer from the server
|
|
410
412
|
*/
|
|
411
|
-
pollSdpAnswer(
|
|
412
|
-
return __async(this,
|
|
413
|
+
pollSdpAnswer(_0) {
|
|
414
|
+
return __async(this, arguments, function* (sessionId, maxAttempts = DEFAULT_MAX_ATTEMPTS) {
|
|
413
415
|
console.debug(
|
|
414
416
|
"[CoordinatorClient] Polling for SDP answer for session:",
|
|
415
417
|
sessionId
|
|
@@ -417,9 +419,14 @@ var CoordinatorClient = class {
|
|
|
417
419
|
let backoffMs = INITIAL_BACKOFF_MS;
|
|
418
420
|
let attempt = 0;
|
|
419
421
|
while (true) {
|
|
422
|
+
if (attempt >= maxAttempts) {
|
|
423
|
+
throw new Error(
|
|
424
|
+
`SDP polling exceeded maximum attempts (${maxAttempts}) for session ${sessionId}`
|
|
425
|
+
);
|
|
426
|
+
}
|
|
420
427
|
attempt++;
|
|
421
428
|
console.debug(
|
|
422
|
-
`[CoordinatorClient] SDP poll attempt ${attempt} for session ${sessionId}`
|
|
429
|
+
`[CoordinatorClient] SDP poll attempt ${attempt}/${maxAttempts} for session ${sessionId}`
|
|
423
430
|
);
|
|
424
431
|
const response = yield fetch(
|
|
425
432
|
`${this.baseUrl}/sessions/${sessionId}/sdp_params`,
|
|
@@ -456,9 +463,10 @@ var CoordinatorClient = class {
|
|
|
456
463
|
* falls back to polling. If no sdpOffer is provided, goes directly to polling.
|
|
457
464
|
* @param sessionId - The session ID to connect to
|
|
458
465
|
* @param sdpOffer - Optional SDP offer from the local WebRTC peer connection
|
|
466
|
+
* @param maxAttempts - Optional maximum number of polling attempts before giving up
|
|
459
467
|
* @returns The SDP answer from the server
|
|
460
468
|
*/
|
|
461
|
-
connect(sessionId, sdpOffer) {
|
|
469
|
+
connect(sessionId, sdpOffer, maxAttempts) {
|
|
462
470
|
return __async(this, null, function* () {
|
|
463
471
|
console.debug("[CoordinatorClient] Connecting to session:", sessionId);
|
|
464
472
|
if (sdpOffer) {
|
|
@@ -467,7 +475,7 @@ var CoordinatorClient = class {
|
|
|
467
475
|
return answer;
|
|
468
476
|
}
|
|
469
477
|
}
|
|
470
|
-
return this.pollSdpAnswer(sessionId);
|
|
478
|
+
return this.pollSdpAnswer(sessionId, maxAttempts);
|
|
471
479
|
});
|
|
472
480
|
}
|
|
473
481
|
/**
|
|
@@ -1011,8 +1019,9 @@ var Reactor = class {
|
|
|
1011
1019
|
}
|
|
1012
1020
|
/**
|
|
1013
1021
|
* Public method for reconnecting to an existing session, that may have been interrupted but can be recovered.
|
|
1022
|
+
* @param options Optional connect options (e.g. maxAttempts for SDP polling)
|
|
1014
1023
|
*/
|
|
1015
|
-
reconnect() {
|
|
1024
|
+
reconnect(options) {
|
|
1016
1025
|
return __async(this, null, function* () {
|
|
1017
1026
|
if (!this.sessionId || !this.coordinatorClient) {
|
|
1018
1027
|
console.warn("[Reactor] No active session to reconnect to.");
|
|
@@ -1032,7 +1041,8 @@ var Reactor = class {
|
|
|
1032
1041
|
try {
|
|
1033
1042
|
const sdpAnswer = yield this.coordinatorClient.connect(
|
|
1034
1043
|
this.sessionId,
|
|
1035
|
-
sdpOffer
|
|
1044
|
+
sdpOffer,
|
|
1045
|
+
options == null ? void 0 : options.maxAttempts
|
|
1036
1046
|
);
|
|
1037
1047
|
yield this.machineClient.connect(sdpAnswer);
|
|
1038
1048
|
this.setStatus("ready");
|
|
@@ -1056,8 +1066,10 @@ var Reactor = class {
|
|
|
1056
1066
|
* Connects to the coordinator and waits for a GPU to be assigned.
|
|
1057
1067
|
* Once a GPU is assigned, the Reactor will connect to the gpu machine via WebRTC.
|
|
1058
1068
|
* If no authentication is provided and not in local mode, an error is thrown.
|
|
1069
|
+
* @param jwtToken Optional JWT token for authentication
|
|
1070
|
+
* @param options Optional connect options (e.g. maxAttempts for SDP polling)
|
|
1059
1071
|
*/
|
|
1060
|
-
connect(jwtToken) {
|
|
1072
|
+
connect(jwtToken, options) {
|
|
1061
1073
|
return __async(this, null, function* () {
|
|
1062
1074
|
console.debug("[Reactor] Connecting, status:", this.status);
|
|
1063
1075
|
if (jwtToken == void 0 && !this.local) {
|
|
@@ -1074,7 +1086,7 @@ var Reactor = class {
|
|
|
1074
1086
|
this.coordinatorClient = this.local ? new LocalCoordinatorClient(this.coordinatorUrl) : new CoordinatorClient({
|
|
1075
1087
|
baseUrl: this.coordinatorUrl,
|
|
1076
1088
|
jwtToken,
|
|
1077
|
-
// Safe: validated
|
|
1089
|
+
// Safe: validated above
|
|
1078
1090
|
model: this.model
|
|
1079
1091
|
});
|
|
1080
1092
|
const iceServers = yield this.coordinatorClient.getIceServers();
|
|
@@ -1083,7 +1095,11 @@ var Reactor = class {
|
|
|
1083
1095
|
const sdpOffer = yield this.machineClient.createOffer();
|
|
1084
1096
|
const sessionId = yield this.coordinatorClient.createSession(sdpOffer);
|
|
1085
1097
|
this.setSessionId(sessionId);
|
|
1086
|
-
const sdpAnswer = yield this.coordinatorClient.connect(
|
|
1098
|
+
const sdpAnswer = yield this.coordinatorClient.connect(
|
|
1099
|
+
sessionId,
|
|
1100
|
+
void 0,
|
|
1101
|
+
options == null ? void 0 : options.maxAttempts
|
|
1102
|
+
);
|
|
1087
1103
|
yield this.machineClient.connect(sdpAnswer);
|
|
1088
1104
|
} catch (error) {
|
|
1089
1105
|
console.error("[Reactor] Connection failed:", error);
|
|
@@ -1093,7 +1109,14 @@ var Reactor = class {
|
|
|
1093
1109
|
"coordinator",
|
|
1094
1110
|
true
|
|
1095
1111
|
);
|
|
1096
|
-
|
|
1112
|
+
try {
|
|
1113
|
+
yield this.disconnect(false);
|
|
1114
|
+
} catch (disconnectError) {
|
|
1115
|
+
console.error(
|
|
1116
|
+
"[Reactor] Failed to clean up after connection failure:",
|
|
1117
|
+
disconnectError
|
|
1118
|
+
);
|
|
1119
|
+
}
|
|
1097
1120
|
throw error;
|
|
1098
1121
|
}
|
|
1099
1122
|
});
|
|
@@ -1325,13 +1348,13 @@ var createReactorStore = (initProps, publicState = defaultInitState) => {
|
|
|
1325
1348
|
throw error;
|
|
1326
1349
|
}
|
|
1327
1350
|
}),
|
|
1328
|
-
connect: (jwtToken) => __async(null, null, function* () {
|
|
1351
|
+
connect: (jwtToken, options) => __async(null, null, function* () {
|
|
1329
1352
|
if (jwtToken === void 0) {
|
|
1330
1353
|
jwtToken = get().jwtToken;
|
|
1331
1354
|
}
|
|
1332
1355
|
console.debug("[ReactorStore] Connect called.");
|
|
1333
1356
|
try {
|
|
1334
|
-
yield get().internal.reactor.connect(jwtToken);
|
|
1357
|
+
yield get().internal.reactor.connect(jwtToken, options);
|
|
1335
1358
|
console.debug("[ReactorStore] Connect completed successfully");
|
|
1336
1359
|
} catch (error) {
|
|
1337
1360
|
console.error("[ReactorStore] Connect failed:", error);
|
|
@@ -1376,10 +1399,10 @@ var createReactorStore = (initProps, publicState = defaultInitState) => {
|
|
|
1376
1399
|
throw error;
|
|
1377
1400
|
}
|
|
1378
1401
|
}),
|
|
1379
|
-
reconnect: () => __async(null, null, function* () {
|
|
1402
|
+
reconnect: (options) => __async(null, null, function* () {
|
|
1380
1403
|
console.debug("[ReactorStore] Reconnecting");
|
|
1381
1404
|
try {
|
|
1382
|
-
yield get().internal.reactor.reconnect();
|
|
1405
|
+
yield get().internal.reactor.reconnect(options);
|
|
1383
1406
|
console.debug("[ReactorStore] Reconnect completed successfully");
|
|
1384
1407
|
} catch (error) {
|
|
1385
1408
|
console.error("[ReactorStore] Failed to reconnect:", error);
|
|
@@ -1396,11 +1419,11 @@ import { jsx } from "react/jsx-runtime";
|
|
|
1396
1419
|
function ReactorProvider(_a) {
|
|
1397
1420
|
var _b = _a, {
|
|
1398
1421
|
children,
|
|
1399
|
-
|
|
1422
|
+
connectOptions,
|
|
1400
1423
|
jwtToken
|
|
1401
1424
|
} = _b, props = __objRest(_b, [
|
|
1402
1425
|
"children",
|
|
1403
|
-
"
|
|
1426
|
+
"connectOptions",
|
|
1404
1427
|
"jwtToken"
|
|
1405
1428
|
]);
|
|
1406
1429
|
const storeRef = useRef(void 0);
|
|
@@ -1415,14 +1438,16 @@ function ReactorProvider(_a) {
|
|
|
1415
1438
|
);
|
|
1416
1439
|
console.debug("[ReactorProvider] Reactor store created successfully");
|
|
1417
1440
|
}
|
|
1441
|
+
const _a2 = connectOptions != null ? connectOptions : {}, { autoConnect = false } = _a2, pollingOptions = __objRest(_a2, ["autoConnect"]);
|
|
1418
1442
|
const { coordinatorUrl, modelName, local } = props;
|
|
1443
|
+
const maxAttempts = pollingOptions.maxAttempts;
|
|
1419
1444
|
useEffect(() => {
|
|
1420
1445
|
const handleBeforeUnload = () => {
|
|
1421
|
-
var
|
|
1446
|
+
var _a3;
|
|
1422
1447
|
console.debug(
|
|
1423
1448
|
"[ReactorProvider] Page unloading, performing non-recoverable disconnect"
|
|
1424
1449
|
);
|
|
1425
|
-
(
|
|
1450
|
+
(_a3 = storeRef.current) == null ? void 0 : _a3.getState().internal.reactor.disconnect(false);
|
|
1426
1451
|
};
|
|
1427
1452
|
window.addEventListener("beforeunload", handleBeforeUnload);
|
|
1428
1453
|
return () => {
|
|
@@ -1437,7 +1462,7 @@ function ReactorProvider(_a) {
|
|
|
1437
1462
|
console.debug(
|
|
1438
1463
|
"[ReactorProvider] Starting autoconnect in first render..."
|
|
1439
1464
|
);
|
|
1440
|
-
current2.getState().connect(jwtToken).then(() => {
|
|
1465
|
+
current2.getState().connect(jwtToken, pollingOptions).then(() => {
|
|
1441
1466
|
console.debug(
|
|
1442
1467
|
"[ReactorProvider] Autoconnect successful in first render"
|
|
1443
1468
|
);
|
|
@@ -1480,7 +1505,7 @@ function ReactorProvider(_a) {
|
|
|
1480
1505
|
);
|
|
1481
1506
|
if (autoConnect && current.getState().status === "disconnected" && jwtToken) {
|
|
1482
1507
|
console.debug("[ReactorProvider] Starting autoconnect...");
|
|
1483
|
-
current.getState().connect(jwtToken).then(() => {
|
|
1508
|
+
current.getState().connect(jwtToken, pollingOptions).then(() => {
|
|
1484
1509
|
console.debug("[ReactorProvider] Autoconnect successful");
|
|
1485
1510
|
}).catch((error) => {
|
|
1486
1511
|
console.error("[ReactorProvider] Failed to autoconnect:", error);
|
|
@@ -1496,7 +1521,7 @@ function ReactorProvider(_a) {
|
|
|
1496
1521
|
console.error("[ReactorProvider] Failed to disconnect:", error);
|
|
1497
1522
|
});
|
|
1498
1523
|
};
|
|
1499
|
-
}, [coordinatorUrl, modelName, autoConnect, local, jwtToken]);
|
|
1524
|
+
}, [coordinatorUrl, modelName, autoConnect, local, jwtToken, maxAttempts]);
|
|
1500
1525
|
return /* @__PURE__ */ jsx(ReactorContext.Provider, { value: storeRef.current, children });
|
|
1501
1526
|
}
|
|
1502
1527
|
function useReactorStore(selector) {
|