@ricsam/isolate-daemon 0.1.21 → 0.1.22

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.
@@ -48,6 +48,25 @@ var import_callback_fs_handler = require("./callback-fs-handler.cjs");
48
48
  var import_isolate_runtime = require("@ricsam/isolate-runtime");
49
49
  var LINKER_CONFLICT_ERROR = "Module is currently being linked by another linker";
50
50
  var NULL_BODY_STATUSES = new Set([101, 103, 204, 205, 304]);
51
+ var DEFAULT_CALLBACK_TIMEOUT_MS = 120000;
52
+ var FETCH_CALLBACK_TIMEOUT_MS = 35000;
53
+ function createAbortError(reason = "The operation was aborted") {
54
+ if (typeof DOMException !== "undefined") {
55
+ return new DOMException(reason, "AbortError");
56
+ }
57
+ const error = new Error(reason);
58
+ error.name = "AbortError";
59
+ return error;
60
+ }
61
+ function sendCallbackAbortMessage(connection, targetRequestId, reason) {
62
+ const abortMessage = {
63
+ type: import_isolate_protocol.MessageType.CALLBACK_ABORT,
64
+ requestId: connection.nextRequestId++,
65
+ targetRequestId,
66
+ reason
67
+ };
68
+ sendMessage(connection.socket, abortMessage);
69
+ }
51
70
  function getErrorText(error) {
52
71
  if (error instanceof Error) {
53
72
  const cause = error.cause;
@@ -122,6 +141,7 @@ function handleConnection(socket, state) {
122
141
  }
123
142
  }
124
143
  for (const [, pending] of connection.pendingCallbacks) {
144
+ pending.cleanup?.();
125
145
  pending.reject(new Error("Connection closed"));
126
146
  }
127
147
  connection.pendingCallbacks.clear();
@@ -455,14 +475,14 @@ async function waitForConnection(callbackContext) {
455
475
  }
456
476
  throw new Error("No connection available and no reconnection pending");
457
477
  }
458
- async function invokeCallbackWithReconnect(callbackContext, getCallbackId, args, label, invokeClientCallback) {
478
+ async function invokeCallbackWithReconnect(callbackContext, getCallbackId, args, label, invokeClientCallback, options) {
459
479
  const conn = await waitForConnection(callbackContext);
460
480
  const cbId = getCallbackId();
461
481
  if (cbId === undefined) {
462
482
  throw new Error(`${label} callback not available`);
463
483
  }
464
484
  try {
465
- return await invokeClientCallback(conn, cbId, args);
485
+ return await invokeClientCallback(conn, cbId, args, options);
466
486
  } catch (err) {
467
487
  if (callbackContext.reconnectionPromise && !callbackContext.connection) {
468
488
  const newConn = await callbackContext.reconnectionPromise.promise;
@@ -470,7 +490,7 @@ async function invokeCallbackWithReconnect(callbackContext, getCallbackId, args,
470
490
  if (newCbId === undefined) {
471
491
  throw new Error(`${label} callback not available after reconnection`);
472
492
  }
473
- return invokeClientCallback(newConn, newCbId, args);
493
+ return invokeClientCallback(newConn, newCbId, args, options);
474
494
  }
475
495
  throw err;
476
496
  }
@@ -793,6 +813,9 @@ async function handleCreateRuntime(message, connection, state) {
793
813
  }
794
814
  },
795
815
  fetch: async (url, init) => {
816
+ if (init.signal.aborted) {
817
+ throw createAbortError();
818
+ }
796
819
  const serialized = {
797
820
  url,
798
821
  method: init.method,
@@ -800,7 +823,16 @@ async function handleCreateRuntime(message, connection, state) {
800
823
  body: init.rawBody,
801
824
  signalAborted: init.signal.aborted
802
825
  };
803
- const result = await invokeCallbackWithReconnect(callbackContext, () => callbackContext.fetch, [serialized], "Fetch", invokeClientCallback);
826
+ const callbackAbortController = new AbortController;
827
+ const onInitAbort = () => callbackAbortController.abort();
828
+ init.signal.addEventListener("abort", onInitAbort, { once: true });
829
+ const result = await invokeCallbackWithReconnect(callbackContext, () => callbackContext.fetch, [serialized], "Fetch", invokeClientCallback, {
830
+ signal: callbackAbortController.signal,
831
+ timeoutMs: FETCH_CALLBACK_TIMEOUT_MS,
832
+ timeoutLabel: "fetch callback"
833
+ }).finally(() => {
834
+ init.signal.removeEventListener("abort", onInitAbort);
835
+ });
804
836
  if (result && typeof result === "object" && result.__streamingResponse) {
805
837
  const response = result.response;
806
838
  response.__isCallbackStream = true;
@@ -1331,6 +1363,7 @@ function handleCallbackResponse(message, connection) {
1331
1363
  return;
1332
1364
  }
1333
1365
  connection.pendingCallbacks.delete(message.requestId);
1366
+ pending.cleanup?.();
1334
1367
  if (message.error) {
1335
1368
  const error = new Error(message.error.message);
1336
1369
  error.name = message.error.name;
@@ -1342,12 +1375,68 @@ function handleCallbackResponse(message, connection) {
1342
1375
  pending.resolve(message.result);
1343
1376
  }
1344
1377
  }
1345
- async function invokeClientCallback(connection, callbackId, args) {
1378
+ async function invokeClientCallback(connection, callbackId, args, options) {
1346
1379
  const requestId = connection.nextCallbackId++;
1380
+ const timeoutMs = options?.timeoutMs ?? DEFAULT_CALLBACK_TIMEOUT_MS;
1347
1381
  return new Promise((resolve, reject) => {
1382
+ let settled = false;
1383
+ let timeoutId;
1384
+ let onAbort;
1385
+ let callbackInvokeSent = false;
1386
+ const settle = (handler, value) => {
1387
+ if (settled)
1388
+ return;
1389
+ settled = true;
1390
+ connection.pendingCallbacks.delete(requestId);
1391
+ if (timeoutId) {
1392
+ clearTimeout(timeoutId);
1393
+ timeoutId = undefined;
1394
+ }
1395
+ if (options?.signal && onAbort) {
1396
+ options.signal.removeEventListener("abort", onAbort);
1397
+ }
1398
+ handler(value);
1399
+ };
1400
+ onAbort = () => {
1401
+ if (settled)
1402
+ return;
1403
+ if (callbackInvokeSent) {
1404
+ sendCallbackAbortMessage(connection, requestId, options?.timeoutLabel ? `${options.timeoutLabel} aborted` : "Callback aborted");
1405
+ }
1406
+ settle(reject, createAbortError());
1407
+ };
1408
+ if (options?.signal) {
1409
+ if (options.signal.aborted) {
1410
+ onAbort();
1411
+ return;
1412
+ }
1413
+ options.signal.addEventListener("abort", onAbort, { once: true });
1414
+ }
1415
+ if (timeoutMs > 0) {
1416
+ timeoutId = setTimeout(() => {
1417
+ if (settled)
1418
+ return;
1419
+ const label = options?.timeoutLabel ?? "callback";
1420
+ const timeoutError = new Error(`${label} timed out after ${timeoutMs}ms`);
1421
+ if (callbackInvokeSent) {
1422
+ sendCallbackAbortMessage(connection, requestId, timeoutError.message);
1423
+ }
1424
+ settle(reject, timeoutError);
1425
+ }, timeoutMs);
1426
+ }
1348
1427
  const pending = {
1349
- resolve,
1350
- reject
1428
+ callbackId,
1429
+ cleanup: () => {
1430
+ if (timeoutId) {
1431
+ clearTimeout(timeoutId);
1432
+ timeoutId = undefined;
1433
+ }
1434
+ if (options?.signal && onAbort) {
1435
+ options.signal.removeEventListener("abort", onAbort);
1436
+ }
1437
+ },
1438
+ resolve: (result) => settle(resolve, result),
1439
+ reject: (error) => settle(reject, error)
1351
1440
  };
1352
1441
  connection.pendingCallbacks.set(requestId, pending);
1353
1442
  const invoke = {
@@ -1357,6 +1446,7 @@ async function invokeClientCallback(connection, callbackId, args) {
1357
1446
  args
1358
1447
  };
1359
1448
  sendMessage(connection.socket, invoke);
1449
+ callbackInvokeSent = true;
1360
1450
  });
1361
1451
  }
1362
1452
  function handleStreamPush(message, connection) {
@@ -1773,4 +1863,4 @@ async function handleClearCollectedData(message, connection, state) {
1773
1863
  }
1774
1864
  }
1775
1865
 
1776
- //# debugId=CCDD5E4DA24900F364756E2164756E21
1866
+ //# debugId=8F51D70F9171DF6C64756E2164756E21