@ricsam/isolate-runtime 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.
@@ -4,23 +4,6 @@ var __defProp = Object.defineProperty;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __reExport = (target, mod, secondTarget) => {
8
- for (let key of __getOwnPropNames(mod))
9
- if (!__hasOwnProp.call(target, key) && key !== "default")
10
- __defProp(target, key, {
11
- get: () => mod[key],
12
- enumerable: true
13
- });
14
- if (secondTarget) {
15
- for (let key of __getOwnPropNames(mod))
16
- if (!__hasOwnProp.call(secondTarget, key) && key !== "default")
17
- __defProp(secondTarget, key, {
18
- get: () => mod[key],
19
- enumerable: true
20
- });
21
- return secondTarget;
22
- }
23
- };
24
7
  var __toESM = (mod, isNodeMode, target) => {
25
8
  target = mod != null ? __create(__getProtoOf(mod)) : {};
26
9
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
@@ -74,6 +57,8 @@ __export(exports_src, {
74
57
  normalizeEntryFilename: () => import_isolate_protocol2.normalizeEntryFilename,
75
58
  hasTests: () => import_isolate_test_environment2.hasTests,
76
59
  getTestCount: () => import_isolate_test_environment2.getTestCount,
60
+ getDefaultPlaywrightHandlerMetadata: () => import_isolate_playwright2.getDefaultPlaywrightHandlerMetadata,
61
+ defaultPlaywrightHandler: () => import_isolate_playwright2.defaultPlaywrightHandler,
77
62
  createRuntime: () => createRuntime,
78
63
  createPlaywrightHandler: () => import_isolate_playwright2.createPlaywrightHandler,
79
64
  createNodeFileSystemHandler: () => import_isolate_fs2.createNodeFileSystemHandler
@@ -106,7 +91,6 @@ var import_isolate_path2 = require("@ricsam/isolate-path");
106
91
  var import_isolate_timers2 = require("@ricsam/isolate-timers");
107
92
  var import_isolate_test_environment2 = require("@ricsam/isolate-test-environment");
108
93
  var import_isolate_playwright2 = require("@ricsam/isolate-playwright");
109
- __reExport(exports_src, require("./internal.cjs"), module.exports);
110
94
  var iteratorSessions = new Map;
111
95
  var nextIteratorId = 1;
112
96
  var ISOLATE_MARSHAL_CODE = `
@@ -232,6 +216,68 @@ var ISOLATE_MARSHAL_CODE = `
232
216
  }
233
217
  return fd;
234
218
  }
219
+ case 'CallbackRef': {
220
+ // Create a proxy function that invokes the callback
221
+ const callbackId = value.callbackId;
222
+ return function(...args) {
223
+ const argsJson = JSON.stringify(marshalForHost(args));
224
+ const resultJson = __customFn_invoke.applySyncPromise(undefined, [callbackId, argsJson]);
225
+ const result = JSON.parse(resultJson);
226
+ if (result.ok) {
227
+ return unmarshalFromHost(result.value);
228
+ } else {
229
+ const error = new Error(result.error.message);
230
+ error.name = result.error.name;
231
+ throw error;
232
+ }
233
+ };
234
+ }
235
+ case 'PromiseRef': {
236
+ // Create a proxy Promise that resolves via callback
237
+ const promiseId = value.promiseId;
238
+ return new Promise((resolve, reject) => {
239
+ try {
240
+ const argsJson = JSON.stringify([promiseId]);
241
+ const resultJson = __customFn_invoke.applySyncPromise(undefined, [value.__resolveCallbackId, argsJson]);
242
+ const result = JSON.parse(resultJson);
243
+ if (result.ok) {
244
+ resolve(unmarshalFromHost(result.value));
245
+ } else {
246
+ reject(new Error(result.error.message));
247
+ }
248
+ } catch (e) {
249
+ reject(e);
250
+ }
251
+ });
252
+ }
253
+ case 'AsyncIteratorRef': {
254
+ const iteratorId = value.iteratorId;
255
+ const nextCallbackId = value.__nextCallbackId;
256
+ const returnCallbackId = value.__returnCallbackId;
257
+ return {
258
+ [Symbol.asyncIterator]() { return this; },
259
+ async next() {
260
+ const argsJson = JSON.stringify([iteratorId]);
261
+ const resultJson = __customFn_invoke.applySyncPromise(undefined, [nextCallbackId, argsJson]);
262
+ const result = JSON.parse(resultJson);
263
+ if (!result.ok) {
264
+ const error = new Error(result.error.message);
265
+ error.name = result.error.name;
266
+ throw error;
267
+ }
268
+ return {
269
+ done: result.value.done,
270
+ value: unmarshalFromHost(result.value.value)
271
+ };
272
+ },
273
+ async return(v) {
274
+ const argsJson = JSON.stringify([iteratorId, marshalForHost(v)]);
275
+ const resultJson = __customFn_invoke.applySyncPromise(undefined, [returnCallbackId, argsJson]);
276
+ const result = JSON.parse(resultJson);
277
+ return { done: true, value: result.ok ? unmarshalFromHost(result.value) : undefined };
278
+ }
279
+ };
280
+ }
235
281
  default:
236
282
  // Unknown ref type, return as-is
237
283
  break;
@@ -255,9 +301,27 @@ var ISOLATE_MARSHAL_CODE = `
255
301
  globalThis.__unmarshalFromHost = unmarshalFromHost;
256
302
  })();
257
303
  `;
258
- async function setupCustomFunctions(context, customFunctions) {
304
+ async function setupCustomFunctions(context, customFunctions, marshalOptions) {
259
305
  const global = context.global;
260
- const invokeCallbackRef = new import_isolated_vm.default.Reference(async (name, argsJson) => {
306
+ const invokeCallbackRef = new import_isolated_vm.default.Reference(async (nameOrId, argsJson) => {
307
+ if (typeof nameOrId === "number" && marshalOptions) {
308
+ const rawArgs2 = JSON.parse(argsJson);
309
+ const args2 = import_isolate_protocol3.unmarshalValue(rawArgs2);
310
+ try {
311
+ const result = await marshalOptions.invokeCallback(nameOrId, args2);
312
+ const ctx = marshalOptions.createMarshalContext();
313
+ const marshalledResult = await import_isolate_protocol3.marshalValue(result, ctx);
314
+ const processedResult = marshalOptions.addCallbackIdsToRefs(marshalledResult);
315
+ return JSON.stringify({ ok: true, value: processedResult });
316
+ } catch (error) {
317
+ const err = error;
318
+ return JSON.stringify({
319
+ ok: false,
320
+ error: { message: err.message, name: err.name }
321
+ });
322
+ }
323
+ }
324
+ const name = String(nameOrId);
261
325
  const def = customFunctions[name];
262
326
  if (!def) {
263
327
  return JSON.stringify({
@@ -271,7 +335,13 @@ async function setupCustomFunctions(context, customFunctions) {
271
335
  const rawArgs = JSON.parse(argsJson);
272
336
  const args = import_isolate_protocol3.unmarshalValue(rawArgs);
273
337
  try {
274
- const result = def.type === "async" ? await def.fn(...args) : def.fn(...args);
338
+ const result = await def.fn(...args);
339
+ if (marshalOptions) {
340
+ const ctx = marshalOptions.createMarshalContext();
341
+ const marshalledResult2 = await import_isolate_protocol3.marshalValue(result, ctx);
342
+ const processedResult = marshalOptions.addCallbackIdsToRefs(marshalledResult2);
343
+ return JSON.stringify({ ok: true, value: processedResult });
344
+ }
275
345
  const marshalledResult = await import_isolate_protocol3.marshalValue(result);
276
346
  return JSON.stringify({ ok: true, value: marshalledResult });
277
347
  } catch (error) {
@@ -327,7 +397,14 @@ async function setupCustomFunctions(context, customFunctions) {
327
397
  if (result.done) {
328
398
  iteratorSessions.delete(iteratorId);
329
399
  }
330
- const marshalledValue = await import_isolate_protocol3.marshalValue(result.value);
400
+ let marshalledValue;
401
+ if (marshalOptions) {
402
+ const ctx = marshalOptions.createMarshalContext();
403
+ marshalledValue = await import_isolate_protocol3.marshalValue(result.value, ctx);
404
+ marshalledValue = marshalOptions.addCallbackIdsToRefs(marshalledValue);
405
+ } else {
406
+ marshalledValue = await import_isolate_protocol3.marshalValue(result.value);
407
+ }
331
408
  return JSON.stringify({
332
409
  ok: true,
333
410
  done: result.done,
@@ -353,7 +430,14 @@ async function setupCustomFunctions(context, customFunctions) {
353
430
  const value = import_isolate_protocol3.unmarshalValue(rawValue);
354
431
  const result = await session.iterator.return?.(value);
355
432
  iteratorSessions.delete(iteratorId);
356
- const marshalledValue = await import_isolate_protocol3.marshalValue(result?.value);
433
+ let marshalledValue;
434
+ if (marshalOptions) {
435
+ const ctx = marshalOptions.createMarshalContext();
436
+ marshalledValue = await import_isolate_protocol3.marshalValue(result?.value, ctx);
437
+ marshalledValue = marshalOptions.addCallbackIdsToRefs(marshalledValue);
438
+ } else {
439
+ marshalledValue = await import_isolate_protocol3.marshalValue(result?.value);
440
+ }
357
441
  return JSON.stringify({ ok: true, done: true, value: marshalledValue });
358
442
  } catch (error) {
359
443
  const err = error;
@@ -383,7 +467,14 @@ async function setupCustomFunctions(context, customFunctions) {
383
467
  });
384
468
  const result = await session.iterator.throw?.(error);
385
469
  iteratorSessions.delete(iteratorId);
386
- const marshalledValue = await import_isolate_protocol3.marshalValue(result?.value);
470
+ let marshalledValue;
471
+ if (marshalOptions) {
472
+ const ctx = marshalOptions.createMarshalContext();
473
+ marshalledValue = await import_isolate_protocol3.marshalValue(result?.value, ctx);
474
+ marshalledValue = marshalOptions.addCallbackIdsToRefs(marshalledValue);
475
+ } else {
476
+ marshalledValue = await import_isolate_protocol3.marshalValue(result?.value);
477
+ }
387
478
  return JSON.stringify({
388
479
  ok: true,
389
480
  done: result?.done ?? true,
@@ -474,8 +565,114 @@ async function setupCustomFunctions(context, customFunctions) {
474
565
  }
475
566
  return invokeCallbackRef;
476
567
  }
568
+ function createLocalCustomFunctionsMarshalOptions() {
569
+ const returnedCallbacks = new Map;
570
+ const returnedPromises = new Map;
571
+ const returnedIterators = new Map;
572
+ let nextLocalCallbackId = 1e6;
573
+ const createMarshalContext = () => ({
574
+ registerCallback: (fn) => {
575
+ const callbackId = nextLocalCallbackId++;
576
+ returnedCallbacks.set(callbackId, fn);
577
+ return callbackId;
578
+ },
579
+ registerPromise: (promise) => {
580
+ const promiseId = nextLocalCallbackId++;
581
+ returnedPromises.set(promiseId, promise);
582
+ return promiseId;
583
+ },
584
+ registerIterator: (iterator) => {
585
+ const iteratorId = nextLocalCallbackId++;
586
+ returnedIterators.set(iteratorId, iterator);
587
+ return iteratorId;
588
+ }
589
+ });
590
+ const isPromiseRef = (value) => typeof value === "object" && value !== null && value.__type === "PromiseRef";
591
+ const isAsyncIteratorRef = (value) => typeof value === "object" && value !== null && value.__type === "AsyncIteratorRef";
592
+ const addCallbackIdsToRefs = (value) => {
593
+ if (value === null || typeof value !== "object")
594
+ return value;
595
+ if (isPromiseRef(value)) {
596
+ if ("__resolveCallbackId" in value)
597
+ return value;
598
+ const resolveCallbackId = nextLocalCallbackId++;
599
+ returnedCallbacks.set(resolveCallbackId, async (promiseId) => {
600
+ const promise = returnedPromises.get(promiseId);
601
+ if (!promise) {
602
+ throw new Error(`Promise ${promiseId} not found`);
603
+ }
604
+ const result2 = await promise;
605
+ returnedPromises.delete(promiseId);
606
+ const ctx = createMarshalContext();
607
+ const marshalled = await import_isolate_protocol3.marshalValue(result2, ctx);
608
+ return addCallbackIdsToRefs(marshalled);
609
+ });
610
+ return { ...value, __resolveCallbackId: resolveCallbackId };
611
+ }
612
+ if (isAsyncIteratorRef(value)) {
613
+ if ("__nextCallbackId" in value)
614
+ return value;
615
+ const nextCallbackId = nextLocalCallbackId++;
616
+ returnedCallbacks.set(nextCallbackId, async (iteratorId) => {
617
+ const iterator = returnedIterators.get(iteratorId);
618
+ if (!iterator) {
619
+ throw new Error(`Iterator ${iteratorId} not found`);
620
+ }
621
+ const result2 = await iterator.next();
622
+ if (result2.done) {
623
+ returnedIterators.delete(iteratorId);
624
+ }
625
+ const ctx = createMarshalContext();
626
+ const marshalledValue = await import_isolate_protocol3.marshalValue(result2.value, ctx);
627
+ return {
628
+ done: result2.done,
629
+ value: addCallbackIdsToRefs(marshalledValue)
630
+ };
631
+ });
632
+ const returnCallbackId = nextLocalCallbackId++;
633
+ returnedCallbacks.set(returnCallbackId, async (iteratorId, returnValue) => {
634
+ const iterator = returnedIterators.get(iteratorId);
635
+ returnedIterators.delete(iteratorId);
636
+ if (!iterator || !iterator.return) {
637
+ return { done: true, value: undefined };
638
+ }
639
+ const result2 = await iterator.return(returnValue);
640
+ const ctx = createMarshalContext();
641
+ const marshalledValue = await import_isolate_protocol3.marshalValue(result2.value, ctx);
642
+ return {
643
+ done: true,
644
+ value: addCallbackIdsToRefs(marshalledValue)
645
+ };
646
+ });
647
+ return {
648
+ ...value,
649
+ __nextCallbackId: nextCallbackId,
650
+ __returnCallbackId: returnCallbackId
651
+ };
652
+ }
653
+ if (Array.isArray(value)) {
654
+ return value.map((item) => addCallbackIdsToRefs(item));
655
+ }
656
+ const result = {};
657
+ for (const key of Object.keys(value)) {
658
+ result[key] = addCallbackIdsToRefs(value[key]);
659
+ }
660
+ return result;
661
+ };
662
+ const invokeCallback = async (callbackId, args) => {
663
+ const callback = returnedCallbacks.get(callbackId);
664
+ if (!callback) {
665
+ throw new Error(`Local callback ${callbackId} not found`);
666
+ }
667
+ return await callback(...args);
668
+ };
669
+ return { createMarshalContext, addCallbackIdsToRefs, invokeCallback };
670
+ }
477
671
  function createModuleResolver(state) {
478
672
  return async (specifier, referrer) => {
673
+ const staticCached = state.staticModuleCache.get(specifier);
674
+ if (staticCached)
675
+ return staticCached;
479
676
  const cached = state.moduleCache.get(specifier);
480
677
  if (cached)
481
678
  return cached;
@@ -484,29 +681,74 @@ function createModuleResolver(state) {
484
681
  }
485
682
  const importerPath = state.moduleToFilename.get(referrer) ?? "<unknown>";
486
683
  const importerResolveDir = import_node_path.default.posix.dirname(importerPath);
487
- const { code, resolveDir } = await state.moduleLoader(specifier, {
684
+ const result = await state.moduleLoader(specifier, {
488
685
  path: importerPath,
489
686
  resolveDir: importerResolveDir
490
687
  });
688
+ const { code, resolveDir } = result;
491
689
  const hash = import_isolate_transform.contentHash(code);
492
690
  const cacheKey = `${specifier}:${hash}`;
691
+ const inFlightKey = `${result.static ? "static" : "dynamic"}:${cacheKey}`;
692
+ const staticCachedAfterLoad = state.staticModuleCache.get(specifier);
693
+ if (staticCachedAfterLoad)
694
+ return staticCachedAfterLoad;
695
+ const cachedAfterLoad = state.moduleCache.get(specifier);
696
+ if (cachedAfterLoad)
697
+ return cachedAfterLoad;
493
698
  const hashCached = state.moduleCache.get(cacheKey);
494
699
  if (hashCached)
495
700
  return hashCached;
496
- const transformed = await import_isolate_transform.transformModuleCode(code, specifier);
497
- if (transformed.sourceMap) {
498
- state.sourceMaps.set(specifier, transformed.sourceMap);
701
+ const inFlight = state.moduleLoadsInFlight.get(inFlightKey);
702
+ if (inFlight)
703
+ return inFlight;
704
+ const loadPromise = (async () => {
705
+ let mod;
706
+ try {
707
+ let transformed = state.transformCache.get(hash);
708
+ if (!transformed) {
709
+ transformed = await import_isolate_transform.transformModuleCode(code, specifier);
710
+ state.transformCache.set(hash, transformed);
711
+ }
712
+ if (transformed.sourceMap) {
713
+ state.sourceMaps.set(specifier, transformed.sourceMap);
714
+ }
715
+ mod = await state.isolate.compileModule(transformed.code, {
716
+ filename: specifier
717
+ });
718
+ const resolvedPath = import_node_path.default.posix.join(resolveDir, import_node_path.default.posix.basename(specifier));
719
+ state.moduleToFilename.set(mod, resolvedPath);
720
+ if (result.static) {
721
+ state.staticModuleCache.set(specifier, mod);
722
+ } else {
723
+ state.moduleCache.set(specifier, mod);
724
+ state.moduleCache.set(cacheKey, mod);
725
+ }
726
+ return mod;
727
+ } catch (err) {
728
+ if (mod) {
729
+ state.moduleToFilename.delete(mod);
730
+ if (result.static) {
731
+ if (state.staticModuleCache.get(specifier) === mod) {
732
+ state.staticModuleCache.delete(specifier);
733
+ }
734
+ } else {
735
+ if (state.moduleCache.get(specifier) === mod) {
736
+ state.moduleCache.delete(specifier);
737
+ }
738
+ if (state.moduleCache.get(cacheKey) === mod) {
739
+ state.moduleCache.delete(cacheKey);
740
+ }
741
+ }
742
+ }
743
+ throw err;
744
+ }
745
+ })();
746
+ state.moduleLoadsInFlight.set(inFlightKey, loadPromise);
747
+ try {
748
+ return await loadPromise;
749
+ } finally {
750
+ state.moduleLoadsInFlight.delete(inFlightKey);
499
751
  }
500
- const mod = await state.isolate.compileModule(transformed.code, {
501
- filename: specifier
502
- });
503
- const resolvedPath = import_node_path.default.posix.join(resolveDir, import_node_path.default.posix.basename(specifier));
504
- state.moduleToFilename.set(mod, resolvedPath);
505
- state.moduleCache.set(specifier, mod);
506
- state.moduleCache.set(cacheKey, mod);
507
- const resolver = createModuleResolver(state);
508
- await mod.instantiate(state.context, resolver);
509
- return mod;
510
752
  };
511
753
  }
512
754
  function convertFetchCallback(callback) {
@@ -514,8 +756,8 @@ function convertFetchCallback(callback) {
514
756
  return {};
515
757
  }
516
758
  return {
517
- onFetch: async (request) => {
518
- return Promise.resolve(callback(request));
759
+ onFetch: async (url, init) => {
760
+ return Promise.resolve(callback(url, init));
519
761
  }
520
762
  };
521
763
  }
@@ -531,8 +773,13 @@ async function createRuntime(options) {
531
773
  context,
532
774
  handles: {},
533
775
  moduleCache: new Map,
776
+ staticModuleCache: new Map,
777
+ moduleLoadsInFlight: new Map,
778
+ transformCache: new Map,
534
779
  moduleToFilename: new Map,
535
780
  sourceMaps: new Map,
781
+ pendingCallbacks: [],
782
+ evalChain: Promise.resolve(),
536
783
  moduleLoader: opts.moduleLoader,
537
784
  customFunctions: opts.customFunctions
538
785
  };
@@ -547,13 +794,17 @@ async function createRuntime(options) {
547
794
  state.handles.fs = await import_isolate_fs.setupFs(context, opts.fs);
548
795
  }
549
796
  if (opts.customFunctions) {
550
- state.customFnInvokeRef = await setupCustomFunctions(context, opts.customFunctions);
797
+ const customMarshalOptions = opts.customFunctionsMarshalOptions ?? createLocalCustomFunctionsMarshalOptions();
798
+ state.customFnInvokeRef = await setupCustomFunctions(context, opts.customFunctions, customMarshalOptions);
551
799
  }
552
800
  if (opts.testEnvironment) {
553
801
  const testEnvOptions = typeof opts.testEnvironment === "object" ? opts.testEnvironment : undefined;
554
802
  state.handles.testEnvironment = await import_isolate_test_environment.setupTestEnvironment(context, testEnvOptions);
555
803
  }
556
804
  if (opts.playwright) {
805
+ if (!opts.playwright.handler) {
806
+ throw new Error("Playwright configured without handler. Provide playwright.handler in createRuntime options.");
807
+ }
557
808
  let eventCallback = opts.playwright.onEvent;
558
809
  if (opts.playwright.console && opts.console?.onEntry) {
559
810
  const originalCallback = eventCallback;
@@ -572,12 +823,13 @@ async function createRuntime(options) {
572
823
  }
573
824
  };
574
825
  }
575
- state.handles.playwright = await import_isolate_playwright.setupPlaywright(context, {
576
- page: opts.playwright.page,
826
+ const playwrightSetupOptions = {
827
+ handler: opts.playwright.handler,
577
828
  timeout: opts.playwright.timeout,
578
829
  console: opts.playwright.console && !opts.console?.onEntry,
579
830
  onEvent: eventCallback
580
- });
831
+ };
832
+ state.handles.playwright = await import_isolate_playwright.setupPlaywright(context, playwrightSetupOptions);
581
833
  }
582
834
  const fetchHandle = {
583
835
  async dispatchRequest(request, options2) {
@@ -633,6 +885,48 @@ async function createRuntime(options) {
633
885
  throw new Error("Fetch handle not available");
634
886
  }
635
887
  return state.handles.fetch.hasActiveConnections();
888
+ },
889
+ dispatchClientWebSocketOpen(socketId, protocol, extensions) {
890
+ if (!state.handles.fetch) {
891
+ throw new Error("Fetch handle not available");
892
+ }
893
+ state.handles.fetch.dispatchClientWebSocketOpen(socketId, protocol, extensions);
894
+ },
895
+ dispatchClientWebSocketMessage(socketId, data) {
896
+ if (!state.handles.fetch) {
897
+ throw new Error("Fetch handle not available");
898
+ }
899
+ state.handles.fetch.dispatchClientWebSocketMessage(socketId, data);
900
+ },
901
+ dispatchClientWebSocketClose(socketId, code, reason, wasClean) {
902
+ if (!state.handles.fetch) {
903
+ throw new Error("Fetch handle not available");
904
+ }
905
+ state.handles.fetch.dispatchClientWebSocketClose(socketId, code, reason, wasClean);
906
+ },
907
+ dispatchClientWebSocketError(socketId) {
908
+ if (!state.handles.fetch) {
909
+ throw new Error("Fetch handle not available");
910
+ }
911
+ state.handles.fetch.dispatchClientWebSocketError(socketId);
912
+ },
913
+ onClientWebSocketCommand(callback) {
914
+ if (!state.handles.fetch) {
915
+ throw new Error("Fetch handle not available");
916
+ }
917
+ return state.handles.fetch.onClientWebSocketCommand(callback);
918
+ },
919
+ onEvent(callback) {
920
+ if (!state.handles.fetch) {
921
+ throw new Error("Fetch handle not available");
922
+ }
923
+ return state.handles.fetch.onEvent(callback);
924
+ },
925
+ dispatchEvent(event, payload) {
926
+ if (!state.handles.fetch) {
927
+ throw new Error("Fetch handle not available");
928
+ }
929
+ state.handles.fetch.dispatchEvent(event, payload);
636
930
  }
637
931
  };
638
932
  const timersHandle = {
@@ -655,11 +949,27 @@ async function createRuntime(options) {
655
949
  }
656
950
  };
657
951
  const testEnvironmentHandle = {
658
- async runTests(_timeout) {
952
+ async runTests(timeout) {
659
953
  if (!state.handles.testEnvironment) {
660
954
  throw new Error("Test environment not enabled. Set testEnvironment: true in createRuntime options.");
661
955
  }
662
- return import_isolate_test_environment.runTests(state.context);
956
+ if (timeout === undefined) {
957
+ return import_isolate_test_environment.runTests(state.context);
958
+ }
959
+ let timeoutId;
960
+ const timeoutPromise = new Promise((_, reject) => {
961
+ timeoutId = setTimeout(() => reject(new Error("Test timeout")), timeout);
962
+ });
963
+ try {
964
+ return await Promise.race([
965
+ import_isolate_test_environment.runTests(state.context),
966
+ timeoutPromise
967
+ ]);
968
+ } finally {
969
+ if (timeoutId) {
970
+ clearTimeout(timeoutId);
971
+ }
972
+ }
663
973
  },
664
974
  hasTests() {
665
975
  if (!state.handles.testEnvironment) {
@@ -680,7 +990,7 @@ async function createRuntime(options) {
680
990
  const playwrightHandle = {
681
991
  getCollectedData() {
682
992
  if (!state.handles.playwright) {
683
- throw new Error("Playwright not configured. Provide playwright.page in createRuntime options.");
993
+ throw new Error("Playwright not configured. Provide playwright.handler in createRuntime options.");
684
994
  }
685
995
  return {
686
996
  browserConsoleLogs: state.handles.playwright.getBrowserConsoleLogs(),
@@ -694,43 +1004,62 @@ async function createRuntime(options) {
694
1004
  };
695
1005
  return {
696
1006
  id,
1007
+ pendingCallbacks: state.pendingCallbacks,
697
1008
  fetch: fetchHandle,
698
1009
  timers: timersHandle,
699
1010
  console: consoleHandle,
700
1011
  testEnvironment: testEnvironmentHandle,
701
1012
  playwright: playwrightHandle,
702
1013
  async eval(code, filenameOrOptions) {
703
- const options2 = typeof filenameOrOptions === "string" ? { filename: filenameOrOptions } : filenameOrOptions;
704
- const filename = import_isolate_protocol.normalizeEntryFilename(options2?.filename);
705
- try {
706
- const transformed = await import_isolate_transform.transformEntryCode(code, filename);
707
- if (transformed.sourceMap) {
708
- state.sourceMaps.set(filename, transformed.sourceMap);
709
- }
710
- const mod = await state.isolate.compileModule(transformed.code, {
711
- filename
712
- });
713
- state.moduleToFilename.set(mod, filename);
714
- const resolver = createModuleResolver(state);
715
- await mod.instantiate(state.context, resolver);
716
- await mod.evaluate();
717
- const ns = mod.namespace;
718
- const runRef = await ns.get("default", { reference: true });
1014
+ const runEval = async () => {
1015
+ const options2 = typeof filenameOrOptions === "string" ? { filename: filenameOrOptions } : filenameOrOptions;
1016
+ const filename = import_isolate_protocol.normalizeEntryFilename(options2?.filename);
719
1017
  try {
720
- await runRef.apply(undefined, [], {
721
- result: { promise: true },
722
- ...options2?.maxExecutionMs ? { timeout: options2.maxExecutionMs } : {}
1018
+ const transformed = await import_isolate_transform.transformEntryCode(code, filename);
1019
+ if (transformed.sourceMap) {
1020
+ state.sourceMaps.set(filename, transformed.sourceMap);
1021
+ }
1022
+ const mod = await state.isolate.compileModule(transformed.code, {
1023
+ filename
723
1024
  });
724
- } finally {
725
- runRef.release();
726
- }
727
- } catch (err) {
728
- const error = err;
729
- if (error.stack && state.sourceMaps.size > 0) {
730
- error.stack = import_isolate_transform.mapErrorStack(error.stack, state.sourceMaps);
1025
+ state.moduleToFilename.set(mod, filename);
1026
+ const resolver = createModuleResolver(state);
1027
+ await mod.instantiate(state.context, resolver);
1028
+ await mod.evaluate();
1029
+ const ns = mod.namespace;
1030
+ const runRef = await ns.get("default", { reference: true });
1031
+ try {
1032
+ await runRef.apply(undefined, [], {
1033
+ result: { promise: true }
1034
+ });
1035
+ } finally {
1036
+ runRef.release();
1037
+ }
1038
+ if (state.pendingCallbacks.length > 0) {
1039
+ await Promise.all(state.pendingCallbacks);
1040
+ state.pendingCallbacks.length = 0;
1041
+ }
1042
+ } catch (err) {
1043
+ const error = err;
1044
+ if (error.stack && state.sourceMaps.size > 0) {
1045
+ error.stack = import_isolate_transform.mapErrorStack(error.stack, state.sourceMaps);
1046
+ }
1047
+ throw error;
731
1048
  }
732
- throw error;
733
- }
1049
+ };
1050
+ const queuedEval = state.evalChain.then(runEval, runEval);
1051
+ state.evalChain = queuedEval.then(() => {
1052
+ return;
1053
+ }, () => {
1054
+ return;
1055
+ });
1056
+ return queuedEval;
1057
+ },
1058
+ clearModuleCache() {
1059
+ state.moduleCache.clear();
1060
+ state.moduleLoadsInFlight.clear();
1061
+ state.moduleToFilename.clear();
1062
+ state.sourceMaps.clear();
734
1063
  },
735
1064
  async dispose() {
736
1065
  if (state.customFnInvokeRef) {
@@ -747,10 +1076,11 @@ async function createRuntime(options) {
747
1076
  state.handles.console?.dispose();
748
1077
  state.handles.core?.dispose();
749
1078
  state.moduleCache.clear();
1079
+ state.moduleLoadsInFlight.clear();
750
1080
  state.context.release();
751
1081
  state.isolate.dispose();
752
1082
  }
753
1083
  };
754
1084
  }
755
1085
 
756
- //# debugId=230C5D24BE3157C264756E2164756E21
1086
+ //# debugId=9159E7F9BC462BBB64756E2164756E21