@ricsam/isolate-client 0.1.1 → 0.1.5
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 +313 -39
- package/dist/cjs/connection.cjs +785 -104
- package/dist/cjs/connection.cjs.map +3 -3
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/connection.mjs +790 -105
- package/dist/mjs/connection.mjs.map +3 -3
- package/dist/mjs/index.mjs.map +1 -1
- package/dist/mjs/package.json +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/types.d.ts +207 -82
- package/package.json +10 -1
package/dist/mjs/connection.mjs
CHANGED
|
@@ -4,9 +4,15 @@ import { connect as netConnect } from "net";
|
|
|
4
4
|
import {
|
|
5
5
|
createFrameParser,
|
|
6
6
|
buildFrame,
|
|
7
|
-
MessageType
|
|
7
|
+
MessageType,
|
|
8
|
+
STREAM_THRESHOLD,
|
|
9
|
+
STREAM_CHUNK_SIZE,
|
|
10
|
+
STREAM_DEFAULT_CREDIT,
|
|
11
|
+
marshalValue
|
|
8
12
|
} from "@ricsam/isolate-protocol";
|
|
13
|
+
import { createPlaywrightHandler } from "@ricsam/isolate-playwright/client";
|
|
9
14
|
var DEFAULT_TIMEOUT = 30000;
|
|
15
|
+
var isolateWsCallbacks = new Map;
|
|
10
16
|
async function connect(options = {}) {
|
|
11
17
|
const socket = await createSocket(options);
|
|
12
18
|
const state = {
|
|
@@ -15,8 +21,10 @@ async function connect(options = {}) {
|
|
|
15
21
|
callbacks: new Map,
|
|
16
22
|
nextRequestId: 1,
|
|
17
23
|
nextCallbackId: 1,
|
|
24
|
+
nextStreamId: 1,
|
|
18
25
|
connected: true,
|
|
19
|
-
|
|
26
|
+
streamResponses: new Map,
|
|
27
|
+
uploadStreams: new Map
|
|
20
28
|
};
|
|
21
29
|
const parser = createFrameParser();
|
|
22
30
|
socket.on("data", (data) => {
|
|
@@ -111,21 +119,157 @@ function handleMessage(message, state) {
|
|
|
111
119
|
}
|
|
112
120
|
case MessageType.PONG:
|
|
113
121
|
break;
|
|
114
|
-
case MessageType.
|
|
115
|
-
const
|
|
116
|
-
const
|
|
117
|
-
if (
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
handler.onNetworkRequest?.(event.payload);
|
|
124
|
-
break;
|
|
125
|
-
case "networkResponse":
|
|
126
|
-
handler.onNetworkResponse?.(event.payload);
|
|
127
|
-
break;
|
|
122
|
+
case MessageType.WS_COMMAND: {
|
|
123
|
+
const msg = message;
|
|
124
|
+
const callbacks = isolateWsCallbacks.get(msg.isolateId);
|
|
125
|
+
if (callbacks) {
|
|
126
|
+
let data;
|
|
127
|
+
if (msg.command.data instanceof Uint8Array) {
|
|
128
|
+
data = msg.command.data.buffer.slice(msg.command.data.byteOffset, msg.command.data.byteOffset + msg.command.data.byteLength);
|
|
129
|
+
} else {
|
|
130
|
+
data = msg.command.data;
|
|
128
131
|
}
|
|
132
|
+
const cmd = {
|
|
133
|
+
type: msg.command.type,
|
|
134
|
+
connectionId: msg.command.connectionId,
|
|
135
|
+
data,
|
|
136
|
+
code: msg.command.code,
|
|
137
|
+
reason: msg.command.reason
|
|
138
|
+
};
|
|
139
|
+
for (const cb of callbacks) {
|
|
140
|
+
cb(cmd);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
case MessageType.RESPONSE_STREAM_START: {
|
|
146
|
+
const msg = message;
|
|
147
|
+
const receiver = {
|
|
148
|
+
streamId: msg.streamId,
|
|
149
|
+
requestId: msg.requestId,
|
|
150
|
+
metadata: msg.metadata,
|
|
151
|
+
controller: null,
|
|
152
|
+
state: "active",
|
|
153
|
+
pendingChunks: []
|
|
154
|
+
};
|
|
155
|
+
const readableStream = new ReadableStream({
|
|
156
|
+
start(controller) {
|
|
157
|
+
receiver.controller = controller;
|
|
158
|
+
},
|
|
159
|
+
pull(_controller) {
|
|
160
|
+
while (receiver.pendingChunks.length > 0) {
|
|
161
|
+
const chunk = receiver.pendingChunks.shift();
|
|
162
|
+
receiver.controller.enqueue(chunk);
|
|
163
|
+
}
|
|
164
|
+
if (receiver.state === "closed") {
|
|
165
|
+
receiver.controller.close();
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (receiver.state === "errored") {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
sendMessage(state.socket, {
|
|
172
|
+
type: MessageType.STREAM_PULL,
|
|
173
|
+
streamId: msg.streamId,
|
|
174
|
+
maxBytes: STREAM_DEFAULT_CREDIT
|
|
175
|
+
});
|
|
176
|
+
return new Promise((resolve) => {
|
|
177
|
+
receiver.pullResolver = resolve;
|
|
178
|
+
});
|
|
179
|
+
},
|
|
180
|
+
cancel(_reason) {
|
|
181
|
+
receiver.state = "errored";
|
|
182
|
+
sendMessage(state.socket, {
|
|
183
|
+
type: MessageType.STREAM_ERROR,
|
|
184
|
+
streamId: msg.streamId,
|
|
185
|
+
error: "Stream cancelled by consumer"
|
|
186
|
+
});
|
|
187
|
+
state.streamResponses.delete(msg.streamId);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
state.streamResponses.set(msg.streamId, receiver);
|
|
191
|
+
const pending = state.pendingRequests.get(msg.requestId);
|
|
192
|
+
if (pending) {
|
|
193
|
+
state.pendingRequests.delete(msg.requestId);
|
|
194
|
+
if (pending.timeoutId)
|
|
195
|
+
clearTimeout(pending.timeoutId);
|
|
196
|
+
const response = new Response(readableStream, {
|
|
197
|
+
status: msg.metadata?.status ?? 200,
|
|
198
|
+
statusText: msg.metadata?.statusText ?? "OK",
|
|
199
|
+
headers: msg.metadata?.headers
|
|
200
|
+
});
|
|
201
|
+
pending.resolve({ response, __streaming: true });
|
|
202
|
+
}
|
|
203
|
+
sendMessage(state.socket, {
|
|
204
|
+
type: MessageType.STREAM_PULL,
|
|
205
|
+
streamId: msg.streamId,
|
|
206
|
+
maxBytes: STREAM_DEFAULT_CREDIT
|
|
207
|
+
});
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
case MessageType.RESPONSE_STREAM_CHUNK: {
|
|
211
|
+
const msg = message;
|
|
212
|
+
const receiver = state.streamResponses.get(msg.streamId);
|
|
213
|
+
if (receiver && receiver.state === "active") {
|
|
214
|
+
if (receiver.pullResolver) {
|
|
215
|
+
receiver.controller.enqueue(msg.chunk);
|
|
216
|
+
const resolver = receiver.pullResolver;
|
|
217
|
+
receiver.pullResolver = undefined;
|
|
218
|
+
resolver();
|
|
219
|
+
} else {
|
|
220
|
+
receiver.pendingChunks.push(msg.chunk);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
case MessageType.RESPONSE_STREAM_END: {
|
|
226
|
+
const msg = message;
|
|
227
|
+
const receiver = state.streamResponses.get(msg.streamId);
|
|
228
|
+
if (receiver) {
|
|
229
|
+
receiver.state = "closed";
|
|
230
|
+
while (receiver.pendingChunks.length > 0) {
|
|
231
|
+
const chunk = receiver.pendingChunks.shift();
|
|
232
|
+
receiver.controller.enqueue(chunk);
|
|
233
|
+
}
|
|
234
|
+
receiver.controller.close();
|
|
235
|
+
if (receiver.pullResolver) {
|
|
236
|
+
const resolver = receiver.pullResolver;
|
|
237
|
+
receiver.pullResolver = undefined;
|
|
238
|
+
resolver();
|
|
239
|
+
}
|
|
240
|
+
state.streamResponses.delete(msg.streamId);
|
|
241
|
+
}
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
case MessageType.STREAM_PULL: {
|
|
245
|
+
const msg = message;
|
|
246
|
+
const session = state.uploadStreams.get(msg.streamId);
|
|
247
|
+
if (session) {
|
|
248
|
+
session.credit += msg.maxBytes;
|
|
249
|
+
if (session.creditResolver) {
|
|
250
|
+
session.creditResolver();
|
|
251
|
+
session.creditResolver = undefined;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
256
|
+
case MessageType.STREAM_ERROR: {
|
|
257
|
+
const msg = message;
|
|
258
|
+
const uploadSession = state.uploadStreams.get(msg.streamId);
|
|
259
|
+
if (uploadSession) {
|
|
260
|
+
uploadSession.state = "closed";
|
|
261
|
+
state.uploadStreams.delete(msg.streamId);
|
|
262
|
+
}
|
|
263
|
+
const receiver = state.streamResponses.get(msg.streamId);
|
|
264
|
+
if (receiver) {
|
|
265
|
+
receiver.state = "errored";
|
|
266
|
+
receiver.controller.error(new Error(msg.error));
|
|
267
|
+
if (receiver.pullResolver) {
|
|
268
|
+
const resolver = receiver.pullResolver;
|
|
269
|
+
receiver.pullResolver = undefined;
|
|
270
|
+
resolver();
|
|
271
|
+
}
|
|
272
|
+
state.streamResponses.delete(msg.streamId);
|
|
129
273
|
}
|
|
130
274
|
break;
|
|
131
275
|
}
|
|
@@ -193,64 +337,291 @@ async function createRuntime(state, options = {}) {
|
|
|
193
337
|
if (options.fs) {
|
|
194
338
|
callbacks.fs = registerFsCallbacks(state, options.fs);
|
|
195
339
|
}
|
|
340
|
+
if (options.moduleLoader) {
|
|
341
|
+
callbacks.moduleLoader = registerModuleLoaderCallback(state, options.moduleLoader);
|
|
342
|
+
}
|
|
343
|
+
if (options.customFunctions) {
|
|
344
|
+
callbacks.custom = registerCustomFunctions(state, options.customFunctions);
|
|
345
|
+
}
|
|
346
|
+
let playwrightHandler;
|
|
347
|
+
if (options.playwright) {
|
|
348
|
+
playwrightHandler = createPlaywrightHandler(options.playwright.page, {
|
|
349
|
+
timeout: options.playwright.timeout,
|
|
350
|
+
baseUrl: options.playwright.baseUrl
|
|
351
|
+
});
|
|
352
|
+
const handlerCallbackId = state.nextCallbackId++;
|
|
353
|
+
state.callbacks.set(handlerCallbackId, async (opJson) => {
|
|
354
|
+
const op = JSON.parse(opJson);
|
|
355
|
+
const result2 = await playwrightHandler(op);
|
|
356
|
+
return JSON.stringify(result2);
|
|
357
|
+
});
|
|
358
|
+
const hasOnEvent = !!options.playwright.onEvent;
|
|
359
|
+
const hasConsoleHandler = options.playwright.console && options.console?.onEntry;
|
|
360
|
+
let browserConsoleLogCallbackId;
|
|
361
|
+
if (hasOnEvent || hasConsoleHandler) {
|
|
362
|
+
browserConsoleLogCallbackId = registerEventCallback(state, (entry) => {
|
|
363
|
+
const browserEntry = entry;
|
|
364
|
+
if (options.playwright.onEvent) {
|
|
365
|
+
options.playwright.onEvent({
|
|
366
|
+
type: "browserConsoleLog",
|
|
367
|
+
level: browserEntry.level,
|
|
368
|
+
args: browserEntry.args,
|
|
369
|
+
timestamp: browserEntry.timestamp
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
if (options.playwright.console && options.console?.onEntry) {
|
|
373
|
+
options.console.onEntry({
|
|
374
|
+
type: "browserOutput",
|
|
375
|
+
level: browserEntry.level,
|
|
376
|
+
args: browserEntry.args,
|
|
377
|
+
timestamp: browserEntry.timestamp
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
let networkRequestCallbackId;
|
|
383
|
+
if (hasOnEvent) {
|
|
384
|
+
networkRequestCallbackId = registerEventCallback(state, (info) => {
|
|
385
|
+
const reqInfo = info;
|
|
386
|
+
options.playwright.onEvent({
|
|
387
|
+
type: "networkRequest",
|
|
388
|
+
url: reqInfo.url,
|
|
389
|
+
method: reqInfo.method,
|
|
390
|
+
headers: reqInfo.headers,
|
|
391
|
+
postData: reqInfo.postData,
|
|
392
|
+
resourceType: reqInfo.resourceType,
|
|
393
|
+
timestamp: reqInfo.timestamp
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
let networkResponseCallbackId;
|
|
398
|
+
if (hasOnEvent) {
|
|
399
|
+
networkResponseCallbackId = registerEventCallback(state, (info) => {
|
|
400
|
+
const resInfo = info;
|
|
401
|
+
options.playwright.onEvent({
|
|
402
|
+
type: "networkResponse",
|
|
403
|
+
url: resInfo.url,
|
|
404
|
+
status: resInfo.status,
|
|
405
|
+
statusText: resInfo.statusText,
|
|
406
|
+
headers: resInfo.headers,
|
|
407
|
+
timestamp: resInfo.timestamp
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
callbacks.playwright = {
|
|
412
|
+
handlerCallbackId,
|
|
413
|
+
console: options.playwright.console && !options.console?.onEntry,
|
|
414
|
+
onBrowserConsoleLogCallbackId: browserConsoleLogCallbackId,
|
|
415
|
+
onNetworkRequestCallbackId: networkRequestCallbackId,
|
|
416
|
+
onNetworkResponseCallbackId: networkResponseCallbackId
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
let testEnvironmentOption;
|
|
420
|
+
if (options.testEnvironment) {
|
|
421
|
+
if (typeof options.testEnvironment === "object") {
|
|
422
|
+
const testEnvOptions = options.testEnvironment;
|
|
423
|
+
const testEnvCallbacks = {};
|
|
424
|
+
if (testEnvOptions.onEvent) {
|
|
425
|
+
const userOnEvent = testEnvOptions.onEvent;
|
|
426
|
+
const onEventCallbackId = registerEventCallback(state, (eventJson) => {
|
|
427
|
+
const event = JSON.parse(eventJson);
|
|
428
|
+
userOnEvent(event);
|
|
429
|
+
});
|
|
430
|
+
testEnvCallbacks.onEvent = {
|
|
431
|
+
callbackId: onEventCallbackId,
|
|
432
|
+
name: "testEnvironment.onEvent",
|
|
433
|
+
type: "sync"
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
testEnvironmentOption = {
|
|
437
|
+
callbacks: testEnvCallbacks,
|
|
438
|
+
testTimeout: testEnvOptions.testTimeout
|
|
439
|
+
};
|
|
440
|
+
} else {
|
|
441
|
+
testEnvironmentOption = true;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
196
444
|
const requestId = state.nextRequestId++;
|
|
197
445
|
const request = {
|
|
198
446
|
type: MessageType.CREATE_RUNTIME,
|
|
199
447
|
requestId,
|
|
200
448
|
options: {
|
|
201
|
-
|
|
202
|
-
|
|
449
|
+
memoryLimitMB: options.memoryLimitMB,
|
|
450
|
+
cwd: options.cwd,
|
|
451
|
+
callbacks,
|
|
452
|
+
testEnvironment: testEnvironmentOption
|
|
203
453
|
}
|
|
204
454
|
};
|
|
205
455
|
const result = await sendRequest(state, request);
|
|
206
456
|
const isolateId = result.isolateId;
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
457
|
+
const wsCommandCallbacks = new Set;
|
|
458
|
+
isolateWsCallbacks.set(isolateId, wsCommandCallbacks);
|
|
459
|
+
const fetchHandle = {
|
|
460
|
+
async dispatchRequest(req, opts) {
|
|
461
|
+
const reqId = state.nextRequestId++;
|
|
462
|
+
const serialized = await serializeRequestWithStreaming(state, req);
|
|
463
|
+
const { bodyStream, ...serializableRequest } = serialized;
|
|
464
|
+
const request2 = {
|
|
465
|
+
type: MessageType.DISPATCH_REQUEST,
|
|
466
|
+
requestId: reqId,
|
|
467
|
+
isolateId,
|
|
468
|
+
request: serializableRequest,
|
|
469
|
+
options: opts
|
|
470
|
+
};
|
|
471
|
+
const handleResponse = (res) => {
|
|
472
|
+
if (res.__streaming && res.response instanceof Response) {
|
|
473
|
+
return res.response;
|
|
474
|
+
}
|
|
475
|
+
return deserializeResponse(res.response);
|
|
476
|
+
};
|
|
477
|
+
if (serialized.bodyStreamId !== undefined && bodyStream) {
|
|
478
|
+
const streamId = serialized.bodyStreamId;
|
|
479
|
+
const responsePromise = sendRequest(state, request2, opts?.timeout ?? DEFAULT_TIMEOUT);
|
|
480
|
+
await sendBodyStream(state, streamId, bodyStream);
|
|
481
|
+
const res = await responsePromise;
|
|
482
|
+
return handleResponse(res);
|
|
483
|
+
} else {
|
|
484
|
+
const res = await sendRequest(state, request2, opts?.timeout ?? DEFAULT_TIMEOUT);
|
|
485
|
+
return handleResponse(res);
|
|
486
|
+
}
|
|
487
|
+
},
|
|
488
|
+
async getUpgradeRequest() {
|
|
210
489
|
const reqId = state.nextRequestId++;
|
|
211
490
|
const req = {
|
|
212
|
-
type: MessageType.
|
|
491
|
+
type: MessageType.FETCH_GET_UPGRADE_REQUEST,
|
|
492
|
+
requestId: reqId,
|
|
493
|
+
isolateId
|
|
494
|
+
};
|
|
495
|
+
return sendRequest(state, req);
|
|
496
|
+
},
|
|
497
|
+
async dispatchWebSocketOpen(connectionId) {
|
|
498
|
+
const reqId = state.nextRequestId++;
|
|
499
|
+
const req = {
|
|
500
|
+
type: MessageType.WS_OPEN,
|
|
213
501
|
requestId: reqId,
|
|
214
502
|
isolateId,
|
|
215
|
-
|
|
216
|
-
filename
|
|
503
|
+
connectionId
|
|
217
504
|
};
|
|
218
|
-
|
|
219
|
-
return res.value;
|
|
505
|
+
await sendRequest(state, req);
|
|
220
506
|
},
|
|
221
|
-
|
|
507
|
+
async dispatchWebSocketMessage(connectionId, message) {
|
|
222
508
|
const reqId = state.nextRequestId++;
|
|
223
|
-
const
|
|
509
|
+
const data = message instanceof ArrayBuffer ? new Uint8Array(message) : message;
|
|
224
510
|
const req = {
|
|
225
|
-
type: MessageType.
|
|
511
|
+
type: MessageType.WS_MESSAGE,
|
|
512
|
+
requestId: reqId,
|
|
513
|
+
isolateId,
|
|
514
|
+
connectionId,
|
|
515
|
+
data
|
|
516
|
+
};
|
|
517
|
+
await sendRequest(state, req);
|
|
518
|
+
},
|
|
519
|
+
async dispatchWebSocketClose(connectionId, code, reason) {
|
|
520
|
+
const reqId = state.nextRequestId++;
|
|
521
|
+
const req = {
|
|
522
|
+
type: MessageType.WS_CLOSE,
|
|
226
523
|
requestId: reqId,
|
|
227
524
|
isolateId,
|
|
228
|
-
|
|
229
|
-
|
|
525
|
+
connectionId,
|
|
526
|
+
code,
|
|
527
|
+
reason
|
|
230
528
|
};
|
|
231
|
-
|
|
232
|
-
return deserializeResponse(res.response);
|
|
529
|
+
await sendRequest(state, req);
|
|
233
530
|
},
|
|
234
|
-
|
|
531
|
+
async dispatchWebSocketError(connectionId, error) {
|
|
235
532
|
const reqId = state.nextRequestId++;
|
|
236
533
|
const req = {
|
|
237
|
-
type: MessageType.
|
|
534
|
+
type: MessageType.FETCH_WS_ERROR,
|
|
238
535
|
requestId: reqId,
|
|
239
536
|
isolateId,
|
|
240
|
-
|
|
537
|
+
connectionId,
|
|
538
|
+
error: error.message
|
|
241
539
|
};
|
|
242
540
|
await sendRequest(state, req);
|
|
243
541
|
},
|
|
244
|
-
|
|
542
|
+
onWebSocketCommand(callback) {
|
|
543
|
+
wsCommandCallbacks.add(callback);
|
|
544
|
+
return () => {
|
|
545
|
+
wsCommandCallbacks.delete(callback);
|
|
546
|
+
};
|
|
547
|
+
},
|
|
548
|
+
async hasServeHandler() {
|
|
549
|
+
const reqId = state.nextRequestId++;
|
|
550
|
+
const req = {
|
|
551
|
+
type: MessageType.FETCH_HAS_SERVE_HANDLER,
|
|
552
|
+
requestId: reqId,
|
|
553
|
+
isolateId
|
|
554
|
+
};
|
|
555
|
+
return sendRequest(state, req);
|
|
556
|
+
},
|
|
557
|
+
async hasActiveConnections() {
|
|
558
|
+
const reqId = state.nextRequestId++;
|
|
559
|
+
const req = {
|
|
560
|
+
type: MessageType.FETCH_HAS_ACTIVE_CONNECTIONS,
|
|
561
|
+
requestId: reqId,
|
|
562
|
+
isolateId
|
|
563
|
+
};
|
|
564
|
+
return sendRequest(state, req);
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
const timersHandle = {
|
|
568
|
+
async clearAll() {
|
|
569
|
+
const reqId = state.nextRequestId++;
|
|
570
|
+
const req = {
|
|
571
|
+
type: MessageType.TIMERS_CLEAR_ALL,
|
|
572
|
+
requestId: reqId,
|
|
573
|
+
isolateId
|
|
574
|
+
};
|
|
575
|
+
await sendRequest(state, req);
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
const consoleHandle = {
|
|
579
|
+
async reset() {
|
|
245
580
|
const reqId = state.nextRequestId++;
|
|
246
581
|
const req = {
|
|
247
|
-
type: MessageType.
|
|
582
|
+
type: MessageType.CONSOLE_RESET,
|
|
248
583
|
requestId: reqId,
|
|
249
584
|
isolateId
|
|
250
585
|
};
|
|
251
586
|
await sendRequest(state, req);
|
|
252
587
|
},
|
|
253
|
-
|
|
588
|
+
async getTimers() {
|
|
589
|
+
const reqId = state.nextRequestId++;
|
|
590
|
+
const req = {
|
|
591
|
+
type: MessageType.CONSOLE_GET_TIMERS,
|
|
592
|
+
requestId: reqId,
|
|
593
|
+
isolateId
|
|
594
|
+
};
|
|
595
|
+
const result2 = await sendRequest(state, req);
|
|
596
|
+
return new Map(Object.entries(result2));
|
|
597
|
+
},
|
|
598
|
+
async getCounters() {
|
|
599
|
+
const reqId = state.nextRequestId++;
|
|
600
|
+
const req = {
|
|
601
|
+
type: MessageType.CONSOLE_GET_COUNTERS,
|
|
602
|
+
requestId: reqId,
|
|
603
|
+
isolateId
|
|
604
|
+
};
|
|
605
|
+
const result2 = await sendRequest(state, req);
|
|
606
|
+
return new Map(Object.entries(result2));
|
|
607
|
+
},
|
|
608
|
+
async getGroupDepth() {
|
|
609
|
+
const reqId = state.nextRequestId++;
|
|
610
|
+
const req = {
|
|
611
|
+
type: MessageType.CONSOLE_GET_GROUP_DEPTH,
|
|
612
|
+
requestId: reqId,
|
|
613
|
+
isolateId
|
|
614
|
+
};
|
|
615
|
+
return sendRequest(state, req);
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
const testEnvironmentEnabled = !!options.testEnvironment;
|
|
619
|
+
const playwrightEnabled = !!options.playwright;
|
|
620
|
+
const testEnvironmentHandle = {
|
|
621
|
+
async runTests(timeout) {
|
|
622
|
+
if (!testEnvironmentEnabled) {
|
|
623
|
+
throw new Error("Test environment not enabled. Set testEnvironment: true in createRuntime options.");
|
|
624
|
+
}
|
|
254
625
|
const reqId = state.nextRequestId++;
|
|
255
626
|
const req = {
|
|
256
627
|
type: MessageType.RUN_TESTS,
|
|
@@ -260,47 +631,48 @@ async function createRuntime(state, options = {}) {
|
|
|
260
631
|
};
|
|
261
632
|
return sendRequest(state, req, timeout ?? DEFAULT_TIMEOUT);
|
|
262
633
|
},
|
|
263
|
-
|
|
634
|
+
async hasTests() {
|
|
635
|
+
if (!testEnvironmentEnabled) {
|
|
636
|
+
throw new Error("Test environment not enabled. Set testEnvironment: true in createRuntime options.");
|
|
637
|
+
}
|
|
264
638
|
const reqId = state.nextRequestId++;
|
|
265
639
|
const req = {
|
|
266
|
-
type: MessageType.
|
|
640
|
+
type: MessageType.HAS_TESTS,
|
|
267
641
|
requestId: reqId,
|
|
268
|
-
isolateId
|
|
269
|
-
options: {
|
|
270
|
-
browserType: playwrightOptions?.browserType,
|
|
271
|
-
headless: playwrightOptions?.headless,
|
|
272
|
-
baseURL: playwrightOptions?.baseURL
|
|
273
|
-
}
|
|
642
|
+
isolateId
|
|
274
643
|
};
|
|
275
|
-
|
|
276
|
-
state.playwrightEventHandlers.set(isolateId, {
|
|
277
|
-
onConsoleLog: playwrightOptions.onConsoleLog,
|
|
278
|
-
onNetworkRequest: playwrightOptions.onNetworkRequest,
|
|
279
|
-
onNetworkResponse: playwrightOptions.onNetworkResponse
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
await sendRequest(state, req);
|
|
644
|
+
return sendRequest(state, req);
|
|
283
645
|
},
|
|
284
|
-
|
|
646
|
+
async getTestCount() {
|
|
647
|
+
if (!testEnvironmentEnabled) {
|
|
648
|
+
throw new Error("Test environment not enabled. Set testEnvironment: true in createRuntime options.");
|
|
649
|
+
}
|
|
285
650
|
const reqId = state.nextRequestId++;
|
|
286
651
|
const req = {
|
|
287
|
-
type: MessageType.
|
|
652
|
+
type: MessageType.GET_TEST_COUNT,
|
|
288
653
|
requestId: reqId,
|
|
289
|
-
isolateId
|
|
290
|
-
timeout
|
|
654
|
+
isolateId
|
|
291
655
|
};
|
|
292
|
-
return sendRequest(state, req
|
|
656
|
+
return sendRequest(state, req);
|
|
293
657
|
},
|
|
294
|
-
|
|
658
|
+
async reset() {
|
|
659
|
+
if (!testEnvironmentEnabled) {
|
|
660
|
+
throw new Error("Test environment not enabled. Set testEnvironment: true in createRuntime options.");
|
|
661
|
+
}
|
|
295
662
|
const reqId = state.nextRequestId++;
|
|
296
663
|
const req = {
|
|
297
|
-
type: MessageType.
|
|
664
|
+
type: MessageType.RESET_TEST_ENV,
|
|
298
665
|
requestId: reqId,
|
|
299
666
|
isolateId
|
|
300
667
|
};
|
|
301
668
|
await sendRequest(state, req);
|
|
302
|
-
}
|
|
303
|
-
|
|
669
|
+
}
|
|
670
|
+
};
|
|
671
|
+
const playwrightHandle = {
|
|
672
|
+
async getCollectedData() {
|
|
673
|
+
if (!playwrightEnabled) {
|
|
674
|
+
throw new Error("Playwright not configured. Provide playwright.page in createRuntime options.");
|
|
675
|
+
}
|
|
304
676
|
const reqId = state.nextRequestId++;
|
|
305
677
|
const req = {
|
|
306
678
|
type: MessageType.GET_COLLECTED_DATA,
|
|
@@ -309,8 +681,43 @@ async function createRuntime(state, options = {}) {
|
|
|
309
681
|
};
|
|
310
682
|
return sendRequest(state, req);
|
|
311
683
|
},
|
|
684
|
+
async clearCollectedData() {
|
|
685
|
+
if (!playwrightEnabled) {
|
|
686
|
+
throw new Error("Playwright not configured. Provide playwright.page in createRuntime options.");
|
|
687
|
+
}
|
|
688
|
+
const reqId = state.nextRequestId++;
|
|
689
|
+
const req = {
|
|
690
|
+
type: MessageType.CLEAR_COLLECTED_DATA,
|
|
691
|
+
requestId: reqId,
|
|
692
|
+
isolateId
|
|
693
|
+
};
|
|
694
|
+
await sendRequest(state, req);
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
return {
|
|
698
|
+
id: isolateId,
|
|
699
|
+
isolateId,
|
|
700
|
+
fetch: fetchHandle,
|
|
701
|
+
timers: timersHandle,
|
|
702
|
+
console: consoleHandle,
|
|
703
|
+
testEnvironment: testEnvironmentHandle,
|
|
704
|
+
playwright: playwrightHandle,
|
|
705
|
+
eval: async (code, filenameOrOptions) => {
|
|
706
|
+
const reqId = state.nextRequestId++;
|
|
707
|
+
const options2 = typeof filenameOrOptions === "string" ? { filename: filenameOrOptions } : filenameOrOptions;
|
|
708
|
+
const req = {
|
|
709
|
+
type: MessageType.EVAL,
|
|
710
|
+
requestId: reqId,
|
|
711
|
+
isolateId,
|
|
712
|
+
code,
|
|
713
|
+
filename: options2?.filename,
|
|
714
|
+
maxExecutionMs: options2?.maxExecutionMs,
|
|
715
|
+
module: true
|
|
716
|
+
};
|
|
717
|
+
await sendRequest(state, req);
|
|
718
|
+
},
|
|
312
719
|
dispose: async () => {
|
|
313
|
-
|
|
720
|
+
isolateWsCallbacks.delete(isolateId);
|
|
314
721
|
const reqId = state.nextRequestId++;
|
|
315
722
|
const req = {
|
|
316
723
|
type: MessageType.DISPOSE_RUNTIME,
|
|
@@ -321,27 +728,23 @@ async function createRuntime(state, options = {}) {
|
|
|
321
728
|
}
|
|
322
729
|
};
|
|
323
730
|
}
|
|
731
|
+
function registerEventCallback(state, handler) {
|
|
732
|
+
const callbackId = state.nextCallbackId++;
|
|
733
|
+
state.callbacks.set(callbackId, (data) => {
|
|
734
|
+
handler(data);
|
|
735
|
+
return;
|
|
736
|
+
});
|
|
737
|
+
return callbackId;
|
|
738
|
+
}
|
|
324
739
|
function registerConsoleCallbacks(state, callbacks) {
|
|
325
740
|
const registrations = {};
|
|
326
|
-
|
|
741
|
+
if (callbacks.onEntry) {
|
|
327
742
|
const callbackId = state.nextCallbackId++;
|
|
328
|
-
state.callbacks.set(callbackId, (
|
|
329
|
-
|
|
743
|
+
state.callbacks.set(callbackId, (entry) => {
|
|
744
|
+
callbacks.onEntry(entry);
|
|
330
745
|
});
|
|
331
|
-
registrations
|
|
332
|
-
}
|
|
333
|
-
if (callbacks.log)
|
|
334
|
-
register("log", callbacks.log);
|
|
335
|
-
if (callbacks.warn)
|
|
336
|
-
register("warn", callbacks.warn);
|
|
337
|
-
if (callbacks.error)
|
|
338
|
-
register("error", callbacks.error);
|
|
339
|
-
if (callbacks.info)
|
|
340
|
-
register("info", callbacks.info);
|
|
341
|
-
if (callbacks.debug)
|
|
342
|
-
register("debug", callbacks.debug);
|
|
343
|
-
if (callbacks.dir)
|
|
344
|
-
register("dir", callbacks.dir);
|
|
746
|
+
registrations.onEntry = { callbackId, name: "onEntry", type: "sync" };
|
|
747
|
+
}
|
|
345
748
|
return registrations;
|
|
346
749
|
}
|
|
347
750
|
function registerFetchCallback(state, callback) {
|
|
@@ -351,7 +754,7 @@ function registerFetchCallback(state, callback) {
|
|
|
351
754
|
const response = await callback(request);
|
|
352
755
|
return serializeResponse(response);
|
|
353
756
|
});
|
|
354
|
-
return { callbackId, name: "fetch",
|
|
757
|
+
return { callbackId, name: "fetch", type: "async" };
|
|
355
758
|
}
|
|
356
759
|
function registerFsCallbacks(state, callbacks) {
|
|
357
760
|
const registrations = {};
|
|
@@ -361,7 +764,7 @@ function registerFsCallbacks(state, callbacks) {
|
|
|
361
764
|
const result = await callbacks.readFile(path);
|
|
362
765
|
return new Uint8Array(result);
|
|
363
766
|
});
|
|
364
|
-
registrations.readFile = { callbackId, name: "readFile",
|
|
767
|
+
registrations.readFile = { callbackId, name: "readFile", type: "async" };
|
|
365
768
|
}
|
|
366
769
|
if (callbacks.writeFile) {
|
|
367
770
|
const callbackId = state.nextCallbackId++;
|
|
@@ -378,67 +781,251 @@ function registerFsCallbacks(state, callbacks) {
|
|
|
378
781
|
}
|
|
379
782
|
await callbacks.writeFile(path, buffer);
|
|
380
783
|
});
|
|
381
|
-
registrations.writeFile = { callbackId, name: "writeFile",
|
|
784
|
+
registrations.writeFile = { callbackId, name: "writeFile", type: "async" };
|
|
382
785
|
}
|
|
383
786
|
if (callbacks.unlink) {
|
|
384
787
|
const callbackId = state.nextCallbackId++;
|
|
385
788
|
state.callbacks.set(callbackId, async (path) => {
|
|
386
789
|
await callbacks.unlink(path);
|
|
387
790
|
});
|
|
388
|
-
registrations.unlink = { callbackId, name: "unlink",
|
|
791
|
+
registrations.unlink = { callbackId, name: "unlink", type: "async" };
|
|
389
792
|
}
|
|
390
793
|
if (callbacks.readdir) {
|
|
391
794
|
const callbackId = state.nextCallbackId++;
|
|
392
795
|
state.callbacks.set(callbackId, async (path) => {
|
|
393
796
|
return callbacks.readdir(path);
|
|
394
797
|
});
|
|
395
|
-
registrations.readdir = { callbackId, name: "readdir",
|
|
798
|
+
registrations.readdir = { callbackId, name: "readdir", type: "async" };
|
|
396
799
|
}
|
|
397
800
|
if (callbacks.mkdir) {
|
|
398
801
|
const callbackId = state.nextCallbackId++;
|
|
399
802
|
state.callbacks.set(callbackId, async (path, options) => {
|
|
400
803
|
await callbacks.mkdir(path, options);
|
|
401
804
|
});
|
|
402
|
-
registrations.mkdir = { callbackId, name: "mkdir",
|
|
805
|
+
registrations.mkdir = { callbackId, name: "mkdir", type: "async" };
|
|
403
806
|
}
|
|
404
807
|
if (callbacks.rmdir) {
|
|
405
808
|
const callbackId = state.nextCallbackId++;
|
|
406
809
|
state.callbacks.set(callbackId, async (path) => {
|
|
407
810
|
await callbacks.rmdir(path);
|
|
408
811
|
});
|
|
409
|
-
registrations.rmdir = { callbackId, name: "rmdir",
|
|
812
|
+
registrations.rmdir = { callbackId, name: "rmdir", type: "async" };
|
|
410
813
|
}
|
|
411
814
|
if (callbacks.stat) {
|
|
412
815
|
const callbackId = state.nextCallbackId++;
|
|
413
816
|
state.callbacks.set(callbackId, async (path) => {
|
|
414
817
|
return callbacks.stat(path);
|
|
415
818
|
});
|
|
416
|
-
registrations.stat = { callbackId, name: "stat",
|
|
819
|
+
registrations.stat = { callbackId, name: "stat", type: "async" };
|
|
417
820
|
}
|
|
418
821
|
if (callbacks.rename) {
|
|
419
822
|
const callbackId = state.nextCallbackId++;
|
|
420
823
|
state.callbacks.set(callbackId, async (from, to) => {
|
|
421
824
|
await callbacks.rename(from, to);
|
|
422
825
|
});
|
|
423
|
-
registrations.rename = { callbackId, name: "rename",
|
|
826
|
+
registrations.rename = { callbackId, name: "rename", type: "async" };
|
|
424
827
|
}
|
|
425
828
|
return registrations;
|
|
426
829
|
}
|
|
427
|
-
|
|
428
|
-
const
|
|
429
|
-
|
|
430
|
-
|
|
830
|
+
function registerModuleLoaderCallback(state, callback) {
|
|
831
|
+
const callbackId = state.nextCallbackId++;
|
|
832
|
+
state.callbacks.set(callbackId, async (moduleName) => {
|
|
833
|
+
return callback(moduleName);
|
|
431
834
|
});
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
835
|
+
return { callbackId, name: "moduleLoader", type: "async" };
|
|
836
|
+
}
|
|
837
|
+
var clientIteratorSessions = new Map;
|
|
838
|
+
var nextClientIteratorId = 1;
|
|
839
|
+
var returnedPromiseRegistry = new Map;
|
|
840
|
+
var returnedIteratorRegistry = new Map;
|
|
841
|
+
function isPromiseRef(value) {
|
|
842
|
+
return typeof value === "object" && value !== null && value.__type === "PromiseRef";
|
|
843
|
+
}
|
|
844
|
+
function isAsyncIteratorRef(value) {
|
|
845
|
+
return typeof value === "object" && value !== null && value.__type === "AsyncIteratorRef";
|
|
846
|
+
}
|
|
847
|
+
function registerCustomFunctions(state, customFunctions) {
|
|
848
|
+
const registrations = {};
|
|
849
|
+
for (const [name, def] of Object.entries(customFunctions)) {
|
|
850
|
+
if (def.type === "asyncIterator") {
|
|
851
|
+
const startCallbackId = state.nextCallbackId++;
|
|
852
|
+
state.callbacks.set(startCallbackId, async (...args) => {
|
|
853
|
+
try {
|
|
854
|
+
const fn = def.fn;
|
|
855
|
+
const iterator = fn(...args);
|
|
856
|
+
const iteratorId = nextClientIteratorId++;
|
|
857
|
+
clientIteratorSessions.set(iteratorId, { iterator });
|
|
858
|
+
return { iteratorId };
|
|
859
|
+
} catch (error) {
|
|
860
|
+
throw error;
|
|
861
|
+
}
|
|
862
|
+
});
|
|
863
|
+
const nextCallbackId = state.nextCallbackId++;
|
|
864
|
+
state.callbacks.set(nextCallbackId, async (iteratorId) => {
|
|
865
|
+
const session = clientIteratorSessions.get(iteratorId);
|
|
866
|
+
if (!session) {
|
|
867
|
+
throw new Error(`Iterator session ${iteratorId} not found`);
|
|
868
|
+
}
|
|
869
|
+
try {
|
|
870
|
+
const result = await session.iterator.next();
|
|
871
|
+
if (result.done) {
|
|
872
|
+
clientIteratorSessions.delete(iteratorId);
|
|
873
|
+
}
|
|
874
|
+
return { done: result.done, value: await marshalValue(result.value) };
|
|
875
|
+
} catch (error) {
|
|
876
|
+
clientIteratorSessions.delete(iteratorId);
|
|
877
|
+
throw error;
|
|
878
|
+
}
|
|
879
|
+
});
|
|
880
|
+
const returnCallbackId = state.nextCallbackId++;
|
|
881
|
+
state.callbacks.set(returnCallbackId, async (iteratorId, value) => {
|
|
882
|
+
const session = clientIteratorSessions.get(iteratorId);
|
|
883
|
+
if (!session) {
|
|
884
|
+
return { done: true, value: await marshalValue(undefined) };
|
|
885
|
+
}
|
|
886
|
+
try {
|
|
887
|
+
const result = await session.iterator.return?.(value);
|
|
888
|
+
clientIteratorSessions.delete(iteratorId);
|
|
889
|
+
return { done: true, value: await marshalValue(result?.value) };
|
|
890
|
+
} catch (error) {
|
|
891
|
+
clientIteratorSessions.delete(iteratorId);
|
|
892
|
+
throw error;
|
|
893
|
+
}
|
|
894
|
+
});
|
|
895
|
+
const throwCallbackId = state.nextCallbackId++;
|
|
896
|
+
state.callbacks.set(throwCallbackId, async (iteratorId, errorData) => {
|
|
897
|
+
const session = clientIteratorSessions.get(iteratorId);
|
|
898
|
+
if (!session) {
|
|
899
|
+
throw new Error(`Iterator session ${iteratorId} not found`);
|
|
900
|
+
}
|
|
901
|
+
try {
|
|
902
|
+
const errInfo = errorData;
|
|
903
|
+
const error = Object.assign(new Error(errInfo.message), { name: errInfo.name });
|
|
904
|
+
const result = await session.iterator.throw?.(error);
|
|
905
|
+
clientIteratorSessions.delete(iteratorId);
|
|
906
|
+
return { done: result?.done ?? true, value: await marshalValue(result?.value) };
|
|
907
|
+
} catch (error) {
|
|
908
|
+
clientIteratorSessions.delete(iteratorId);
|
|
909
|
+
throw error;
|
|
910
|
+
}
|
|
911
|
+
});
|
|
912
|
+
registrations[`${name}:start`] = { callbackId: startCallbackId, name: `${name}:start`, type: "async" };
|
|
913
|
+
registrations[`${name}:next`] = { callbackId: nextCallbackId, name: `${name}:next`, type: "async" };
|
|
914
|
+
registrations[`${name}:return`] = { callbackId: returnCallbackId, name: `${name}:return`, type: "async" };
|
|
915
|
+
registrations[`${name}:throw`] = { callbackId: throwCallbackId, name: `${name}:throw`, type: "async" };
|
|
916
|
+
registrations[name] = {
|
|
917
|
+
callbackId: startCallbackId,
|
|
918
|
+
name,
|
|
919
|
+
type: "asyncIterator"
|
|
920
|
+
};
|
|
921
|
+
} else {
|
|
922
|
+
const callbackId = state.nextCallbackId++;
|
|
923
|
+
state.callbacks.set(callbackId, async (...args) => {
|
|
924
|
+
const result = await def.fn(...args);
|
|
925
|
+
const addCallbackIdsToRefs = (value) => {
|
|
926
|
+
if (value === null || typeof value !== "object") {
|
|
927
|
+
return value;
|
|
928
|
+
}
|
|
929
|
+
if (isPromiseRef(value)) {
|
|
930
|
+
const resolveCallbackId = state.nextCallbackId++;
|
|
931
|
+
state.callbacks.set(resolveCallbackId, async (...args2) => {
|
|
932
|
+
const promiseId = args2[0];
|
|
933
|
+
const promise = returnedPromiseRegistry.get(promiseId);
|
|
934
|
+
if (!promise) {
|
|
935
|
+
throw new Error(`Promise ${promiseId} not found`);
|
|
936
|
+
}
|
|
937
|
+
const promiseResult = await promise;
|
|
938
|
+
returnedPromiseRegistry.delete(promiseId);
|
|
939
|
+
const marshalledResult = await marshalValue(promiseResult, marshalCtx);
|
|
940
|
+
return addCallbackIdsToRefs(marshalledResult);
|
|
941
|
+
});
|
|
942
|
+
return {
|
|
943
|
+
...value,
|
|
944
|
+
__resolveCallbackId: resolveCallbackId
|
|
945
|
+
};
|
|
946
|
+
}
|
|
947
|
+
if (isAsyncIteratorRef(value)) {
|
|
948
|
+
const nextCallbackId = state.nextCallbackId++;
|
|
949
|
+
state.callbacks.set(nextCallbackId, async (...args2) => {
|
|
950
|
+
const iteratorId = args2[0];
|
|
951
|
+
const iterator = returnedIteratorRegistry.get(iteratorId);
|
|
952
|
+
if (!iterator) {
|
|
953
|
+
throw new Error(`Iterator ${iteratorId} not found`);
|
|
954
|
+
}
|
|
955
|
+
const iterResult = await iterator.next();
|
|
956
|
+
if (iterResult.done) {
|
|
957
|
+
returnedIteratorRegistry.delete(iteratorId);
|
|
958
|
+
}
|
|
959
|
+
const marshalledValue = await marshalValue(iterResult.value, marshalCtx);
|
|
960
|
+
return {
|
|
961
|
+
done: iterResult.done,
|
|
962
|
+
value: addCallbackIdsToRefs(marshalledValue)
|
|
963
|
+
};
|
|
964
|
+
});
|
|
965
|
+
const returnCallbackId = state.nextCallbackId++;
|
|
966
|
+
state.callbacks.set(returnCallbackId, async (...args2) => {
|
|
967
|
+
const iteratorId = args2[0];
|
|
968
|
+
const returnValue = args2[1];
|
|
969
|
+
const iterator = returnedIteratorRegistry.get(iteratorId);
|
|
970
|
+
returnedIteratorRegistry.delete(iteratorId);
|
|
971
|
+
if (!iterator || !iterator.return) {
|
|
972
|
+
return { done: true, value: undefined };
|
|
973
|
+
}
|
|
974
|
+
const iterResult = await iterator.return(returnValue);
|
|
975
|
+
const marshalledValue = await marshalValue(iterResult.value, marshalCtx);
|
|
976
|
+
return {
|
|
977
|
+
done: true,
|
|
978
|
+
value: addCallbackIdsToRefs(marshalledValue)
|
|
979
|
+
};
|
|
980
|
+
});
|
|
981
|
+
return {
|
|
982
|
+
...value,
|
|
983
|
+
__nextCallbackId: nextCallbackId,
|
|
984
|
+
__returnCallbackId: returnCallbackId
|
|
985
|
+
};
|
|
986
|
+
}
|
|
987
|
+
if (Array.isArray(value)) {
|
|
988
|
+
return value.map((item) => addCallbackIdsToRefs(item));
|
|
989
|
+
}
|
|
990
|
+
const objResult = {};
|
|
991
|
+
for (const key of Object.keys(value)) {
|
|
992
|
+
objResult[key] = addCallbackIdsToRefs(value[key]);
|
|
993
|
+
}
|
|
994
|
+
return objResult;
|
|
995
|
+
};
|
|
996
|
+
const marshalCtx = {
|
|
997
|
+
registerCallback: (fn) => {
|
|
998
|
+
const returnedCallbackId = state.nextCallbackId++;
|
|
999
|
+
state.callbacks.set(returnedCallbackId, async (...args2) => {
|
|
1000
|
+
const fnResult = await fn(...args2);
|
|
1001
|
+
const marshalledResult = await marshalValue(fnResult, marshalCtx);
|
|
1002
|
+
return addCallbackIdsToRefs(marshalledResult);
|
|
1003
|
+
});
|
|
1004
|
+
return returnedCallbackId;
|
|
1005
|
+
},
|
|
1006
|
+
registerPromise: (promise) => {
|
|
1007
|
+
const promiseId = state.nextCallbackId++;
|
|
1008
|
+
returnedPromiseRegistry.set(promiseId, promise);
|
|
1009
|
+
return promiseId;
|
|
1010
|
+
},
|
|
1011
|
+
registerIterator: (iterator) => {
|
|
1012
|
+
const iteratorId = state.nextCallbackId++;
|
|
1013
|
+
returnedIteratorRegistry.set(iteratorId, iterator);
|
|
1014
|
+
return iteratorId;
|
|
1015
|
+
}
|
|
1016
|
+
};
|
|
1017
|
+
const marshalled = await marshalValue(result, marshalCtx);
|
|
1018
|
+
const withCallbackIds = addCallbackIdsToRefs(marshalled);
|
|
1019
|
+
return withCallbackIds;
|
|
1020
|
+
});
|
|
1021
|
+
registrations[name] = {
|
|
1022
|
+
callbackId,
|
|
1023
|
+
name,
|
|
1024
|
+
type: def.type
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
435
1027
|
}
|
|
436
|
-
return
|
|
437
|
-
method: request.method,
|
|
438
|
-
url: request.url,
|
|
439
|
-
headers,
|
|
440
|
-
body
|
|
441
|
-
};
|
|
1028
|
+
return registrations;
|
|
442
1029
|
}
|
|
443
1030
|
async function serializeResponse(response) {
|
|
444
1031
|
const headers = [];
|
|
@@ -470,8 +1057,106 @@ function deserializeResponse(data) {
|
|
|
470
1057
|
headers: data.headers
|
|
471
1058
|
});
|
|
472
1059
|
}
|
|
1060
|
+
async function serializeRequestWithStreaming(state, request) {
|
|
1061
|
+
const headers = [];
|
|
1062
|
+
request.headers.forEach((value, key) => {
|
|
1063
|
+
headers.push([key, value]);
|
|
1064
|
+
});
|
|
1065
|
+
let body = null;
|
|
1066
|
+
let bodyStreamId;
|
|
1067
|
+
let bodyStream;
|
|
1068
|
+
if (request.body) {
|
|
1069
|
+
const contentLength = request.headers.get("content-length");
|
|
1070
|
+
const knownSize = contentLength ? parseInt(contentLength, 10) : null;
|
|
1071
|
+
if (knownSize !== null && knownSize > STREAM_THRESHOLD) {
|
|
1072
|
+
bodyStreamId = state.nextStreamId++;
|
|
1073
|
+
bodyStream = request.body;
|
|
1074
|
+
} else {
|
|
1075
|
+
const clonedRequest = request.clone();
|
|
1076
|
+
try {
|
|
1077
|
+
body = new Uint8Array(await request.arrayBuffer());
|
|
1078
|
+
if (body.length > STREAM_THRESHOLD) {
|
|
1079
|
+
bodyStreamId = state.nextStreamId++;
|
|
1080
|
+
bodyStream = clonedRequest.body;
|
|
1081
|
+
body = null;
|
|
1082
|
+
}
|
|
1083
|
+
} catch {
|
|
1084
|
+
bodyStreamId = state.nextStreamId++;
|
|
1085
|
+
bodyStream = clonedRequest.body;
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
const result = {
|
|
1090
|
+
method: request.method,
|
|
1091
|
+
url: request.url,
|
|
1092
|
+
headers,
|
|
1093
|
+
body
|
|
1094
|
+
};
|
|
1095
|
+
if (bodyStreamId !== undefined) {
|
|
1096
|
+
result.bodyStreamId = bodyStreamId;
|
|
1097
|
+
result.bodyStream = bodyStream;
|
|
1098
|
+
}
|
|
1099
|
+
return result;
|
|
1100
|
+
}
|
|
1101
|
+
function waitForUploadCredit(session) {
|
|
1102
|
+
return new Promise((resolve) => {
|
|
1103
|
+
session.creditResolver = resolve;
|
|
1104
|
+
});
|
|
1105
|
+
}
|
|
1106
|
+
async function sendBodyStream(state, streamId, body) {
|
|
1107
|
+
const session = {
|
|
1108
|
+
streamId,
|
|
1109
|
+
requestId: 0,
|
|
1110
|
+
state: "active",
|
|
1111
|
+
bytesTransferred: 0,
|
|
1112
|
+
credit: 0
|
|
1113
|
+
};
|
|
1114
|
+
state.uploadStreams.set(streamId, session);
|
|
1115
|
+
const reader = body.getReader();
|
|
1116
|
+
try {
|
|
1117
|
+
while (true) {
|
|
1118
|
+
if (session.state !== "active") {
|
|
1119
|
+
throw new Error("Stream cancelled");
|
|
1120
|
+
}
|
|
1121
|
+
while (session.credit < STREAM_CHUNK_SIZE && session.state === "active") {
|
|
1122
|
+
await waitForUploadCredit(session);
|
|
1123
|
+
}
|
|
1124
|
+
if (session.state !== "active") {
|
|
1125
|
+
throw new Error("Stream cancelled");
|
|
1126
|
+
}
|
|
1127
|
+
const { done, value } = await reader.read();
|
|
1128
|
+
if (done) {
|
|
1129
|
+
sendMessage(state.socket, {
|
|
1130
|
+
type: MessageType.STREAM_CLOSE,
|
|
1131
|
+
streamId
|
|
1132
|
+
});
|
|
1133
|
+
break;
|
|
1134
|
+
}
|
|
1135
|
+
for (let offset = 0;offset < value.length; offset += STREAM_CHUNK_SIZE) {
|
|
1136
|
+
const chunk = value.slice(offset, offset + STREAM_CHUNK_SIZE);
|
|
1137
|
+
sendMessage(state.socket, {
|
|
1138
|
+
type: MessageType.STREAM_PUSH,
|
|
1139
|
+
streamId,
|
|
1140
|
+
chunk
|
|
1141
|
+
});
|
|
1142
|
+
session.credit -= chunk.length;
|
|
1143
|
+
session.bytesTransferred += chunk.length;
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
} catch (err) {
|
|
1147
|
+
sendMessage(state.socket, {
|
|
1148
|
+
type: MessageType.STREAM_ERROR,
|
|
1149
|
+
streamId,
|
|
1150
|
+
error: err.message
|
|
1151
|
+
});
|
|
1152
|
+
throw err;
|
|
1153
|
+
} finally {
|
|
1154
|
+
reader.releaseLock();
|
|
1155
|
+
state.uploadStreams.delete(streamId);
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
473
1158
|
export {
|
|
474
1159
|
connect
|
|
475
1160
|
};
|
|
476
1161
|
|
|
477
|
-
//# debugId=
|
|
1162
|
+
//# debugId=2BAB1C12EE66984164756E2164756E21
|