@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.
- package/README.md +88 -24
- package/dist/cjs/index.cjs +406 -76
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/index.mjs +412 -62
- package/dist/mjs/index.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/types/index.d.ts +45 -5
- package/package.json +1 -1
- package/dist/cjs/internal.cjs +0 -95
- package/dist/cjs/internal.cjs.map +0 -10
- package/dist/mjs/internal.mjs +0 -52
- package/dist/mjs/internal.mjs.map +0 -10
- package/dist/types/internal.d.ts +0 -39
package/dist/mjs/index.mjs
CHANGED
|
@@ -23,7 +23,9 @@ import {
|
|
|
23
23
|
hasTests as hasTestsInContext,
|
|
24
24
|
getTestCount as getTestCountInContext
|
|
25
25
|
} from "@ricsam/isolate-test-environment";
|
|
26
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
setupPlaywright
|
|
28
|
+
} from "@ricsam/isolate-playwright";
|
|
27
29
|
import {
|
|
28
30
|
marshalValue,
|
|
29
31
|
unmarshalValue
|
|
@@ -47,10 +49,10 @@ import {
|
|
|
47
49
|
} from "@ricsam/isolate-test-environment";
|
|
48
50
|
import {
|
|
49
51
|
setupPlaywright as setupPlaywright2,
|
|
50
|
-
createPlaywrightHandler
|
|
52
|
+
createPlaywrightHandler,
|
|
53
|
+
defaultPlaywrightHandler,
|
|
54
|
+
getDefaultPlaywrightHandlerMetadata
|
|
51
55
|
} from "@ricsam/isolate-playwright";
|
|
52
|
-
|
|
53
|
-
export * from "./internal.mjs";
|
|
54
56
|
var iteratorSessions = new Map;
|
|
55
57
|
var nextIteratorId = 1;
|
|
56
58
|
var ISOLATE_MARSHAL_CODE = `
|
|
@@ -176,6 +178,68 @@ var ISOLATE_MARSHAL_CODE = `
|
|
|
176
178
|
}
|
|
177
179
|
return fd;
|
|
178
180
|
}
|
|
181
|
+
case 'CallbackRef': {
|
|
182
|
+
// Create a proxy function that invokes the callback
|
|
183
|
+
const callbackId = value.callbackId;
|
|
184
|
+
return function(...args) {
|
|
185
|
+
const argsJson = JSON.stringify(marshalForHost(args));
|
|
186
|
+
const resultJson = __customFn_invoke.applySyncPromise(undefined, [callbackId, argsJson]);
|
|
187
|
+
const result = JSON.parse(resultJson);
|
|
188
|
+
if (result.ok) {
|
|
189
|
+
return unmarshalFromHost(result.value);
|
|
190
|
+
} else {
|
|
191
|
+
const error = new Error(result.error.message);
|
|
192
|
+
error.name = result.error.name;
|
|
193
|
+
throw error;
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
case 'PromiseRef': {
|
|
198
|
+
// Create a proxy Promise that resolves via callback
|
|
199
|
+
const promiseId = value.promiseId;
|
|
200
|
+
return new Promise((resolve, reject) => {
|
|
201
|
+
try {
|
|
202
|
+
const argsJson = JSON.stringify([promiseId]);
|
|
203
|
+
const resultJson = __customFn_invoke.applySyncPromise(undefined, [value.__resolveCallbackId, argsJson]);
|
|
204
|
+
const result = JSON.parse(resultJson);
|
|
205
|
+
if (result.ok) {
|
|
206
|
+
resolve(unmarshalFromHost(result.value));
|
|
207
|
+
} else {
|
|
208
|
+
reject(new Error(result.error.message));
|
|
209
|
+
}
|
|
210
|
+
} catch (e) {
|
|
211
|
+
reject(e);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
case 'AsyncIteratorRef': {
|
|
216
|
+
const iteratorId = value.iteratorId;
|
|
217
|
+
const nextCallbackId = value.__nextCallbackId;
|
|
218
|
+
const returnCallbackId = value.__returnCallbackId;
|
|
219
|
+
return {
|
|
220
|
+
[Symbol.asyncIterator]() { return this; },
|
|
221
|
+
async next() {
|
|
222
|
+
const argsJson = JSON.stringify([iteratorId]);
|
|
223
|
+
const resultJson = __customFn_invoke.applySyncPromise(undefined, [nextCallbackId, argsJson]);
|
|
224
|
+
const result = JSON.parse(resultJson);
|
|
225
|
+
if (!result.ok) {
|
|
226
|
+
const error = new Error(result.error.message);
|
|
227
|
+
error.name = result.error.name;
|
|
228
|
+
throw error;
|
|
229
|
+
}
|
|
230
|
+
return {
|
|
231
|
+
done: result.value.done,
|
|
232
|
+
value: unmarshalFromHost(result.value.value)
|
|
233
|
+
};
|
|
234
|
+
},
|
|
235
|
+
async return(v) {
|
|
236
|
+
const argsJson = JSON.stringify([iteratorId, marshalForHost(v)]);
|
|
237
|
+
const resultJson = __customFn_invoke.applySyncPromise(undefined, [returnCallbackId, argsJson]);
|
|
238
|
+
const result = JSON.parse(resultJson);
|
|
239
|
+
return { done: true, value: result.ok ? unmarshalFromHost(result.value) : undefined };
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
}
|
|
179
243
|
default:
|
|
180
244
|
// Unknown ref type, return as-is
|
|
181
245
|
break;
|
|
@@ -199,9 +263,27 @@ var ISOLATE_MARSHAL_CODE = `
|
|
|
199
263
|
globalThis.__unmarshalFromHost = unmarshalFromHost;
|
|
200
264
|
})();
|
|
201
265
|
`;
|
|
202
|
-
async function setupCustomFunctions(context, customFunctions) {
|
|
266
|
+
async function setupCustomFunctions(context, customFunctions, marshalOptions) {
|
|
203
267
|
const global = context.global;
|
|
204
|
-
const invokeCallbackRef = new ivm.Reference(async (
|
|
268
|
+
const invokeCallbackRef = new ivm.Reference(async (nameOrId, argsJson) => {
|
|
269
|
+
if (typeof nameOrId === "number" && marshalOptions) {
|
|
270
|
+
const rawArgs2 = JSON.parse(argsJson);
|
|
271
|
+
const args2 = unmarshalValue(rawArgs2);
|
|
272
|
+
try {
|
|
273
|
+
const result = await marshalOptions.invokeCallback(nameOrId, args2);
|
|
274
|
+
const ctx = marshalOptions.createMarshalContext();
|
|
275
|
+
const marshalledResult = await marshalValue(result, ctx);
|
|
276
|
+
const processedResult = marshalOptions.addCallbackIdsToRefs(marshalledResult);
|
|
277
|
+
return JSON.stringify({ ok: true, value: processedResult });
|
|
278
|
+
} catch (error) {
|
|
279
|
+
const err = error;
|
|
280
|
+
return JSON.stringify({
|
|
281
|
+
ok: false,
|
|
282
|
+
error: { message: err.message, name: err.name }
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
const name = String(nameOrId);
|
|
205
287
|
const def = customFunctions[name];
|
|
206
288
|
if (!def) {
|
|
207
289
|
return JSON.stringify({
|
|
@@ -215,7 +297,13 @@ async function setupCustomFunctions(context, customFunctions) {
|
|
|
215
297
|
const rawArgs = JSON.parse(argsJson);
|
|
216
298
|
const args = unmarshalValue(rawArgs);
|
|
217
299
|
try {
|
|
218
|
-
const result =
|
|
300
|
+
const result = await def.fn(...args);
|
|
301
|
+
if (marshalOptions) {
|
|
302
|
+
const ctx = marshalOptions.createMarshalContext();
|
|
303
|
+
const marshalledResult2 = await marshalValue(result, ctx);
|
|
304
|
+
const processedResult = marshalOptions.addCallbackIdsToRefs(marshalledResult2);
|
|
305
|
+
return JSON.stringify({ ok: true, value: processedResult });
|
|
306
|
+
}
|
|
219
307
|
const marshalledResult = await marshalValue(result);
|
|
220
308
|
return JSON.stringify({ ok: true, value: marshalledResult });
|
|
221
309
|
} catch (error) {
|
|
@@ -271,7 +359,14 @@ async function setupCustomFunctions(context, customFunctions) {
|
|
|
271
359
|
if (result.done) {
|
|
272
360
|
iteratorSessions.delete(iteratorId);
|
|
273
361
|
}
|
|
274
|
-
|
|
362
|
+
let marshalledValue;
|
|
363
|
+
if (marshalOptions) {
|
|
364
|
+
const ctx = marshalOptions.createMarshalContext();
|
|
365
|
+
marshalledValue = await marshalValue(result.value, ctx);
|
|
366
|
+
marshalledValue = marshalOptions.addCallbackIdsToRefs(marshalledValue);
|
|
367
|
+
} else {
|
|
368
|
+
marshalledValue = await marshalValue(result.value);
|
|
369
|
+
}
|
|
275
370
|
return JSON.stringify({
|
|
276
371
|
ok: true,
|
|
277
372
|
done: result.done,
|
|
@@ -297,7 +392,14 @@ async function setupCustomFunctions(context, customFunctions) {
|
|
|
297
392
|
const value = unmarshalValue(rawValue);
|
|
298
393
|
const result = await session.iterator.return?.(value);
|
|
299
394
|
iteratorSessions.delete(iteratorId);
|
|
300
|
-
|
|
395
|
+
let marshalledValue;
|
|
396
|
+
if (marshalOptions) {
|
|
397
|
+
const ctx = marshalOptions.createMarshalContext();
|
|
398
|
+
marshalledValue = await marshalValue(result?.value, ctx);
|
|
399
|
+
marshalledValue = marshalOptions.addCallbackIdsToRefs(marshalledValue);
|
|
400
|
+
} else {
|
|
401
|
+
marshalledValue = await marshalValue(result?.value);
|
|
402
|
+
}
|
|
301
403
|
return JSON.stringify({ ok: true, done: true, value: marshalledValue });
|
|
302
404
|
} catch (error) {
|
|
303
405
|
const err = error;
|
|
@@ -327,7 +429,14 @@ async function setupCustomFunctions(context, customFunctions) {
|
|
|
327
429
|
});
|
|
328
430
|
const result = await session.iterator.throw?.(error);
|
|
329
431
|
iteratorSessions.delete(iteratorId);
|
|
330
|
-
|
|
432
|
+
let marshalledValue;
|
|
433
|
+
if (marshalOptions) {
|
|
434
|
+
const ctx = marshalOptions.createMarshalContext();
|
|
435
|
+
marshalledValue = await marshalValue(result?.value, ctx);
|
|
436
|
+
marshalledValue = marshalOptions.addCallbackIdsToRefs(marshalledValue);
|
|
437
|
+
} else {
|
|
438
|
+
marshalledValue = await marshalValue(result?.value);
|
|
439
|
+
}
|
|
331
440
|
return JSON.stringify({
|
|
332
441
|
ok: true,
|
|
333
442
|
done: result?.done ?? true,
|
|
@@ -418,8 +527,114 @@ async function setupCustomFunctions(context, customFunctions) {
|
|
|
418
527
|
}
|
|
419
528
|
return invokeCallbackRef;
|
|
420
529
|
}
|
|
530
|
+
function createLocalCustomFunctionsMarshalOptions() {
|
|
531
|
+
const returnedCallbacks = new Map;
|
|
532
|
+
const returnedPromises = new Map;
|
|
533
|
+
const returnedIterators = new Map;
|
|
534
|
+
let nextLocalCallbackId = 1e6;
|
|
535
|
+
const createMarshalContext = () => ({
|
|
536
|
+
registerCallback: (fn) => {
|
|
537
|
+
const callbackId = nextLocalCallbackId++;
|
|
538
|
+
returnedCallbacks.set(callbackId, fn);
|
|
539
|
+
return callbackId;
|
|
540
|
+
},
|
|
541
|
+
registerPromise: (promise) => {
|
|
542
|
+
const promiseId = nextLocalCallbackId++;
|
|
543
|
+
returnedPromises.set(promiseId, promise);
|
|
544
|
+
return promiseId;
|
|
545
|
+
},
|
|
546
|
+
registerIterator: (iterator) => {
|
|
547
|
+
const iteratorId = nextLocalCallbackId++;
|
|
548
|
+
returnedIterators.set(iteratorId, iterator);
|
|
549
|
+
return iteratorId;
|
|
550
|
+
}
|
|
551
|
+
});
|
|
552
|
+
const isPromiseRef = (value) => typeof value === "object" && value !== null && value.__type === "PromiseRef";
|
|
553
|
+
const isAsyncIteratorRef = (value) => typeof value === "object" && value !== null && value.__type === "AsyncIteratorRef";
|
|
554
|
+
const addCallbackIdsToRefs = (value) => {
|
|
555
|
+
if (value === null || typeof value !== "object")
|
|
556
|
+
return value;
|
|
557
|
+
if (isPromiseRef(value)) {
|
|
558
|
+
if ("__resolveCallbackId" in value)
|
|
559
|
+
return value;
|
|
560
|
+
const resolveCallbackId = nextLocalCallbackId++;
|
|
561
|
+
returnedCallbacks.set(resolveCallbackId, async (promiseId) => {
|
|
562
|
+
const promise = returnedPromises.get(promiseId);
|
|
563
|
+
if (!promise) {
|
|
564
|
+
throw new Error(`Promise ${promiseId} not found`);
|
|
565
|
+
}
|
|
566
|
+
const result2 = await promise;
|
|
567
|
+
returnedPromises.delete(promiseId);
|
|
568
|
+
const ctx = createMarshalContext();
|
|
569
|
+
const marshalled = await marshalValue(result2, ctx);
|
|
570
|
+
return addCallbackIdsToRefs(marshalled);
|
|
571
|
+
});
|
|
572
|
+
return { ...value, __resolveCallbackId: resolveCallbackId };
|
|
573
|
+
}
|
|
574
|
+
if (isAsyncIteratorRef(value)) {
|
|
575
|
+
if ("__nextCallbackId" in value)
|
|
576
|
+
return value;
|
|
577
|
+
const nextCallbackId = nextLocalCallbackId++;
|
|
578
|
+
returnedCallbacks.set(nextCallbackId, async (iteratorId) => {
|
|
579
|
+
const iterator = returnedIterators.get(iteratorId);
|
|
580
|
+
if (!iterator) {
|
|
581
|
+
throw new Error(`Iterator ${iteratorId} not found`);
|
|
582
|
+
}
|
|
583
|
+
const result2 = await iterator.next();
|
|
584
|
+
if (result2.done) {
|
|
585
|
+
returnedIterators.delete(iteratorId);
|
|
586
|
+
}
|
|
587
|
+
const ctx = createMarshalContext();
|
|
588
|
+
const marshalledValue = await marshalValue(result2.value, ctx);
|
|
589
|
+
return {
|
|
590
|
+
done: result2.done,
|
|
591
|
+
value: addCallbackIdsToRefs(marshalledValue)
|
|
592
|
+
};
|
|
593
|
+
});
|
|
594
|
+
const returnCallbackId = nextLocalCallbackId++;
|
|
595
|
+
returnedCallbacks.set(returnCallbackId, async (iteratorId, returnValue) => {
|
|
596
|
+
const iterator = returnedIterators.get(iteratorId);
|
|
597
|
+
returnedIterators.delete(iteratorId);
|
|
598
|
+
if (!iterator || !iterator.return) {
|
|
599
|
+
return { done: true, value: undefined };
|
|
600
|
+
}
|
|
601
|
+
const result2 = await iterator.return(returnValue);
|
|
602
|
+
const ctx = createMarshalContext();
|
|
603
|
+
const marshalledValue = await marshalValue(result2.value, ctx);
|
|
604
|
+
return {
|
|
605
|
+
done: true,
|
|
606
|
+
value: addCallbackIdsToRefs(marshalledValue)
|
|
607
|
+
};
|
|
608
|
+
});
|
|
609
|
+
return {
|
|
610
|
+
...value,
|
|
611
|
+
__nextCallbackId: nextCallbackId,
|
|
612
|
+
__returnCallbackId: returnCallbackId
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
if (Array.isArray(value)) {
|
|
616
|
+
return value.map((item) => addCallbackIdsToRefs(item));
|
|
617
|
+
}
|
|
618
|
+
const result = {};
|
|
619
|
+
for (const key of Object.keys(value)) {
|
|
620
|
+
result[key] = addCallbackIdsToRefs(value[key]);
|
|
621
|
+
}
|
|
622
|
+
return result;
|
|
623
|
+
};
|
|
624
|
+
const invokeCallback = async (callbackId, args) => {
|
|
625
|
+
const callback = returnedCallbacks.get(callbackId);
|
|
626
|
+
if (!callback) {
|
|
627
|
+
throw new Error(`Local callback ${callbackId} not found`);
|
|
628
|
+
}
|
|
629
|
+
return await callback(...args);
|
|
630
|
+
};
|
|
631
|
+
return { createMarshalContext, addCallbackIdsToRefs, invokeCallback };
|
|
632
|
+
}
|
|
421
633
|
function createModuleResolver(state) {
|
|
422
634
|
return async (specifier, referrer) => {
|
|
635
|
+
const staticCached = state.staticModuleCache.get(specifier);
|
|
636
|
+
if (staticCached)
|
|
637
|
+
return staticCached;
|
|
423
638
|
const cached = state.moduleCache.get(specifier);
|
|
424
639
|
if (cached)
|
|
425
640
|
return cached;
|
|
@@ -428,29 +643,74 @@ function createModuleResolver(state) {
|
|
|
428
643
|
}
|
|
429
644
|
const importerPath = state.moduleToFilename.get(referrer) ?? "<unknown>";
|
|
430
645
|
const importerResolveDir = path.posix.dirname(importerPath);
|
|
431
|
-
const
|
|
646
|
+
const result = await state.moduleLoader(specifier, {
|
|
432
647
|
path: importerPath,
|
|
433
648
|
resolveDir: importerResolveDir
|
|
434
649
|
});
|
|
650
|
+
const { code, resolveDir } = result;
|
|
435
651
|
const hash = contentHash(code);
|
|
436
652
|
const cacheKey = `${specifier}:${hash}`;
|
|
653
|
+
const inFlightKey = `${result.static ? "static" : "dynamic"}:${cacheKey}`;
|
|
654
|
+
const staticCachedAfterLoad = state.staticModuleCache.get(specifier);
|
|
655
|
+
if (staticCachedAfterLoad)
|
|
656
|
+
return staticCachedAfterLoad;
|
|
657
|
+
const cachedAfterLoad = state.moduleCache.get(specifier);
|
|
658
|
+
if (cachedAfterLoad)
|
|
659
|
+
return cachedAfterLoad;
|
|
437
660
|
const hashCached = state.moduleCache.get(cacheKey);
|
|
438
661
|
if (hashCached)
|
|
439
662
|
return hashCached;
|
|
440
|
-
const
|
|
441
|
-
if (
|
|
442
|
-
|
|
663
|
+
const inFlight = state.moduleLoadsInFlight.get(inFlightKey);
|
|
664
|
+
if (inFlight)
|
|
665
|
+
return inFlight;
|
|
666
|
+
const loadPromise = (async () => {
|
|
667
|
+
let mod;
|
|
668
|
+
try {
|
|
669
|
+
let transformed = state.transformCache.get(hash);
|
|
670
|
+
if (!transformed) {
|
|
671
|
+
transformed = await transformModuleCode(code, specifier);
|
|
672
|
+
state.transformCache.set(hash, transformed);
|
|
673
|
+
}
|
|
674
|
+
if (transformed.sourceMap) {
|
|
675
|
+
state.sourceMaps.set(specifier, transformed.sourceMap);
|
|
676
|
+
}
|
|
677
|
+
mod = await state.isolate.compileModule(transformed.code, {
|
|
678
|
+
filename: specifier
|
|
679
|
+
});
|
|
680
|
+
const resolvedPath = path.posix.join(resolveDir, path.posix.basename(specifier));
|
|
681
|
+
state.moduleToFilename.set(mod, resolvedPath);
|
|
682
|
+
if (result.static) {
|
|
683
|
+
state.staticModuleCache.set(specifier, mod);
|
|
684
|
+
} else {
|
|
685
|
+
state.moduleCache.set(specifier, mod);
|
|
686
|
+
state.moduleCache.set(cacheKey, mod);
|
|
687
|
+
}
|
|
688
|
+
return mod;
|
|
689
|
+
} catch (err) {
|
|
690
|
+
if (mod) {
|
|
691
|
+
state.moduleToFilename.delete(mod);
|
|
692
|
+
if (result.static) {
|
|
693
|
+
if (state.staticModuleCache.get(specifier) === mod) {
|
|
694
|
+
state.staticModuleCache.delete(specifier);
|
|
695
|
+
}
|
|
696
|
+
} else {
|
|
697
|
+
if (state.moduleCache.get(specifier) === mod) {
|
|
698
|
+
state.moduleCache.delete(specifier);
|
|
699
|
+
}
|
|
700
|
+
if (state.moduleCache.get(cacheKey) === mod) {
|
|
701
|
+
state.moduleCache.delete(cacheKey);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
throw err;
|
|
706
|
+
}
|
|
707
|
+
})();
|
|
708
|
+
state.moduleLoadsInFlight.set(inFlightKey, loadPromise);
|
|
709
|
+
try {
|
|
710
|
+
return await loadPromise;
|
|
711
|
+
} finally {
|
|
712
|
+
state.moduleLoadsInFlight.delete(inFlightKey);
|
|
443
713
|
}
|
|
444
|
-
const mod = await state.isolate.compileModule(transformed.code, {
|
|
445
|
-
filename: specifier
|
|
446
|
-
});
|
|
447
|
-
const resolvedPath = path.posix.join(resolveDir, path.posix.basename(specifier));
|
|
448
|
-
state.moduleToFilename.set(mod, resolvedPath);
|
|
449
|
-
state.moduleCache.set(specifier, mod);
|
|
450
|
-
state.moduleCache.set(cacheKey, mod);
|
|
451
|
-
const resolver = createModuleResolver(state);
|
|
452
|
-
await mod.instantiate(state.context, resolver);
|
|
453
|
-
return mod;
|
|
454
714
|
};
|
|
455
715
|
}
|
|
456
716
|
function convertFetchCallback(callback) {
|
|
@@ -458,8 +718,8 @@ function convertFetchCallback(callback) {
|
|
|
458
718
|
return {};
|
|
459
719
|
}
|
|
460
720
|
return {
|
|
461
|
-
onFetch: async (
|
|
462
|
-
return Promise.resolve(callback(
|
|
721
|
+
onFetch: async (url, init) => {
|
|
722
|
+
return Promise.resolve(callback(url, init));
|
|
463
723
|
}
|
|
464
724
|
};
|
|
465
725
|
}
|
|
@@ -475,8 +735,13 @@ async function createRuntime(options) {
|
|
|
475
735
|
context,
|
|
476
736
|
handles: {},
|
|
477
737
|
moduleCache: new Map,
|
|
738
|
+
staticModuleCache: new Map,
|
|
739
|
+
moduleLoadsInFlight: new Map,
|
|
740
|
+
transformCache: new Map,
|
|
478
741
|
moduleToFilename: new Map,
|
|
479
742
|
sourceMaps: new Map,
|
|
743
|
+
pendingCallbacks: [],
|
|
744
|
+
evalChain: Promise.resolve(),
|
|
480
745
|
moduleLoader: opts.moduleLoader,
|
|
481
746
|
customFunctions: opts.customFunctions
|
|
482
747
|
};
|
|
@@ -491,13 +756,17 @@ async function createRuntime(options) {
|
|
|
491
756
|
state.handles.fs = await setupFs(context, opts.fs);
|
|
492
757
|
}
|
|
493
758
|
if (opts.customFunctions) {
|
|
494
|
-
|
|
759
|
+
const customMarshalOptions = opts.customFunctionsMarshalOptions ?? createLocalCustomFunctionsMarshalOptions();
|
|
760
|
+
state.customFnInvokeRef = await setupCustomFunctions(context, opts.customFunctions, customMarshalOptions);
|
|
495
761
|
}
|
|
496
762
|
if (opts.testEnvironment) {
|
|
497
763
|
const testEnvOptions = typeof opts.testEnvironment === "object" ? opts.testEnvironment : undefined;
|
|
498
764
|
state.handles.testEnvironment = await setupTestEnvironment(context, testEnvOptions);
|
|
499
765
|
}
|
|
500
766
|
if (opts.playwright) {
|
|
767
|
+
if (!opts.playwright.handler) {
|
|
768
|
+
throw new Error("Playwright configured without handler. Provide playwright.handler in createRuntime options.");
|
|
769
|
+
}
|
|
501
770
|
let eventCallback = opts.playwright.onEvent;
|
|
502
771
|
if (opts.playwright.console && opts.console?.onEntry) {
|
|
503
772
|
const originalCallback = eventCallback;
|
|
@@ -516,12 +785,13 @@ async function createRuntime(options) {
|
|
|
516
785
|
}
|
|
517
786
|
};
|
|
518
787
|
}
|
|
519
|
-
|
|
520
|
-
|
|
788
|
+
const playwrightSetupOptions = {
|
|
789
|
+
handler: opts.playwright.handler,
|
|
521
790
|
timeout: opts.playwright.timeout,
|
|
522
791
|
console: opts.playwright.console && !opts.console?.onEntry,
|
|
523
792
|
onEvent: eventCallback
|
|
524
|
-
}
|
|
793
|
+
};
|
|
794
|
+
state.handles.playwright = await setupPlaywright(context, playwrightSetupOptions);
|
|
525
795
|
}
|
|
526
796
|
const fetchHandle = {
|
|
527
797
|
async dispatchRequest(request, options2) {
|
|
@@ -577,6 +847,48 @@ async function createRuntime(options) {
|
|
|
577
847
|
throw new Error("Fetch handle not available");
|
|
578
848
|
}
|
|
579
849
|
return state.handles.fetch.hasActiveConnections();
|
|
850
|
+
},
|
|
851
|
+
dispatchClientWebSocketOpen(socketId, protocol, extensions) {
|
|
852
|
+
if (!state.handles.fetch) {
|
|
853
|
+
throw new Error("Fetch handle not available");
|
|
854
|
+
}
|
|
855
|
+
state.handles.fetch.dispatchClientWebSocketOpen(socketId, protocol, extensions);
|
|
856
|
+
},
|
|
857
|
+
dispatchClientWebSocketMessage(socketId, data) {
|
|
858
|
+
if (!state.handles.fetch) {
|
|
859
|
+
throw new Error("Fetch handle not available");
|
|
860
|
+
}
|
|
861
|
+
state.handles.fetch.dispatchClientWebSocketMessage(socketId, data);
|
|
862
|
+
},
|
|
863
|
+
dispatchClientWebSocketClose(socketId, code, reason, wasClean) {
|
|
864
|
+
if (!state.handles.fetch) {
|
|
865
|
+
throw new Error("Fetch handle not available");
|
|
866
|
+
}
|
|
867
|
+
state.handles.fetch.dispatchClientWebSocketClose(socketId, code, reason, wasClean);
|
|
868
|
+
},
|
|
869
|
+
dispatchClientWebSocketError(socketId) {
|
|
870
|
+
if (!state.handles.fetch) {
|
|
871
|
+
throw new Error("Fetch handle not available");
|
|
872
|
+
}
|
|
873
|
+
state.handles.fetch.dispatchClientWebSocketError(socketId);
|
|
874
|
+
},
|
|
875
|
+
onClientWebSocketCommand(callback) {
|
|
876
|
+
if (!state.handles.fetch) {
|
|
877
|
+
throw new Error("Fetch handle not available");
|
|
878
|
+
}
|
|
879
|
+
return state.handles.fetch.onClientWebSocketCommand(callback);
|
|
880
|
+
},
|
|
881
|
+
onEvent(callback) {
|
|
882
|
+
if (!state.handles.fetch) {
|
|
883
|
+
throw new Error("Fetch handle not available");
|
|
884
|
+
}
|
|
885
|
+
return state.handles.fetch.onEvent(callback);
|
|
886
|
+
},
|
|
887
|
+
dispatchEvent(event, payload) {
|
|
888
|
+
if (!state.handles.fetch) {
|
|
889
|
+
throw new Error("Fetch handle not available");
|
|
890
|
+
}
|
|
891
|
+
state.handles.fetch.dispatchEvent(event, payload);
|
|
580
892
|
}
|
|
581
893
|
};
|
|
582
894
|
const timersHandle = {
|
|
@@ -599,11 +911,27 @@ async function createRuntime(options) {
|
|
|
599
911
|
}
|
|
600
912
|
};
|
|
601
913
|
const testEnvironmentHandle = {
|
|
602
|
-
async runTests(
|
|
914
|
+
async runTests(timeout) {
|
|
603
915
|
if (!state.handles.testEnvironment) {
|
|
604
916
|
throw new Error("Test environment not enabled. Set testEnvironment: true in createRuntime options.");
|
|
605
917
|
}
|
|
606
|
-
|
|
918
|
+
if (timeout === undefined) {
|
|
919
|
+
return runTestsInContext(state.context);
|
|
920
|
+
}
|
|
921
|
+
let timeoutId;
|
|
922
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
923
|
+
timeoutId = setTimeout(() => reject(new Error("Test timeout")), timeout);
|
|
924
|
+
});
|
|
925
|
+
try {
|
|
926
|
+
return await Promise.race([
|
|
927
|
+
runTestsInContext(state.context),
|
|
928
|
+
timeoutPromise
|
|
929
|
+
]);
|
|
930
|
+
} finally {
|
|
931
|
+
if (timeoutId) {
|
|
932
|
+
clearTimeout(timeoutId);
|
|
933
|
+
}
|
|
934
|
+
}
|
|
607
935
|
},
|
|
608
936
|
hasTests() {
|
|
609
937
|
if (!state.handles.testEnvironment) {
|
|
@@ -624,7 +952,7 @@ async function createRuntime(options) {
|
|
|
624
952
|
const playwrightHandle = {
|
|
625
953
|
getCollectedData() {
|
|
626
954
|
if (!state.handles.playwright) {
|
|
627
|
-
throw new Error("Playwright not configured. Provide playwright.
|
|
955
|
+
throw new Error("Playwright not configured. Provide playwright.handler in createRuntime options.");
|
|
628
956
|
}
|
|
629
957
|
return {
|
|
630
958
|
browserConsoleLogs: state.handles.playwright.getBrowserConsoleLogs(),
|
|
@@ -638,43 +966,62 @@ async function createRuntime(options) {
|
|
|
638
966
|
};
|
|
639
967
|
return {
|
|
640
968
|
id,
|
|
969
|
+
pendingCallbacks: state.pendingCallbacks,
|
|
641
970
|
fetch: fetchHandle,
|
|
642
971
|
timers: timersHandle,
|
|
643
972
|
console: consoleHandle,
|
|
644
973
|
testEnvironment: testEnvironmentHandle,
|
|
645
974
|
playwright: playwrightHandle,
|
|
646
975
|
async eval(code, filenameOrOptions) {
|
|
647
|
-
const
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
const transformed = await transformEntryCode(code, filename);
|
|
651
|
-
if (transformed.sourceMap) {
|
|
652
|
-
state.sourceMaps.set(filename, transformed.sourceMap);
|
|
653
|
-
}
|
|
654
|
-
const mod = await state.isolate.compileModule(transformed.code, {
|
|
655
|
-
filename
|
|
656
|
-
});
|
|
657
|
-
state.moduleToFilename.set(mod, filename);
|
|
658
|
-
const resolver = createModuleResolver(state);
|
|
659
|
-
await mod.instantiate(state.context, resolver);
|
|
660
|
-
await mod.evaluate();
|
|
661
|
-
const ns = mod.namespace;
|
|
662
|
-
const runRef = await ns.get("default", { reference: true });
|
|
976
|
+
const runEval = async () => {
|
|
977
|
+
const options2 = typeof filenameOrOptions === "string" ? { filename: filenameOrOptions } : filenameOrOptions;
|
|
978
|
+
const filename = normalizeEntryFilename(options2?.filename);
|
|
663
979
|
try {
|
|
664
|
-
await
|
|
665
|
-
|
|
666
|
-
|
|
980
|
+
const transformed = await transformEntryCode(code, filename);
|
|
981
|
+
if (transformed.sourceMap) {
|
|
982
|
+
state.sourceMaps.set(filename, transformed.sourceMap);
|
|
983
|
+
}
|
|
984
|
+
const mod = await state.isolate.compileModule(transformed.code, {
|
|
985
|
+
filename
|
|
667
986
|
});
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
987
|
+
state.moduleToFilename.set(mod, filename);
|
|
988
|
+
const resolver = createModuleResolver(state);
|
|
989
|
+
await mod.instantiate(state.context, resolver);
|
|
990
|
+
await mod.evaluate();
|
|
991
|
+
const ns = mod.namespace;
|
|
992
|
+
const runRef = await ns.get("default", { reference: true });
|
|
993
|
+
try {
|
|
994
|
+
await runRef.apply(undefined, [], {
|
|
995
|
+
result: { promise: true }
|
|
996
|
+
});
|
|
997
|
+
} finally {
|
|
998
|
+
runRef.release();
|
|
999
|
+
}
|
|
1000
|
+
if (state.pendingCallbacks.length > 0) {
|
|
1001
|
+
await Promise.all(state.pendingCallbacks);
|
|
1002
|
+
state.pendingCallbacks.length = 0;
|
|
1003
|
+
}
|
|
1004
|
+
} catch (err) {
|
|
1005
|
+
const error = err;
|
|
1006
|
+
if (error.stack && state.sourceMaps.size > 0) {
|
|
1007
|
+
error.stack = mapErrorStack(error.stack, state.sourceMaps);
|
|
1008
|
+
}
|
|
1009
|
+
throw error;
|
|
675
1010
|
}
|
|
676
|
-
|
|
677
|
-
|
|
1011
|
+
};
|
|
1012
|
+
const queuedEval = state.evalChain.then(runEval, runEval);
|
|
1013
|
+
state.evalChain = queuedEval.then(() => {
|
|
1014
|
+
return;
|
|
1015
|
+
}, () => {
|
|
1016
|
+
return;
|
|
1017
|
+
});
|
|
1018
|
+
return queuedEval;
|
|
1019
|
+
},
|
|
1020
|
+
clearModuleCache() {
|
|
1021
|
+
state.moduleCache.clear();
|
|
1022
|
+
state.moduleLoadsInFlight.clear();
|
|
1023
|
+
state.moduleToFilename.clear();
|
|
1024
|
+
state.sourceMaps.clear();
|
|
678
1025
|
},
|
|
679
1026
|
async dispose() {
|
|
680
1027
|
if (state.customFnInvokeRef) {
|
|
@@ -691,6 +1038,7 @@ async function createRuntime(options) {
|
|
|
691
1038
|
state.handles.console?.dispose();
|
|
692
1039
|
state.handles.core?.dispose();
|
|
693
1040
|
state.moduleCache.clear();
|
|
1041
|
+
state.moduleLoadsInFlight.clear();
|
|
694
1042
|
state.context.release();
|
|
695
1043
|
state.isolate.dispose();
|
|
696
1044
|
}
|
|
@@ -712,9 +1060,11 @@ export {
|
|
|
712
1060
|
normalizeEntryFilename2 as normalizeEntryFilename,
|
|
713
1061
|
hasTests,
|
|
714
1062
|
getTestCount,
|
|
1063
|
+
getDefaultPlaywrightHandlerMetadata,
|
|
1064
|
+
defaultPlaywrightHandler,
|
|
715
1065
|
createRuntime,
|
|
716
1066
|
createPlaywrightHandler,
|
|
717
1067
|
createNodeFileSystemHandler
|
|
718
1068
|
};
|
|
719
1069
|
|
|
720
|
-
//# debugId=
|
|
1070
|
+
//# debugId=42C800BEB0731DA164756E2164756E21
|