@ricsam/isolate-daemon 0.1.0 → 0.1.4

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.
@@ -1,8 +1,21 @@
1
1
  // @bun @bun-cjs
2
- (function(exports, require, module, __filename, __dirname) {var __defProp = Object.defineProperty;
2
+ (function(exports, require, module, __filename, __dirname) {var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
3
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
6
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __toESM = (mod, isNodeMode, target) => {
9
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
10
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
11
+ for (let key of __getOwnPropNames(mod))
12
+ if (!__hasOwnProp.call(to, key))
13
+ __defProp(to, key, {
14
+ get: () => mod[key],
15
+ enumerable: true
16
+ });
17
+ return to;
18
+ };
6
19
  var __moduleCache = /* @__PURE__ */ new WeakMap;
7
20
  var __toCommonJS = (from) => {
8
21
  var entry = __moduleCache.get(from), desc;
@@ -34,11 +47,11 @@ __export(exports_connection, {
34
47
  });
35
48
  module.exports = __toCommonJS(exports_connection);
36
49
  var import_node_crypto = require("crypto");
50
+ var import_isolated_vm = __toESM(require("isolated-vm"));
37
51
  var import_isolate_protocol = require("@ricsam/isolate-protocol");
38
52
  var import_callback_fs_handler = require("./callback-fs-handler.cjs");
39
53
  var import_isolate_test_environment = require("@ricsam/isolate-test-environment");
40
54
  var import_isolate_playwright = require("@ricsam/isolate-playwright");
41
- var import_playwright = require("playwright");
42
55
  var import_isolate_runtime = require("@ricsam/isolate-runtime");
43
56
  function handleConnection(socket, state) {
44
57
  const connection = {
@@ -48,7 +61,9 @@ function handleConnection(socket, state) {
48
61
  pendingCallbacks: new Map,
49
62
  nextRequestId: 1,
50
63
  nextCallbackId: 1,
51
- nextStreamId: 1
64
+ nextStreamId: 1,
65
+ activeStreams: new Map,
66
+ streamReceivers: new Map
52
67
  };
53
68
  state.connections.set(socket, connection);
54
69
  const parser = import_isolate_protocol.createFrameParser();
@@ -72,12 +87,6 @@ function handleConnection(socket, state) {
72
87
  if (instance.playwrightHandle) {
73
88
  instance.playwrightHandle.dispose();
74
89
  }
75
- if (instance.browserContext) {
76
- instance.browserContext.close().catch(() => {});
77
- }
78
- if (instance.browser) {
79
- instance.browser.close().catch(() => {});
80
- }
81
90
  instance.runtime.dispose();
82
91
  } catch {}
83
92
  state.isolates.delete(isolateId);
@@ -129,20 +138,56 @@ async function handleMessage(message, connection, state) {
129
138
  case import_isolate_protocol.MessageType.DISPATCH_REQUEST:
130
139
  await handleDispatchRequest(message, connection, state);
131
140
  break;
132
- case import_isolate_protocol.MessageType.TICK:
133
- await handleTick(message, connection, state);
134
- break;
135
141
  case import_isolate_protocol.MessageType.CALLBACK_RESPONSE:
136
142
  handleCallbackResponse(message, connection);
137
143
  break;
138
- case import_isolate_protocol.MessageType.SETUP_TEST_ENV:
139
- await handleSetupTestEnv(message, connection, state);
144
+ case import_isolate_protocol.MessageType.WS_OPEN:
145
+ await handleWsOpen(message, connection, state);
146
+ break;
147
+ case import_isolate_protocol.MessageType.WS_MESSAGE:
148
+ await handleWsMessage(message, connection, state);
149
+ break;
150
+ case import_isolate_protocol.MessageType.WS_CLOSE:
151
+ await handleWsClose(message, connection, state);
152
+ break;
153
+ case import_isolate_protocol.MessageType.FETCH_GET_UPGRADE_REQUEST:
154
+ await handleFetchGetUpgradeRequest(message, connection, state);
155
+ break;
156
+ case import_isolate_protocol.MessageType.FETCH_HAS_SERVE_HANDLER:
157
+ await handleFetchHasServeHandler(message, connection, state);
158
+ break;
159
+ case import_isolate_protocol.MessageType.FETCH_HAS_ACTIVE_CONNECTIONS:
160
+ await handleFetchHasActiveConnections(message, connection, state);
161
+ break;
162
+ case import_isolate_protocol.MessageType.FETCH_WS_ERROR:
163
+ await handleFetchWsError(message, connection, state);
164
+ break;
165
+ case import_isolate_protocol.MessageType.TIMERS_CLEAR_ALL:
166
+ await handleTimersClearAll(message, connection, state);
167
+ break;
168
+ case import_isolate_protocol.MessageType.CONSOLE_RESET:
169
+ await handleConsoleReset(message, connection, state);
170
+ break;
171
+ case import_isolate_protocol.MessageType.CONSOLE_GET_TIMERS:
172
+ await handleConsoleGetTimers(message, connection, state);
173
+ break;
174
+ case import_isolate_protocol.MessageType.CONSOLE_GET_COUNTERS:
175
+ await handleConsoleGetCounters(message, connection, state);
176
+ break;
177
+ case import_isolate_protocol.MessageType.CONSOLE_GET_GROUP_DEPTH:
178
+ await handleConsoleGetGroupDepth(message, connection, state);
140
179
  break;
141
180
  case import_isolate_protocol.MessageType.RUN_TESTS:
142
181
  await handleRunTests(message, connection, state);
143
182
  break;
144
- case import_isolate_protocol.MessageType.SETUP_PLAYWRIGHT:
145
- await handleSetupPlaywright(message, connection, state);
183
+ case import_isolate_protocol.MessageType.RESET_TEST_ENV:
184
+ await handleResetTestEnv(message, connection, state);
185
+ break;
186
+ case import_isolate_protocol.MessageType.HAS_TESTS:
187
+ await handleHasTests(message, connection, state);
188
+ break;
189
+ case import_isolate_protocol.MessageType.GET_TEST_COUNT:
190
+ await handleGetTestCount(message, connection, state);
146
191
  break;
147
192
  case import_isolate_protocol.MessageType.RUN_PLAYWRIGHT_TESTS:
148
193
  await handleRunPlaywrightTests(message, connection, state);
@@ -153,9 +198,24 @@ async function handleMessage(message, connection, state) {
153
198
  case import_isolate_protocol.MessageType.GET_COLLECTED_DATA:
154
199
  await handleGetCollectedData(message, connection, state);
155
200
  break;
201
+ case import_isolate_protocol.MessageType.CLEAR_COLLECTED_DATA:
202
+ await handleClearCollectedData(message, connection, state);
203
+ break;
156
204
  case import_isolate_protocol.MessageType.PING:
157
205
  sendMessage(connection.socket, { type: import_isolate_protocol.MessageType.PONG });
158
206
  break;
207
+ case import_isolate_protocol.MessageType.STREAM_PUSH:
208
+ handleStreamPush(message, connection);
209
+ break;
210
+ case import_isolate_protocol.MessageType.STREAM_PULL:
211
+ handleStreamPull(message, connection);
212
+ break;
213
+ case import_isolate_protocol.MessageType.STREAM_CLOSE:
214
+ handleStreamClose(message, connection);
215
+ break;
216
+ case import_isolate_protocol.MessageType.STREAM_ERROR:
217
+ handleStreamError(message, connection);
218
+ break;
159
219
  default:
160
220
  sendError(connection.socket, message.requestId ?? 0, import_isolate_protocol.ErrorCode.UNKNOWN_MESSAGE_TYPE, `Unknown message type: ${message.type}`);
161
221
  }
@@ -170,16 +230,16 @@ async function handleCreateRuntime(message, connection, state) {
170
230
  const consoleCallbacks = message.options.callbacks?.console;
171
231
  const fetchCallback = message.options.callbacks?.fetch;
172
232
  const fsCallbacks = message.options.callbacks?.fs;
173
- const runtime = await import_isolate_runtime.createRuntime({
174
- memoryLimit: message.options.memoryLimit ?? state.options.defaultMemoryLimit,
175
- console: consoleCallbacks ? {
176
- onLog: async (level, ...args) => {
177
- const levelCallback = consoleCallbacks[level];
178
- if (levelCallback) {
179
- await invokeClientCallback(connection, levelCallback.callbackId, [level, ...args]);
180
- } else if (consoleCallbacks.log) {
181
- await invokeClientCallback(connection, consoleCallbacks.log.callbackId, [level, ...args]);
182
- }
233
+ const moduleLoaderCallback = message.options.callbacks?.moduleLoader;
234
+ const customCallbacks = message.options.callbacks?.custom;
235
+ const pendingCallbacks = [];
236
+ const runtime = await import_isolate_runtime.createInternalRuntime({
237
+ memoryLimitMB: message.options.memoryLimitMB ?? state.options.defaultMemoryLimitMB,
238
+ cwd: message.options.cwd,
239
+ console: consoleCallbacks?.onEntry ? {
240
+ onEntry: (entry) => {
241
+ const promise = invokeClientCallback(connection, consoleCallbacks.onEntry.callbackId, [entry]).catch(() => {});
242
+ pendingCallbacks.push(promise);
183
243
  }
184
244
  } : undefined,
185
245
  fetch: fetchCallback ? {
@@ -206,14 +266,25 @@ async function handleCreateRuntime(message, connection, state) {
206
266
  ownerConnection: connection.socket,
207
267
  callbacks: new Map,
208
268
  createdAt: Date.now(),
209
- lastActivity: Date.now()
269
+ lastActivity: Date.now(),
270
+ pendingCallbacks,
271
+ returnedCallbacks: new Map,
272
+ returnedPromises: new Map,
273
+ returnedIterators: new Map,
274
+ nextLocalCallbackId: 1e6
210
275
  };
211
- if (consoleCallbacks) {
212
- for (const [name, reg] of Object.entries(consoleCallbacks)) {
213
- if (reg) {
214
- instance.callbacks.set(reg.callbackId, { ...reg, name });
215
- }
216
- }
276
+ if (moduleLoaderCallback) {
277
+ instance.moduleLoaderCallbackId = moduleLoaderCallback.callbackId;
278
+ instance.moduleCache = new Map;
279
+ }
280
+ if (customCallbacks) {
281
+ await setupCustomFunctions(runtime.context, customCallbacks, connection, instance);
282
+ }
283
+ if (consoleCallbacks?.onEntry) {
284
+ instance.callbacks.set(consoleCallbacks.onEntry.callbackId, {
285
+ ...consoleCallbacks.onEntry,
286
+ name: "onEntry"
287
+ });
217
288
  }
218
289
  if (fetchCallback) {
219
290
  instance.callbacks.set(fetchCallback.callbackId, fetchCallback);
@@ -225,9 +296,86 @@ async function handleCreateRuntime(message, connection, state) {
225
296
  }
226
297
  }
227
298
  }
299
+ if (moduleLoaderCallback) {
300
+ instance.callbacks.set(moduleLoaderCallback.callbackId, moduleLoaderCallback);
301
+ }
302
+ if (customCallbacks) {
303
+ for (const [name, reg] of Object.entries(customCallbacks)) {
304
+ if (reg) {
305
+ instance.callbacks.set(reg.callbackId, { ...reg, name });
306
+ }
307
+ }
308
+ }
309
+ if (message.options.testEnvironment) {
310
+ const testEnvOption = message.options.testEnvironment;
311
+ const testEnvOptions = typeof testEnvOption === "object" ? testEnvOption : undefined;
312
+ const onEventCallback = testEnvOptions?.callbacks?.onEvent;
313
+ await import_isolate_test_environment.setupTestEnvironment(runtime.context, {
314
+ onEvent: onEventCallback ? (event) => {
315
+ const promise = invokeClientCallback(connection, onEventCallback.callbackId, [JSON.stringify(event)]).catch(() => {});
316
+ pendingCallbacks.push(promise);
317
+ } : undefined,
318
+ testTimeout: testEnvOptions?.testTimeout
319
+ });
320
+ instance.testEnvironmentEnabled = true;
321
+ if (onEventCallback) {
322
+ instance.callbacks.set(onEventCallback.callbackId, {
323
+ ...onEventCallback,
324
+ name: "testEnvironment.onEvent"
325
+ });
326
+ }
327
+ }
328
+ const playwrightCallbacks = message.options.callbacks?.playwright;
329
+ if (playwrightCallbacks) {
330
+ const handler = async (op) => {
331
+ try {
332
+ const resultJson = await invokeClientCallback(connection, playwrightCallbacks.handlerCallbackId, [JSON.stringify(op)]);
333
+ return JSON.parse(resultJson);
334
+ } catch (err) {
335
+ const error = err;
336
+ return { ok: false, error: { name: error.name, message: error.message } };
337
+ }
338
+ };
339
+ instance.playwrightHandle = await import_isolate_playwright.setupPlaywright(runtime.context, {
340
+ handler,
341
+ console: playwrightCallbacks.console,
342
+ onEvent: (event) => {
343
+ if (event.type === "browserConsoleLog" && playwrightCallbacks.onBrowserConsoleLogCallbackId) {
344
+ const promise = invokeClientCallback(connection, playwrightCallbacks.onBrowserConsoleLogCallbackId, [{ level: event.level, args: event.args, timestamp: event.timestamp }]).catch(() => {});
345
+ pendingCallbacks.push(promise);
346
+ } else if (event.type === "networkRequest" && playwrightCallbacks.onNetworkRequestCallbackId) {
347
+ const promise = invokeClientCallback(connection, playwrightCallbacks.onNetworkRequestCallbackId, [event]).catch(() => {});
348
+ pendingCallbacks.push(promise);
349
+ } else if (event.type === "networkResponse" && playwrightCallbacks.onNetworkResponseCallbackId) {
350
+ const promise = invokeClientCallback(connection, playwrightCallbacks.onNetworkResponseCallbackId, [event]).catch(() => {});
351
+ pendingCallbacks.push(promise);
352
+ }
353
+ }
354
+ });
355
+ }
228
356
  state.isolates.set(isolateId, instance);
229
357
  connection.isolates.add(isolateId);
230
358
  state.stats.totalIsolatesCreated++;
359
+ instance.runtime.fetch.onWebSocketCommand((cmd) => {
360
+ let data;
361
+ if (cmd.data instanceof ArrayBuffer) {
362
+ data = new Uint8Array(cmd.data);
363
+ } else {
364
+ data = cmd.data;
365
+ }
366
+ const wsCommandMsg = {
367
+ type: import_isolate_protocol.MessageType.WS_COMMAND,
368
+ isolateId,
369
+ command: {
370
+ type: cmd.type,
371
+ connectionId: cmd.connectionId,
372
+ data,
373
+ code: cmd.code,
374
+ reason: cmd.reason
375
+ }
376
+ };
377
+ sendMessage(connection.socket, wsCommandMsg);
378
+ });
231
379
  sendOk(connection.socket, message.requestId, { isolateId });
232
380
  } catch (err) {
233
381
  const error = err;
@@ -248,12 +396,6 @@ async function handleDisposeRuntime(message, connection, state) {
248
396
  if (instance.playwrightHandle) {
249
397
  instance.playwrightHandle.dispose();
250
398
  }
251
- if (instance.browserContext) {
252
- await instance.browserContext.close();
253
- }
254
- if (instance.browser) {
255
- await instance.browser.close();
256
- }
257
399
  instance.runtime.dispose();
258
400
  state.isolates.delete(message.isolateId);
259
401
  connection.isolates.delete(message.isolateId);
@@ -271,13 +413,26 @@ async function handleEval(message, connection, state) {
271
413
  }
272
414
  instance.lastActivity = Date.now();
273
415
  try {
274
- const result = instance.runtime.context.evalSync(message.code, {
275
- filename: message.filename
416
+ const mod = await instance.runtime.isolate.compileModule(message.code, {
417
+ filename: message.filename ?? "<eval>"
276
418
  });
277
- sendOk(connection.socket, message.requestId, { value: result });
419
+ if (instance.moduleLoaderCallbackId) {
420
+ const resolver = createModuleResolver(instance, connection);
421
+ await mod.instantiate(instance.runtime.context, resolver);
422
+ } else {
423
+ await mod.instantiate(instance.runtime.context, (specifier) => {
424
+ throw new Error(`No module loader registered. Cannot import: ${specifier}`);
425
+ });
426
+ }
427
+ const timeout = message.maxExecutionMs;
428
+ await mod.evaluate(timeout ? { timeout } : undefined);
429
+ await Promise.all(instance.pendingCallbacks);
430
+ instance.pendingCallbacks.length = 0;
431
+ sendOk(connection.socket, message.requestId, { value: undefined });
278
432
  } catch (err) {
279
433
  const error = err;
280
- sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
434
+ const isTimeoutError = error.message?.includes("Script execution timed out");
435
+ 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 });
281
436
  }
282
437
  }
283
438
  async function handleDispatchRequest(message, connection, state) {
@@ -288,24 +443,135 @@ async function handleDispatchRequest(message, connection, state) {
288
443
  }
289
444
  instance.lastActivity = Date.now();
290
445
  try {
446
+ let requestBody = null;
447
+ if (message.request.bodyStreamId !== undefined) {
448
+ requestBody = await receiveStreamedBody(connection, message.request.bodyStreamId);
449
+ } else if (message.request.body) {
450
+ requestBody = message.request.body;
451
+ }
291
452
  const request = new Request(message.request.url, {
292
453
  method: message.request.method,
293
454
  headers: message.request.headers,
294
- body: message.request.body
455
+ body: requestBody
295
456
  });
296
- const response = await instance.runtime.fetch.dispatchRequest(request, {
297
- tick: async () => {
298
- await instance.runtime.tick();
457
+ const response = await instance.runtime.fetch.dispatchRequest(request);
458
+ const contentLength = response.headers.get("content-length");
459
+ const knownSize = contentLength ? parseInt(contentLength, 10) : null;
460
+ if (knownSize !== null && knownSize > import_isolate_protocol.STREAM_THRESHOLD) {
461
+ await sendStreamedResponse(connection, message.requestId, response);
462
+ } else {
463
+ const clonedResponse = response.clone();
464
+ try {
465
+ const serialized = await serializeResponse(response);
466
+ if (serialized.body && serialized.body.length > import_isolate_protocol.STREAM_THRESHOLD) {
467
+ await sendStreamedResponse(connection, message.requestId, clonedResponse);
468
+ } else {
469
+ sendOk(connection.socket, message.requestId, { response: serialized });
470
+ }
471
+ } catch {
472
+ await sendStreamedResponse(connection, message.requestId, clonedResponse);
299
473
  }
474
+ }
475
+ } catch (err) {
476
+ const error = err;
477
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
478
+ }
479
+ }
480
+ function receiveStreamedBody(connection, streamId) {
481
+ return new Promise((resolve, reject) => {
482
+ const receiver = {
483
+ streamId,
484
+ requestId: 0,
485
+ chunks: [],
486
+ totalBytes: 0,
487
+ resolve,
488
+ reject
489
+ };
490
+ connection.streamReceivers.set(streamId, receiver);
491
+ sendMessage(connection.socket, {
492
+ type: import_isolate_protocol.MessageType.STREAM_PULL,
493
+ streamId,
494
+ maxBytes: import_isolate_protocol.STREAM_DEFAULT_CREDIT
300
495
  });
301
- const serialized = await serializeResponse(response);
302
- sendOk(connection.socket, message.requestId, { response: serialized });
496
+ });
497
+ }
498
+ async function handleWsOpen(message, connection, state) {
499
+ const instance = state.isolates.get(message.isolateId);
500
+ if (!instance) {
501
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
502
+ return;
503
+ }
504
+ instance.lastActivity = Date.now();
505
+ try {
506
+ instance.runtime.fetch.dispatchWebSocketOpen(message.connectionId);
507
+ sendOk(connection.socket, message.requestId);
508
+ } catch (err) {
509
+ const error = err;
510
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
511
+ }
512
+ }
513
+ async function handleWsMessage(message, connection, state) {
514
+ const instance = state.isolates.get(message.isolateId);
515
+ if (!instance) {
516
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
517
+ return;
518
+ }
519
+ instance.lastActivity = Date.now();
520
+ try {
521
+ const data = message.data instanceof Uint8Array ? message.data.buffer.slice(message.data.byteOffset, message.data.byteOffset + message.data.byteLength) : message.data;
522
+ instance.runtime.fetch.dispatchWebSocketMessage(message.connectionId, data);
523
+ sendOk(connection.socket, message.requestId);
524
+ } catch (err) {
525
+ const error = err;
526
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
527
+ }
528
+ }
529
+ async function handleWsClose(message, connection, state) {
530
+ const instance = state.isolates.get(message.isolateId);
531
+ if (!instance) {
532
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
533
+ return;
534
+ }
535
+ instance.lastActivity = Date.now();
536
+ try {
537
+ instance.runtime.fetch.dispatchWebSocketClose(message.connectionId, message.code, message.reason);
538
+ sendOk(connection.socket, message.requestId);
539
+ } catch (err) {
540
+ const error = err;
541
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
542
+ }
543
+ }
544
+ async function handleFetchGetUpgradeRequest(message, connection, state) {
545
+ const instance = state.isolates.get(message.isolateId);
546
+ if (!instance) {
547
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
548
+ return;
549
+ }
550
+ instance.lastActivity = Date.now();
551
+ try {
552
+ const upgradeRequest = instance.runtime.fetch.getUpgradeRequest();
553
+ sendOk(connection.socket, message.requestId, upgradeRequest);
554
+ } catch (err) {
555
+ const error = err;
556
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
557
+ }
558
+ }
559
+ async function handleFetchHasServeHandler(message, connection, state) {
560
+ const instance = state.isolates.get(message.isolateId);
561
+ if (!instance) {
562
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
563
+ return;
564
+ }
565
+ instance.lastActivity = Date.now();
566
+ try {
567
+ const hasHandler = instance.runtime.fetch.hasServeHandler();
568
+ sendOk(connection.socket, message.requestId, hasHandler);
303
569
  } catch (err) {
304
570
  const error = err;
305
571
  sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
306
572
  }
307
573
  }
308
- async function handleTick(message, connection, state) {
574
+ async function handleFetchHasActiveConnections(message, connection, state) {
309
575
  const instance = state.isolates.get(message.isolateId);
310
576
  if (!instance) {
311
577
  sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
@@ -313,13 +579,103 @@ async function handleTick(message, connection, state) {
313
579
  }
314
580
  instance.lastActivity = Date.now();
315
581
  try {
316
- instance.runtime.tick(message.ms);
582
+ const hasConnections = instance.runtime.fetch.hasActiveConnections();
583
+ sendOk(connection.socket, message.requestId, hasConnections);
584
+ } catch (err) {
585
+ const error = err;
586
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
587
+ }
588
+ }
589
+ async function handleFetchWsError(message, connection, state) {
590
+ const instance = state.isolates.get(message.isolateId);
591
+ if (!instance) {
592
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
593
+ return;
594
+ }
595
+ instance.lastActivity = Date.now();
596
+ try {
597
+ instance.runtime.fetch.dispatchWebSocketError(message.connectionId, new Error(message.error));
317
598
  sendOk(connection.socket, message.requestId);
318
599
  } catch (err) {
319
600
  const error = err;
320
601
  sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
321
602
  }
322
603
  }
604
+ async function handleTimersClearAll(message, connection, state) {
605
+ const instance = state.isolates.get(message.isolateId);
606
+ if (!instance) {
607
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
608
+ return;
609
+ }
610
+ instance.lastActivity = Date.now();
611
+ try {
612
+ instance.runtime.timers.clearAll();
613
+ sendOk(connection.socket, message.requestId);
614
+ } catch (err) {
615
+ const error = err;
616
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
617
+ }
618
+ }
619
+ async function handleConsoleReset(message, connection, state) {
620
+ const instance = state.isolates.get(message.isolateId);
621
+ if (!instance) {
622
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
623
+ return;
624
+ }
625
+ instance.lastActivity = Date.now();
626
+ try {
627
+ instance.runtime.console.reset();
628
+ sendOk(connection.socket, message.requestId);
629
+ } catch (err) {
630
+ const error = err;
631
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
632
+ }
633
+ }
634
+ async function handleConsoleGetTimers(message, connection, state) {
635
+ const instance = state.isolates.get(message.isolateId);
636
+ if (!instance) {
637
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
638
+ return;
639
+ }
640
+ instance.lastActivity = Date.now();
641
+ try {
642
+ const timers = instance.runtime.console.getTimers();
643
+ sendOk(connection.socket, message.requestId, Object.fromEntries(timers));
644
+ } catch (err) {
645
+ const error = err;
646
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
647
+ }
648
+ }
649
+ async function handleConsoleGetCounters(message, connection, state) {
650
+ const instance = state.isolates.get(message.isolateId);
651
+ if (!instance) {
652
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
653
+ return;
654
+ }
655
+ instance.lastActivity = Date.now();
656
+ try {
657
+ const counters = instance.runtime.console.getCounters();
658
+ sendOk(connection.socket, message.requestId, Object.fromEntries(counters));
659
+ } catch (err) {
660
+ const error = err;
661
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
662
+ }
663
+ }
664
+ async function handleConsoleGetGroupDepth(message, connection, state) {
665
+ const instance = state.isolates.get(message.isolateId);
666
+ if (!instance) {
667
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
668
+ return;
669
+ }
670
+ instance.lastActivity = Date.now();
671
+ try {
672
+ const depth = instance.runtime.console.getGroupDepth();
673
+ sendOk(connection.socket, message.requestId, depth);
674
+ } catch (err) {
675
+ const error = err;
676
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
677
+ }
678
+ }
323
679
  function handleCallbackResponse(message, connection) {
324
680
  const pending = connection.pendingCallbacks.get(message.requestId);
325
681
  if (!pending) {
@@ -363,6 +719,477 @@ async function invokeClientCallback(connection, callbackId, args, timeout = 1e4)
363
719
  sendMessage(connection.socket, invoke);
364
720
  });
365
721
  }
722
+ var ISOLATE_MARSHAL_CODE = `
723
+ (function() {
724
+ // Marshal a value (JavaScript \u2192 Ref)
725
+ function marshalForHost(value, depth = 0) {
726
+ if (depth > 100) throw new Error('Maximum marshalling depth exceeded');
727
+
728
+ if (value === null) return null;
729
+ if (value === undefined) return { __type: 'UndefinedRef' };
730
+
731
+ const type = typeof value;
732
+ if (type === 'string' || type === 'number' || type === 'boolean') return value;
733
+ if (type === 'bigint') return { __type: 'BigIntRef', value: value.toString() };
734
+ if (type === 'function') throw new Error('Cannot marshal functions from isolate');
735
+ if (type === 'symbol') throw new Error('Cannot marshal Symbol values');
736
+
737
+ if (type === 'object') {
738
+ if (value instanceof Date) {
739
+ return { __type: 'DateRef', timestamp: value.getTime() };
740
+ }
741
+ if (value instanceof RegExp) {
742
+ return { __type: 'RegExpRef', source: value.source, flags: value.flags };
743
+ }
744
+ if (value instanceof URL) {
745
+ return { __type: 'URLRef', href: value.href };
746
+ }
747
+ if (typeof Headers !== 'undefined' && value instanceof Headers) {
748
+ const pairs = [];
749
+ value.forEach((v, k) => pairs.push([k, v]));
750
+ return { __type: 'HeadersRef', pairs };
751
+ }
752
+ if (value instanceof Uint8Array) {
753
+ return { __type: 'Uint8ArrayRef', data: Array.from(value) };
754
+ }
755
+ if (value instanceof ArrayBuffer) {
756
+ return { __type: 'Uint8ArrayRef', data: Array.from(new Uint8Array(value)) };
757
+ }
758
+ if (typeof Request !== 'undefined' && value instanceof Request) {
759
+ throw new Error('Cannot marshal Request from isolate. Use fetch callback instead.');
760
+ }
761
+ if (typeof Response !== 'undefined' && value instanceof Response) {
762
+ throw new Error('Cannot marshal Response from isolate. Return plain objects instead.');
763
+ }
764
+ if (typeof File !== 'undefined' && value instanceof File) {
765
+ throw new Error('Cannot marshal File from isolate.');
766
+ }
767
+ if (typeof Blob !== 'undefined' && value instanceof Blob) {
768
+ throw new Error('Cannot marshal Blob from isolate.');
769
+ }
770
+ if (typeof FormData !== 'undefined' && value instanceof FormData) {
771
+ throw new Error('Cannot marshal FormData from isolate.');
772
+ }
773
+ if (Array.isArray(value)) {
774
+ return value.map(v => marshalForHost(v, depth + 1));
775
+ }
776
+ // Plain object
777
+ const result = {};
778
+ for (const key of Object.keys(value)) {
779
+ result[key] = marshalForHost(value[key], depth + 1);
780
+ }
781
+ return result;
782
+ }
783
+ return value;
784
+ }
785
+
786
+ // Unmarshal a value (Ref \u2192 JavaScript)
787
+ function unmarshalFromHost(value, depth = 0) {
788
+ if (depth > 100) throw new Error('Maximum unmarshalling depth exceeded');
789
+
790
+ if (value === null) return null;
791
+ if (typeof value !== 'object') return value;
792
+
793
+ if (value.__type) {
794
+ switch (value.__type) {
795
+ case 'UndefinedRef': return undefined;
796
+ case 'DateRef': return new Date(value.timestamp);
797
+ case 'RegExpRef': return new RegExp(value.source, value.flags);
798
+ case 'BigIntRef': return BigInt(value.value);
799
+ case 'URLRef': return new URL(value.href);
800
+ case 'HeadersRef': return new Headers(value.pairs);
801
+ case 'Uint8ArrayRef': return new Uint8Array(value.data);
802
+ case 'RequestRef': {
803
+ const init = {
804
+ method: value.method,
805
+ headers: value.headers,
806
+ body: value.body ? new Uint8Array(value.body) : null,
807
+ };
808
+ if (value.mode) init.mode = value.mode;
809
+ if (value.credentials) init.credentials = value.credentials;
810
+ if (value.cache) init.cache = value.cache;
811
+ if (value.redirect) init.redirect = value.redirect;
812
+ if (value.referrer) init.referrer = value.referrer;
813
+ if (value.referrerPolicy) init.referrerPolicy = value.referrerPolicy;
814
+ if (value.integrity) init.integrity = value.integrity;
815
+ return new Request(value.url, init);
816
+ }
817
+ case 'ResponseRef': {
818
+ return new Response(value.body ? new Uint8Array(value.body) : null, {
819
+ status: value.status,
820
+ statusText: value.statusText,
821
+ headers: value.headers,
822
+ });
823
+ }
824
+ case 'FileRef': {
825
+ if (!value.name) {
826
+ return new Blob([new Uint8Array(value.data)], { type: value.type });
827
+ }
828
+ return new File([new Uint8Array(value.data)], value.name, {
829
+ type: value.type,
830
+ lastModified: value.lastModified,
831
+ });
832
+ }
833
+ case 'FormDataRef': {
834
+ const fd = new FormData();
835
+ for (const [key, entry] of value.entries) {
836
+ if (typeof entry === 'string') {
837
+ fd.append(key, entry);
838
+ } else {
839
+ const file = unmarshalFromHost(entry, depth + 1);
840
+ fd.append(key, file);
841
+ }
842
+ }
843
+ return fd;
844
+ }
845
+ case 'CallbackRef': {
846
+ // Create a proxy function that invokes the callback
847
+ const callbackId = value.callbackId;
848
+ return function(...args) {
849
+ const argsJson = JSON.stringify(marshalForHost(args));
850
+ const resultJson = __customFn_invoke.applySyncPromise(undefined, [callbackId, argsJson]);
851
+ const result = JSON.parse(resultJson);
852
+ if (result.ok) {
853
+ return unmarshalFromHost(result.value);
854
+ } else {
855
+ const error = new Error(result.error.message);
856
+ error.name = result.error.name;
857
+ throw error;
858
+ }
859
+ };
860
+ }
861
+ case 'PromiseRef': {
862
+ // Create a proxy Promise that resolves via callback
863
+ const promiseId = value.promiseId;
864
+ return new Promise((resolve, reject) => {
865
+ try {
866
+ const argsJson = JSON.stringify([promiseId]);
867
+ const resultJson = __customFn_invoke.applySyncPromise(undefined, [value.__resolveCallbackId, argsJson]);
868
+ const result = JSON.parse(resultJson);
869
+ if (result.ok) {
870
+ resolve(unmarshalFromHost(result.value));
871
+ } else {
872
+ reject(new Error(result.error.message));
873
+ }
874
+ } catch (e) {
875
+ reject(e);
876
+ }
877
+ });
878
+ }
879
+ case 'AsyncIteratorRef': {
880
+ const iteratorId = value.iteratorId;
881
+ const nextCallbackId = value.__nextCallbackId;
882
+ const returnCallbackId = value.__returnCallbackId;
883
+ return {
884
+ [Symbol.asyncIterator]() { return this; },
885
+ async next() {
886
+ const argsJson = JSON.stringify([iteratorId]);
887
+ const resultJson = __customFn_invoke.applySyncPromise(undefined, [nextCallbackId, argsJson]);
888
+ const result = JSON.parse(resultJson);
889
+ if (!result.ok) {
890
+ const error = new Error(result.error.message);
891
+ error.name = result.error.name;
892
+ throw error;
893
+ }
894
+ return {
895
+ done: result.value.done,
896
+ value: unmarshalFromHost(result.value.value)
897
+ };
898
+ },
899
+ async return(v) {
900
+ const argsJson = JSON.stringify([iteratorId, marshalForHost(v)]);
901
+ const resultJson = __customFn_invoke.applySyncPromise(undefined, [returnCallbackId, argsJson]);
902
+ const result = JSON.parse(resultJson);
903
+ return { done: true, value: result.ok ? unmarshalFromHost(result.value) : undefined };
904
+ }
905
+ };
906
+ }
907
+ default:
908
+ // Unknown ref type, return as-is
909
+ break;
910
+ }
911
+ }
912
+
913
+ if (Array.isArray(value)) {
914
+ return value.map(v => unmarshalFromHost(v, depth + 1));
915
+ }
916
+
917
+ // Plain object - recursively unmarshal
918
+ const result = {};
919
+ for (const key of Object.keys(value)) {
920
+ result[key] = unmarshalFromHost(value[key], depth + 1);
921
+ }
922
+ return result;
923
+ }
924
+
925
+ globalThis.__marshalForHost = marshalForHost;
926
+ globalThis.__unmarshalFromHost = unmarshalFromHost;
927
+ })();
928
+ `;
929
+ var LOCAL_CALLBACK_THRESHOLD = 1e6;
930
+ function isPromiseRef(value) {
931
+ return typeof value === "object" && value !== null && value.__type === "PromiseRef";
932
+ }
933
+ function isAsyncIteratorRef(value) {
934
+ return typeof value === "object" && value !== null && value.__type === "AsyncIteratorRef";
935
+ }
936
+ function isLocalCallbackId(callbackId) {
937
+ return callbackId >= LOCAL_CALLBACK_THRESHOLD;
938
+ }
939
+ async function setupCustomFunctions(context, customCallbacks, connection, instance) {
940
+ const global = context.global;
941
+ function createMarshalContext() {
942
+ return {
943
+ registerCallback: (fn) => {
944
+ const callbackId = instance.nextLocalCallbackId++;
945
+ instance.returnedCallbacks.set(callbackId, fn);
946
+ return callbackId;
947
+ },
948
+ registerPromise: (promise) => {
949
+ const promiseId = instance.nextLocalCallbackId++;
950
+ instance.returnedPromises.set(promiseId, promise);
951
+ return promiseId;
952
+ },
953
+ registerIterator: (iterator) => {
954
+ const iteratorId = instance.nextLocalCallbackId++;
955
+ instance.returnedIterators.set(iteratorId, iterator);
956
+ return iteratorId;
957
+ }
958
+ };
959
+ }
960
+ function addCallbackIdsToRefs(value) {
961
+ if (value === null || typeof value !== "object") {
962
+ return value;
963
+ }
964
+ if (isPromiseRef(value)) {
965
+ if ("__resolveCallbackId" in value) {
966
+ return value;
967
+ }
968
+ const resolveCallbackId = instance.nextLocalCallbackId++;
969
+ instance.returnedCallbacks.set(resolveCallbackId, async (promiseId) => {
970
+ const promise = instance.returnedPromises.get(promiseId);
971
+ if (!promise) {
972
+ throw new Error(`Promise ${promiseId} not found`);
973
+ }
974
+ const result2 = await promise;
975
+ instance.returnedPromises.delete(promiseId);
976
+ const ctx = createMarshalContext();
977
+ const marshalled = await import_isolate_protocol.marshalValue(result2, ctx);
978
+ return addCallbackIdsToRefs(marshalled);
979
+ });
980
+ return {
981
+ ...value,
982
+ __resolveCallbackId: resolveCallbackId
983
+ };
984
+ }
985
+ if (isAsyncIteratorRef(value)) {
986
+ if ("__nextCallbackId" in value) {
987
+ return value;
988
+ }
989
+ const nextCallbackId = instance.nextLocalCallbackId++;
990
+ instance.returnedCallbacks.set(nextCallbackId, async (iteratorId) => {
991
+ const iterator = instance.returnedIterators.get(iteratorId);
992
+ if (!iterator) {
993
+ throw new Error(`Iterator ${iteratorId} not found`);
994
+ }
995
+ const result2 = await iterator.next();
996
+ if (result2.done) {
997
+ instance.returnedIterators.delete(iteratorId);
998
+ }
999
+ const ctx = createMarshalContext();
1000
+ const marshalledValue = await import_isolate_protocol.marshalValue(result2.value, ctx);
1001
+ return {
1002
+ done: result2.done,
1003
+ value: addCallbackIdsToRefs(marshalledValue)
1004
+ };
1005
+ });
1006
+ const returnCallbackId = instance.nextLocalCallbackId++;
1007
+ instance.returnedCallbacks.set(returnCallbackId, async (iteratorId, returnValue) => {
1008
+ const iterator = instance.returnedIterators.get(iteratorId);
1009
+ instance.returnedIterators.delete(iteratorId);
1010
+ if (!iterator || !iterator.return) {
1011
+ return { done: true, value: undefined };
1012
+ }
1013
+ const result2 = await iterator.return(returnValue);
1014
+ const ctx = createMarshalContext();
1015
+ const marshalledValue = await import_isolate_protocol.marshalValue(result2.value, ctx);
1016
+ return {
1017
+ done: true,
1018
+ value: addCallbackIdsToRefs(marshalledValue)
1019
+ };
1020
+ });
1021
+ return {
1022
+ ...value,
1023
+ __nextCallbackId: nextCallbackId,
1024
+ __returnCallbackId: returnCallbackId
1025
+ };
1026
+ }
1027
+ if (Array.isArray(value)) {
1028
+ return value.map((item) => addCallbackIdsToRefs(item));
1029
+ }
1030
+ const result = {};
1031
+ for (const key of Object.keys(value)) {
1032
+ result[key] = addCallbackIdsToRefs(value[key]);
1033
+ }
1034
+ return result;
1035
+ }
1036
+ const invokeCallbackRef = new import_isolated_vm.default.Reference(async (callbackId, argsJson) => {
1037
+ const marshalledArgs = JSON.parse(argsJson);
1038
+ const args = import_isolate_protocol.unmarshalValue(marshalledArgs);
1039
+ try {
1040
+ let result;
1041
+ if (isLocalCallbackId(callbackId)) {
1042
+ const callback = instance.returnedCallbacks.get(callbackId);
1043
+ if (!callback) {
1044
+ throw new Error(`Local callback ${callbackId} not found`);
1045
+ }
1046
+ result = await callback(...args);
1047
+ } else {
1048
+ result = await invokeClientCallback(connection, callbackId, args);
1049
+ }
1050
+ const ctx = createMarshalContext();
1051
+ const marshalledResult = await import_isolate_protocol.marshalValue({ ok: true, value: result }, ctx);
1052
+ const processedResult = addCallbackIdsToRefs(marshalledResult);
1053
+ return JSON.stringify(processedResult);
1054
+ } catch (error) {
1055
+ const err = error;
1056
+ return JSON.stringify({
1057
+ ok: false,
1058
+ error: { message: err.message, name: err.name }
1059
+ });
1060
+ }
1061
+ });
1062
+ global.setSync("__customFn_invoke", invokeCallbackRef);
1063
+ context.evalSync(ISOLATE_MARSHAL_CODE);
1064
+ for (const [name, registration] of Object.entries(customCallbacks)) {
1065
+ if (name.includes(":")) {
1066
+ continue;
1067
+ }
1068
+ if (registration.type === "sync") {
1069
+ context.evalSync(`
1070
+ globalThis.${name} = function(...args) {
1071
+ const argsJson = JSON.stringify(__marshalForHost(args));
1072
+ const resultJson = __customFn_invoke.applySyncPromise(
1073
+ undefined,
1074
+ [${registration.callbackId}, argsJson]
1075
+ );
1076
+ const result = JSON.parse(resultJson);
1077
+ if (result.ok) {
1078
+ return __unmarshalFromHost(result.value);
1079
+ } else {
1080
+ const error = new Error(result.error.message);
1081
+ error.name = result.error.name;
1082
+ throw error;
1083
+ }
1084
+ };
1085
+ `);
1086
+ } else if (registration.type === "asyncIterator") {
1087
+ const startReg = customCallbacks[`${name}:start`];
1088
+ const nextReg = customCallbacks[`${name}:next`];
1089
+ const returnReg = customCallbacks[`${name}:return`];
1090
+ const throwReg = customCallbacks[`${name}:throw`];
1091
+ if (!startReg || !nextReg || !returnReg || !throwReg) {
1092
+ throw new Error(`Missing companion callbacks for asyncIterator function "${name}"`);
1093
+ }
1094
+ context.evalSync(`
1095
+ globalThis.${name} = function(...args) {
1096
+ // Start the iterator and get the iteratorId
1097
+ const argsJson = JSON.stringify(__marshalForHost(args));
1098
+ const startResultJson = __customFn_invoke.applySyncPromise(
1099
+ undefined,
1100
+ [${startReg.callbackId}, argsJson]
1101
+ );
1102
+ const startResult = JSON.parse(startResultJson);
1103
+ if (!startResult.ok) {
1104
+ const error = new Error(startResult.error.message);
1105
+ error.name = startResult.error.name;
1106
+ throw error;
1107
+ }
1108
+ const iteratorId = __unmarshalFromHost(startResult.value).iteratorId;
1109
+
1110
+ return {
1111
+ [Symbol.asyncIterator]() { return this; },
1112
+ async next() {
1113
+ const argsJson = JSON.stringify(__marshalForHost([iteratorId]));
1114
+ const resultJson = __customFn_invoke.applySyncPromise(
1115
+ undefined,
1116
+ [${nextReg.callbackId}, argsJson]
1117
+ );
1118
+ const result = JSON.parse(resultJson);
1119
+ if (!result.ok) {
1120
+ const error = new Error(result.error.message);
1121
+ error.name = result.error.name;
1122
+ throw error;
1123
+ }
1124
+ const val = __unmarshalFromHost(result.value);
1125
+ return { done: val.done, value: val.value };
1126
+ },
1127
+ async return(v) {
1128
+ const argsJson = JSON.stringify(__marshalForHost([iteratorId, v]));
1129
+ const resultJson = __customFn_invoke.applySyncPromise(
1130
+ undefined,
1131
+ [${returnReg.callbackId}, argsJson]
1132
+ );
1133
+ const result = JSON.parse(resultJson);
1134
+ return { done: true, value: result.ok ? __unmarshalFromHost(result.value) : undefined };
1135
+ },
1136
+ async throw(e) {
1137
+ const argsJson = JSON.stringify(__marshalForHost([iteratorId, { message: e?.message, name: e?.name }]));
1138
+ const resultJson = __customFn_invoke.applySyncPromise(
1139
+ undefined,
1140
+ [${throwReg.callbackId}, argsJson]
1141
+ );
1142
+ const result = JSON.parse(resultJson);
1143
+ if (!result.ok) {
1144
+ const error = new Error(result.error.message);
1145
+ error.name = result.error.name;
1146
+ throw error;
1147
+ }
1148
+ const val = __unmarshalFromHost(result.value);
1149
+ return { done: val.done, value: val.value };
1150
+ }
1151
+ };
1152
+ };
1153
+ `);
1154
+ } else if (registration.type === "async") {
1155
+ context.evalSync(`
1156
+ globalThis.${name} = async function(...args) {
1157
+ const argsJson = JSON.stringify(__marshalForHost(args));
1158
+ const resultJson = __customFn_invoke.applySyncPromise(
1159
+ undefined,
1160
+ [${registration.callbackId}, argsJson]
1161
+ );
1162
+ const result = JSON.parse(resultJson);
1163
+ if (result.ok) {
1164
+ return __unmarshalFromHost(result.value);
1165
+ } else {
1166
+ const error = new Error(result.error.message);
1167
+ error.name = result.error.name;
1168
+ throw error;
1169
+ }
1170
+ };
1171
+ `);
1172
+ }
1173
+ }
1174
+ }
1175
+ function createModuleResolver(instance, connection) {
1176
+ return async (specifier, _referrer) => {
1177
+ const cached = instance.moduleCache?.get(specifier);
1178
+ if (cached)
1179
+ return cached;
1180
+ if (!instance.moduleLoaderCallbackId) {
1181
+ throw new Error(`Module not found: ${specifier}`);
1182
+ }
1183
+ const code = await invokeClientCallback(connection, instance.moduleLoaderCallbackId, [specifier]);
1184
+ const mod = await instance.runtime.isolate.compileModule(code, {
1185
+ filename: specifier
1186
+ });
1187
+ const resolver = createModuleResolver(instance, connection);
1188
+ await mod.instantiate(instance.runtime.context, resolver);
1189
+ instance.moduleCache?.set(specifier, mod);
1190
+ return mod;
1191
+ };
1192
+ }
366
1193
  async function serializeRequest(request) {
367
1194
  const headers = [];
368
1195
  request.headers.forEach((value, key) => {
@@ -402,19 +1229,144 @@ function deserializeResponse(data) {
402
1229
  headers: data.headers
403
1230
  });
404
1231
  }
405
- async function handleSetupTestEnv(message, connection, state) {
406
- const instance = state.isolates.get(message.isolateId);
407
- if (!instance) {
408
- sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1232
+ function handleStreamPush(message, connection) {
1233
+ const receiver = connection.streamReceivers.get(message.streamId);
1234
+ if (!receiver) {
1235
+ sendMessage(connection.socket, {
1236
+ type: import_isolate_protocol.MessageType.STREAM_ERROR,
1237
+ streamId: message.streamId,
1238
+ error: "Stream not found"
1239
+ });
409
1240
  return;
410
1241
  }
411
- instance.lastActivity = Date.now();
1242
+ receiver.chunks.push(message.chunk);
1243
+ receiver.totalBytes += message.chunk.length;
1244
+ sendMessage(connection.socket, {
1245
+ type: import_isolate_protocol.MessageType.STREAM_PULL,
1246
+ streamId: message.streamId,
1247
+ maxBytes: import_isolate_protocol.STREAM_DEFAULT_CREDIT
1248
+ });
1249
+ }
1250
+ function handleStreamPull(message, connection) {
1251
+ const session = connection.activeStreams.get(message.streamId);
1252
+ if (!session) {
1253
+ return;
1254
+ }
1255
+ session.credit += message.maxBytes;
1256
+ if (session.creditResolver) {
1257
+ session.creditResolver();
1258
+ session.creditResolver = undefined;
1259
+ }
1260
+ }
1261
+ function handleStreamClose(message, connection) {
1262
+ const receiver = connection.streamReceivers.get(message.streamId);
1263
+ if (!receiver) {
1264
+ return;
1265
+ }
1266
+ const totalLength = receiver.chunks.reduce((sum, chunk) => sum + chunk.length, 0);
1267
+ const body = new Uint8Array(totalLength);
1268
+ let offset = 0;
1269
+ for (const chunk of receiver.chunks) {
1270
+ body.set(chunk, offset);
1271
+ offset += chunk.length;
1272
+ }
1273
+ receiver.resolve(body);
1274
+ connection.streamReceivers.delete(message.streamId);
1275
+ }
1276
+ function handleStreamError(message, connection) {
1277
+ const receiver = connection.streamReceivers.get(message.streamId);
1278
+ if (receiver) {
1279
+ receiver.reject(new Error(message.error));
1280
+ connection.streamReceivers.delete(message.streamId);
1281
+ }
1282
+ const session = connection.activeStreams.get(message.streamId);
1283
+ if (session) {
1284
+ session.state = "closed";
1285
+ connection.activeStreams.delete(message.streamId);
1286
+ }
1287
+ }
1288
+ function waitForCredit(session) {
1289
+ return new Promise((resolve) => {
1290
+ session.creditResolver = resolve;
1291
+ });
1292
+ }
1293
+ async function sendStreamedResponse(connection, requestId, response) {
1294
+ const streamId = connection.nextStreamId++;
1295
+ const headers = [];
1296
+ response.headers.forEach((value, key) => {
1297
+ headers.push([key, value]);
1298
+ });
1299
+ const startMsg = {
1300
+ type: import_isolate_protocol.MessageType.RESPONSE_STREAM_START,
1301
+ requestId,
1302
+ streamId,
1303
+ metadata: {
1304
+ status: response.status,
1305
+ statusText: response.statusText,
1306
+ headers
1307
+ }
1308
+ };
1309
+ sendMessage(connection.socket, startMsg);
1310
+ if (!response.body) {
1311
+ const endMsg = {
1312
+ type: import_isolate_protocol.MessageType.RESPONSE_STREAM_END,
1313
+ requestId,
1314
+ streamId
1315
+ };
1316
+ sendMessage(connection.socket, endMsg);
1317
+ return;
1318
+ }
1319
+ const session = {
1320
+ streamId,
1321
+ direction: "download",
1322
+ requestId,
1323
+ state: "active",
1324
+ bytesTransferred: 0,
1325
+ credit: import_isolate_protocol.STREAM_DEFAULT_CREDIT
1326
+ };
1327
+ connection.activeStreams.set(streamId, session);
1328
+ const reader = response.body.getReader();
412
1329
  try {
413
- await import_isolate_test_environment.setupTestEnvironment(instance.runtime.context);
414
- sendOk(connection.socket, message.requestId);
1330
+ while (true) {
1331
+ while (session.credit < import_isolate_protocol.STREAM_CHUNK_SIZE && session.state === "active") {
1332
+ await waitForCredit(session);
1333
+ }
1334
+ if (session.state !== "active") {
1335
+ throw new Error("Stream cancelled");
1336
+ }
1337
+ const { done, value } = await reader.read();
1338
+ if (done) {
1339
+ const endMsg = {
1340
+ type: import_isolate_protocol.MessageType.RESPONSE_STREAM_END,
1341
+ requestId,
1342
+ streamId
1343
+ };
1344
+ sendMessage(connection.socket, endMsg);
1345
+ break;
1346
+ }
1347
+ for (let offset = 0;offset < value.length; offset += import_isolate_protocol.STREAM_CHUNK_SIZE) {
1348
+ const chunk = value.slice(offset, offset + import_isolate_protocol.STREAM_CHUNK_SIZE);
1349
+ const chunkMsg = {
1350
+ type: import_isolate_protocol.MessageType.RESPONSE_STREAM_CHUNK,
1351
+ requestId,
1352
+ streamId,
1353
+ chunk
1354
+ };
1355
+ sendMessage(connection.socket, chunkMsg);
1356
+ session.credit -= chunk.length;
1357
+ session.bytesTransferred += chunk.length;
1358
+ }
1359
+ }
415
1360
  } catch (err) {
416
- const error = err;
417
- sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1361
+ const errorMsg = {
1362
+ type: import_isolate_protocol.MessageType.STREAM_ERROR,
1363
+ streamId,
1364
+ error: err.message
1365
+ };
1366
+ sendMessage(connection.socket, errorMsg);
1367
+ } finally {
1368
+ reader.releaseLock();
1369
+ connection.activeStreams.delete(streamId);
418
1370
  }
419
1371
  }
420
1372
  async function handleRunTests(message, connection, state) {
@@ -423,6 +1375,10 @@ async function handleRunTests(message, connection, state) {
423
1375
  sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
424
1376
  return;
425
1377
  }
1378
+ if (!instance.testEnvironmentEnabled) {
1379
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, "Test environment not enabled. Set testEnvironment: true in createRuntime options.");
1380
+ return;
1381
+ }
426
1382
  instance.lastActivity = Date.now();
427
1383
  try {
428
1384
  const timeout = message.timeout ?? 30000;
@@ -439,119 +1395,69 @@ async function handleRunTests(message, connection, state) {
439
1395
  sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
440
1396
  }
441
1397
  }
442
- async function handleSetupPlaywright(message, connection, state) {
1398
+ async function handleResetTestEnv(message, connection, state) {
443
1399
  const instance = state.isolates.get(message.isolateId);
444
1400
  if (!instance) {
445
1401
  sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
446
1402
  return;
447
1403
  }
448
- if (instance.browser) {
449
- sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, "Playwright already set up for this isolate");
1404
+ if (!instance.testEnvironmentEnabled) {
1405
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, "Test environment not enabled. Set testEnvironment: true in createRuntime options.");
450
1406
  return;
451
1407
  }
452
1408
  instance.lastActivity = Date.now();
453
1409
  try {
454
- const browserType = message.options.browserType ?? "chromium";
455
- const headless = message.options.headless ?? true;
456
- let browser;
457
- switch (browserType) {
458
- case "firefox":
459
- browser = await import_playwright.firefox.launch({ headless });
460
- break;
461
- case "webkit":
462
- browser = await import_playwright.webkit.launch({ headless });
463
- break;
464
- default:
465
- browser = await import_playwright.chromium.launch({ headless });
466
- }
467
- const browserContext = await browser.newContext();
468
- const page = await browserContext.newPage();
469
- const playwrightHandle = await import_isolate_playwright.setupPlaywright(instance.runtime.context, {
470
- page,
471
- baseUrl: message.options.baseURL,
472
- onConsoleLog: (level, ...args) => {
473
- const event = {
474
- type: import_isolate_protocol.MessageType.PLAYWRIGHT_EVENT,
475
- isolateId: message.isolateId,
476
- eventType: "consoleLog",
477
- payload: { level, args }
478
- };
479
- sendMessage(connection.socket, event);
480
- },
481
- onNetworkRequest: (info) => {
482
- const event = {
483
- type: import_isolate_protocol.MessageType.PLAYWRIGHT_EVENT,
484
- isolateId: message.isolateId,
485
- eventType: "networkRequest",
486
- payload: info
487
- };
488
- sendMessage(connection.socket, event);
489
- },
490
- onNetworkResponse: (info) => {
491
- const event = {
492
- type: import_isolate_protocol.MessageType.PLAYWRIGHT_EVENT,
493
- isolateId: message.isolateId,
494
- eventType: "networkResponse",
495
- payload: info
496
- };
497
- sendMessage(connection.socket, event);
498
- }
499
- });
500
- instance.browser = browser;
501
- instance.browserContext = browserContext;
502
- instance.page = page;
503
- instance.playwrightHandle = playwrightHandle;
1410
+ await instance.runtime.context.eval("__resetTestEnvironment()", { promise: true });
504
1411
  sendOk(connection.socket, message.requestId);
505
1412
  } catch (err) {
506
1413
  const error = err;
507
1414
  sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
508
1415
  }
509
1416
  }
510
- async function handleRunPlaywrightTests(message, connection, state) {
1417
+ async function handleHasTests(message, connection, state) {
511
1418
  const instance = state.isolates.get(message.isolateId);
512
1419
  if (!instance) {
513
1420
  sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
514
1421
  return;
515
1422
  }
516
- if (!instance.playwrightHandle) {
517
- sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, "Playwright not set up for this isolate");
1423
+ if (!instance.testEnvironmentEnabled) {
1424
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, "Test environment not enabled. Set testEnvironment: true in createRuntime options.");
518
1425
  return;
519
1426
  }
520
1427
  instance.lastActivity = Date.now();
521
1428
  try {
522
- const timeout = message.timeout ?? 30000;
523
- const timeoutPromise = new Promise((_, reject) => {
524
- setTimeout(() => reject(new Error("Playwright test timeout")), timeout);
525
- });
526
- const results = await Promise.race([
527
- import_isolate_playwright.runPlaywrightTests(instance.runtime.context),
528
- timeoutPromise
529
- ]);
530
- sendOk(connection.socket, message.requestId, results);
1429
+ const result = import_isolate_test_environment.hasTests(instance.runtime.context);
1430
+ sendOk(connection.socket, message.requestId, result);
531
1431
  } catch (err) {
532
1432
  const error = err;
533
1433
  sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
534
1434
  }
535
1435
  }
536
- async function handleResetPlaywrightTests(message, connection, state) {
1436
+ async function handleGetTestCount(message, connection, state) {
537
1437
  const instance = state.isolates.get(message.isolateId);
538
1438
  if (!instance) {
539
1439
  sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
540
1440
  return;
541
1441
  }
542
- if (!instance.playwrightHandle) {
543
- sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, "Playwright not set up for this isolate");
1442
+ if (!instance.testEnvironmentEnabled) {
1443
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, "Test environment not enabled. Set testEnvironment: true in createRuntime options.");
544
1444
  return;
545
1445
  }
546
1446
  instance.lastActivity = Date.now();
547
1447
  try {
548
- await import_isolate_playwright.resetPlaywrightTests(instance.runtime.context);
549
- sendOk(connection.socket, message.requestId);
1448
+ const result = import_isolate_test_environment.getTestCount(instance.runtime.context);
1449
+ sendOk(connection.socket, message.requestId, result);
550
1450
  } catch (err) {
551
1451
  const error = err;
552
1452
  sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
553
1453
  }
554
1454
  }
1455
+ async function handleRunPlaywrightTests(message, connection, _state) {
1456
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, "playwright.runTests() has been removed. Use testEnvironment.runTests() instead.");
1457
+ }
1458
+ async function handleResetPlaywrightTests(message, connection, _state) {
1459
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, "playwright.reset() has been removed. Use testEnvironment.reset() instead.");
1460
+ }
555
1461
  async function handleGetCollectedData(message, connection, state) {
556
1462
  const instance = state.isolates.get(message.isolateId);
557
1463
  if (!instance) {
@@ -559,13 +1465,13 @@ async function handleGetCollectedData(message, connection, state) {
559
1465
  return;
560
1466
  }
561
1467
  if (!instance.playwrightHandle) {
562
- sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, "Playwright not set up for this isolate");
1468
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, "Playwright not configured. Provide playwright.page in createRuntime options.");
563
1469
  return;
564
1470
  }
565
1471
  instance.lastActivity = Date.now();
566
1472
  try {
567
1473
  const data = {
568
- consoleLogs: instance.playwrightHandle.getConsoleLogs(),
1474
+ browserConsoleLogs: instance.playwrightHandle.getBrowserConsoleLogs(),
569
1475
  networkRequests: instance.playwrightHandle.getNetworkRequests(),
570
1476
  networkResponses: instance.playwrightHandle.getNetworkResponses()
571
1477
  };
@@ -575,6 +1481,25 @@ async function handleGetCollectedData(message, connection, state) {
575
1481
  sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
576
1482
  }
577
1483
  }
1484
+ async function handleClearCollectedData(message, connection, state) {
1485
+ const instance = state.isolates.get(message.isolateId);
1486
+ if (!instance) {
1487
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1488
+ return;
1489
+ }
1490
+ if (!instance.playwrightHandle) {
1491
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, "Playwright not configured. Provide playwright.page in createRuntime options.");
1492
+ return;
1493
+ }
1494
+ instance.lastActivity = Date.now();
1495
+ try {
1496
+ instance.playwrightHandle.clearCollected();
1497
+ sendOk(connection.socket, message.requestId);
1498
+ } catch (err) {
1499
+ const error = err;
1500
+ sendError(connection.socket, message.requestId, import_isolate_protocol.ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1501
+ }
1502
+ }
578
1503
  })
579
1504
 
580
- //# debugId=2FA1AEE5C513B77464756E2164756E21
1505
+ //# debugId=A7BAC1A3990C35CA64756E2164756E21