@ricsam/isolate-client 0.1.4 → 0.1.6
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 +89 -0
- package/dist/cjs/connection.cjs +146 -49
- 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 +145 -48
- 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 +14 -0
- package/package.json +1 -1
package/dist/mjs/connection.mjs
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
STREAM_DEFAULT_CREDIT,
|
|
11
11
|
marshalValue
|
|
12
12
|
} from "@ricsam/isolate-protocol";
|
|
13
|
-
import { createPlaywrightHandler } from "@ricsam/isolate-playwright";
|
|
13
|
+
import { createPlaywrightHandler } from "@ricsam/isolate-playwright/client";
|
|
14
14
|
var DEFAULT_TIMEOUT = 30000;
|
|
15
15
|
var isolateWsCallbacks = new Map;
|
|
16
16
|
async function connect(options = {}) {
|
|
@@ -24,7 +24,8 @@ async function connect(options = {}) {
|
|
|
24
24
|
nextStreamId: 1,
|
|
25
25
|
connected: true,
|
|
26
26
|
streamResponses: new Map,
|
|
27
|
-
uploadStreams: new Map
|
|
27
|
+
uploadStreams: new Map,
|
|
28
|
+
moduleSourceCache: new Map
|
|
28
29
|
};
|
|
29
30
|
const parser = createFrameParser();
|
|
30
31
|
socket.on("data", (data) => {
|
|
@@ -39,15 +40,38 @@ async function connect(options = {}) {
|
|
|
39
40
|
socket.on("close", () => {
|
|
40
41
|
state.connected = false;
|
|
41
42
|
for (const [, pending] of state.pendingRequests) {
|
|
43
|
+
if (pending.timeoutId) {
|
|
44
|
+
clearTimeout(pending.timeoutId);
|
|
45
|
+
}
|
|
42
46
|
pending.reject(new Error("Connection closed"));
|
|
43
47
|
}
|
|
44
48
|
state.pendingRequests.clear();
|
|
49
|
+
for (const [, receiver] of state.streamResponses) {
|
|
50
|
+
receiver.state = "errored";
|
|
51
|
+
receiver.error = new Error("Connection closed");
|
|
52
|
+
const resolvers = receiver.pullResolvers.splice(0);
|
|
53
|
+
for (const resolver of resolvers) {
|
|
54
|
+
resolver();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
state.streamResponses.clear();
|
|
58
|
+
for (const [, session] of state.uploadStreams) {
|
|
59
|
+
session.state = "closed";
|
|
60
|
+
if (session.creditResolver) {
|
|
61
|
+
session.creditResolver();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
state.uploadStreams.clear();
|
|
45
65
|
});
|
|
46
66
|
socket.on("error", (err) => {
|
|
47
67
|
console.error("Socket error:", err);
|
|
48
68
|
});
|
|
49
69
|
return {
|
|
50
70
|
createRuntime: (runtimeOptions) => createRuntime(state, runtimeOptions),
|
|
71
|
+
createNamespace: (id) => ({
|
|
72
|
+
id,
|
|
73
|
+
createRuntime: (runtimeOptions) => createRuntime(state, runtimeOptions, id)
|
|
74
|
+
}),
|
|
51
75
|
close: async () => {
|
|
52
76
|
state.connected = false;
|
|
53
77
|
socket.destroy();
|
|
@@ -148,10 +172,76 @@ function handleMessage(message, state) {
|
|
|
148
172
|
streamId: msg.streamId,
|
|
149
173
|
requestId: msg.requestId,
|
|
150
174
|
metadata: msg.metadata,
|
|
151
|
-
|
|
152
|
-
|
|
175
|
+
controller: null,
|
|
176
|
+
state: "active",
|
|
177
|
+
pendingChunks: [],
|
|
178
|
+
pullResolvers: [],
|
|
179
|
+
controllerFinalized: false
|
|
153
180
|
};
|
|
181
|
+
const readableStream = new ReadableStream({
|
|
182
|
+
start(controller) {
|
|
183
|
+
receiver.controller = controller;
|
|
184
|
+
},
|
|
185
|
+
pull(_controller) {
|
|
186
|
+
if (receiver.controllerFinalized) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
while (receiver.pendingChunks.length > 0) {
|
|
190
|
+
const chunk = receiver.pendingChunks.shift();
|
|
191
|
+
receiver.controller.enqueue(chunk);
|
|
192
|
+
}
|
|
193
|
+
if (receiver.state === "closed") {
|
|
194
|
+
if (!receiver.controllerFinalized) {
|
|
195
|
+
receiver.controllerFinalized = true;
|
|
196
|
+
receiver.controller.close();
|
|
197
|
+
}
|
|
198
|
+
return Promise.resolve();
|
|
199
|
+
}
|
|
200
|
+
if (receiver.state === "errored") {
|
|
201
|
+
if (!receiver.controllerFinalized && receiver.error) {
|
|
202
|
+
receiver.controllerFinalized = true;
|
|
203
|
+
receiver.controller.error(receiver.error);
|
|
204
|
+
}
|
|
205
|
+
return Promise.resolve();
|
|
206
|
+
}
|
|
207
|
+
sendMessage(state.socket, {
|
|
208
|
+
type: MessageType.STREAM_PULL,
|
|
209
|
+
streamId: msg.streamId,
|
|
210
|
+
maxBytes: STREAM_DEFAULT_CREDIT
|
|
211
|
+
});
|
|
212
|
+
return new Promise((resolve) => {
|
|
213
|
+
receiver.pullResolvers.push(resolve);
|
|
214
|
+
});
|
|
215
|
+
},
|
|
216
|
+
cancel(_reason) {
|
|
217
|
+
receiver.state = "closed";
|
|
218
|
+
receiver.controllerFinalized = true;
|
|
219
|
+
const resolvers = receiver.pullResolvers.splice(0);
|
|
220
|
+
for (const resolver of resolvers) {
|
|
221
|
+
resolver();
|
|
222
|
+
}
|
|
223
|
+
sendMessage(state.socket, {
|
|
224
|
+
type: MessageType.STREAM_ERROR,
|
|
225
|
+
streamId: msg.streamId,
|
|
226
|
+
error: "Stream cancelled by consumer"
|
|
227
|
+
});
|
|
228
|
+
state.streamResponses.delete(msg.streamId);
|
|
229
|
+
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
230
|
+
}
|
|
231
|
+
});
|
|
154
232
|
state.streamResponses.set(msg.streamId, receiver);
|
|
233
|
+
const pending = state.pendingRequests.get(msg.requestId);
|
|
234
|
+
if (pending) {
|
|
235
|
+
state.pendingRequests.delete(msg.requestId);
|
|
236
|
+
if (pending.timeoutId)
|
|
237
|
+
clearTimeout(pending.timeoutId);
|
|
238
|
+
const response = new Response(readableStream, {
|
|
239
|
+
status: msg.metadata?.status ?? 200,
|
|
240
|
+
statusText: msg.metadata?.statusText ?? "OK",
|
|
241
|
+
headers: msg.metadata?.headers
|
|
242
|
+
});
|
|
243
|
+
pending.resolve({ response, __streaming: true });
|
|
244
|
+
}
|
|
155
245
|
sendMessage(state.socket, {
|
|
156
246
|
type: MessageType.STREAM_PULL,
|
|
157
247
|
streamId: msg.streamId,
|
|
@@ -162,14 +252,14 @@ function handleMessage(message, state) {
|
|
|
162
252
|
case MessageType.RESPONSE_STREAM_CHUNK: {
|
|
163
253
|
const msg = message;
|
|
164
254
|
const receiver = state.streamResponses.get(msg.streamId);
|
|
165
|
-
if (receiver) {
|
|
166
|
-
receiver.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
255
|
+
if (receiver && receiver.state === "active") {
|
|
256
|
+
if (receiver.pullResolvers.length > 0) {
|
|
257
|
+
receiver.controller.enqueue(msg.chunk);
|
|
258
|
+
const resolver = receiver.pullResolvers.shift();
|
|
259
|
+
resolver();
|
|
260
|
+
} else {
|
|
261
|
+
receiver.pendingChunks.push(msg.chunk);
|
|
262
|
+
}
|
|
173
263
|
}
|
|
174
264
|
break;
|
|
175
265
|
}
|
|
@@ -177,20 +267,18 @@ function handleMessage(message, state) {
|
|
|
177
267
|
const msg = message;
|
|
178
268
|
const receiver = state.streamResponses.get(msg.streamId);
|
|
179
269
|
if (receiver) {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
});
|
|
270
|
+
receiver.state = "closed";
|
|
271
|
+
while (receiver.pendingChunks.length > 0) {
|
|
272
|
+
const chunk = receiver.pendingChunks.shift();
|
|
273
|
+
receiver.controller.enqueue(chunk);
|
|
274
|
+
}
|
|
275
|
+
if (!receiver.controllerFinalized) {
|
|
276
|
+
receiver.controllerFinalized = true;
|
|
277
|
+
receiver.controller.close();
|
|
278
|
+
}
|
|
279
|
+
const resolvers = receiver.pullResolvers.splice(0);
|
|
280
|
+
for (const resolver of resolvers) {
|
|
281
|
+
resolver();
|
|
194
282
|
}
|
|
195
283
|
state.streamResponses.delete(msg.streamId);
|
|
196
284
|
}
|
|
@@ -217,12 +305,15 @@ function handleMessage(message, state) {
|
|
|
217
305
|
}
|
|
218
306
|
const receiver = state.streamResponses.get(msg.streamId);
|
|
219
307
|
if (receiver) {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
308
|
+
receiver.state = "errored";
|
|
309
|
+
receiver.error = new Error(msg.error);
|
|
310
|
+
while (receiver.pendingChunks.length > 0) {
|
|
311
|
+
const chunk = receiver.pendingChunks.shift();
|
|
312
|
+
receiver.controller.enqueue(chunk);
|
|
313
|
+
}
|
|
314
|
+
const resolvers = receiver.pullResolvers.splice(0);
|
|
315
|
+
for (const resolver of resolvers) {
|
|
316
|
+
resolver();
|
|
226
317
|
}
|
|
227
318
|
state.streamResponses.delete(msg.streamId);
|
|
228
319
|
}
|
|
@@ -232,16 +323,6 @@ function handleMessage(message, state) {
|
|
|
232
323
|
console.warn(`Unexpected message type: ${message.type}`);
|
|
233
324
|
}
|
|
234
325
|
}
|
|
235
|
-
function concatUint8Arrays(arrays) {
|
|
236
|
-
const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);
|
|
237
|
-
const result = new Uint8Array(totalLength);
|
|
238
|
-
let offset = 0;
|
|
239
|
-
for (const arr of arrays) {
|
|
240
|
-
result.set(arr, offset);
|
|
241
|
-
offset += arr.length;
|
|
242
|
-
}
|
|
243
|
-
return result;
|
|
244
|
-
}
|
|
245
326
|
async function handleCallbackInvoke(invoke, state) {
|
|
246
327
|
const callback = state.callbacks.get(invoke.callbackId);
|
|
247
328
|
const response = {
|
|
@@ -291,7 +372,7 @@ function sendRequest(state, message, timeout = DEFAULT_TIMEOUT) {
|
|
|
291
372
|
sendMessage(state.socket, message);
|
|
292
373
|
});
|
|
293
374
|
}
|
|
294
|
-
async function createRuntime(state, options = {}) {
|
|
375
|
+
async function createRuntime(state, options = {}, namespaceId) {
|
|
295
376
|
const callbacks = {};
|
|
296
377
|
if (options.console) {
|
|
297
378
|
callbacks.console = registerConsoleCallbacks(state, options.console);
|
|
@@ -414,11 +495,13 @@ async function createRuntime(state, options = {}) {
|
|
|
414
495
|
memoryLimitMB: options.memoryLimitMB,
|
|
415
496
|
cwd: options.cwd,
|
|
416
497
|
callbacks,
|
|
417
|
-
testEnvironment: testEnvironmentOption
|
|
498
|
+
testEnvironment: testEnvironmentOption,
|
|
499
|
+
namespaceId
|
|
418
500
|
}
|
|
419
501
|
};
|
|
420
502
|
const result = await sendRequest(state, request);
|
|
421
503
|
const isolateId = result.isolateId;
|
|
504
|
+
const reused = result.reused ?? false;
|
|
422
505
|
const wsCommandCallbacks = new Set;
|
|
423
506
|
isolateWsCallbacks.set(isolateId, wsCommandCallbacks);
|
|
424
507
|
const fetchHandle = {
|
|
@@ -433,15 +516,21 @@ async function createRuntime(state, options = {}) {
|
|
|
433
516
|
request: serializableRequest,
|
|
434
517
|
options: opts
|
|
435
518
|
};
|
|
519
|
+
const handleResponse = (res) => {
|
|
520
|
+
if (res.__streaming && res.response instanceof Response) {
|
|
521
|
+
return res.response;
|
|
522
|
+
}
|
|
523
|
+
return deserializeResponse(res.response);
|
|
524
|
+
};
|
|
436
525
|
if (serialized.bodyStreamId !== undefined && bodyStream) {
|
|
437
526
|
const streamId = serialized.bodyStreamId;
|
|
438
527
|
const responsePromise = sendRequest(state, request2, opts?.timeout ?? DEFAULT_TIMEOUT);
|
|
439
528
|
await sendBodyStream(state, streamId, bodyStream);
|
|
440
529
|
const res = await responsePromise;
|
|
441
|
-
return
|
|
530
|
+
return handleResponse(res);
|
|
442
531
|
} else {
|
|
443
532
|
const res = await sendRequest(state, request2, opts?.timeout ?? DEFAULT_TIMEOUT);
|
|
444
|
-
return
|
|
533
|
+
return handleResponse(res);
|
|
445
534
|
}
|
|
446
535
|
},
|
|
447
536
|
async getUpgradeRequest() {
|
|
@@ -656,6 +745,7 @@ async function createRuntime(state, options = {}) {
|
|
|
656
745
|
return {
|
|
657
746
|
id: isolateId,
|
|
658
747
|
isolateId,
|
|
748
|
+
reused,
|
|
659
749
|
fetch: fetchHandle,
|
|
660
750
|
timers: timersHandle,
|
|
661
751
|
console: consoleHandle,
|
|
@@ -789,7 +879,14 @@ function registerFsCallbacks(state, callbacks) {
|
|
|
789
879
|
function registerModuleLoaderCallback(state, callback) {
|
|
790
880
|
const callbackId = state.nextCallbackId++;
|
|
791
881
|
state.callbacks.set(callbackId, async (moduleName) => {
|
|
792
|
-
|
|
882
|
+
const specifier = moduleName;
|
|
883
|
+
const cached = state.moduleSourceCache.get(specifier);
|
|
884
|
+
if (cached !== undefined) {
|
|
885
|
+
return cached;
|
|
886
|
+
}
|
|
887
|
+
const source = await callback(specifier);
|
|
888
|
+
state.moduleSourceCache.set(specifier, source);
|
|
889
|
+
return source;
|
|
793
890
|
});
|
|
794
891
|
return { callbackId, name: "moduleLoader", type: "async" };
|
|
795
892
|
}
|
|
@@ -1118,4 +1215,4 @@ export {
|
|
|
1118
1215
|
connect
|
|
1119
1216
|
};
|
|
1120
1217
|
|
|
1121
|
-
//# debugId=
|
|
1218
|
+
//# debugId=B4800C212010D2AD64756E2164756E21
|