@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.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 = 3e4;
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 geometric backoff.
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(sessionId) {
412
- return __async(this, null, function* () {
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 on line 186-188
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(sessionId);
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
- this.setStatus("disconnected");
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
- autoConnect = true,
1422
+ connectOptions,
1400
1423
  jwtToken
1401
1424
  } = _b, props = __objRest(_b, [
1402
1425
  "children",
1403
- "autoConnect",
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 _a2;
1446
+ var _a3;
1422
1447
  console.debug(
1423
1448
  "[ReactorProvider] Page unloading, performing non-recoverable disconnect"
1424
1449
  );
1425
- (_a2 = storeRef.current) == null ? void 0 : _a2.getState().internal.reactor.disconnect(false);
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) {