@ricsam/isolate-daemon 0.1.12 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/connection.cjs +453 -750
- package/dist/cjs/connection.cjs.map +3 -3
- package/dist/cjs/daemon.cjs +8 -1
- package/dist/cjs/daemon.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/connection.mjs +455 -753
- package/dist/mjs/connection.mjs.map +3 -3
- package/dist/mjs/daemon.mjs +8 -1
- package/dist/mjs/daemon.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/types/daemon.d.ts +0 -13
- package/dist/types/types.d.ts +11 -19
- package/package.json +1 -1
package/dist/cjs/connection.cjs
CHANGED
|
@@ -1,20 +1,7 @@
|
|
|
1
|
-
var __create = Object.create;
|
|
2
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
3
1
|
var __defProp = Object.defineProperty;
|
|
4
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
4
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
-
for (let key of __getOwnPropNames(mod))
|
|
11
|
-
if (!__hasOwnProp.call(to, key))
|
|
12
|
-
__defProp(to, key, {
|
|
13
|
-
get: () => mod[key],
|
|
14
|
-
enumerable: true
|
|
15
|
-
});
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
5
|
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
19
6
|
var __toCommonJS = (from) => {
|
|
20
7
|
var entry = __moduleCache.get(from), desc;
|
|
@@ -46,14 +33,9 @@ __export(exports_connection, {
|
|
|
46
33
|
});
|
|
47
34
|
module.exports = __toCommonJS(exports_connection);
|
|
48
35
|
var import_node_crypto = require("node:crypto");
|
|
49
|
-
var import_node_path = __toESM(require("node:path"));
|
|
50
|
-
var import_isolated_vm = __toESM(require("isolated-vm"));
|
|
51
36
|
var import_isolate_protocol = require("@ricsam/isolate-protocol");
|
|
52
37
|
var import_callback_fs_handler = require("./callback-fs-handler.cjs");
|
|
53
|
-
var import_isolate_test_environment = require("@ricsam/isolate-test-environment");
|
|
54
|
-
var import_isolate_playwright = require("@ricsam/isolate-playwright");
|
|
55
38
|
var import_isolate_runtime = require("@ricsam/isolate-runtime");
|
|
56
|
-
var import_isolate_transform = require("@ricsam/isolate-transform");
|
|
57
39
|
function handleConnection(socket, state) {
|
|
58
40
|
const connection = {
|
|
59
41
|
socket,
|
|
@@ -88,12 +70,7 @@ function handleConnection(socket, state) {
|
|
|
88
70
|
if (instance.namespaceId != null && !instance.isDisposed) {
|
|
89
71
|
softDeleteRuntime(instance, state);
|
|
90
72
|
} else if (!instance.isDisposed) {
|
|
91
|
-
|
|
92
|
-
if (instance.playwrightHandle) {
|
|
93
|
-
instance.playwrightHandle.dispose();
|
|
94
|
-
}
|
|
95
|
-
instance.runtime.dispose();
|
|
96
|
-
} catch {}
|
|
73
|
+
instance.runtime.dispose().catch(() => {});
|
|
97
74
|
state.isolates.delete(isolateId);
|
|
98
75
|
}
|
|
99
76
|
}
|
|
@@ -199,12 +176,6 @@ async function handleMessage(message, connection, state) {
|
|
|
199
176
|
case import_isolate_protocol.MessageType.GET_TEST_COUNT:
|
|
200
177
|
await handleGetTestCount(message, connection, state);
|
|
201
178
|
break;
|
|
202
|
-
case import_isolate_protocol.MessageType.RUN_PLAYWRIGHT_TESTS:
|
|
203
|
-
await handleRunPlaywrightTests(message, connection, state);
|
|
204
|
-
break;
|
|
205
|
-
case import_isolate_protocol.MessageType.RESET_PLAYWRIGHT_TESTS:
|
|
206
|
-
await handleResetPlaywrightTests(message, connection, state);
|
|
207
|
-
break;
|
|
208
179
|
case import_isolate_protocol.MessageType.GET_COLLECTED_DATA:
|
|
209
180
|
await handleGetCollectedData(message, connection, state);
|
|
210
181
|
break;
|
|
@@ -235,6 +206,18 @@ async function handleMessage(message, connection, state) {
|
|
|
235
206
|
case import_isolate_protocol.MessageType.CALLBACK_STREAM_END:
|
|
236
207
|
handleCallbackStreamEnd(message, connection);
|
|
237
208
|
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);
|
|
220
|
+
break;
|
|
238
221
|
default:
|
|
239
222
|
sendError(connection.socket, message.requestId ?? 0, import_isolate_protocol.ErrorCode.UNKNOWN_MESSAGE_TYPE, `Unknown message type: ${message.type}`);
|
|
240
223
|
}
|
|
@@ -243,13 +226,17 @@ function softDeleteRuntime(instance, state) {
|
|
|
243
226
|
instance.isDisposed = true;
|
|
244
227
|
instance.disposedAt = Date.now();
|
|
245
228
|
instance.ownerConnection = null;
|
|
229
|
+
if (instance.callbackContext) {
|
|
230
|
+
instance.callbackContext.connection = null;
|
|
231
|
+
}
|
|
246
232
|
instance.callbacks.clear();
|
|
247
233
|
instance.runtime.timers.clearAll();
|
|
248
234
|
instance.runtime.console.reset();
|
|
249
|
-
instance.pendingCallbacks.length = 0;
|
|
235
|
+
instance.runtime.pendingCallbacks.length = 0;
|
|
250
236
|
instance.returnedCallbacks?.clear();
|
|
251
237
|
instance.returnedPromises?.clear();
|
|
252
238
|
instance.returnedIterators?.clear();
|
|
239
|
+
instance.runtime.clearModuleCache();
|
|
253
240
|
}
|
|
254
241
|
function reuseNamespacedRuntime(instance, connection, message, state) {
|
|
255
242
|
instance.ownerConnection = connection.socket;
|
|
@@ -258,11 +245,19 @@ function reuseNamespacedRuntime(instance, connection, message, state) {
|
|
|
258
245
|
instance.lastActivity = Date.now();
|
|
259
246
|
connection.isolates.add(instance.isolateId);
|
|
260
247
|
const callbacks = message.options.callbacks;
|
|
248
|
+
const testEnvOptions = message.options.testEnvironment != null && typeof message.options.testEnvironment === "object" ? message.options.testEnvironment : undefined;
|
|
261
249
|
if (instance.callbackContext) {
|
|
262
250
|
instance.callbackContext.connection = connection;
|
|
263
251
|
instance.callbackContext.consoleOnEntry = callbacks?.console?.onEntry?.callbackId;
|
|
264
252
|
instance.callbackContext.fetch = callbacks?.fetch?.callbackId;
|
|
265
253
|
instance.callbackContext.moduleLoader = callbacks?.moduleLoader?.callbackId;
|
|
254
|
+
instance.callbackContext.testEnvironmentOnEvent = testEnvOptions?.callbacks?.onEvent?.callbackId;
|
|
255
|
+
instance.callbackContext.playwright = {
|
|
256
|
+
handlerCallbackId: callbacks?.playwright?.handlerCallbackId,
|
|
257
|
+
onBrowserConsoleLogCallbackId: callbacks?.playwright?.onBrowserConsoleLogCallbackId,
|
|
258
|
+
onNetworkRequestCallbackId: callbacks?.playwright?.onNetworkRequestCallbackId,
|
|
259
|
+
onNetworkResponseCallbackId: callbacks?.playwright?.onNetworkResponseCallbackId
|
|
260
|
+
};
|
|
266
261
|
instance.callbackContext.fs = {
|
|
267
262
|
readFile: callbacks?.fs?.readFile?.callbackId,
|
|
268
263
|
writeFile: callbacks?.fs?.writeFile?.callbackId,
|
|
@@ -299,7 +294,6 @@ function reuseNamespacedRuntime(instance, connection, message, state) {
|
|
|
299
294
|
}
|
|
300
295
|
}
|
|
301
296
|
if (callbacks?.moduleLoader) {
|
|
302
|
-
instance.moduleLoaderCallbackId = callbacks.moduleLoader.callbackId;
|
|
303
297
|
instance.callbacks.set(callbacks.moduleLoader.callbackId, callbacks.moduleLoader);
|
|
304
298
|
}
|
|
305
299
|
if (callbacks?.custom) {
|
|
@@ -309,23 +303,46 @@ function reuseNamespacedRuntime(instance, connection, message, state) {
|
|
|
309
303
|
}
|
|
310
304
|
}
|
|
311
305
|
}
|
|
306
|
+
if (testEnvOptions?.callbacks?.onEvent) {
|
|
307
|
+
instance.callbacks.set(testEnvOptions.callbacks.onEvent.callbackId, {
|
|
308
|
+
...testEnvOptions.callbacks.onEvent,
|
|
309
|
+
name: "testEnvironment.onEvent"
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
if (callbacks?.playwright) {
|
|
313
|
+
instance.callbacks.set(callbacks.playwright.handlerCallbackId, {
|
|
314
|
+
callbackId: callbacks.playwright.handlerCallbackId,
|
|
315
|
+
name: "playwright.handler",
|
|
316
|
+
type: "async"
|
|
317
|
+
});
|
|
318
|
+
if (callbacks.playwright.onBrowserConsoleLogCallbackId !== undefined) {
|
|
319
|
+
instance.callbacks.set(callbacks.playwright.onBrowserConsoleLogCallbackId, {
|
|
320
|
+
callbackId: callbacks.playwright.onBrowserConsoleLogCallbackId,
|
|
321
|
+
name: "playwright.onBrowserConsoleLog",
|
|
322
|
+
type: "sync"
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
if (callbacks.playwright.onNetworkRequestCallbackId !== undefined) {
|
|
326
|
+
instance.callbacks.set(callbacks.playwright.onNetworkRequestCallbackId, {
|
|
327
|
+
callbackId: callbacks.playwright.onNetworkRequestCallbackId,
|
|
328
|
+
name: "playwright.onNetworkRequest",
|
|
329
|
+
type: "sync"
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
if (callbacks.playwright.onNetworkResponseCallbackId !== undefined) {
|
|
333
|
+
instance.callbacks.set(callbacks.playwright.onNetworkResponseCallbackId, {
|
|
334
|
+
callbackId: callbacks.playwright.onNetworkResponseCallbackId,
|
|
335
|
+
name: "playwright.onNetworkResponse",
|
|
336
|
+
type: "sync"
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
}
|
|
312
340
|
instance.returnedCallbacks = new Map;
|
|
313
341
|
instance.returnedPromises = new Map;
|
|
314
342
|
instance.returnedIterators = new Map;
|
|
315
343
|
instance.nextLocalCallbackId = 1e6;
|
|
316
|
-
if (callbacks?.custom) {
|
|
317
|
-
const newCallbackIdMap = {};
|
|
318
|
-
for (const [name, reg] of Object.entries(callbacks.custom)) {
|
|
319
|
-
if (reg) {
|
|
320
|
-
newCallbackIdMap[name] = reg.callbackId;
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
try {
|
|
324
|
-
instance.runtime.context.global.setSync("__customFnCallbackIds", new import_isolated_vm.default.ExternalCopy(newCallbackIdMap).copyInto());
|
|
325
|
-
} catch {}
|
|
326
|
-
}
|
|
327
344
|
}
|
|
328
|
-
function evictOldestDisposedRuntime(state) {
|
|
345
|
+
async function evictOldestDisposedRuntime(state) {
|
|
329
346
|
let oldest = null;
|
|
330
347
|
let oldestTime = Infinity;
|
|
331
348
|
for (const [, instance] of state.isolates) {
|
|
@@ -338,10 +355,7 @@ function evictOldestDisposedRuntime(state) {
|
|
|
338
355
|
}
|
|
339
356
|
if (oldest) {
|
|
340
357
|
try {
|
|
341
|
-
|
|
342
|
-
oldest.playwrightHandle.dispose();
|
|
343
|
-
}
|
|
344
|
-
oldest.runtime.dispose();
|
|
358
|
+
await oldest.runtime.dispose();
|
|
345
359
|
} catch {}
|
|
346
360
|
state.isolates.delete(oldest.isolateId);
|
|
347
361
|
if (oldest.namespaceId != null) {
|
|
@@ -376,7 +390,7 @@ async function handleCreateRuntime(message, connection, state) {
|
|
|
376
390
|
}
|
|
377
391
|
}
|
|
378
392
|
if (state.isolates.size >= state.options.maxIsolates) {
|
|
379
|
-
if (!evictOldestDisposedRuntime(state)) {
|
|
393
|
+
if (!await evictOldestDisposedRuntime(state)) {
|
|
380
394
|
sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_MEMORY_LIMIT, `Maximum isolates (${state.options.maxIsolates}) reached`);
|
|
381
395
|
return;
|
|
382
396
|
}
|
|
@@ -388,12 +402,18 @@ async function handleCreateRuntime(message, connection, state) {
|
|
|
388
402
|
const fsCallbacks = message.options.callbacks?.fs;
|
|
389
403
|
const moduleLoaderCallback = message.options.callbacks?.moduleLoader;
|
|
390
404
|
const customCallbacks = message.options.callbacks?.custom;
|
|
391
|
-
const pendingCallbacks = [];
|
|
392
405
|
const callbackContext = {
|
|
393
406
|
connection,
|
|
394
407
|
consoleOnEntry: consoleCallbacks?.onEntry?.callbackId,
|
|
395
408
|
fetch: fetchCallback?.callbackId,
|
|
396
409
|
moduleLoader: moduleLoaderCallback?.callbackId,
|
|
410
|
+
testEnvironmentOnEvent: message.options.testEnvironment != null && typeof message.options.testEnvironment === "object" ? message.options.testEnvironment.callbacks?.onEvent?.callbackId : undefined,
|
|
411
|
+
playwright: {
|
|
412
|
+
handlerCallbackId: message.options.callbacks?.playwright?.handlerCallbackId,
|
|
413
|
+
onBrowserConsoleLogCallbackId: message.options.callbacks?.playwright?.onBrowserConsoleLogCallbackId,
|
|
414
|
+
onNetworkRequestCallbackId: message.options.callbacks?.playwright?.onNetworkRequestCallbackId,
|
|
415
|
+
onNetworkResponseCallbackId: message.options.callbacks?.playwright?.onNetworkResponseCallbackId
|
|
416
|
+
},
|
|
397
417
|
fs: {
|
|
398
418
|
readFile: fsCallbacks?.readFile?.callbackId,
|
|
399
419
|
writeFile: fsCallbacks?.writeFile?.callbackId,
|
|
@@ -405,7 +425,248 @@ async function handleCreateRuntime(message, connection, state) {
|
|
|
405
425
|
},
|
|
406
426
|
custom: new Map(customCallbacks ? Object.entries(customCallbacks).map(([name, reg]) => [name, reg.callbackId]) : [])
|
|
407
427
|
};
|
|
408
|
-
const
|
|
428
|
+
const instance = {
|
|
429
|
+
isolateId,
|
|
430
|
+
runtime: null,
|
|
431
|
+
ownerConnection: connection.socket,
|
|
432
|
+
callbacks: new Map,
|
|
433
|
+
createdAt: Date.now(),
|
|
434
|
+
lastActivity: Date.now(),
|
|
435
|
+
returnedCallbacks: new Map,
|
|
436
|
+
returnedPromises: new Map,
|
|
437
|
+
returnedIterators: new Map,
|
|
438
|
+
nextLocalCallbackId: 1e6,
|
|
439
|
+
namespaceId,
|
|
440
|
+
isDisposed: false,
|
|
441
|
+
callbackContext
|
|
442
|
+
};
|
|
443
|
+
let bridgedCustomFunctions;
|
|
444
|
+
let customFnMarshalOptions;
|
|
445
|
+
if (customCallbacks) {
|
|
446
|
+
const createMarshalContext = () => ({
|
|
447
|
+
registerCallback: (fn) => {
|
|
448
|
+
const callbackId = instance.nextLocalCallbackId++;
|
|
449
|
+
instance.returnedCallbacks.set(callbackId, fn);
|
|
450
|
+
return callbackId;
|
|
451
|
+
},
|
|
452
|
+
registerPromise: (promise) => {
|
|
453
|
+
const promiseId = instance.nextLocalCallbackId++;
|
|
454
|
+
instance.returnedPromises.set(promiseId, promise);
|
|
455
|
+
return promiseId;
|
|
456
|
+
},
|
|
457
|
+
registerIterator: (iterator) => {
|
|
458
|
+
const iteratorId = instance.nextLocalCallbackId++;
|
|
459
|
+
instance.returnedIterators.set(iteratorId, iterator);
|
|
460
|
+
return iteratorId;
|
|
461
|
+
}
|
|
462
|
+
});
|
|
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
|
+
const addCallbackIdsToRefs = (value) => {
|
|
466
|
+
if (value === null || typeof value !== "object")
|
|
467
|
+
return value;
|
|
468
|
+
if (isPromiseRef(value)) {
|
|
469
|
+
if ("__resolveCallbackId" in value)
|
|
470
|
+
return value;
|
|
471
|
+
const resolveCallbackId = instance.nextLocalCallbackId++;
|
|
472
|
+
instance.returnedCallbacks.set(resolveCallbackId, async (promiseId) => {
|
|
473
|
+
const promise = instance.returnedPromises.get(promiseId);
|
|
474
|
+
if (!promise)
|
|
475
|
+
throw new Error(`Promise ${promiseId} not found`);
|
|
476
|
+
const result2 = await promise;
|
|
477
|
+
instance.returnedPromises.delete(promiseId);
|
|
478
|
+
const ctx = createMarshalContext();
|
|
479
|
+
const marshalled = await import_isolate_protocol.marshalValue(result2, ctx);
|
|
480
|
+
return addCallbackIdsToRefs(marshalled);
|
|
481
|
+
});
|
|
482
|
+
return { ...value, __resolveCallbackId: resolveCallbackId };
|
|
483
|
+
}
|
|
484
|
+
if (isAsyncIteratorRef(value)) {
|
|
485
|
+
if ("__nextCallbackId" in value)
|
|
486
|
+
return value;
|
|
487
|
+
const nextCallbackId = instance.nextLocalCallbackId++;
|
|
488
|
+
instance.returnedCallbacks.set(nextCallbackId, async (iteratorId) => {
|
|
489
|
+
const iterator = instance.returnedIterators.get(iteratorId);
|
|
490
|
+
if (!iterator)
|
|
491
|
+
throw new Error(`Iterator ${iteratorId} not found`);
|
|
492
|
+
const result2 = await iterator.next();
|
|
493
|
+
if (result2.done)
|
|
494
|
+
instance.returnedIterators.delete(iteratorId);
|
|
495
|
+
const ctx = createMarshalContext();
|
|
496
|
+
const marshalledValue = await import_isolate_protocol.marshalValue(result2.value, ctx);
|
|
497
|
+
return { done: result2.done, value: addCallbackIdsToRefs(marshalledValue) };
|
|
498
|
+
});
|
|
499
|
+
const returnCallbackId = instance.nextLocalCallbackId++;
|
|
500
|
+
instance.returnedCallbacks.set(returnCallbackId, async (iteratorId, returnValue) => {
|
|
501
|
+
const iterator = instance.returnedIterators.get(iteratorId);
|
|
502
|
+
instance.returnedIterators.delete(iteratorId);
|
|
503
|
+
if (!iterator || !iterator.return)
|
|
504
|
+
return { done: true, value: undefined };
|
|
505
|
+
const result2 = await iterator.return(returnValue);
|
|
506
|
+
const ctx = createMarshalContext();
|
|
507
|
+
const marshalledValue = await import_isolate_protocol.marshalValue(result2.value, ctx);
|
|
508
|
+
return { done: true, value: addCallbackIdsToRefs(marshalledValue) };
|
|
509
|
+
});
|
|
510
|
+
return { ...value, __nextCallbackId: nextCallbackId, __returnCallbackId: returnCallbackId };
|
|
511
|
+
}
|
|
512
|
+
if (Array.isArray(value))
|
|
513
|
+
return value.map((item) => addCallbackIdsToRefs(item));
|
|
514
|
+
const result = {};
|
|
515
|
+
for (const key of Object.keys(value)) {
|
|
516
|
+
result[key] = addCallbackIdsToRefs(value[key]);
|
|
517
|
+
}
|
|
518
|
+
return result;
|
|
519
|
+
};
|
|
520
|
+
const LOCAL_CALLBACK_THRESHOLD = 1e6;
|
|
521
|
+
const invokeCallback = async (callbackId, args) => {
|
|
522
|
+
if (callbackId >= LOCAL_CALLBACK_THRESHOLD) {
|
|
523
|
+
const callback = instance.returnedCallbacks.get(callbackId);
|
|
524
|
+
if (!callback) {
|
|
525
|
+
throw new Error(`Local callback ${callbackId} not found`);
|
|
526
|
+
}
|
|
527
|
+
return await callback(...args);
|
|
528
|
+
} else {
|
|
529
|
+
const conn = callbackContext.connection;
|
|
530
|
+
if (!conn) {
|
|
531
|
+
throw new Error(`No connection available for callback ${callbackId}`);
|
|
532
|
+
}
|
|
533
|
+
return invokeClientCallback(conn, callbackId, args);
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
customFnMarshalOptions = { createMarshalContext, addCallbackIdsToRefs, invokeCallback };
|
|
537
|
+
bridgedCustomFunctions = {};
|
|
538
|
+
for (const [name, registration] of Object.entries(customCallbacks)) {
|
|
539
|
+
if (name.includes(":"))
|
|
540
|
+
continue;
|
|
541
|
+
const callbackContext_ = callbackContext;
|
|
542
|
+
if (registration.type === "asyncIterator") {
|
|
543
|
+
bridgedCustomFunctions[name] = {
|
|
544
|
+
type: "asyncIterator",
|
|
545
|
+
fn: (...args) => {
|
|
546
|
+
const startCallbackId = callbackContext_.custom.get(`${name}:start`);
|
|
547
|
+
const nextCallbackId = callbackContext_.custom.get(`${name}:next`);
|
|
548
|
+
const returnCallbackId = callbackContext_.custom.get(`${name}:return`);
|
|
549
|
+
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);
|
|
555
|
+
const iteratorId = startResult.iteratorId;
|
|
556
|
+
try {
|
|
557
|
+
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]);
|
|
563
|
+
if (nextResult.done)
|
|
564
|
+
return nextResult.value;
|
|
565
|
+
yield nextResult.value;
|
|
566
|
+
}
|
|
567
|
+
} finally {
|
|
568
|
+
const retConn = callbackContext_.connection;
|
|
569
|
+
if (retConn && returnCallbackId !== undefined) {
|
|
570
|
+
await invokeClientCallback(retConn, returnCallbackId, [iteratorId]).catch(() => {});
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
return bridgedIterator();
|
|
575
|
+
}
|
|
576
|
+
};
|
|
577
|
+
} else {
|
|
578
|
+
bridgedCustomFunctions[name] = {
|
|
579
|
+
type: registration.type,
|
|
580
|
+
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);
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
let moduleLoader;
|
|
593
|
+
if (moduleLoaderCallback) {
|
|
594
|
+
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]);
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
let testEnvironment;
|
|
604
|
+
if (message.options.testEnvironment) {
|
|
605
|
+
const testEnvOption = message.options.testEnvironment;
|
|
606
|
+
const testEnvOptions = typeof testEnvOption === "object" ? testEnvOption : undefined;
|
|
607
|
+
testEnvironment = {
|
|
608
|
+
onEvent: testEnvOptions?.callbacks?.onEvent ? (event) => {
|
|
609
|
+
const conn = callbackContext.connection;
|
|
610
|
+
const callbackId = callbackContext.testEnvironmentOnEvent;
|
|
611
|
+
if (!conn || callbackId === undefined) {
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
const promise = invokeClientCallback(conn, callbackId, [JSON.stringify(event)]).catch(() => {});
|
|
615
|
+
instance.runtime?.pendingCallbacks?.push(promise);
|
|
616
|
+
} : undefined,
|
|
617
|
+
testTimeout: testEnvOptions?.testTimeout
|
|
618
|
+
};
|
|
619
|
+
if (testEnvOptions?.callbacks?.onEvent) {
|
|
620
|
+
instance.callbacks.set(testEnvOptions.callbacks.onEvent.callbackId, {
|
|
621
|
+
...testEnvOptions.callbacks.onEvent,
|
|
622
|
+
name: "testEnvironment.onEvent"
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
let playwrightOptions;
|
|
627
|
+
const playwrightCallbacks = message.options.callbacks?.playwright;
|
|
628
|
+
if (playwrightCallbacks) {
|
|
629
|
+
playwrightOptions = {
|
|
630
|
+
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
|
+
try {
|
|
643
|
+
const resultJson = await invokeClientCallback(conn, callbackId, [JSON.stringify(op)], 60000);
|
|
644
|
+
return JSON.parse(resultJson);
|
|
645
|
+
} catch (err) {
|
|
646
|
+
const error = err;
|
|
647
|
+
return { ok: false, error: { name: error.name, message: error.message } };
|
|
648
|
+
}
|
|
649
|
+
},
|
|
650
|
+
console: playwrightCallbacks.console,
|
|
651
|
+
onEvent: (event) => {
|
|
652
|
+
const conn = callbackContext.connection;
|
|
653
|
+
if (!conn) {
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
if (event.type === "browserConsoleLog" && callbackContext.playwright.onBrowserConsoleLogCallbackId !== undefined) {
|
|
657
|
+
const promise = invokeClientCallback(conn, callbackContext.playwright.onBrowserConsoleLogCallbackId, [{ level: event.level, stdout: event.stdout, timestamp: event.timestamp }]).catch(() => {});
|
|
658
|
+
instance.runtime?.pendingCallbacks?.push(promise);
|
|
659
|
+
} else if (event.type === "networkRequest" && callbackContext.playwright.onNetworkRequestCallbackId !== undefined) {
|
|
660
|
+
const promise = invokeClientCallback(conn, callbackContext.playwright.onNetworkRequestCallbackId, [event]).catch(() => {});
|
|
661
|
+
instance.runtime?.pendingCallbacks?.push(promise);
|
|
662
|
+
} else if (event.type === "networkResponse" && callbackContext.playwright.onNetworkResponseCallbackId !== undefined) {
|
|
663
|
+
const promise = invokeClientCallback(conn, callbackContext.playwright.onNetworkResponseCallbackId, [event]).catch(() => {});
|
|
664
|
+
instance.runtime?.pendingCallbacks?.push(promise);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
const runtime = await import_isolate_runtime.createRuntime({
|
|
409
670
|
memoryLimitMB: message.options.memoryLimitMB ?? state.options.defaultMemoryLimitMB,
|
|
410
671
|
cwd: message.options.cwd,
|
|
411
672
|
console: {
|
|
@@ -415,28 +676,31 @@ async function handleCreateRuntime(message, connection, state) {
|
|
|
415
676
|
if (!conn || callbackId === undefined)
|
|
416
677
|
return;
|
|
417
678
|
const promise = invokeClientCallback(conn, callbackId, [entry]).catch(() => {});
|
|
418
|
-
pendingCallbacks.push(promise);
|
|
679
|
+
runtime.pendingCallbacks.push(promise);
|
|
419
680
|
}
|
|
420
681
|
},
|
|
421
|
-
fetch: {
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
682
|
+
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
|
+
const serialized = {
|
|
689
|
+
url,
|
|
690
|
+
method: init.method,
|
|
691
|
+
headers: init.headers,
|
|
692
|
+
body: init.rawBody
|
|
693
|
+
};
|
|
694
|
+
const result = await invokeClientCallback(conn, callbackId, [serialized], 60000);
|
|
695
|
+
if (result && typeof result === "object" && result.__streamingResponse) {
|
|
696
|
+
const response = result.response;
|
|
697
|
+
response.__isCallbackStream = true;
|
|
698
|
+
return response;
|
|
436
699
|
}
|
|
700
|
+
return deserializeResponse(result);
|
|
437
701
|
},
|
|
438
702
|
fs: {
|
|
439
|
-
getDirectory: async (
|
|
703
|
+
getDirectory: async (dirPath) => {
|
|
440
704
|
const conn = callbackContext.connection;
|
|
441
705
|
if (!conn) {
|
|
442
706
|
throw new Error("FS callbacks not available");
|
|
@@ -445,35 +709,17 @@ async function handleCreateRuntime(message, connection, state) {
|
|
|
445
709
|
connection: conn,
|
|
446
710
|
callbackContext,
|
|
447
711
|
invokeClientCallback,
|
|
448
|
-
basePath:
|
|
712
|
+
basePath: dirPath
|
|
449
713
|
});
|
|
450
714
|
}
|
|
451
|
-
}
|
|
715
|
+
},
|
|
716
|
+
moduleLoader,
|
|
717
|
+
customFunctions: bridgedCustomFunctions,
|
|
718
|
+
customFunctionsMarshalOptions: customFnMarshalOptions,
|
|
719
|
+
testEnvironment,
|
|
720
|
+
playwright: playwrightOptions
|
|
452
721
|
});
|
|
453
|
-
|
|
454
|
-
isolateId,
|
|
455
|
-
runtime,
|
|
456
|
-
ownerConnection: connection.socket,
|
|
457
|
-
callbacks: new Map,
|
|
458
|
-
createdAt: Date.now(),
|
|
459
|
-
lastActivity: Date.now(),
|
|
460
|
-
pendingCallbacks,
|
|
461
|
-
returnedCallbacks: new Map,
|
|
462
|
-
returnedPromises: new Map,
|
|
463
|
-
returnedIterators: new Map,
|
|
464
|
-
nextLocalCallbackId: 1e6,
|
|
465
|
-
namespaceId,
|
|
466
|
-
isDisposed: false,
|
|
467
|
-
callbackContext
|
|
468
|
-
};
|
|
469
|
-
if (moduleLoaderCallback) {
|
|
470
|
-
instance.moduleLoaderCallbackId = moduleLoaderCallback.callbackId;
|
|
471
|
-
instance.moduleCache = new Map;
|
|
472
|
-
instance.moduleToFilename = new Map;
|
|
473
|
-
}
|
|
474
|
-
if (customCallbacks) {
|
|
475
|
-
await setupCustomFunctions(runtime.context, customCallbacks, connection, instance);
|
|
476
|
-
}
|
|
722
|
+
instance.runtime = runtime;
|
|
477
723
|
if (consoleCallbacks?.onEntry) {
|
|
478
724
|
instance.callbacks.set(consoleCallbacks.onEntry.callbackId, {
|
|
479
725
|
...consoleCallbacks.onEntry,
|
|
@@ -500,52 +746,33 @@ async function handleCreateRuntime(message, connection, state) {
|
|
|
500
746
|
}
|
|
501
747
|
}
|
|
502
748
|
}
|
|
503
|
-
if (
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
onEvent: onEventCallback ? (event) => {
|
|
509
|
-
const promise = invokeClientCallback(connection, onEventCallback.callbackId, [JSON.stringify(event)]).catch(() => {});
|
|
510
|
-
pendingCallbacks.push(promise);
|
|
511
|
-
} : undefined,
|
|
512
|
-
testTimeout: testEnvOptions?.testTimeout
|
|
749
|
+
if (playwrightCallbacks) {
|
|
750
|
+
instance.callbacks.set(playwrightCallbacks.handlerCallbackId, {
|
|
751
|
+
callbackId: playwrightCallbacks.handlerCallbackId,
|
|
752
|
+
name: "playwright.handler",
|
|
753
|
+
type: "async"
|
|
513
754
|
});
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
755
|
+
if (playwrightCallbacks.onBrowserConsoleLogCallbackId !== undefined) {
|
|
756
|
+
instance.callbacks.set(playwrightCallbacks.onBrowserConsoleLogCallbackId, {
|
|
757
|
+
callbackId: playwrightCallbacks.onBrowserConsoleLogCallbackId,
|
|
758
|
+
name: "playwright.onBrowserConsoleLog",
|
|
759
|
+
type: "sync"
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
if (playwrightCallbacks.onNetworkRequestCallbackId !== undefined) {
|
|
763
|
+
instance.callbacks.set(playwrightCallbacks.onNetworkRequestCallbackId, {
|
|
764
|
+
callbackId: playwrightCallbacks.onNetworkRequestCallbackId,
|
|
765
|
+
name: "playwright.onNetworkRequest",
|
|
766
|
+
type: "sync"
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
if (playwrightCallbacks.onNetworkResponseCallbackId !== undefined) {
|
|
770
|
+
instance.callbacks.set(playwrightCallbacks.onNetworkResponseCallbackId, {
|
|
771
|
+
callbackId: playwrightCallbacks.onNetworkResponseCallbackId,
|
|
772
|
+
name: "playwright.onNetworkResponse",
|
|
773
|
+
type: "sync"
|
|
519
774
|
});
|
|
520
775
|
}
|
|
521
|
-
}
|
|
522
|
-
const playwrightCallbacks = message.options.callbacks?.playwright;
|
|
523
|
-
if (playwrightCallbacks) {
|
|
524
|
-
const handler = async (op) => {
|
|
525
|
-
try {
|
|
526
|
-
const resultJson = await invokeClientCallback(connection, playwrightCallbacks.handlerCallbackId, [JSON.stringify(op)]);
|
|
527
|
-
return JSON.parse(resultJson);
|
|
528
|
-
} catch (err) {
|
|
529
|
-
const error = err;
|
|
530
|
-
return { ok: false, error: { name: error.name, message: error.message } };
|
|
531
|
-
}
|
|
532
|
-
};
|
|
533
|
-
instance.playwrightHandle = await import_isolate_playwright.setupPlaywright(runtime.context, {
|
|
534
|
-
handler,
|
|
535
|
-
console: playwrightCallbacks.console,
|
|
536
|
-
onEvent: (event) => {
|
|
537
|
-
if (event.type === "browserConsoleLog" && playwrightCallbacks.onBrowserConsoleLogCallbackId) {
|
|
538
|
-
const promise = invokeClientCallback(connection, playwrightCallbacks.onBrowserConsoleLogCallbackId, [{ level: event.level, stdout: event.stdout, timestamp: event.timestamp }]).catch(() => {});
|
|
539
|
-
pendingCallbacks.push(promise);
|
|
540
|
-
} else if (event.type === "networkRequest" && playwrightCallbacks.onNetworkRequestCallbackId) {
|
|
541
|
-
const promise = invokeClientCallback(connection, playwrightCallbacks.onNetworkRequestCallbackId, [event]).catch(() => {});
|
|
542
|
-
pendingCallbacks.push(promise);
|
|
543
|
-
} else if (event.type === "networkResponse" && playwrightCallbacks.onNetworkResponseCallbackId) {
|
|
544
|
-
const promise = invokeClientCallback(connection, playwrightCallbacks.onNetworkResponseCallbackId, [event]).catch(() => {});
|
|
545
|
-
pendingCallbacks.push(promise);
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
});
|
|
549
776
|
}
|
|
550
777
|
state.isolates.set(isolateId, instance);
|
|
551
778
|
connection.isolates.add(isolateId);
|
|
@@ -553,7 +780,11 @@ async function handleCreateRuntime(message, connection, state) {
|
|
|
553
780
|
if (namespaceId != null) {
|
|
554
781
|
state.namespacedRuntimes.set(namespaceId, instance);
|
|
555
782
|
}
|
|
556
|
-
|
|
783
|
+
runtime.fetch.onWebSocketCommand((cmd) => {
|
|
784
|
+
const targetConnection = callbackContext.connection;
|
|
785
|
+
if (!targetConnection) {
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
557
788
|
let data;
|
|
558
789
|
if (cmd.data instanceof ArrayBuffer) {
|
|
559
790
|
data = new Uint8Array(cmd.data);
|
|
@@ -571,7 +802,49 @@ async function handleCreateRuntime(message, connection, state) {
|
|
|
571
802
|
reason: cmd.reason
|
|
572
803
|
}
|
|
573
804
|
};
|
|
574
|
-
sendMessage(
|
|
805
|
+
sendMessage(targetConnection.socket, wsCommandMsg);
|
|
806
|
+
});
|
|
807
|
+
runtime.fetch.onClientWebSocketCommand((cmd) => {
|
|
808
|
+
const targetConnection = callbackContext.connection;
|
|
809
|
+
if (!targetConnection) {
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
let data;
|
|
813
|
+
if (cmd.data instanceof ArrayBuffer) {
|
|
814
|
+
data = new Uint8Array(cmd.data);
|
|
815
|
+
} else {
|
|
816
|
+
data = cmd.data;
|
|
817
|
+
}
|
|
818
|
+
if (cmd.type === "connect") {
|
|
819
|
+
const msg = {
|
|
820
|
+
type: import_isolate_protocol.MessageType.CLIENT_WS_CONNECT,
|
|
821
|
+
requestId: 0,
|
|
822
|
+
isolateId,
|
|
823
|
+
socketId: cmd.socketId,
|
|
824
|
+
url: cmd.url,
|
|
825
|
+
protocols: cmd.protocols
|
|
826
|
+
};
|
|
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,
|
|
832
|
+
isolateId,
|
|
833
|
+
socketId: cmd.socketId,
|
|
834
|
+
data
|
|
835
|
+
};
|
|
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,
|
|
841
|
+
isolateId,
|
|
842
|
+
socketId: cmd.socketId,
|
|
843
|
+
code: cmd.code,
|
|
844
|
+
reason: cmd.reason
|
|
845
|
+
};
|
|
846
|
+
sendMessage(targetConnection.socket, msg);
|
|
847
|
+
}
|
|
575
848
|
});
|
|
576
849
|
sendOk(connection.socket, message.requestId, { isolateId, reused: false });
|
|
577
850
|
} catch (err) {
|
|
@@ -594,10 +867,7 @@ async function handleDisposeRuntime(message, connection, state) {
|
|
|
594
867
|
if (instance.namespaceId != null) {
|
|
595
868
|
softDeleteRuntime(instance, state);
|
|
596
869
|
} else {
|
|
597
|
-
|
|
598
|
-
instance.playwrightHandle.dispose();
|
|
599
|
-
}
|
|
600
|
-
instance.runtime.dispose();
|
|
870
|
+
await instance.runtime.dispose();
|
|
601
871
|
state.isolates.delete(message.isolateId);
|
|
602
872
|
}
|
|
603
873
|
sendOk(connection.socket, message.requestId);
|
|
@@ -614,45 +884,13 @@ async function handleEval(message, connection, state) {
|
|
|
614
884
|
}
|
|
615
885
|
instance.lastActivity = Date.now();
|
|
616
886
|
try {
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
if (!instance.sourceMaps) {
|
|
621
|
-
instance.sourceMaps = new Map;
|
|
622
|
-
}
|
|
623
|
-
instance.sourceMaps.set(filename, transformed.sourceMap);
|
|
624
|
-
}
|
|
625
|
-
const mod = await instance.runtime.isolate.compileModule(transformed.code, {
|
|
626
|
-
filename
|
|
887
|
+
await instance.runtime.eval(message.code, {
|
|
888
|
+
filename: message.filename,
|
|
889
|
+
maxExecutionMs: message.maxExecutionMs
|
|
627
890
|
});
|
|
628
|
-
if (instance.moduleLoaderCallbackId) {
|
|
629
|
-
instance.moduleToFilename?.set(mod, filename);
|
|
630
|
-
const resolver = createModuleResolver(instance, connection);
|
|
631
|
-
await mod.instantiate(instance.runtime.context, resolver);
|
|
632
|
-
} else {
|
|
633
|
-
await mod.instantiate(instance.runtime.context, (specifier) => {
|
|
634
|
-
throw new Error(`No module loader registered. Cannot import: ${specifier}`);
|
|
635
|
-
});
|
|
636
|
-
}
|
|
637
|
-
await mod.evaluate();
|
|
638
|
-
const ns = mod.namespace;
|
|
639
|
-
const runRef = await ns.get("default", { reference: true });
|
|
640
|
-
try {
|
|
641
|
-
await runRef.apply(undefined, [], {
|
|
642
|
-
result: { promise: true },
|
|
643
|
-
...message.maxExecutionMs ? { timeout: message.maxExecutionMs } : {}
|
|
644
|
-
});
|
|
645
|
-
} finally {
|
|
646
|
-
runRef.release();
|
|
647
|
-
}
|
|
648
|
-
await Promise.all(instance.pendingCallbacks);
|
|
649
|
-
instance.pendingCallbacks.length = 0;
|
|
650
891
|
sendOk(connection.socket, message.requestId, { value: undefined });
|
|
651
892
|
} catch (err) {
|
|
652
893
|
const error = err;
|
|
653
|
-
if (error.stack && instance.sourceMaps?.size) {
|
|
654
|
-
error.stack = import_isolate_transform.mapErrorStack(error.stack, instance.sourceMaps);
|
|
655
|
-
}
|
|
656
894
|
const isTimeoutError = error.message?.includes("Script execution timed out");
|
|
657
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 });
|
|
658
896
|
}
|
|
@@ -762,6 +1000,35 @@ async function handleWsClose(message, connection, state) {
|
|
|
762
1000
|
sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
|
|
763
1001
|
}
|
|
764
1002
|
}
|
|
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) {
|
|
1019
|
+
const instance = state.isolates.get(message.isolateId);
|
|
1020
|
+
if (!instance)
|
|
1021
|
+
return;
|
|
1022
|
+
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);
|
|
1031
|
+
}
|
|
765
1032
|
async function handleFetchGetUpgradeRequest(message, connection, state) {
|
|
766
1033
|
const instance = state.isolates.get(message.isolateId);
|
|
767
1034
|
if (!instance) {
|
|
@@ -940,523 +1207,6 @@ async function invokeClientCallback(connection, callbackId, args, timeout = 1e4)
|
|
|
940
1207
|
sendMessage(connection.socket, invoke);
|
|
941
1208
|
});
|
|
942
1209
|
}
|
|
943
|
-
var ISOLATE_MARSHAL_CODE = `
|
|
944
|
-
(function() {
|
|
945
|
-
// Marshal a value (JavaScript → Ref)
|
|
946
|
-
function marshalForHost(value, depth = 0) {
|
|
947
|
-
if (depth > 100) throw new Error('Maximum marshalling depth exceeded');
|
|
948
|
-
|
|
949
|
-
if (value === null) return null;
|
|
950
|
-
if (value === undefined) return { __type: 'UndefinedRef' };
|
|
951
|
-
|
|
952
|
-
const type = typeof value;
|
|
953
|
-
if (type === 'string' || type === 'number' || type === 'boolean') return value;
|
|
954
|
-
if (type === 'bigint') return { __type: 'BigIntRef', value: value.toString() };
|
|
955
|
-
if (type === 'function') throw new Error('Cannot marshal functions from isolate');
|
|
956
|
-
if (type === 'symbol') throw new Error('Cannot marshal Symbol values');
|
|
957
|
-
|
|
958
|
-
if (type === 'object') {
|
|
959
|
-
if (value instanceof Date) {
|
|
960
|
-
return { __type: 'DateRef', timestamp: value.getTime() };
|
|
961
|
-
}
|
|
962
|
-
if (value instanceof RegExp) {
|
|
963
|
-
return { __type: 'RegExpRef', source: value.source, flags: value.flags };
|
|
964
|
-
}
|
|
965
|
-
if (value instanceof URL) {
|
|
966
|
-
return { __type: 'URLRef', href: value.href };
|
|
967
|
-
}
|
|
968
|
-
if (typeof Headers !== 'undefined' && value instanceof Headers) {
|
|
969
|
-
const pairs = [];
|
|
970
|
-
value.forEach((v, k) => pairs.push([k, v]));
|
|
971
|
-
return { __type: 'HeadersRef', pairs };
|
|
972
|
-
}
|
|
973
|
-
if (value instanceof Uint8Array) {
|
|
974
|
-
return { __type: 'Uint8ArrayRef', data: Array.from(value) };
|
|
975
|
-
}
|
|
976
|
-
if (value instanceof ArrayBuffer) {
|
|
977
|
-
return { __type: 'Uint8ArrayRef', data: Array.from(new Uint8Array(value)) };
|
|
978
|
-
}
|
|
979
|
-
if (typeof Request !== 'undefined' && value instanceof Request) {
|
|
980
|
-
throw new Error('Cannot marshal Request from isolate. Use fetch callback instead.');
|
|
981
|
-
}
|
|
982
|
-
if (typeof Response !== 'undefined' && value instanceof Response) {
|
|
983
|
-
throw new Error('Cannot marshal Response from isolate. Return plain objects instead.');
|
|
984
|
-
}
|
|
985
|
-
if (typeof File !== 'undefined' && value instanceof File) {
|
|
986
|
-
throw new Error('Cannot marshal File from isolate.');
|
|
987
|
-
}
|
|
988
|
-
if (typeof Blob !== 'undefined' && value instanceof Blob) {
|
|
989
|
-
throw new Error('Cannot marshal Blob from isolate.');
|
|
990
|
-
}
|
|
991
|
-
if (typeof FormData !== 'undefined' && value instanceof FormData) {
|
|
992
|
-
throw new Error('Cannot marshal FormData from isolate.');
|
|
993
|
-
}
|
|
994
|
-
if (Array.isArray(value)) {
|
|
995
|
-
return value.map(v => marshalForHost(v, depth + 1));
|
|
996
|
-
}
|
|
997
|
-
// Plain object
|
|
998
|
-
const result = {};
|
|
999
|
-
for (const key of Object.keys(value)) {
|
|
1000
|
-
result[key] = marshalForHost(value[key], depth + 1);
|
|
1001
|
-
}
|
|
1002
|
-
return result;
|
|
1003
|
-
}
|
|
1004
|
-
return value;
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
|
-
// Unmarshal a value (Ref → JavaScript)
|
|
1008
|
-
function unmarshalFromHost(value, depth = 0) {
|
|
1009
|
-
if (depth > 100) throw new Error('Maximum unmarshalling depth exceeded');
|
|
1010
|
-
|
|
1011
|
-
if (value === null) return null;
|
|
1012
|
-
if (typeof value !== 'object') return value;
|
|
1013
|
-
|
|
1014
|
-
if (value.__type) {
|
|
1015
|
-
switch (value.__type) {
|
|
1016
|
-
case 'UndefinedRef': return undefined;
|
|
1017
|
-
case 'DateRef': return new Date(value.timestamp);
|
|
1018
|
-
case 'RegExpRef': return new RegExp(value.source, value.flags);
|
|
1019
|
-
case 'BigIntRef': return BigInt(value.value);
|
|
1020
|
-
case 'URLRef': return new URL(value.href);
|
|
1021
|
-
case 'HeadersRef': return new Headers(value.pairs);
|
|
1022
|
-
case 'Uint8ArrayRef': return new Uint8Array(value.data);
|
|
1023
|
-
case 'RequestRef': {
|
|
1024
|
-
const init = {
|
|
1025
|
-
method: value.method,
|
|
1026
|
-
headers: value.headers,
|
|
1027
|
-
body: value.body ? new Uint8Array(value.body) : null,
|
|
1028
|
-
};
|
|
1029
|
-
if (value.mode) init.mode = value.mode;
|
|
1030
|
-
if (value.credentials) init.credentials = value.credentials;
|
|
1031
|
-
if (value.cache) init.cache = value.cache;
|
|
1032
|
-
if (value.redirect) init.redirect = value.redirect;
|
|
1033
|
-
if (value.referrer) init.referrer = value.referrer;
|
|
1034
|
-
if (value.referrerPolicy) init.referrerPolicy = value.referrerPolicy;
|
|
1035
|
-
if (value.integrity) init.integrity = value.integrity;
|
|
1036
|
-
return new Request(value.url, init);
|
|
1037
|
-
}
|
|
1038
|
-
case 'ResponseRef': {
|
|
1039
|
-
return new Response(value.body ? new Uint8Array(value.body) : null, {
|
|
1040
|
-
status: value.status,
|
|
1041
|
-
statusText: value.statusText,
|
|
1042
|
-
headers: value.headers,
|
|
1043
|
-
});
|
|
1044
|
-
}
|
|
1045
|
-
case 'FileRef': {
|
|
1046
|
-
if (!value.name) {
|
|
1047
|
-
return new Blob([new Uint8Array(value.data)], { type: value.type });
|
|
1048
|
-
}
|
|
1049
|
-
return new File([new Uint8Array(value.data)], value.name, {
|
|
1050
|
-
type: value.type,
|
|
1051
|
-
lastModified: value.lastModified,
|
|
1052
|
-
});
|
|
1053
|
-
}
|
|
1054
|
-
case 'FormDataRef': {
|
|
1055
|
-
const fd = new FormData();
|
|
1056
|
-
for (const [key, entry] of value.entries) {
|
|
1057
|
-
if (typeof entry === 'string') {
|
|
1058
|
-
fd.append(key, entry);
|
|
1059
|
-
} else {
|
|
1060
|
-
const file = unmarshalFromHost(entry, depth + 1);
|
|
1061
|
-
fd.append(key, file);
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
|
-
return fd;
|
|
1065
|
-
}
|
|
1066
|
-
case 'CallbackRef': {
|
|
1067
|
-
// Create a proxy function that invokes the callback
|
|
1068
|
-
const callbackId = value.callbackId;
|
|
1069
|
-
return function(...args) {
|
|
1070
|
-
const argsJson = JSON.stringify(marshalForHost(args));
|
|
1071
|
-
const resultJson = __customFn_invoke.applySyncPromise(undefined, [callbackId, argsJson]);
|
|
1072
|
-
const result = JSON.parse(resultJson);
|
|
1073
|
-
if (result.ok) {
|
|
1074
|
-
return unmarshalFromHost(result.value);
|
|
1075
|
-
} else {
|
|
1076
|
-
const error = new Error(result.error.message);
|
|
1077
|
-
error.name = result.error.name;
|
|
1078
|
-
throw error;
|
|
1079
|
-
}
|
|
1080
|
-
};
|
|
1081
|
-
}
|
|
1082
|
-
case 'PromiseRef': {
|
|
1083
|
-
// Create a proxy Promise that resolves via callback
|
|
1084
|
-
const promiseId = value.promiseId;
|
|
1085
|
-
return new Promise((resolve, reject) => {
|
|
1086
|
-
try {
|
|
1087
|
-
const argsJson = JSON.stringify([promiseId]);
|
|
1088
|
-
const resultJson = __customFn_invoke.applySyncPromise(undefined, [value.__resolveCallbackId, argsJson]);
|
|
1089
|
-
const result = JSON.parse(resultJson);
|
|
1090
|
-
if (result.ok) {
|
|
1091
|
-
resolve(unmarshalFromHost(result.value));
|
|
1092
|
-
} else {
|
|
1093
|
-
reject(new Error(result.error.message));
|
|
1094
|
-
}
|
|
1095
|
-
} catch (e) {
|
|
1096
|
-
reject(e);
|
|
1097
|
-
}
|
|
1098
|
-
});
|
|
1099
|
-
}
|
|
1100
|
-
case 'AsyncIteratorRef': {
|
|
1101
|
-
const iteratorId = value.iteratorId;
|
|
1102
|
-
const nextCallbackId = value.__nextCallbackId;
|
|
1103
|
-
const returnCallbackId = value.__returnCallbackId;
|
|
1104
|
-
return {
|
|
1105
|
-
[Symbol.asyncIterator]() { return this; },
|
|
1106
|
-
async next() {
|
|
1107
|
-
const argsJson = JSON.stringify([iteratorId]);
|
|
1108
|
-
const resultJson = __customFn_invoke.applySyncPromise(undefined, [nextCallbackId, argsJson]);
|
|
1109
|
-
const result = JSON.parse(resultJson);
|
|
1110
|
-
if (!result.ok) {
|
|
1111
|
-
const error = new Error(result.error.message);
|
|
1112
|
-
error.name = result.error.name;
|
|
1113
|
-
throw error;
|
|
1114
|
-
}
|
|
1115
|
-
return {
|
|
1116
|
-
done: result.value.done,
|
|
1117
|
-
value: unmarshalFromHost(result.value.value)
|
|
1118
|
-
};
|
|
1119
|
-
},
|
|
1120
|
-
async return(v) {
|
|
1121
|
-
const argsJson = JSON.stringify([iteratorId, marshalForHost(v)]);
|
|
1122
|
-
const resultJson = __customFn_invoke.applySyncPromise(undefined, [returnCallbackId, argsJson]);
|
|
1123
|
-
const result = JSON.parse(resultJson);
|
|
1124
|
-
return { done: true, value: result.ok ? unmarshalFromHost(result.value) : undefined };
|
|
1125
|
-
}
|
|
1126
|
-
};
|
|
1127
|
-
}
|
|
1128
|
-
default:
|
|
1129
|
-
// Unknown ref type, return as-is
|
|
1130
|
-
break;
|
|
1131
|
-
}
|
|
1132
|
-
}
|
|
1133
|
-
|
|
1134
|
-
if (Array.isArray(value)) {
|
|
1135
|
-
return value.map(v => unmarshalFromHost(v, depth + 1));
|
|
1136
|
-
}
|
|
1137
|
-
|
|
1138
|
-
// Plain object - recursively unmarshal
|
|
1139
|
-
const result = {};
|
|
1140
|
-
for (const key of Object.keys(value)) {
|
|
1141
|
-
result[key] = unmarshalFromHost(value[key], depth + 1);
|
|
1142
|
-
}
|
|
1143
|
-
return result;
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
|
-
globalThis.__marshalForHost = marshalForHost;
|
|
1147
|
-
globalThis.__unmarshalFromHost = unmarshalFromHost;
|
|
1148
|
-
})();
|
|
1149
|
-
`;
|
|
1150
|
-
var LOCAL_CALLBACK_THRESHOLD = 1e6;
|
|
1151
|
-
function isPromiseRef(value) {
|
|
1152
|
-
return typeof value === "object" && value !== null && value.__type === "PromiseRef";
|
|
1153
|
-
}
|
|
1154
|
-
function isAsyncIteratorRef(value) {
|
|
1155
|
-
return typeof value === "object" && value !== null && value.__type === "AsyncIteratorRef";
|
|
1156
|
-
}
|
|
1157
|
-
function isLocalCallbackId(callbackId) {
|
|
1158
|
-
return callbackId >= LOCAL_CALLBACK_THRESHOLD;
|
|
1159
|
-
}
|
|
1160
|
-
async function setupCustomFunctions(context, customCallbacks, connection, instance) {
|
|
1161
|
-
const global = context.global;
|
|
1162
|
-
function createMarshalContext() {
|
|
1163
|
-
return {
|
|
1164
|
-
registerCallback: (fn) => {
|
|
1165
|
-
const callbackId = instance.nextLocalCallbackId++;
|
|
1166
|
-
instance.returnedCallbacks.set(callbackId, fn);
|
|
1167
|
-
return callbackId;
|
|
1168
|
-
},
|
|
1169
|
-
registerPromise: (promise) => {
|
|
1170
|
-
const promiseId = instance.nextLocalCallbackId++;
|
|
1171
|
-
instance.returnedPromises.set(promiseId, promise);
|
|
1172
|
-
return promiseId;
|
|
1173
|
-
},
|
|
1174
|
-
registerIterator: (iterator) => {
|
|
1175
|
-
const iteratorId = instance.nextLocalCallbackId++;
|
|
1176
|
-
instance.returnedIterators.set(iteratorId, iterator);
|
|
1177
|
-
return iteratorId;
|
|
1178
|
-
}
|
|
1179
|
-
};
|
|
1180
|
-
}
|
|
1181
|
-
function addCallbackIdsToRefs(value) {
|
|
1182
|
-
if (value === null || typeof value !== "object") {
|
|
1183
|
-
return value;
|
|
1184
|
-
}
|
|
1185
|
-
if (isPromiseRef(value)) {
|
|
1186
|
-
if ("__resolveCallbackId" in value) {
|
|
1187
|
-
return value;
|
|
1188
|
-
}
|
|
1189
|
-
const resolveCallbackId = instance.nextLocalCallbackId++;
|
|
1190
|
-
instance.returnedCallbacks.set(resolveCallbackId, async (promiseId) => {
|
|
1191
|
-
const promise = instance.returnedPromises.get(promiseId);
|
|
1192
|
-
if (!promise) {
|
|
1193
|
-
throw new Error(`Promise ${promiseId} not found`);
|
|
1194
|
-
}
|
|
1195
|
-
const result2 = await promise;
|
|
1196
|
-
instance.returnedPromises.delete(promiseId);
|
|
1197
|
-
const ctx = createMarshalContext();
|
|
1198
|
-
const marshalled = await import_isolate_protocol.marshalValue(result2, ctx);
|
|
1199
|
-
return addCallbackIdsToRefs(marshalled);
|
|
1200
|
-
});
|
|
1201
|
-
return {
|
|
1202
|
-
...value,
|
|
1203
|
-
__resolveCallbackId: resolveCallbackId
|
|
1204
|
-
};
|
|
1205
|
-
}
|
|
1206
|
-
if (isAsyncIteratorRef(value)) {
|
|
1207
|
-
if ("__nextCallbackId" in value) {
|
|
1208
|
-
return value;
|
|
1209
|
-
}
|
|
1210
|
-
const nextCallbackId = instance.nextLocalCallbackId++;
|
|
1211
|
-
instance.returnedCallbacks.set(nextCallbackId, async (iteratorId) => {
|
|
1212
|
-
const iterator = instance.returnedIterators.get(iteratorId);
|
|
1213
|
-
if (!iterator) {
|
|
1214
|
-
throw new Error(`Iterator ${iteratorId} not found`);
|
|
1215
|
-
}
|
|
1216
|
-
const result2 = await iterator.next();
|
|
1217
|
-
if (result2.done) {
|
|
1218
|
-
instance.returnedIterators.delete(iteratorId);
|
|
1219
|
-
}
|
|
1220
|
-
const ctx = createMarshalContext();
|
|
1221
|
-
const marshalledValue = await import_isolate_protocol.marshalValue(result2.value, ctx);
|
|
1222
|
-
return {
|
|
1223
|
-
done: result2.done,
|
|
1224
|
-
value: addCallbackIdsToRefs(marshalledValue)
|
|
1225
|
-
};
|
|
1226
|
-
});
|
|
1227
|
-
const returnCallbackId = instance.nextLocalCallbackId++;
|
|
1228
|
-
instance.returnedCallbacks.set(returnCallbackId, async (iteratorId, returnValue) => {
|
|
1229
|
-
const iterator = instance.returnedIterators.get(iteratorId);
|
|
1230
|
-
instance.returnedIterators.delete(iteratorId);
|
|
1231
|
-
if (!iterator || !iterator.return) {
|
|
1232
|
-
return { done: true, value: undefined };
|
|
1233
|
-
}
|
|
1234
|
-
const result2 = await iterator.return(returnValue);
|
|
1235
|
-
const ctx = createMarshalContext();
|
|
1236
|
-
const marshalledValue = await import_isolate_protocol.marshalValue(result2.value, ctx);
|
|
1237
|
-
return {
|
|
1238
|
-
done: true,
|
|
1239
|
-
value: addCallbackIdsToRefs(marshalledValue)
|
|
1240
|
-
};
|
|
1241
|
-
});
|
|
1242
|
-
return {
|
|
1243
|
-
...value,
|
|
1244
|
-
__nextCallbackId: nextCallbackId,
|
|
1245
|
-
__returnCallbackId: returnCallbackId
|
|
1246
|
-
};
|
|
1247
|
-
}
|
|
1248
|
-
if (Array.isArray(value)) {
|
|
1249
|
-
return value.map((item) => addCallbackIdsToRefs(item));
|
|
1250
|
-
}
|
|
1251
|
-
const result = {};
|
|
1252
|
-
for (const key of Object.keys(value)) {
|
|
1253
|
-
result[key] = addCallbackIdsToRefs(value[key]);
|
|
1254
|
-
}
|
|
1255
|
-
return result;
|
|
1256
|
-
}
|
|
1257
|
-
const invokeCallbackRef = new import_isolated_vm.default.Reference(async (callbackId, argsJson) => {
|
|
1258
|
-
const marshalledArgs = JSON.parse(argsJson);
|
|
1259
|
-
const args = import_isolate_protocol.unmarshalValue(marshalledArgs);
|
|
1260
|
-
try {
|
|
1261
|
-
let result;
|
|
1262
|
-
if (isLocalCallbackId(callbackId)) {
|
|
1263
|
-
const callback = instance.returnedCallbacks.get(callbackId);
|
|
1264
|
-
if (!callback) {
|
|
1265
|
-
throw new Error(`Local callback ${callbackId} not found`);
|
|
1266
|
-
}
|
|
1267
|
-
result = await callback(...args);
|
|
1268
|
-
} else {
|
|
1269
|
-
const conn = instance.callbackContext?.connection || connection;
|
|
1270
|
-
result = await invokeClientCallback(conn, callbackId, args);
|
|
1271
|
-
}
|
|
1272
|
-
const ctx = createMarshalContext();
|
|
1273
|
-
const marshalledResult = await import_isolate_protocol.marshalValue({ ok: true, value: result }, ctx);
|
|
1274
|
-
const processedResult = addCallbackIdsToRefs(marshalledResult);
|
|
1275
|
-
return JSON.stringify(processedResult);
|
|
1276
|
-
} catch (error) {
|
|
1277
|
-
const err = error;
|
|
1278
|
-
return JSON.stringify({
|
|
1279
|
-
ok: false,
|
|
1280
|
-
error: { message: err.message, name: err.name }
|
|
1281
|
-
});
|
|
1282
|
-
}
|
|
1283
|
-
});
|
|
1284
|
-
global.setSync("__customFn_invoke", invokeCallbackRef);
|
|
1285
|
-
context.evalSync(ISOLATE_MARSHAL_CODE);
|
|
1286
|
-
const callbackIdMap = {};
|
|
1287
|
-
for (const [name, registration] of Object.entries(customCallbacks)) {
|
|
1288
|
-
callbackIdMap[name] = registration.callbackId;
|
|
1289
|
-
}
|
|
1290
|
-
global.setSync("__customFnCallbackIds", new import_isolated_vm.default.ExternalCopy(callbackIdMap).copyInto());
|
|
1291
|
-
for (const [name, registration] of Object.entries(customCallbacks)) {
|
|
1292
|
-
if (name.includes(":")) {
|
|
1293
|
-
continue;
|
|
1294
|
-
}
|
|
1295
|
-
if (registration.type === "sync") {
|
|
1296
|
-
context.evalSync(`
|
|
1297
|
-
globalThis.${name} = function(...args) {
|
|
1298
|
-
const callbackId = globalThis.__customFnCallbackIds["${name}"];
|
|
1299
|
-
const argsJson = JSON.stringify(__marshalForHost(args));
|
|
1300
|
-
const resultJson = __customFn_invoke.applySyncPromise(
|
|
1301
|
-
undefined,
|
|
1302
|
-
[callbackId, argsJson]
|
|
1303
|
-
);
|
|
1304
|
-
const result = JSON.parse(resultJson);
|
|
1305
|
-
if (result.ok) {
|
|
1306
|
-
return __unmarshalFromHost(result.value);
|
|
1307
|
-
} else {
|
|
1308
|
-
const error = new Error(result.error.message);
|
|
1309
|
-
error.name = result.error.name;
|
|
1310
|
-
throw error;
|
|
1311
|
-
}
|
|
1312
|
-
};
|
|
1313
|
-
`);
|
|
1314
|
-
} else if (registration.type === "asyncIterator") {
|
|
1315
|
-
const startReg = customCallbacks[`${name}:start`];
|
|
1316
|
-
const nextReg = customCallbacks[`${name}:next`];
|
|
1317
|
-
const returnReg = customCallbacks[`${name}:return`];
|
|
1318
|
-
const throwReg = customCallbacks[`${name}:throw`];
|
|
1319
|
-
if (!startReg || !nextReg || !returnReg || !throwReg) {
|
|
1320
|
-
throw new Error(`Missing companion callbacks for asyncIterator function "${name}"`);
|
|
1321
|
-
}
|
|
1322
|
-
context.evalSync(`
|
|
1323
|
-
globalThis.${name} = function(...args) {
|
|
1324
|
-
// Start the iterator and get the iteratorId
|
|
1325
|
-
const startCallbackId = globalThis.__customFnCallbackIds["${name}:start"];
|
|
1326
|
-
const argsJson = JSON.stringify(__marshalForHost(args));
|
|
1327
|
-
const startResultJson = __customFn_invoke.applySyncPromise(
|
|
1328
|
-
undefined,
|
|
1329
|
-
[startCallbackId, argsJson]
|
|
1330
|
-
);
|
|
1331
|
-
const startResult = JSON.parse(startResultJson);
|
|
1332
|
-
if (!startResult.ok) {
|
|
1333
|
-
const error = new Error(startResult.error.message);
|
|
1334
|
-
error.name = startResult.error.name;
|
|
1335
|
-
throw error;
|
|
1336
|
-
}
|
|
1337
|
-
const iteratorId = __unmarshalFromHost(startResult.value).iteratorId;
|
|
1338
|
-
|
|
1339
|
-
return {
|
|
1340
|
-
[Symbol.asyncIterator]() { return this; },
|
|
1341
|
-
async next() {
|
|
1342
|
-
const nextCallbackId = globalThis.__customFnCallbackIds["${name}:next"];
|
|
1343
|
-
const argsJson = JSON.stringify(__marshalForHost([iteratorId]));
|
|
1344
|
-
const resultJson = __customFn_invoke.applySyncPromise(
|
|
1345
|
-
undefined,
|
|
1346
|
-
[nextCallbackId, argsJson]
|
|
1347
|
-
);
|
|
1348
|
-
const result = JSON.parse(resultJson);
|
|
1349
|
-
if (!result.ok) {
|
|
1350
|
-
const error = new Error(result.error.message);
|
|
1351
|
-
error.name = result.error.name;
|
|
1352
|
-
throw error;
|
|
1353
|
-
}
|
|
1354
|
-
const val = __unmarshalFromHost(result.value);
|
|
1355
|
-
return { done: val.done, value: val.value };
|
|
1356
|
-
},
|
|
1357
|
-
async return(v) {
|
|
1358
|
-
const returnCallbackId = globalThis.__customFnCallbackIds["${name}:return"];
|
|
1359
|
-
const argsJson = JSON.stringify(__marshalForHost([iteratorId, v]));
|
|
1360
|
-
const resultJson = __customFn_invoke.applySyncPromise(
|
|
1361
|
-
undefined,
|
|
1362
|
-
[returnCallbackId, argsJson]
|
|
1363
|
-
);
|
|
1364
|
-
const result = JSON.parse(resultJson);
|
|
1365
|
-
return { done: true, value: result.ok ? __unmarshalFromHost(result.value) : undefined };
|
|
1366
|
-
},
|
|
1367
|
-
async throw(e) {
|
|
1368
|
-
const throwCallbackId = globalThis.__customFnCallbackIds["${name}:throw"];
|
|
1369
|
-
const argsJson = JSON.stringify(__marshalForHost([iteratorId, { message: e?.message, name: e?.name }]));
|
|
1370
|
-
const resultJson = __customFn_invoke.applySyncPromise(
|
|
1371
|
-
undefined,
|
|
1372
|
-
[throwCallbackId, argsJson]
|
|
1373
|
-
);
|
|
1374
|
-
const result = JSON.parse(resultJson);
|
|
1375
|
-
if (!result.ok) {
|
|
1376
|
-
const error = new Error(result.error.message);
|
|
1377
|
-
error.name = result.error.name;
|
|
1378
|
-
throw error;
|
|
1379
|
-
}
|
|
1380
|
-
const val = __unmarshalFromHost(result.value);
|
|
1381
|
-
return { done: val.done, value: val.value };
|
|
1382
|
-
}
|
|
1383
|
-
};
|
|
1384
|
-
};
|
|
1385
|
-
`);
|
|
1386
|
-
} else if (registration.type === "async") {
|
|
1387
|
-
context.evalSync(`
|
|
1388
|
-
globalThis.${name} = async function(...args) {
|
|
1389
|
-
const callbackId = globalThis.__customFnCallbackIds["${name}"];
|
|
1390
|
-
const argsJson = JSON.stringify(__marshalForHost(args));
|
|
1391
|
-
const resultJson = __customFn_invoke.applySyncPromise(
|
|
1392
|
-
undefined,
|
|
1393
|
-
[callbackId, argsJson]
|
|
1394
|
-
);
|
|
1395
|
-
const result = JSON.parse(resultJson);
|
|
1396
|
-
if (result.ok) {
|
|
1397
|
-
return __unmarshalFromHost(result.value);
|
|
1398
|
-
} else {
|
|
1399
|
-
const error = new Error(result.error.message);
|
|
1400
|
-
error.name = result.error.name;
|
|
1401
|
-
throw error;
|
|
1402
|
-
}
|
|
1403
|
-
};
|
|
1404
|
-
`);
|
|
1405
|
-
}
|
|
1406
|
-
}
|
|
1407
|
-
}
|
|
1408
|
-
function createModuleResolver(instance, connection) {
|
|
1409
|
-
return async (specifier, referrer) => {
|
|
1410
|
-
const cached = instance.moduleCache?.get(specifier);
|
|
1411
|
-
if (cached)
|
|
1412
|
-
return cached;
|
|
1413
|
-
if (!instance.moduleLoaderCallbackId) {
|
|
1414
|
-
throw new Error(`Module not found: ${specifier}`);
|
|
1415
|
-
}
|
|
1416
|
-
const importerPath = instance.moduleToFilename?.get(referrer) ?? "<unknown>";
|
|
1417
|
-
const importerResolveDir = import_node_path.default.posix.dirname(importerPath);
|
|
1418
|
-
const result = await invokeClientCallback(connection, instance.moduleLoaderCallbackId, [specifier, { path: importerPath, resolveDir: importerResolveDir }]);
|
|
1419
|
-
const { code, resolveDir } = result;
|
|
1420
|
-
const hash = import_isolate_transform.contentHash(code);
|
|
1421
|
-
const cacheKey = `${specifier}:${hash}`;
|
|
1422
|
-
const hashCached = instance.moduleCache?.get(cacheKey);
|
|
1423
|
-
if (hashCached)
|
|
1424
|
-
return hashCached;
|
|
1425
|
-
const transformed = await import_isolate_transform.transformModuleCode(code, specifier);
|
|
1426
|
-
if (transformed.sourceMap) {
|
|
1427
|
-
if (!instance.sourceMaps) {
|
|
1428
|
-
instance.sourceMaps = new Map;
|
|
1429
|
-
}
|
|
1430
|
-
instance.sourceMaps.set(specifier, transformed.sourceMap);
|
|
1431
|
-
}
|
|
1432
|
-
const mod = await instance.runtime.isolate.compileModule(transformed.code, {
|
|
1433
|
-
filename: specifier
|
|
1434
|
-
});
|
|
1435
|
-
const resolvedPath = import_node_path.default.posix.join(resolveDir, import_node_path.default.posix.basename(specifier));
|
|
1436
|
-
instance.moduleToFilename?.set(mod, resolvedPath);
|
|
1437
|
-
const resolver = createModuleResolver(instance, connection);
|
|
1438
|
-
await mod.instantiate(instance.runtime.context, resolver);
|
|
1439
|
-
instance.moduleCache?.set(specifier, mod);
|
|
1440
|
-
instance.moduleCache?.set(cacheKey, mod);
|
|
1441
|
-
return mod;
|
|
1442
|
-
};
|
|
1443
|
-
}
|
|
1444
|
-
async function serializeRequest(request) {
|
|
1445
|
-
const headers = [];
|
|
1446
|
-
request.headers.forEach((value, key) => {
|
|
1447
|
-
headers.push([key, value]);
|
|
1448
|
-
});
|
|
1449
|
-
let body = null;
|
|
1450
|
-
if (request.body) {
|
|
1451
|
-
body = new Uint8Array(await request.arrayBuffer());
|
|
1452
|
-
}
|
|
1453
|
-
return {
|
|
1454
|
-
method: request.method,
|
|
1455
|
-
url: request.url,
|
|
1456
|
-
headers,
|
|
1457
|
-
body
|
|
1458
|
-
};
|
|
1459
|
-
}
|
|
1460
1210
|
function deserializeResponse(data) {
|
|
1461
1211
|
return new Response(data.body, {
|
|
1462
1212
|
status: data.status,
|
|
@@ -1723,28 +1473,11 @@ async function handleRunTests(message, connection, state) {
|
|
|
1723
1473
|
sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
|
|
1724
1474
|
return;
|
|
1725
1475
|
}
|
|
1726
|
-
if (!instance.testEnvironmentEnabled) {
|
|
1727
|
-
sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, "Test environment not enabled. Set testEnvironment: true in createRuntime options.");
|
|
1728
|
-
return;
|
|
1729
|
-
}
|
|
1730
1476
|
instance.lastActivity = Date.now();
|
|
1731
1477
|
try {
|
|
1732
1478
|
const timeout = message.timeout ?? 30000;
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
timeoutId = setTimeout(() => reject(new Error("Test timeout")), timeout);
|
|
1736
|
-
});
|
|
1737
|
-
try {
|
|
1738
|
-
const results = await Promise.race([
|
|
1739
|
-
import_isolate_test_environment.runTests(instance.runtime.context),
|
|
1740
|
-
timeoutPromise
|
|
1741
|
-
]);
|
|
1742
|
-
sendOk(connection.socket, message.requestId, results);
|
|
1743
|
-
} finally {
|
|
1744
|
-
if (timeoutId) {
|
|
1745
|
-
clearTimeout(timeoutId);
|
|
1746
|
-
}
|
|
1747
|
-
}
|
|
1479
|
+
const results = await instance.runtime.testEnvironment.runTests(timeout);
|
|
1480
|
+
sendOk(connection.socket, message.requestId, results);
|
|
1748
1481
|
} catch (err) {
|
|
1749
1482
|
const error = err;
|
|
1750
1483
|
sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
|
|
@@ -1756,13 +1489,9 @@ async function handleResetTestEnv(message, connection, state) {
|
|
|
1756
1489
|
sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
|
|
1757
1490
|
return;
|
|
1758
1491
|
}
|
|
1759
|
-
if (!instance.testEnvironmentEnabled) {
|
|
1760
|
-
sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, "Test environment not enabled. Set testEnvironment: true in createRuntime options.");
|
|
1761
|
-
return;
|
|
1762
|
-
}
|
|
1763
1492
|
instance.lastActivity = Date.now();
|
|
1764
1493
|
try {
|
|
1765
|
-
|
|
1494
|
+
instance.runtime.testEnvironment.reset();
|
|
1766
1495
|
sendOk(connection.socket, message.requestId);
|
|
1767
1496
|
} catch (err) {
|
|
1768
1497
|
const error = err;
|
|
@@ -1775,13 +1504,9 @@ async function handleHasTests(message, connection, state) {
|
|
|
1775
1504
|
sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
|
|
1776
1505
|
return;
|
|
1777
1506
|
}
|
|
1778
|
-
if (!instance.testEnvironmentEnabled) {
|
|
1779
|
-
sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, "Test environment not enabled. Set testEnvironment: true in createRuntime options.");
|
|
1780
|
-
return;
|
|
1781
|
-
}
|
|
1782
1507
|
instance.lastActivity = Date.now();
|
|
1783
1508
|
try {
|
|
1784
|
-
const result =
|
|
1509
|
+
const result = instance.runtime.testEnvironment.hasTests();
|
|
1785
1510
|
sendOk(connection.socket, message.requestId, result);
|
|
1786
1511
|
} catch (err) {
|
|
1787
1512
|
const error = err;
|
|
@@ -1794,42 +1519,24 @@ async function handleGetTestCount(message, connection, state) {
|
|
|
1794
1519
|
sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
|
|
1795
1520
|
return;
|
|
1796
1521
|
}
|
|
1797
|
-
if (!instance.testEnvironmentEnabled) {
|
|
1798
|
-
sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, "Test environment not enabled. Set testEnvironment: true in createRuntime options.");
|
|
1799
|
-
return;
|
|
1800
|
-
}
|
|
1801
1522
|
instance.lastActivity = Date.now();
|
|
1802
1523
|
try {
|
|
1803
|
-
const result =
|
|
1524
|
+
const result = instance.runtime.testEnvironment.getTestCount();
|
|
1804
1525
|
sendOk(connection.socket, message.requestId, result);
|
|
1805
1526
|
} catch (err) {
|
|
1806
1527
|
const error = err;
|
|
1807
1528
|
sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
|
|
1808
1529
|
}
|
|
1809
1530
|
}
|
|
1810
|
-
async function handleRunPlaywrightTests(message, connection, _state) {
|
|
1811
|
-
sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, "playwright.runTests() has been removed. Use testEnvironment.runTests() instead.");
|
|
1812
|
-
}
|
|
1813
|
-
async function handleResetPlaywrightTests(message, connection, _state) {
|
|
1814
|
-
sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, "playwright.reset() has been removed. Use testEnvironment.reset() instead.");
|
|
1815
|
-
}
|
|
1816
1531
|
async function handleGetCollectedData(message, connection, state) {
|
|
1817
1532
|
const instance = state.isolates.get(message.isolateId);
|
|
1818
1533
|
if (!instance) {
|
|
1819
1534
|
sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
|
|
1820
1535
|
return;
|
|
1821
1536
|
}
|
|
1822
|
-
if (!instance.playwrightHandle) {
|
|
1823
|
-
sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, "Playwright not configured. Provide playwright.page in createRuntime options.");
|
|
1824
|
-
return;
|
|
1825
|
-
}
|
|
1826
1537
|
instance.lastActivity = Date.now();
|
|
1827
1538
|
try {
|
|
1828
|
-
const data =
|
|
1829
|
-
browserConsoleLogs: instance.playwrightHandle.getBrowserConsoleLogs(),
|
|
1830
|
-
networkRequests: instance.playwrightHandle.getNetworkRequests(),
|
|
1831
|
-
networkResponses: instance.playwrightHandle.getNetworkResponses()
|
|
1832
|
-
};
|
|
1539
|
+
const data = instance.runtime.playwright.getCollectedData();
|
|
1833
1540
|
sendOk(connection.socket, message.requestId, data);
|
|
1834
1541
|
} catch (err) {
|
|
1835
1542
|
const error = err;
|
|
@@ -1842,13 +1549,9 @@ async function handleClearCollectedData(message, connection, state) {
|
|
|
1842
1549
|
sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
|
|
1843
1550
|
return;
|
|
1844
1551
|
}
|
|
1845
|
-
if (!instance.playwrightHandle) {
|
|
1846
|
-
sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, "Playwright not configured. Provide playwright.page in createRuntime options.");
|
|
1847
|
-
return;
|
|
1848
|
-
}
|
|
1849
1552
|
instance.lastActivity = Date.now();
|
|
1850
1553
|
try {
|
|
1851
|
-
instance.
|
|
1554
|
+
instance.runtime.playwright.clearCollectedData();
|
|
1852
1555
|
sendOk(connection.socket, message.requestId);
|
|
1853
1556
|
} catch (err) {
|
|
1854
1557
|
const error = err;
|
|
@@ -1856,4 +1559,4 @@ async function handleClearCollectedData(message, connection, state) {
|
|
|
1856
1559
|
}
|
|
1857
1560
|
}
|
|
1858
1561
|
|
|
1859
|
-
//# debugId=
|
|
1562
|
+
//# debugId=53A5FD566727ACE764756E2164756E21
|