@ricsam/isolate-daemon 0.1.14 → 0.1.16

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.
@@ -36,6 +36,28 @@ var import_node_crypto = require("node:crypto");
36
36
  var import_isolate_protocol = require("@ricsam/isolate-protocol");
37
37
  var import_callback_fs_handler = require("./callback-fs-handler.cjs");
38
38
  var import_isolate_runtime = require("@ricsam/isolate-runtime");
39
+ var LINKER_CONFLICT_ERROR = "Module is currently being linked by another linker";
40
+ function getErrorText(error) {
41
+ if (error instanceof Error) {
42
+ const cause = error.cause;
43
+ const causeText = cause instanceof Error ? `${cause.name}: ${cause.message}
44
+ ${cause.stack ?? ""}` : cause != null ? String(cause) : "";
45
+ return [error.name, error.message, error.stack, causeText].filter((part) => part != null && part !== "").join(`
46
+ `);
47
+ }
48
+ if (typeof error === "string") {
49
+ return error;
50
+ }
51
+ try {
52
+ return JSON.stringify(error);
53
+ } catch {
54
+ return String(error ?? "");
55
+ }
56
+ }
57
+ function isLinkerConflictError(error) {
58
+ const text = getErrorText(error).toLowerCase();
59
+ return text.includes(LINKER_CONFLICT_ERROR.toLowerCase());
60
+ }
39
61
  function handleConnection(socket, state) {
40
62
  const connection = {
41
63
  socket,
@@ -68,17 +90,17 @@ function handleConnection(socket, state) {
68
90
  const instance = state.isolates.get(isolateId);
69
91
  if (instance) {
70
92
  if (instance.namespaceId != null && !instance.isDisposed) {
71
- softDeleteRuntime(instance, state);
93
+ if (instance.isPoisoned) {
94
+ hardDeleteRuntime(instance, state).catch(() => {});
95
+ } else {
96
+ softDeleteRuntime(instance, state);
97
+ }
72
98
  } else if (!instance.isDisposed) {
73
- instance.runtime.dispose().catch(() => {});
74
- state.isolates.delete(isolateId);
99
+ hardDeleteRuntime(instance, state).catch(() => {});
75
100
  }
76
101
  }
77
102
  }
78
103
  for (const [, pending] of connection.pendingCallbacks) {
79
- if (pending.timeoutId) {
80
- clearTimeout(pending.timeoutId);
81
- }
82
104
  pending.reject(new Error("Connection closed"));
83
105
  }
84
106
  connection.pendingCallbacks.clear();
@@ -206,28 +228,64 @@ async function handleMessage(message, connection, state) {
206
228
  case import_isolate_protocol.MessageType.CALLBACK_STREAM_END:
207
229
  handleCallbackStreamEnd(message, connection);
208
230
  break;
209
- case import_isolate_protocol.MessageType.CLIENT_WS_OPENED:
210
- handleClientWsOpened(message, connection, state);
211
- break;
212
- case import_isolate_protocol.MessageType.CLIENT_WS_MESSAGE:
213
- handleClientWsMessage(message, connection, state);
214
- break;
215
- case import_isolate_protocol.MessageType.CLIENT_WS_CLOSED:
216
- handleClientWsClosed(message, connection, state);
217
- break;
218
- case import_isolate_protocol.MessageType.CLIENT_WS_ERROR:
219
- handleClientWsError(message, connection, state);
231
+ case import_isolate_protocol.MessageType.CLIENT_EVENT:
232
+ handleClientEvent(message, connection, state);
220
233
  break;
221
234
  default:
222
235
  sendError(connection.socket, message.requestId ?? 0, import_isolate_protocol.ErrorCode.UNKNOWN_MESSAGE_TYPE, `Unknown message type: ${message.type}`);
223
236
  }
224
237
  }
238
+ async function hardDeleteRuntime(instance, state) {
239
+ try {
240
+ await instance.runtime.dispose();
241
+ } finally {
242
+ state.isolates.delete(instance.isolateId);
243
+ if (instance.namespaceId != null) {
244
+ const indexed = state.namespacedRuntimes.get(instance.namespaceId);
245
+ if (indexed?.isolateId === instance.isolateId) {
246
+ state.namespacedRuntimes.delete(instance.namespaceId);
247
+ }
248
+ }
249
+ instance.isDisposed = true;
250
+ instance.disposedAt = undefined;
251
+ instance.ownerConnection = null;
252
+ if (instance.callbackContext) {
253
+ if (instance.callbackContext.reconnectionPromise) {
254
+ clearTimeout(instance.callbackContext.reconnectionPromise.timeoutId);
255
+ instance.callbackContext.reconnectionPromise.promise.catch(() => {});
256
+ instance.callbackContext.reconnectionPromise.reject(new Error("Runtime was permanently disposed"));
257
+ instance.callbackContext.reconnectionPromise = undefined;
258
+ }
259
+ instance.callbackContext.connection = null;
260
+ }
261
+ }
262
+ }
263
+ var RECONNECTION_TIMEOUT_MS = 30000;
225
264
  function softDeleteRuntime(instance, state) {
226
265
  instance.isDisposed = true;
227
266
  instance.disposedAt = Date.now();
228
267
  instance.ownerConnection = null;
229
268
  if (instance.callbackContext) {
230
269
  instance.callbackContext.connection = null;
270
+ let resolve;
271
+ let reject;
272
+ const promise = new Promise((res, rej) => {
273
+ resolve = res;
274
+ reject = rej;
275
+ });
276
+ promise.catch(() => {});
277
+ const timeoutId = setTimeout(() => {
278
+ if (instance.callbackContext?.reconnectionPromise) {
279
+ instance.callbackContext.reconnectionPromise = undefined;
280
+ reject(new Error("Reconnection timeout: no client reconnected within timeout"));
281
+ }
282
+ }, RECONNECTION_TIMEOUT_MS);
283
+ instance.callbackContext.reconnectionPromise = {
284
+ promise,
285
+ resolve,
286
+ reject,
287
+ timeoutId
288
+ };
231
289
  }
232
290
  instance.callbacks.clear();
233
291
  instance.runtime.timers.clearAll();
@@ -241,6 +299,7 @@ function softDeleteRuntime(instance, state) {
241
299
  function reuseNamespacedRuntime(instance, connection, message, state) {
242
300
  instance.ownerConnection = connection.socket;
243
301
  instance.isDisposed = false;
302
+ instance.isPoisoned = false;
244
303
  instance.disposedAt = undefined;
245
304
  instance.lastActivity = Date.now();
246
305
  connection.isolates.add(instance.isolateId);
@@ -248,6 +307,11 @@ function reuseNamespacedRuntime(instance, connection, message, state) {
248
307
  const testEnvOptions = message.options.testEnvironment != null && typeof message.options.testEnvironment === "object" ? message.options.testEnvironment : undefined;
249
308
  if (instance.callbackContext) {
250
309
  instance.callbackContext.connection = connection;
310
+ if (instance.callbackContext.reconnectionPromise) {
311
+ clearTimeout(instance.callbackContext.reconnectionPromise.timeoutId);
312
+ instance.callbackContext.reconnectionPromise.resolve(connection);
313
+ instance.callbackContext.reconnectionPromise = undefined;
314
+ }
251
315
  instance.callbackContext.consoleOnEntry = callbacks?.console?.onEntry?.callbackId;
252
316
  instance.callbackContext.fetch = callbacks?.fetch?.callbackId;
253
317
  instance.callbackContext.moduleLoader = callbacks?.moduleLoader?.callbackId;
@@ -342,6 +406,35 @@ function reuseNamespacedRuntime(instance, connection, message, state) {
342
406
  instance.returnedIterators = new Map;
343
407
  instance.nextLocalCallbackId = 1e6;
344
408
  }
409
+ async function waitForConnection(callbackContext) {
410
+ if (callbackContext.connection) {
411
+ return callbackContext.connection;
412
+ }
413
+ if (callbackContext.reconnectionPromise) {
414
+ return callbackContext.reconnectionPromise.promise;
415
+ }
416
+ throw new Error("No connection available and no reconnection pending");
417
+ }
418
+ async function invokeCallbackWithReconnect(callbackContext, getCallbackId, args, label, invokeClientCallback) {
419
+ const conn = await waitForConnection(callbackContext);
420
+ const cbId = getCallbackId();
421
+ if (cbId === undefined) {
422
+ throw new Error(`${label} callback not available`);
423
+ }
424
+ try {
425
+ return await invokeClientCallback(conn, cbId, args);
426
+ } catch (err) {
427
+ if (callbackContext.reconnectionPromise && !callbackContext.connection) {
428
+ const newConn = await callbackContext.reconnectionPromise.promise;
429
+ const newCbId = getCallbackId();
430
+ if (newCbId === undefined) {
431
+ throw new Error(`${label} callback not available after reconnection`);
432
+ }
433
+ return invokeClientCallback(newConn, newCbId, args);
434
+ }
435
+ throw err;
436
+ }
437
+ }
345
438
  async function evictOldestDisposedRuntime(state) {
346
439
  let oldest = null;
347
440
  let oldestTime = Infinity;
@@ -355,18 +448,15 @@ async function evictOldestDisposedRuntime(state) {
355
448
  }
356
449
  if (oldest) {
357
450
  try {
358
- await oldest.runtime.dispose();
451
+ await hardDeleteRuntime(oldest, state);
359
452
  } catch {}
360
- state.isolates.delete(oldest.isolateId);
361
- if (oldest.namespaceId != null) {
362
- state.namespacedRuntimes.delete(oldest.namespaceId);
363
- }
364
453
  return true;
365
454
  }
366
455
  return false;
367
456
  }
368
457
  async function handleCreateRuntime(message, connection, state) {
369
458
  const namespaceId = message.options.namespaceId;
459
+ let namespaceCreationLocked = false;
370
460
  if (namespaceId != null) {
371
461
  const existing = state.namespacedRuntimes.get(namespaceId);
372
462
  if (existing) {
@@ -388,14 +478,20 @@ async function handleCreateRuntime(message, connection, state) {
388
478
  });
389
479
  return;
390
480
  }
391
- }
392
- if (state.isolates.size >= state.options.maxIsolates) {
393
- if (!await evictOldestDisposedRuntime(state)) {
394
- sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_MEMORY_LIMIT, `Maximum isolates (${state.options.maxIsolates}) reached`);
481
+ if (state.namespacedCreatesInFlight.has(namespaceId)) {
482
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, `Namespace "${namespaceId}" creation already in progress`);
395
483
  return;
396
484
  }
485
+ state.namespacedCreatesInFlight.add(namespaceId);
486
+ namespaceCreationLocked = true;
397
487
  }
398
488
  try {
489
+ if (state.isolates.size >= state.options.maxIsolates) {
490
+ if (!await evictOldestDisposedRuntime(state)) {
491
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_MEMORY_LIMIT, `Maximum isolates (${state.options.maxIsolates}) reached`);
492
+ return;
493
+ }
494
+ }
399
495
  const isolateId = import_node_crypto.randomUUID();
400
496
  const consoleCallbacks = message.options.callbacks?.console;
401
497
  const fetchCallback = message.options.callbacks?.fetch;
@@ -438,6 +534,7 @@ async function handleCreateRuntime(message, connection, state) {
438
534
  nextLocalCallbackId: 1e6,
439
535
  namespaceId,
440
536
  isDisposed: false,
537
+ isPoisoned: false,
441
538
  callbackContext
442
539
  };
443
540
  let bridgedCustomFunctions;
@@ -460,12 +557,10 @@ async function handleCreateRuntime(message, connection, state) {
460
557
  return iteratorId;
461
558
  }
462
559
  });
463
- const isPromiseRef = (value) => typeof value === "object" && value !== null && value.__type === "PromiseRef";
464
- const isAsyncIteratorRef = (value) => typeof value === "object" && value !== null && value.__type === "AsyncIteratorRef";
465
560
  const addCallbackIdsToRefs = (value) => {
466
561
  if (value === null || typeof value !== "object")
467
562
  return value;
468
- if (isPromiseRef(value)) {
563
+ if (import_isolate_protocol.isPromiseRef(value)) {
469
564
  if ("__resolveCallbackId" in value)
470
565
  return value;
471
566
  const resolveCallbackId = instance.nextLocalCallbackId++;
@@ -481,7 +576,7 @@ async function handleCreateRuntime(message, connection, state) {
481
576
  });
482
577
  return { ...value, __resolveCallbackId: resolveCallbackId };
483
578
  }
484
- if (isAsyncIteratorRef(value)) {
579
+ if (import_isolate_protocol.isAsyncIteratorRef(value)) {
485
580
  if ("__nextCallbackId" in value)
486
581
  return value;
487
582
  const nextCallbackId = instance.nextLocalCallbackId++;
@@ -526,11 +621,16 @@ async function handleCreateRuntime(message, connection, state) {
526
621
  }
527
622
  return await callback(...args);
528
623
  } else {
529
- const conn = callbackContext.connection;
530
- if (!conn) {
531
- throw new Error(`No connection available for callback ${callbackId}`);
624
+ const conn = await waitForConnection(callbackContext);
625
+ try {
626
+ return await invokeClientCallback(conn, callbackId, args);
627
+ } catch (err) {
628
+ if (callbackContext.reconnectionPromise && !callbackContext.connection) {
629
+ const newConn = await callbackContext.reconnectionPromise.promise;
630
+ return invokeClientCallback(newConn, callbackId, args);
631
+ }
632
+ throw err;
532
633
  }
533
- return invokeClientCallback(conn, callbackId, args);
534
634
  }
535
635
  };
536
636
  customFnMarshalOptions = { createMarshalContext, addCallbackIdsToRefs, invokeCallback };
@@ -547,27 +647,20 @@ async function handleCreateRuntime(message, connection, state) {
547
647
  const nextCallbackId = callbackContext_.custom.get(`${name}:next`);
548
648
  const returnCallbackId = callbackContext_.custom.get(`${name}:return`);
549
649
  async function* bridgedIterator() {
550
- const conn = callbackContext_.connection;
551
- if (!conn || startCallbackId === undefined) {
552
- throw new Error(`AsyncIterator callback '${name}' not available`);
553
- }
554
- const startResult = await invokeClientCallback(conn, startCallbackId, args);
650
+ const startResult = await invokeCallbackWithReconnect(callbackContext_, () => callbackContext_.custom.get(`${name}:start`), args, `AsyncIterator '${name}' start`, invokeClientCallback);
555
651
  const iteratorId = startResult.iteratorId;
556
652
  try {
557
653
  while (true) {
558
- const nextConn = callbackContext_.connection;
559
- if (!nextConn || nextCallbackId === undefined) {
560
- throw new Error(`AsyncIterator callback '${name}' not available`);
561
- }
562
- const nextResult = await invokeClientCallback(nextConn, nextCallbackId, [iteratorId]);
654
+ const nextResult = await invokeCallbackWithReconnect(callbackContext_, () => callbackContext_.custom.get(`${name}:next`), [iteratorId], `AsyncIterator '${name}' next`, invokeClientCallback);
563
655
  if (nextResult.done)
564
656
  return nextResult.value;
565
657
  yield nextResult.value;
566
658
  }
567
659
  } finally {
568
660
  const retConn = callbackContext_.connection;
569
- if (retConn && returnCallbackId !== undefined) {
570
- await invokeClientCallback(retConn, returnCallbackId, [iteratorId]).catch(() => {});
661
+ const retCbId = callbackContext_.custom.get(`${name}:return`);
662
+ if (retConn && retCbId !== undefined) {
663
+ await invokeClientCallback(retConn, retCbId, [iteratorId]).catch(() => {});
571
664
  }
572
665
  }
573
666
  }
@@ -578,12 +671,7 @@ async function handleCreateRuntime(message, connection, state) {
578
671
  bridgedCustomFunctions[name] = {
579
672
  type: registration.type,
580
673
  fn: async (...args) => {
581
- const conn = callbackContext_.connection;
582
- const cbId = callbackContext_.custom.get(name);
583
- if (!conn || cbId === undefined) {
584
- throw new Error(`Custom function callback '${name}' not available`);
585
- }
586
- return invokeClientCallback(conn, cbId, args);
674
+ return invokeCallbackWithReconnect(callbackContext_, () => callbackContext_.custom.get(name), args, `Custom function '${name}'`, invokeClientCallback);
587
675
  }
588
676
  };
589
677
  }
@@ -592,12 +680,7 @@ async function handleCreateRuntime(message, connection, state) {
592
680
  let moduleLoader;
593
681
  if (moduleLoaderCallback) {
594
682
  moduleLoader = async (specifier, importer) => {
595
- const conn = callbackContext.connection;
596
- const cbId = callbackContext.moduleLoader;
597
- if (!conn || cbId === undefined) {
598
- throw new Error("Module loader callback not available");
599
- }
600
- return invokeClientCallback(conn, cbId, [specifier, importer]);
683
+ return invokeCallbackWithReconnect(callbackContext, () => callbackContext.moduleLoader, [specifier, importer], "Module loader", invokeClientCallback);
601
684
  };
602
685
  }
603
686
  let testEnvironment;
@@ -628,19 +711,8 @@ async function handleCreateRuntime(message, connection, state) {
628
711
  if (playwrightCallbacks) {
629
712
  playwrightOptions = {
630
713
  handler: async (op) => {
631
- const conn = callbackContext.connection;
632
- const callbackId = callbackContext.playwright.handlerCallbackId;
633
- if (!conn || callbackId === undefined) {
634
- return {
635
- ok: false,
636
- error: {
637
- name: "Error",
638
- message: "Playwright handler callback not available"
639
- }
640
- };
641
- }
642
714
  try {
643
- const resultJson = await invokeClientCallback(conn, callbackId, [JSON.stringify(op)], 60000);
715
+ const resultJson = await invokeCallbackWithReconnect(callbackContext, () => callbackContext.playwright.handlerCallbackId, [JSON.stringify(op)], "Playwright handler", invokeClientCallback);
644
716
  return JSON.parse(resultJson);
645
717
  } catch (err) {
646
718
  const error = err;
@@ -680,31 +752,23 @@ async function handleCreateRuntime(message, connection, state) {
680
752
  }
681
753
  },
682
754
  fetch: async (url, init) => {
683
- const conn = callbackContext.connection;
684
- const callbackId = callbackContext.fetch;
685
- if (!conn || callbackId === undefined) {
686
- throw new Error("Fetch callback not available");
687
- }
688
755
  const serialized = {
689
756
  url,
690
757
  method: init.method,
691
758
  headers: init.headers,
692
759
  body: init.rawBody
693
760
  };
694
- const result = await invokeClientCallback(conn, callbackId, [serialized], 60000);
761
+ const result = await invokeCallbackWithReconnect(callbackContext, () => callbackContext.fetch, [serialized], "Fetch", invokeClientCallback);
695
762
  if (result && typeof result === "object" && result.__streamingResponse) {
696
763
  const response = result.response;
697
764
  response.__isCallbackStream = true;
698
765
  return response;
699
766
  }
700
- return deserializeResponse(result);
767
+ return import_isolate_protocol.deserializeResponse(result);
701
768
  },
702
769
  fs: {
703
770
  getDirectory: async (dirPath) => {
704
- const conn = callbackContext.connection;
705
- if (!conn) {
706
- throw new Error("FS callbacks not available");
707
- }
771
+ const conn = await waitForConnection(callbackContext);
708
772
  return import_callback_fs_handler.createCallbackFileSystemHandler({
709
773
  connection: conn,
710
774
  callbackContext,
@@ -791,18 +855,19 @@ async function handleCreateRuntime(message, connection, state) {
791
855
  } else {
792
856
  data = cmd.data;
793
857
  }
794
- const wsCommandMsg = {
795
- type: import_isolate_protocol.MessageType.WS_COMMAND,
796
- isolateId,
797
- command: {
798
- type: cmd.type,
799
- connectionId: cmd.connectionId,
800
- data,
801
- code: cmd.code,
802
- reason: cmd.reason
803
- }
858
+ const payload = {
859
+ type: cmd.type,
860
+ connectionId: cmd.connectionId,
861
+ data,
862
+ code: cmd.code,
863
+ reason: cmd.reason
804
864
  };
805
- sendMessage(targetConnection.socket, wsCommandMsg);
865
+ sendMessage(targetConnection.socket, {
866
+ type: import_isolate_protocol.MessageType.ISOLATE_EVENT,
867
+ isolateId,
868
+ event: import_isolate_protocol.IsolateEvents.WS_COMMAND,
869
+ payload
870
+ });
806
871
  });
807
872
  runtime.fetch.onClientWebSocketCommand((cmd) => {
808
873
  const targetConnection = callbackContext.connection;
@@ -816,40 +881,62 @@ async function handleCreateRuntime(message, connection, state) {
816
881
  data = cmd.data;
817
882
  }
818
883
  if (cmd.type === "connect") {
819
- const msg = {
820
- type: import_isolate_protocol.MessageType.CLIENT_WS_CONNECT,
821
- requestId: 0,
822
- isolateId,
884
+ const payload = {
823
885
  socketId: cmd.socketId,
824
886
  url: cmd.url,
825
887
  protocols: cmd.protocols
826
888
  };
827
- sendMessage(targetConnection.socket, msg);
828
- } else if (cmd.type === "send") {
829
- const msg = {
830
- type: import_isolate_protocol.MessageType.CLIENT_WS_SEND,
831
- requestId: 0,
889
+ sendMessage(targetConnection.socket, {
890
+ type: import_isolate_protocol.MessageType.ISOLATE_EVENT,
832
891
  isolateId,
892
+ event: import_isolate_protocol.IsolateEvents.WS_CLIENT_CONNECT,
893
+ payload
894
+ });
895
+ } else if (cmd.type === "send") {
896
+ const payload = {
833
897
  socketId: cmd.socketId,
834
898
  data
835
899
  };
836
- sendMessage(targetConnection.socket, msg);
837
- } else if (cmd.type === "close") {
838
- const msg = {
839
- type: import_isolate_protocol.MessageType.CLIENT_WS_CLOSE,
840
- requestId: 0,
900
+ sendMessage(targetConnection.socket, {
901
+ type: import_isolate_protocol.MessageType.ISOLATE_EVENT,
841
902
  isolateId,
903
+ event: import_isolate_protocol.IsolateEvents.WS_CLIENT_SEND,
904
+ payload
905
+ });
906
+ } else if (cmd.type === "close") {
907
+ const payload = {
842
908
  socketId: cmd.socketId,
843
909
  code: cmd.code,
844
910
  reason: cmd.reason
845
911
  };
846
- sendMessage(targetConnection.socket, msg);
912
+ sendMessage(targetConnection.socket, {
913
+ type: import_isolate_protocol.MessageType.ISOLATE_EVENT,
914
+ isolateId,
915
+ event: import_isolate_protocol.IsolateEvents.WS_CLIENT_CLOSE,
916
+ payload
917
+ });
847
918
  }
848
919
  });
920
+ runtime.fetch.onEvent((eventName, payload) => {
921
+ const targetConnection = callbackContext.connection;
922
+ if (!targetConnection) {
923
+ return;
924
+ }
925
+ sendMessage(targetConnection.socket, {
926
+ type: import_isolate_protocol.MessageType.ISOLATE_EVENT,
927
+ isolateId,
928
+ event: eventName,
929
+ payload
930
+ });
931
+ });
849
932
  sendOk(connection.socket, message.requestId, { isolateId, reused: false });
850
933
  } catch (err) {
851
934
  const error = err;
852
935
  sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
936
+ } finally {
937
+ if (namespaceCreationLocked && namespaceId != null) {
938
+ state.namespacedCreatesInFlight.delete(namespaceId);
939
+ }
853
940
  }
854
941
  }
855
942
  async function handleDisposeRuntime(message, connection, state) {
@@ -865,14 +952,20 @@ async function handleDisposeRuntime(message, connection, state) {
865
952
  try {
866
953
  connection.isolates.delete(message.isolateId);
867
954
  if (instance.namespaceId != null) {
868
- softDeleteRuntime(instance, state);
955
+ if (instance.isPoisoned) {
956
+ await hardDeleteRuntime(instance, state);
957
+ } else {
958
+ softDeleteRuntime(instance, state);
959
+ }
869
960
  } else {
870
- await instance.runtime.dispose();
871
- state.isolates.delete(message.isolateId);
961
+ await hardDeleteRuntime(instance, state);
872
962
  }
873
963
  sendOk(connection.socket, message.requestId);
874
964
  } catch (err) {
875
965
  const error = err;
966
+ if (instance.namespaceId != null && isLinkerConflictError(error)) {
967
+ instance.isPoisoned = true;
968
+ }
876
969
  sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
877
970
  }
878
971
  }
@@ -885,14 +978,15 @@ async function handleEval(message, connection, state) {
885
978
  instance.lastActivity = Date.now();
886
979
  try {
887
980
  await instance.runtime.eval(message.code, {
888
- filename: message.filename,
889
- maxExecutionMs: message.maxExecutionMs
981
+ filename: message.filename
890
982
  });
891
983
  sendOk(connection.socket, message.requestId, { value: undefined });
892
984
  } catch (err) {
893
985
  const error = err;
894
- const isTimeoutError = error.message?.includes("Script execution timed out");
895
- sendError(connection.socket, message.requestId, isTimeoutError ? import_isolate_protocol.ErrorCode.ISOLATE_TIMEOUT : import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
986
+ if (instance.namespaceId != null && isLinkerConflictError(error)) {
987
+ instance.isPoisoned = true;
988
+ }
989
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
896
990
  }
897
991
  }
898
992
  async function handleDispatchRequest(message, connection, state) {
@@ -1000,34 +1094,38 @@ async function handleWsClose(message, connection, state) {
1000
1094
  sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1001
1095
  }
1002
1096
  }
1003
- function handleClientWsOpened(message, connection, state) {
1004
- const instance = state.isolates.get(message.isolateId);
1005
- if (!instance)
1006
- return;
1007
- instance.lastActivity = Date.now();
1008
- instance.runtime.fetch.dispatchClientWebSocketOpen(message.socketId, message.protocol, message.extensions);
1009
- }
1010
- function handleClientWsMessage(message, connection, state) {
1011
- const instance = state.isolates.get(message.isolateId);
1012
- if (!instance)
1013
- return;
1014
- instance.lastActivity = Date.now();
1015
- const data = message.data instanceof Uint8Array ? message.data.buffer.slice(message.data.byteOffset, message.data.byteOffset + message.data.byteLength) : message.data;
1016
- instance.runtime.fetch.dispatchClientWebSocketMessage(message.socketId, data);
1017
- }
1018
- function handleClientWsClosed(message, connection, state) {
1097
+ function handleClientEvent(message, connection, state) {
1019
1098
  const instance = state.isolates.get(message.isolateId);
1020
1099
  if (!instance)
1021
1100
  return;
1022
1101
  instance.lastActivity = Date.now();
1023
- instance.runtime.fetch.dispatchClientWebSocketClose(message.socketId, message.code, message.reason, message.wasClean);
1024
- }
1025
- function handleClientWsError(message, connection, state) {
1026
- const instance = state.isolates.get(message.isolateId);
1027
- if (!instance)
1028
- return;
1029
- instance.lastActivity = Date.now();
1030
- instance.runtime.fetch.dispatchClientWebSocketError(message.socketId);
1102
+ switch (message.event) {
1103
+ case import_isolate_protocol.ClientEvents.WS_CLIENT_OPENED: {
1104
+ const payload = message.payload;
1105
+ instance.runtime.fetch.dispatchClientWebSocketOpen(payload.socketId, payload.protocol, payload.extensions);
1106
+ break;
1107
+ }
1108
+ case import_isolate_protocol.ClientEvents.WS_CLIENT_MESSAGE: {
1109
+ const payload = message.payload;
1110
+ const data = payload.data instanceof Uint8Array ? payload.data.buffer.slice(payload.data.byteOffset, payload.data.byteOffset + payload.data.byteLength) : payload.data;
1111
+ instance.runtime.fetch.dispatchClientWebSocketMessage(payload.socketId, data);
1112
+ break;
1113
+ }
1114
+ case import_isolate_protocol.ClientEvents.WS_CLIENT_CLOSED: {
1115
+ const payload = message.payload;
1116
+ instance.runtime.fetch.dispatchClientWebSocketClose(payload.socketId, payload.code, payload.reason, payload.wasClean);
1117
+ break;
1118
+ }
1119
+ case import_isolate_protocol.ClientEvents.WS_CLIENT_ERROR: {
1120
+ const payload = message.payload;
1121
+ instance.runtime.fetch.dispatchClientWebSocketError(payload.socketId);
1122
+ break;
1123
+ }
1124
+ default: {
1125
+ instance.runtime.fetch.dispatchEvent(message.event, message.payload);
1126
+ break;
1127
+ }
1128
+ }
1031
1129
  }
1032
1130
  async function handleFetchGetUpgradeRequest(message, connection, state) {
1033
1131
  const instance = state.isolates.get(message.isolateId);
@@ -1171,9 +1269,6 @@ function handleCallbackResponse(message, connection) {
1171
1269
  return;
1172
1270
  }
1173
1271
  connection.pendingCallbacks.delete(message.requestId);
1174
- if (pending.timeoutId) {
1175
- clearTimeout(pending.timeoutId);
1176
- }
1177
1272
  if (message.error) {
1178
1273
  const error = new Error(message.error.message);
1179
1274
  error.name = message.error.name;
@@ -1185,17 +1280,12 @@ function handleCallbackResponse(message, connection) {
1185
1280
  pending.resolve(message.result);
1186
1281
  }
1187
1282
  }
1188
- async function invokeClientCallback(connection, callbackId, args, timeout = 1e4) {
1283
+ async function invokeClientCallback(connection, callbackId, args) {
1189
1284
  const requestId = connection.nextCallbackId++;
1190
1285
  return new Promise((resolve, reject) => {
1191
- const timeoutId = setTimeout(() => {
1192
- connection.pendingCallbacks.delete(requestId);
1193
- reject(new Error("Callback timeout"));
1194
- }, timeout);
1195
1286
  const pending = {
1196
1287
  resolve,
1197
- reject,
1198
- timeoutId
1288
+ reject
1199
1289
  };
1200
1290
  connection.pendingCallbacks.set(requestId, pending);
1201
1291
  const invoke = {
@@ -1207,13 +1297,6 @@ async function invokeClientCallback(connection, callbackId, args, timeout = 1e4)
1207
1297
  sendMessage(connection.socket, invoke);
1208
1298
  });
1209
1299
  }
1210
- function deserializeResponse(data) {
1211
- return new Response(data.body, {
1212
- status: data.status,
1213
- statusText: data.statusText,
1214
- headers: data.headers
1215
- });
1216
- }
1217
1300
  function handleStreamPush(message, connection) {
1218
1301
  const receiver = connection.streamReceivers.get(message.streamId);
1219
1302
  if (!receiver) {
@@ -1341,9 +1424,6 @@ function handleCallbackStreamStart(message, connection) {
1341
1424
  const pending = connection.pendingCallbacks.get(message.requestId);
1342
1425
  if (pending) {
1343
1426
  connection.pendingCallbacks.delete(message.requestId);
1344
- if (pending.timeoutId) {
1345
- clearTimeout(pending.timeoutId);
1346
- }
1347
1427
  const response = new Response(readableStream, {
1348
1428
  status: message.metadata.status,
1349
1429
  statusText: message.metadata.statusText,
@@ -1474,13 +1554,35 @@ async function handleRunTests(message, connection, state) {
1474
1554
  return;
1475
1555
  }
1476
1556
  instance.lastActivity = Date.now();
1557
+ if (instance.pendingTestRun) {
1558
+ try {
1559
+ const results = await instance.pendingTestRun.promise;
1560
+ const currentConn = instance.callbackContext?.connection;
1561
+ if (currentConn) {
1562
+ sendOk(currentConn.socket, message.requestId, results);
1563
+ }
1564
+ } catch (err) {
1565
+ const error = err;
1566
+ const currentConn = instance.callbackContext?.connection;
1567
+ if (currentConn) {
1568
+ sendError(currentConn.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1569
+ }
1570
+ }
1571
+ return;
1572
+ }
1477
1573
  try {
1478
1574
  const timeout = message.timeout ?? 30000;
1479
- const results = await instance.runtime.testEnvironment.runTests(timeout);
1480
- sendOk(connection.socket, message.requestId, results);
1575
+ const runPromise = instance.runtime.testEnvironment.runTests(timeout);
1576
+ instance.pendingTestRun = { promise: runPromise };
1577
+ const results = await runPromise;
1578
+ instance.pendingTestRun = undefined;
1579
+ const currentConn = instance.callbackContext?.connection ?? connection;
1580
+ sendOk(currentConn.socket, message.requestId, results);
1481
1581
  } catch (err) {
1582
+ instance.pendingTestRun = undefined;
1482
1583
  const error = err;
1483
- sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1584
+ const currentConn = instance.callbackContext?.connection ?? connection;
1585
+ sendError(currentConn.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1484
1586
  }
1485
1587
  }
1486
1588
  async function handleResetTestEnv(message, connection, state) {
@@ -1559,4 +1661,4 @@ async function handleClearCollectedData(message, connection, state) {
1559
1661
  }
1560
1662
  }
1561
1663
 
1562
- //# debugId=53A5FD566727ACE764756E2164756E21
1664
+ //# debugId=D9712A3ECDBAF18B64756E2164756E21