@ricsam/isolate-daemon 0.0.1 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -31
- package/bin/daemon.js +98 -0
- package/dist/cjs/callback-fs-handler.cjs +314 -0
- package/dist/cjs/callback-fs-handler.cjs.map +10 -0
- package/dist/cjs/connection.cjs +580 -0
- package/dist/cjs/connection.cjs.map +10 -0
- package/dist/cjs/index.cjs +132 -0
- package/dist/cjs/index.cjs.map +10 -0
- package/dist/cjs/package.json +5 -0
- package/dist/cjs/types.cjs +26 -0
- package/dist/cjs/types.cjs.map +9 -0
- package/dist/mjs/callback-fs-handler.mjs +283 -0
- package/dist/mjs/callback-fs-handler.mjs.map +10 -0
- package/dist/mjs/connection.mjs +561 -0
- package/dist/mjs/connection.mjs.map +10 -0
- package/dist/mjs/index.mjs +101 -0
- package/dist/mjs/index.mjs.map +10 -0
- package/dist/mjs/package.json +5 -0
- package/dist/mjs/types.mjs +3 -0
- package/dist/mjs/types.mjs.map +9 -0
- package/dist/types/callback-fs-handler.d.ts +25 -0
- package/dist/types/connection.d.ts +9 -0
- package/dist/types/index.d.ts +14 -0
- package/dist/types/types.d.ts +91 -0
- package/package.json +55 -6
|
@@ -0,0 +1,561 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/isolate-daemon/src/connection.ts
|
|
3
|
+
import { randomUUID } from "crypto";
|
|
4
|
+
import {
|
|
5
|
+
createFrameParser,
|
|
6
|
+
buildFrame,
|
|
7
|
+
MessageType,
|
|
8
|
+
ErrorCode
|
|
9
|
+
} from "@ricsam/isolate-protocol";
|
|
10
|
+
import { createCallbackFileSystemHandler } from "./callback-fs-handler.mjs";
|
|
11
|
+
import {
|
|
12
|
+
setupTestEnvironment,
|
|
13
|
+
runTests as runTestsInContext
|
|
14
|
+
} from "@ricsam/isolate-test-environment";
|
|
15
|
+
import {
|
|
16
|
+
setupPlaywright,
|
|
17
|
+
runPlaywrightTests,
|
|
18
|
+
resetPlaywrightTests
|
|
19
|
+
} from "@ricsam/isolate-playwright";
|
|
20
|
+
import { chromium, firefox, webkit } from "playwright";
|
|
21
|
+
import { createRuntime } from "@ricsam/isolate-runtime";
|
|
22
|
+
function handleConnection(socket, state) {
|
|
23
|
+
const connection = {
|
|
24
|
+
socket,
|
|
25
|
+
isolates: new Set,
|
|
26
|
+
pendingRequests: new Map,
|
|
27
|
+
pendingCallbacks: new Map,
|
|
28
|
+
nextRequestId: 1,
|
|
29
|
+
nextCallbackId: 1,
|
|
30
|
+
nextStreamId: 1
|
|
31
|
+
};
|
|
32
|
+
state.connections.set(socket, connection);
|
|
33
|
+
const parser = createFrameParser();
|
|
34
|
+
socket.on("data", (data) => {
|
|
35
|
+
try {
|
|
36
|
+
for (const frame of parser.feed(new Uint8Array(data))) {
|
|
37
|
+
handleMessage(frame.message, connection, state).catch((err) => {
|
|
38
|
+
console.error("Error handling message:", err);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
} catch (err) {
|
|
42
|
+
console.error("Error parsing frame:", err);
|
|
43
|
+
socket.destroy();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
socket.on("close", () => {
|
|
47
|
+
for (const isolateId of connection.isolates) {
|
|
48
|
+
const instance = state.isolates.get(isolateId);
|
|
49
|
+
if (instance) {
|
|
50
|
+
try {
|
|
51
|
+
if (instance.playwrightHandle) {
|
|
52
|
+
instance.playwrightHandle.dispose();
|
|
53
|
+
}
|
|
54
|
+
if (instance.browserContext) {
|
|
55
|
+
instance.browserContext.close().catch(() => {});
|
|
56
|
+
}
|
|
57
|
+
if (instance.browser) {
|
|
58
|
+
instance.browser.close().catch(() => {});
|
|
59
|
+
}
|
|
60
|
+
instance.runtime.dispose();
|
|
61
|
+
} catch {}
|
|
62
|
+
state.isolates.delete(isolateId);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
for (const [, pending] of connection.pendingCallbacks) {
|
|
66
|
+
pending.reject(new Error("Connection closed"));
|
|
67
|
+
}
|
|
68
|
+
state.connections.delete(socket);
|
|
69
|
+
});
|
|
70
|
+
socket.on("error", (err) => {
|
|
71
|
+
console.error("Socket error:", err);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function sendMessage(socket, message) {
|
|
75
|
+
const frame = buildFrame(message);
|
|
76
|
+
socket.write(frame);
|
|
77
|
+
}
|
|
78
|
+
function sendError(socket, requestId, code, message, details) {
|
|
79
|
+
const response = {
|
|
80
|
+
type: MessageType.RESPONSE_ERROR,
|
|
81
|
+
requestId,
|
|
82
|
+
code,
|
|
83
|
+
message,
|
|
84
|
+
details
|
|
85
|
+
};
|
|
86
|
+
sendMessage(socket, response);
|
|
87
|
+
}
|
|
88
|
+
function sendOk(socket, requestId, data) {
|
|
89
|
+
const response = {
|
|
90
|
+
type: MessageType.RESPONSE_OK,
|
|
91
|
+
requestId,
|
|
92
|
+
data
|
|
93
|
+
};
|
|
94
|
+
sendMessage(socket, response);
|
|
95
|
+
}
|
|
96
|
+
async function handleMessage(message, connection, state) {
|
|
97
|
+
state.stats.totalRequestsProcessed++;
|
|
98
|
+
switch (message.type) {
|
|
99
|
+
case MessageType.CREATE_RUNTIME:
|
|
100
|
+
await handleCreateRuntime(message, connection, state);
|
|
101
|
+
break;
|
|
102
|
+
case MessageType.DISPOSE_RUNTIME:
|
|
103
|
+
await handleDisposeRuntime(message, connection, state);
|
|
104
|
+
break;
|
|
105
|
+
case MessageType.EVAL:
|
|
106
|
+
await handleEval(message, connection, state);
|
|
107
|
+
break;
|
|
108
|
+
case MessageType.DISPATCH_REQUEST:
|
|
109
|
+
await handleDispatchRequest(message, connection, state);
|
|
110
|
+
break;
|
|
111
|
+
case MessageType.TICK:
|
|
112
|
+
await handleTick(message, connection, state);
|
|
113
|
+
break;
|
|
114
|
+
case MessageType.CALLBACK_RESPONSE:
|
|
115
|
+
handleCallbackResponse(message, connection);
|
|
116
|
+
break;
|
|
117
|
+
case MessageType.SETUP_TEST_ENV:
|
|
118
|
+
await handleSetupTestEnv(message, connection, state);
|
|
119
|
+
break;
|
|
120
|
+
case MessageType.RUN_TESTS:
|
|
121
|
+
await handleRunTests(message, connection, state);
|
|
122
|
+
break;
|
|
123
|
+
case MessageType.SETUP_PLAYWRIGHT:
|
|
124
|
+
await handleSetupPlaywright(message, connection, state);
|
|
125
|
+
break;
|
|
126
|
+
case MessageType.RUN_PLAYWRIGHT_TESTS:
|
|
127
|
+
await handleRunPlaywrightTests(message, connection, state);
|
|
128
|
+
break;
|
|
129
|
+
case MessageType.RESET_PLAYWRIGHT_TESTS:
|
|
130
|
+
await handleResetPlaywrightTests(message, connection, state);
|
|
131
|
+
break;
|
|
132
|
+
case MessageType.GET_COLLECTED_DATA:
|
|
133
|
+
await handleGetCollectedData(message, connection, state);
|
|
134
|
+
break;
|
|
135
|
+
case MessageType.PING:
|
|
136
|
+
sendMessage(connection.socket, { type: MessageType.PONG });
|
|
137
|
+
break;
|
|
138
|
+
default:
|
|
139
|
+
sendError(connection.socket, message.requestId ?? 0, ErrorCode.UNKNOWN_MESSAGE_TYPE, `Unknown message type: ${message.type}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async function handleCreateRuntime(message, connection, state) {
|
|
143
|
+
if (state.isolates.size >= state.options.maxIsolates) {
|
|
144
|
+
sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_MEMORY_LIMIT, `Maximum isolates (${state.options.maxIsolates}) reached`);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
const isolateId = randomUUID();
|
|
149
|
+
const consoleCallbacks = message.options.callbacks?.console;
|
|
150
|
+
const fetchCallback = message.options.callbacks?.fetch;
|
|
151
|
+
const fsCallbacks = message.options.callbacks?.fs;
|
|
152
|
+
const runtime = await createRuntime({
|
|
153
|
+
memoryLimit: message.options.memoryLimit ?? state.options.defaultMemoryLimit,
|
|
154
|
+
console: consoleCallbacks ? {
|
|
155
|
+
onLog: async (level, ...args) => {
|
|
156
|
+
const levelCallback = consoleCallbacks[level];
|
|
157
|
+
if (levelCallback) {
|
|
158
|
+
await invokeClientCallback(connection, levelCallback.callbackId, [level, ...args]);
|
|
159
|
+
} else if (consoleCallbacks.log) {
|
|
160
|
+
await invokeClientCallback(connection, consoleCallbacks.log.callbackId, [level, ...args]);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
} : undefined,
|
|
164
|
+
fetch: fetchCallback ? {
|
|
165
|
+
onFetch: async (request) => {
|
|
166
|
+
const serialized = await serializeRequest(request);
|
|
167
|
+
const result = await invokeClientCallback(connection, fetchCallback.callbackId, [serialized]);
|
|
168
|
+
return deserializeResponse(result);
|
|
169
|
+
}
|
|
170
|
+
} : undefined,
|
|
171
|
+
fs: fsCallbacks ? {
|
|
172
|
+
getDirectory: async (path) => {
|
|
173
|
+
return createCallbackFileSystemHandler({
|
|
174
|
+
connection,
|
|
175
|
+
callbacks: fsCallbacks,
|
|
176
|
+
invokeClientCallback,
|
|
177
|
+
basePath: path
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
} : undefined
|
|
181
|
+
});
|
|
182
|
+
const instance = {
|
|
183
|
+
isolateId,
|
|
184
|
+
runtime,
|
|
185
|
+
ownerConnection: connection.socket,
|
|
186
|
+
callbacks: new Map,
|
|
187
|
+
createdAt: Date.now(),
|
|
188
|
+
lastActivity: Date.now()
|
|
189
|
+
};
|
|
190
|
+
if (consoleCallbacks) {
|
|
191
|
+
for (const [name, reg] of Object.entries(consoleCallbacks)) {
|
|
192
|
+
if (reg) {
|
|
193
|
+
instance.callbacks.set(reg.callbackId, { ...reg, name });
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (fetchCallback) {
|
|
198
|
+
instance.callbacks.set(fetchCallback.callbackId, fetchCallback);
|
|
199
|
+
}
|
|
200
|
+
if (fsCallbacks) {
|
|
201
|
+
for (const [name, reg] of Object.entries(fsCallbacks)) {
|
|
202
|
+
if (reg) {
|
|
203
|
+
instance.callbacks.set(reg.callbackId, { ...reg, name });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
state.isolates.set(isolateId, instance);
|
|
208
|
+
connection.isolates.add(isolateId);
|
|
209
|
+
state.stats.totalIsolatesCreated++;
|
|
210
|
+
sendOk(connection.socket, message.requestId, { isolateId });
|
|
211
|
+
} catch (err) {
|
|
212
|
+
const error = err;
|
|
213
|
+
sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
async function handleDisposeRuntime(message, connection, state) {
|
|
217
|
+
const instance = state.isolates.get(message.isolateId);
|
|
218
|
+
if (!instance) {
|
|
219
|
+
sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (instance.ownerConnection !== connection.socket) {
|
|
223
|
+
sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not owned by this connection`);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
if (instance.playwrightHandle) {
|
|
228
|
+
instance.playwrightHandle.dispose();
|
|
229
|
+
}
|
|
230
|
+
if (instance.browserContext) {
|
|
231
|
+
await instance.browserContext.close();
|
|
232
|
+
}
|
|
233
|
+
if (instance.browser) {
|
|
234
|
+
await instance.browser.close();
|
|
235
|
+
}
|
|
236
|
+
instance.runtime.dispose();
|
|
237
|
+
state.isolates.delete(message.isolateId);
|
|
238
|
+
connection.isolates.delete(message.isolateId);
|
|
239
|
+
sendOk(connection.socket, message.requestId);
|
|
240
|
+
} catch (err) {
|
|
241
|
+
const error = err;
|
|
242
|
+
sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
async function handleEval(message, connection, state) {
|
|
246
|
+
const instance = state.isolates.get(message.isolateId);
|
|
247
|
+
if (!instance) {
|
|
248
|
+
sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
instance.lastActivity = Date.now();
|
|
252
|
+
try {
|
|
253
|
+
const result = instance.runtime.context.evalSync(message.code, {
|
|
254
|
+
filename: message.filename
|
|
255
|
+
});
|
|
256
|
+
sendOk(connection.socket, message.requestId, { value: result });
|
|
257
|
+
} catch (err) {
|
|
258
|
+
const error = err;
|
|
259
|
+
sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
async function handleDispatchRequest(message, connection, state) {
|
|
263
|
+
const instance = state.isolates.get(message.isolateId);
|
|
264
|
+
if (!instance) {
|
|
265
|
+
sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
instance.lastActivity = Date.now();
|
|
269
|
+
try {
|
|
270
|
+
const request = new Request(message.request.url, {
|
|
271
|
+
method: message.request.method,
|
|
272
|
+
headers: message.request.headers,
|
|
273
|
+
body: message.request.body
|
|
274
|
+
});
|
|
275
|
+
const response = await instance.runtime.fetch.dispatchRequest(request, {
|
|
276
|
+
tick: async () => {
|
|
277
|
+
await instance.runtime.tick();
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
const serialized = await serializeResponse(response);
|
|
281
|
+
sendOk(connection.socket, message.requestId, { response: serialized });
|
|
282
|
+
} catch (err) {
|
|
283
|
+
const error = err;
|
|
284
|
+
sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
async function handleTick(message, connection, state) {
|
|
288
|
+
const instance = state.isolates.get(message.isolateId);
|
|
289
|
+
if (!instance) {
|
|
290
|
+
sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
instance.lastActivity = Date.now();
|
|
294
|
+
try {
|
|
295
|
+
instance.runtime.tick(message.ms);
|
|
296
|
+
sendOk(connection.socket, message.requestId);
|
|
297
|
+
} catch (err) {
|
|
298
|
+
const error = err;
|
|
299
|
+
sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
function handleCallbackResponse(message, connection) {
|
|
303
|
+
const pending = connection.pendingCallbacks.get(message.requestId);
|
|
304
|
+
if (!pending) {
|
|
305
|
+
console.warn(`No pending callback for requestId: ${message.requestId}`);
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
connection.pendingCallbacks.delete(message.requestId);
|
|
309
|
+
if (pending.timeoutId) {
|
|
310
|
+
clearTimeout(pending.timeoutId);
|
|
311
|
+
}
|
|
312
|
+
if (message.error) {
|
|
313
|
+
const error = new Error(message.error.message);
|
|
314
|
+
error.name = message.error.name;
|
|
315
|
+
if (message.error.stack) {
|
|
316
|
+
error.stack = message.error.stack;
|
|
317
|
+
}
|
|
318
|
+
pending.reject(error);
|
|
319
|
+
} else {
|
|
320
|
+
pending.resolve(message.result);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
async function invokeClientCallback(connection, callbackId, args, timeout = 1e4) {
|
|
324
|
+
const requestId = connection.nextCallbackId++;
|
|
325
|
+
return new Promise((resolve, reject) => {
|
|
326
|
+
const timeoutId = setTimeout(() => {
|
|
327
|
+
connection.pendingCallbacks.delete(requestId);
|
|
328
|
+
reject(new Error("Callback timeout"));
|
|
329
|
+
}, timeout);
|
|
330
|
+
const pending = {
|
|
331
|
+
resolve,
|
|
332
|
+
reject,
|
|
333
|
+
timeoutId
|
|
334
|
+
};
|
|
335
|
+
connection.pendingCallbacks.set(requestId, pending);
|
|
336
|
+
const invoke = {
|
|
337
|
+
type: MessageType.CALLBACK_INVOKE,
|
|
338
|
+
requestId,
|
|
339
|
+
callbackId,
|
|
340
|
+
args
|
|
341
|
+
};
|
|
342
|
+
sendMessage(connection.socket, invoke);
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
async function serializeRequest(request) {
|
|
346
|
+
const headers = [];
|
|
347
|
+
request.headers.forEach((value, key) => {
|
|
348
|
+
headers.push([key, value]);
|
|
349
|
+
});
|
|
350
|
+
let body = null;
|
|
351
|
+
if (request.body) {
|
|
352
|
+
body = new Uint8Array(await request.arrayBuffer());
|
|
353
|
+
}
|
|
354
|
+
return {
|
|
355
|
+
method: request.method,
|
|
356
|
+
url: request.url,
|
|
357
|
+
headers,
|
|
358
|
+
body
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
async function serializeResponse(response) {
|
|
362
|
+
const headers = [];
|
|
363
|
+
response.headers.forEach((value, key) => {
|
|
364
|
+
headers.push([key, value]);
|
|
365
|
+
});
|
|
366
|
+
let body = null;
|
|
367
|
+
if (response.body) {
|
|
368
|
+
body = new Uint8Array(await response.arrayBuffer());
|
|
369
|
+
}
|
|
370
|
+
return {
|
|
371
|
+
status: response.status,
|
|
372
|
+
statusText: response.statusText,
|
|
373
|
+
headers,
|
|
374
|
+
body
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
function deserializeResponse(data) {
|
|
378
|
+
return new Response(data.body, {
|
|
379
|
+
status: data.status,
|
|
380
|
+
statusText: data.statusText,
|
|
381
|
+
headers: data.headers
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
async function handleSetupTestEnv(message, connection, state) {
|
|
385
|
+
const instance = state.isolates.get(message.isolateId);
|
|
386
|
+
if (!instance) {
|
|
387
|
+
sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
instance.lastActivity = Date.now();
|
|
391
|
+
try {
|
|
392
|
+
await setupTestEnvironment(instance.runtime.context);
|
|
393
|
+
sendOk(connection.socket, message.requestId);
|
|
394
|
+
} catch (err) {
|
|
395
|
+
const error = err;
|
|
396
|
+
sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
async function handleRunTests(message, connection, state) {
|
|
400
|
+
const instance = state.isolates.get(message.isolateId);
|
|
401
|
+
if (!instance) {
|
|
402
|
+
sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
instance.lastActivity = Date.now();
|
|
406
|
+
try {
|
|
407
|
+
const timeout = message.timeout ?? 30000;
|
|
408
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
409
|
+
setTimeout(() => reject(new Error("Test timeout")), timeout);
|
|
410
|
+
});
|
|
411
|
+
const results = await Promise.race([
|
|
412
|
+
runTestsInContext(instance.runtime.context),
|
|
413
|
+
timeoutPromise
|
|
414
|
+
]);
|
|
415
|
+
sendOk(connection.socket, message.requestId, results);
|
|
416
|
+
} catch (err) {
|
|
417
|
+
const error = err;
|
|
418
|
+
sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
async function handleSetupPlaywright(message, connection, state) {
|
|
422
|
+
const instance = state.isolates.get(message.isolateId);
|
|
423
|
+
if (!instance) {
|
|
424
|
+
sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
if (instance.browser) {
|
|
428
|
+
sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, "Playwright already set up for this isolate");
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
instance.lastActivity = Date.now();
|
|
432
|
+
try {
|
|
433
|
+
const browserType = message.options.browserType ?? "chromium";
|
|
434
|
+
const headless = message.options.headless ?? true;
|
|
435
|
+
let browser;
|
|
436
|
+
switch (browserType) {
|
|
437
|
+
case "firefox":
|
|
438
|
+
browser = await firefox.launch({ headless });
|
|
439
|
+
break;
|
|
440
|
+
case "webkit":
|
|
441
|
+
browser = await webkit.launch({ headless });
|
|
442
|
+
break;
|
|
443
|
+
default:
|
|
444
|
+
browser = await chromium.launch({ headless });
|
|
445
|
+
}
|
|
446
|
+
const browserContext = await browser.newContext();
|
|
447
|
+
const page = await browserContext.newPage();
|
|
448
|
+
const playwrightHandle = await setupPlaywright(instance.runtime.context, {
|
|
449
|
+
page,
|
|
450
|
+
baseUrl: message.options.baseURL,
|
|
451
|
+
onConsoleLog: (level, ...args) => {
|
|
452
|
+
const event = {
|
|
453
|
+
type: MessageType.PLAYWRIGHT_EVENT,
|
|
454
|
+
isolateId: message.isolateId,
|
|
455
|
+
eventType: "consoleLog",
|
|
456
|
+
payload: { level, args }
|
|
457
|
+
};
|
|
458
|
+
sendMessage(connection.socket, event);
|
|
459
|
+
},
|
|
460
|
+
onNetworkRequest: (info) => {
|
|
461
|
+
const event = {
|
|
462
|
+
type: MessageType.PLAYWRIGHT_EVENT,
|
|
463
|
+
isolateId: message.isolateId,
|
|
464
|
+
eventType: "networkRequest",
|
|
465
|
+
payload: info
|
|
466
|
+
};
|
|
467
|
+
sendMessage(connection.socket, event);
|
|
468
|
+
},
|
|
469
|
+
onNetworkResponse: (info) => {
|
|
470
|
+
const event = {
|
|
471
|
+
type: MessageType.PLAYWRIGHT_EVENT,
|
|
472
|
+
isolateId: message.isolateId,
|
|
473
|
+
eventType: "networkResponse",
|
|
474
|
+
payload: info
|
|
475
|
+
};
|
|
476
|
+
sendMessage(connection.socket, event);
|
|
477
|
+
}
|
|
478
|
+
});
|
|
479
|
+
instance.browser = browser;
|
|
480
|
+
instance.browserContext = browserContext;
|
|
481
|
+
instance.page = page;
|
|
482
|
+
instance.playwrightHandle = playwrightHandle;
|
|
483
|
+
sendOk(connection.socket, message.requestId);
|
|
484
|
+
} catch (err) {
|
|
485
|
+
const error = err;
|
|
486
|
+
sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
async function handleRunPlaywrightTests(message, connection, state) {
|
|
490
|
+
const instance = state.isolates.get(message.isolateId);
|
|
491
|
+
if (!instance) {
|
|
492
|
+
sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
if (!instance.playwrightHandle) {
|
|
496
|
+
sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, "Playwright not set up for this isolate");
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
instance.lastActivity = Date.now();
|
|
500
|
+
try {
|
|
501
|
+
const timeout = message.timeout ?? 30000;
|
|
502
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
503
|
+
setTimeout(() => reject(new Error("Playwright test timeout")), timeout);
|
|
504
|
+
});
|
|
505
|
+
const results = await Promise.race([
|
|
506
|
+
runPlaywrightTests(instance.runtime.context),
|
|
507
|
+
timeoutPromise
|
|
508
|
+
]);
|
|
509
|
+
sendOk(connection.socket, message.requestId, results);
|
|
510
|
+
} catch (err) {
|
|
511
|
+
const error = err;
|
|
512
|
+
sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
async function handleResetPlaywrightTests(message, connection, state) {
|
|
516
|
+
const instance = state.isolates.get(message.isolateId);
|
|
517
|
+
if (!instance) {
|
|
518
|
+
sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
if (!instance.playwrightHandle) {
|
|
522
|
+
sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, "Playwright not set up for this isolate");
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
instance.lastActivity = Date.now();
|
|
526
|
+
try {
|
|
527
|
+
await resetPlaywrightTests(instance.runtime.context);
|
|
528
|
+
sendOk(connection.socket, message.requestId);
|
|
529
|
+
} catch (err) {
|
|
530
|
+
const error = err;
|
|
531
|
+
sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
async function handleGetCollectedData(message, connection, state) {
|
|
535
|
+
const instance = state.isolates.get(message.isolateId);
|
|
536
|
+
if (!instance) {
|
|
537
|
+
sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
if (!instance.playwrightHandle) {
|
|
541
|
+
sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, "Playwright not set up for this isolate");
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
instance.lastActivity = Date.now();
|
|
545
|
+
try {
|
|
546
|
+
const data = {
|
|
547
|
+
consoleLogs: instance.playwrightHandle.getConsoleLogs(),
|
|
548
|
+
networkRequests: instance.playwrightHandle.getNetworkRequests(),
|
|
549
|
+
networkResponses: instance.playwrightHandle.getNetworkResponses()
|
|
550
|
+
};
|
|
551
|
+
sendOk(connection.socket, message.requestId, data);
|
|
552
|
+
} catch (err) {
|
|
553
|
+
const error = err;
|
|
554
|
+
sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
export {
|
|
558
|
+
handleConnection
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
//# debugId=4F884F5F7FCD4D4F64756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/connection.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * Connection handling for the isolate daemon.\n */\n\nimport type { Socket } from \"node:net\";\nimport { randomUUID } from \"node:crypto\";\nimport {\n createFrameParser,\n buildFrame,\n MessageType,\n ErrorCode,\n type Message,\n type ResponseOk,\n type ResponseError,\n type CreateRuntimeRequest,\n type DisposeRuntimeRequest,\n type EvalRequest,\n type DispatchRequestRequest,\n type TickRequest,\n type CallbackResponseMsg,\n type CallbackInvoke,\n type SetupTestEnvRequest,\n type RunTestsRequest,\n type SetupPlaywrightRequest,\n type RunPlaywrightTestsRequest,\n type ResetPlaywrightTestsRequest,\n type GetCollectedDataRequest,\n type PlaywrightEvent,\n type FsCallbackRegistrations,\n} from \"@ricsam/isolate-protocol\";\nimport { createCallbackFileSystemHandler } from \"./callback-fs-handler.mjs\";\nimport {\n setupTestEnvironment,\n runTests as runTestsInContext,\n} from \"@ricsam/isolate-test-environment\";\nimport {\n setupPlaywright,\n runPlaywrightTests,\n resetPlaywrightTests,\n} from \"@ricsam/isolate-playwright\";\nimport { chromium, firefox, webkit } from \"playwright\";\nimport { createRuntime, type RuntimeHandle } from \"@ricsam/isolate-runtime\";\nimport type {\n DaemonState,\n ConnectionState,\n IsolateInstance,\n PendingRequest,\n} from \"./types.mjs\";\n\n/**\n * Handle a new client connection.\n */\nexport function handleConnection(socket: Socket, state: DaemonState): void {\n const connection: ConnectionState = {\n socket,\n isolates: new Set(),\n pendingRequests: new Map(),\n pendingCallbacks: new Map(),\n nextRequestId: 1,\n nextCallbackId: 1,\n nextStreamId: 1,\n };\n\n state.connections.set(socket, connection);\n\n const parser = createFrameParser();\n\n socket.on(\"data\", (data) => {\n try {\n for (const frame of parser.feed(new Uint8Array(data))) {\n handleMessage(frame.message, connection, state).catch((err) => {\n console.error(\"Error handling message:\", err);\n });\n }\n } catch (err) {\n console.error(\"Error parsing frame:\", err);\n socket.destroy();\n }\n });\n\n socket.on(\"close\", () => {\n // Dispose all isolates owned by this connection\n for (const isolateId of connection.isolates) {\n const instance = state.isolates.get(isolateId);\n if (instance) {\n try {\n // Clean up Playwright resources if present\n if (instance.playwrightHandle) {\n instance.playwrightHandle.dispose();\n }\n if (instance.browserContext) {\n instance.browserContext.close().catch(() => {});\n }\n if (instance.browser) {\n instance.browser.close().catch(() => {});\n }\n instance.runtime.dispose();\n } catch {\n // Ignore disposal errors\n }\n state.isolates.delete(isolateId);\n }\n }\n\n // Reject pending callbacks\n for (const [, pending] of connection.pendingCallbacks) {\n pending.reject(new Error(\"Connection closed\"));\n }\n\n state.connections.delete(socket);\n });\n\n socket.on(\"error\", (err) => {\n console.error(\"Socket error:\", err);\n });\n}\n\n/**\n * Send a message to a client.\n */\nfunction sendMessage(socket: Socket, message: Message): void {\n const frame = buildFrame(message);\n socket.write(frame);\n}\n\n/**\n * Send an error response.\n */\nfunction sendError(\n socket: Socket,\n requestId: number,\n code: ErrorCode,\n message: string,\n details?: { name: string; stack?: string }\n): void {\n const response: ResponseError = {\n type: MessageType.RESPONSE_ERROR,\n requestId,\n code,\n message,\n details,\n };\n sendMessage(socket, response);\n}\n\n/**\n * Send a success response.\n */\nfunction sendOk(socket: Socket, requestId: number, data?: unknown): void {\n const response: ResponseOk = {\n type: MessageType.RESPONSE_OK,\n requestId,\n data,\n };\n sendMessage(socket, response);\n}\n\n/**\n * Handle an incoming message.\n */\nasync function handleMessage(\n message: Message,\n connection: ConnectionState,\n state: DaemonState\n): Promise<void> {\n state.stats.totalRequestsProcessed++;\n\n switch (message.type) {\n case MessageType.CREATE_RUNTIME:\n await handleCreateRuntime(\n message as CreateRuntimeRequest,\n connection,\n state\n );\n break;\n\n case MessageType.DISPOSE_RUNTIME:\n await handleDisposeRuntime(\n message as DisposeRuntimeRequest,\n connection,\n state\n );\n break;\n\n case MessageType.EVAL:\n await handleEval(message as EvalRequest, connection, state);\n break;\n\n case MessageType.DISPATCH_REQUEST:\n await handleDispatchRequest(\n message as DispatchRequestRequest,\n connection,\n state\n );\n break;\n\n case MessageType.TICK:\n await handleTick(message as TickRequest, connection, state);\n break;\n\n case MessageType.CALLBACK_RESPONSE:\n handleCallbackResponse(message as CallbackResponseMsg, connection);\n break;\n\n case MessageType.SETUP_TEST_ENV:\n await handleSetupTestEnv(\n message as SetupTestEnvRequest,\n connection,\n state\n );\n break;\n\n case MessageType.RUN_TESTS:\n await handleRunTests(message as RunTestsRequest, connection, state);\n break;\n\n case MessageType.SETUP_PLAYWRIGHT:\n await handleSetupPlaywright(\n message as SetupPlaywrightRequest,\n connection,\n state\n );\n break;\n\n case MessageType.RUN_PLAYWRIGHT_TESTS:\n await handleRunPlaywrightTests(\n message as RunPlaywrightTestsRequest,\n connection,\n state\n );\n break;\n\n case MessageType.RESET_PLAYWRIGHT_TESTS:\n await handleResetPlaywrightTests(\n message as ResetPlaywrightTestsRequest,\n connection,\n state\n );\n break;\n\n case MessageType.GET_COLLECTED_DATA:\n await handleGetCollectedData(\n message as GetCollectedDataRequest,\n connection,\n state\n );\n break;\n\n case MessageType.PING:\n sendMessage(connection.socket, { type: MessageType.PONG });\n break;\n\n default:\n sendError(\n connection.socket,\n (message as { requestId?: number }).requestId ?? 0,\n ErrorCode.UNKNOWN_MESSAGE_TYPE,\n `Unknown message type: ${message.type}`\n );\n }\n}\n\n/**\n * Handle CREATE_RUNTIME message.\n */\nasync function handleCreateRuntime(\n message: CreateRuntimeRequest,\n connection: ConnectionState,\n state: DaemonState\n): Promise<void> {\n // Check limits\n if (state.isolates.size >= state.options.maxIsolates) {\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.ISOLATE_MEMORY_LIMIT,\n `Maximum isolates (${state.options.maxIsolates}) reached`\n );\n return;\n }\n\n try {\n const isolateId = randomUUID();\n\n // Create bridged callbacks that invoke the client\n const consoleCallbacks = message.options.callbacks?.console;\n const fetchCallback = message.options.callbacks?.fetch;\n const fsCallbacks = message.options.callbacks?.fs;\n\n const runtime = await createRuntime({\n memoryLimit: message.options.memoryLimit ?? state.options.defaultMemoryLimit,\n console: consoleCallbacks\n ? {\n onLog: async (level, ...args) => {\n // Route to the appropriate callback based on level\n const levelCallback = (consoleCallbacks as Record<string, { callbackId: number } | undefined>)[level];\n if (levelCallback) {\n await invokeClientCallback(\n connection,\n levelCallback.callbackId,\n [level, ...args]\n );\n } else if (consoleCallbacks.log) {\n // Fallback to log callback if specific level callback not registered\n await invokeClientCallback(\n connection,\n consoleCallbacks.log.callbackId,\n [level, ...args]\n );\n }\n },\n }\n : undefined,\n fetch: fetchCallback\n ? {\n onFetch: async (request) => {\n const serialized = await serializeRequest(request);\n const result = await invokeClientCallback(\n connection,\n fetchCallback.callbackId,\n [serialized]\n );\n return deserializeResponse(result as SerializedResponseData);\n },\n }\n : undefined,\n fs: fsCallbacks\n ? {\n getDirectory: async (path: string) => {\n return createCallbackFileSystemHandler({\n connection,\n callbacks: fsCallbacks,\n invokeClientCallback,\n basePath: path,\n });\n },\n }\n : undefined,\n });\n\n const instance: IsolateInstance = {\n isolateId,\n runtime,\n ownerConnection: connection.socket,\n callbacks: new Map(),\n createdAt: Date.now(),\n lastActivity: Date.now(),\n };\n\n // Store callback registrations\n if (consoleCallbacks) {\n for (const [name, reg] of Object.entries(consoleCallbacks)) {\n if (reg) {\n instance.callbacks.set(reg.callbackId, { ...reg, name });\n }\n }\n }\n if (fetchCallback) {\n instance.callbacks.set(fetchCallback.callbackId, fetchCallback);\n }\n if (fsCallbacks) {\n for (const [name, reg] of Object.entries(fsCallbacks)) {\n if (reg) {\n instance.callbacks.set(reg.callbackId, { ...reg, name });\n }\n }\n }\n\n state.isolates.set(isolateId, instance);\n connection.isolates.add(isolateId);\n state.stats.totalIsolatesCreated++;\n\n sendOk(connection.socket, message.requestId, { isolateId });\n } catch (err) {\n const error = err as Error;\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.SCRIPT_ERROR,\n error.message,\n { name: error.name, stack: error.stack }\n );\n }\n}\n\n/**\n * Handle DISPOSE_RUNTIME message.\n */\nasync function handleDisposeRuntime(\n message: DisposeRuntimeRequest,\n connection: ConnectionState,\n state: DaemonState\n): Promise<void> {\n const instance = state.isolates.get(message.isolateId);\n\n if (!instance) {\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.ISOLATE_NOT_FOUND,\n `Isolate not found: ${message.isolateId}`\n );\n return;\n }\n\n if (instance.ownerConnection !== connection.socket) {\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.ISOLATE_NOT_FOUND,\n `Isolate not owned by this connection`\n );\n return;\n }\n\n try {\n // Clean up Playwright resources if present\n if (instance.playwrightHandle) {\n instance.playwrightHandle.dispose();\n }\n if (instance.browserContext) {\n await instance.browserContext.close();\n }\n if (instance.browser) {\n await instance.browser.close();\n }\n\n instance.runtime.dispose();\n state.isolates.delete(message.isolateId);\n connection.isolates.delete(message.isolateId);\n\n sendOk(connection.socket, message.requestId);\n } catch (err) {\n const error = err as Error;\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.SCRIPT_ERROR,\n error.message,\n { name: error.name, stack: error.stack }\n );\n }\n}\n\n/**\n * Handle EVAL message.\n */\nasync function handleEval(\n message: EvalRequest,\n connection: ConnectionState,\n state: DaemonState\n): Promise<void> {\n const instance = state.isolates.get(message.isolateId);\n\n if (!instance) {\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.ISOLATE_NOT_FOUND,\n `Isolate not found: ${message.isolateId}`\n );\n return;\n }\n\n instance.lastActivity = Date.now();\n\n try {\n const result = instance.runtime.context.evalSync(message.code, {\n filename: message.filename,\n });\n sendOk(connection.socket, message.requestId, { value: result });\n } catch (err) {\n const error = err as Error;\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.SCRIPT_ERROR,\n error.message,\n { name: error.name, stack: error.stack }\n );\n }\n}\n\n/**\n * Handle DISPATCH_REQUEST message.\n */\nasync function handleDispatchRequest(\n message: DispatchRequestRequest,\n connection: ConnectionState,\n state: DaemonState\n): Promise<void> {\n const instance = state.isolates.get(message.isolateId);\n\n if (!instance) {\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.ISOLATE_NOT_FOUND,\n `Isolate not found: ${message.isolateId}`\n );\n return;\n }\n\n instance.lastActivity = Date.now();\n\n try {\n // Deserialize the request\n const request = new Request(message.request.url, {\n method: message.request.method,\n headers: message.request.headers,\n body: message.request.body as any,\n });\n\n // Dispatch to isolate\n // Note: Pass tick function for streaming response support\n const response = await instance.runtime.fetch.dispatchRequest(request, {\n tick: async () => {\n await instance.runtime.tick();\n },\n });\n\n // Serialize the response\n const serialized = await serializeResponse(response);\n sendOk(connection.socket, message.requestId, { response: serialized });\n } catch (err) {\n const error = err as Error;\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.SCRIPT_ERROR,\n error.message,\n { name: error.name, stack: error.stack }\n );\n }\n}\n\n/**\n * Handle TICK message.\n */\nasync function handleTick(\n message: TickRequest,\n connection: ConnectionState,\n state: DaemonState\n): Promise<void> {\n const instance = state.isolates.get(message.isolateId);\n\n if (!instance) {\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.ISOLATE_NOT_FOUND,\n `Isolate not found: ${message.isolateId}`\n );\n return;\n }\n\n instance.lastActivity = Date.now();\n\n try {\n instance.runtime.tick(message.ms);\n sendOk(connection.socket, message.requestId);\n } catch (err) {\n const error = err as Error;\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.SCRIPT_ERROR,\n error.message,\n { name: error.name, stack: error.stack }\n );\n }\n}\n\n/**\n * Handle CALLBACK_RESPONSE message (client responding to a callback invocation).\n */\nfunction handleCallbackResponse(\n message: CallbackResponseMsg,\n connection: ConnectionState\n): void {\n const pending = connection.pendingCallbacks.get(message.requestId);\n\n if (!pending) {\n console.warn(`No pending callback for requestId: ${message.requestId}`);\n return;\n }\n\n connection.pendingCallbacks.delete(message.requestId);\n\n if (pending.timeoutId) {\n clearTimeout(pending.timeoutId);\n }\n\n if (message.error) {\n const error = new Error(message.error.message);\n error.name = message.error.name;\n if (message.error.stack) {\n error.stack = message.error.stack;\n }\n pending.reject(error);\n } else {\n pending.resolve(message.result);\n }\n}\n\n/**\n * Invoke a callback on the client side and wait for response.\n */\nasync function invokeClientCallback(\n connection: ConnectionState,\n callbackId: number,\n args: unknown[],\n timeout = 10000\n): Promise<unknown> {\n const requestId = connection.nextCallbackId++;\n\n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n connection.pendingCallbacks.delete(requestId);\n reject(new Error(\"Callback timeout\"));\n }, timeout);\n\n const pending: PendingRequest = {\n resolve,\n reject,\n timeoutId,\n };\n\n connection.pendingCallbacks.set(requestId, pending);\n\n const invoke: CallbackInvoke = {\n type: MessageType.CALLBACK_INVOKE,\n requestId,\n callbackId,\n args,\n };\n\n sendMessage(connection.socket, invoke);\n });\n}\n\n// ============================================================================\n// Request/Response Serialization\n// ============================================================================\n\ninterface SerializedRequestData {\n method: string;\n url: string;\n headers: [string, string][];\n body: Uint8Array | null;\n}\n\ninterface SerializedResponseData {\n status: number;\n statusText: string;\n headers: [string, string][];\n body: Uint8Array | null;\n}\n\nasync function serializeRequest(request: Request): Promise<SerializedRequestData> {\n const headers: [string, string][] = [];\n request.headers.forEach((value, key) => {\n headers.push([key, value]);\n });\n\n let body: Uint8Array | null = null;\n if (request.body) {\n body = new Uint8Array(await request.arrayBuffer());\n }\n\n return {\n method: request.method,\n url: request.url,\n headers,\n body,\n };\n}\n\nasync function serializeResponse(response: Response): Promise<SerializedResponseData> {\n const headers: [string, string][] = [];\n response.headers.forEach((value, key) => {\n headers.push([key, value]);\n });\n\n let body: Uint8Array | null = null;\n if (response.body) {\n body = new Uint8Array(await response.arrayBuffer());\n }\n\n return {\n status: response.status,\n statusText: response.statusText,\n headers,\n body,\n };\n}\n\nfunction deserializeResponse(data: SerializedResponseData): Response {\n return new Response(data.body as any, {\n status: data.status,\n statusText: data.statusText,\n headers: data.headers,\n });\n}\n\n// ============================================================================\n// Test Environment Handlers\n// ============================================================================\n\n/**\n * Handle SETUP_TEST_ENV message.\n */\nasync function handleSetupTestEnv(\n message: SetupTestEnvRequest,\n connection: ConnectionState,\n state: DaemonState\n): Promise<void> {\n const instance = state.isolates.get(message.isolateId);\n\n if (!instance) {\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.ISOLATE_NOT_FOUND,\n `Isolate not found: ${message.isolateId}`\n );\n return;\n }\n\n instance.lastActivity = Date.now();\n\n try {\n // Setup test environment in the isolate's context\n await setupTestEnvironment(instance.runtime.context);\n sendOk(connection.socket, message.requestId);\n } catch (err) {\n const error = err as Error;\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.SCRIPT_ERROR,\n error.message,\n { name: error.name, stack: error.stack }\n );\n }\n}\n\n/**\n * Handle RUN_TESTS message.\n */\nasync function handleRunTests(\n message: RunTestsRequest,\n connection: ConnectionState,\n state: DaemonState\n): Promise<void> {\n const instance = state.isolates.get(message.isolateId);\n\n if (!instance) {\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.ISOLATE_NOT_FOUND,\n `Isolate not found: ${message.isolateId}`\n );\n return;\n }\n\n instance.lastActivity = Date.now();\n\n try {\n // Run tests with optional timeout\n const timeout = message.timeout ?? 30000;\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => reject(new Error(\"Test timeout\")), timeout);\n });\n\n const results = await Promise.race([\n runTestsInContext(instance.runtime.context),\n timeoutPromise,\n ]);\n\n sendOk(connection.socket, message.requestId, results);\n } catch (err) {\n const error = err as Error;\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.SCRIPT_ERROR,\n error.message,\n { name: error.name, stack: error.stack }\n );\n }\n}\n\n// ============================================================================\n// Playwright Handlers\n// ============================================================================\n\n/**\n * Handle SETUP_PLAYWRIGHT message.\n */\nasync function handleSetupPlaywright(\n message: SetupPlaywrightRequest,\n connection: ConnectionState,\n state: DaemonState\n): Promise<void> {\n const instance = state.isolates.get(message.isolateId);\n\n if (!instance) {\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.ISOLATE_NOT_FOUND,\n `Isolate not found: ${message.isolateId}`\n );\n return;\n }\n\n if (instance.browser) {\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.SCRIPT_ERROR,\n \"Playwright already set up for this isolate\"\n );\n return;\n }\n\n instance.lastActivity = Date.now();\n\n try {\n // Launch browser based on type\n const browserType = message.options.browserType ?? \"chromium\";\n const headless = message.options.headless ?? true;\n\n let browser;\n switch (browserType) {\n case \"firefox\":\n browser = await firefox.launch({ headless });\n break;\n case \"webkit\":\n browser = await webkit.launch({ headless });\n break;\n default:\n browser = await chromium.launch({ headless });\n }\n\n // Create context and page\n const browserContext = await browser.newContext();\n const page = await browserContext.newPage();\n\n // Setup Playwright in the isolate context with event streaming\n const playwrightHandle = await setupPlaywright(instance.runtime.context, {\n page,\n baseUrl: message.options.baseURL,\n onConsoleLog: (level, ...args) => {\n // Stream console logs to client\n const event: PlaywrightEvent = {\n type: MessageType.PLAYWRIGHT_EVENT,\n isolateId: message.isolateId,\n eventType: \"consoleLog\",\n payload: { level, args },\n };\n sendMessage(connection.socket, event);\n },\n onNetworkRequest: (info) => {\n // Stream network requests to client\n const event: PlaywrightEvent = {\n type: MessageType.PLAYWRIGHT_EVENT,\n isolateId: message.isolateId,\n eventType: \"networkRequest\",\n payload: info,\n };\n sendMessage(connection.socket, event);\n },\n onNetworkResponse: (info) => {\n // Stream network responses to client\n const event: PlaywrightEvent = {\n type: MessageType.PLAYWRIGHT_EVENT,\n isolateId: message.isolateId,\n eventType: \"networkResponse\",\n payload: info,\n };\n sendMessage(connection.socket, event);\n },\n });\n\n // Store references\n instance.browser = browser;\n instance.browserContext = browserContext;\n instance.page = page;\n instance.playwrightHandle = playwrightHandle;\n\n sendOk(connection.socket, message.requestId);\n } catch (err) {\n const error = err as Error;\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.SCRIPT_ERROR,\n error.message,\n { name: error.name, stack: error.stack }\n );\n }\n}\n\n/**\n * Handle RUN_PLAYWRIGHT_TESTS message.\n */\nasync function handleRunPlaywrightTests(\n message: RunPlaywrightTestsRequest,\n connection: ConnectionState,\n state: DaemonState\n): Promise<void> {\n const instance = state.isolates.get(message.isolateId);\n\n if (!instance) {\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.ISOLATE_NOT_FOUND,\n `Isolate not found: ${message.isolateId}`\n );\n return;\n }\n\n if (!instance.playwrightHandle) {\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.SCRIPT_ERROR,\n \"Playwright not set up for this isolate\"\n );\n return;\n }\n\n instance.lastActivity = Date.now();\n\n try {\n const timeout = message.timeout ?? 30000;\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => reject(new Error(\"Playwright test timeout\")), timeout);\n });\n\n const results = await Promise.race([\n runPlaywrightTests(instance.runtime.context),\n timeoutPromise,\n ]);\n\n sendOk(connection.socket, message.requestId, results);\n } catch (err) {\n const error = err as Error;\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.SCRIPT_ERROR,\n error.message,\n { name: error.name, stack: error.stack }\n );\n }\n}\n\n/**\n * Handle RESET_PLAYWRIGHT_TESTS message.\n */\nasync function handleResetPlaywrightTests(\n message: ResetPlaywrightTestsRequest,\n connection: ConnectionState,\n state: DaemonState\n): Promise<void> {\n const instance = state.isolates.get(message.isolateId);\n\n if (!instance) {\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.ISOLATE_NOT_FOUND,\n `Isolate not found: ${message.isolateId}`\n );\n return;\n }\n\n if (!instance.playwrightHandle) {\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.SCRIPT_ERROR,\n \"Playwright not set up for this isolate\"\n );\n return;\n }\n\n instance.lastActivity = Date.now();\n\n try {\n await resetPlaywrightTests(instance.runtime.context);\n sendOk(connection.socket, message.requestId);\n } catch (err) {\n const error = err as Error;\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.SCRIPT_ERROR,\n error.message,\n { name: error.name, stack: error.stack }\n );\n }\n}\n\n/**\n * Handle GET_COLLECTED_DATA message.\n */\nasync function handleGetCollectedData(\n message: GetCollectedDataRequest,\n connection: ConnectionState,\n state: DaemonState\n): Promise<void> {\n const instance = state.isolates.get(message.isolateId);\n\n if (!instance) {\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.ISOLATE_NOT_FOUND,\n `Isolate not found: ${message.isolateId}`\n );\n return;\n }\n\n if (!instance.playwrightHandle) {\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.SCRIPT_ERROR,\n \"Playwright not set up for this isolate\"\n );\n return;\n }\n\n instance.lastActivity = Date.now();\n\n try {\n const data = {\n consoleLogs: instance.playwrightHandle.getConsoleLogs(),\n networkRequests: instance.playwrightHandle.getNetworkRequests(),\n networkResponses: instance.playwrightHandle.getNetworkResponses(),\n };\n\n sendOk(connection.socket, message.requestId, data);\n } catch (err) {\n const error = err as Error;\n sendError(\n connection.socket,\n message.requestId,\n ErrorCode.SCRIPT_ERROR,\n error.message,\n { name: error.name, stack: error.stack }\n );\n }\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "4F884F5F7FCD4D4F64756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|