@ricsam/isolate-client 0.1.15 → 0.1.17
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 +1 -0
- package/dist/cjs/connection.cjs +354 -199
- package/dist/cjs/connection.cjs.map +3 -3
- package/dist/cjs/index.cjs +2 -1
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/connection.mjs +357 -196
- package/dist/mjs/connection.mjs.map +3 -3
- package/dist/mjs/index.mjs +3 -2
- package/dist/mjs/index.mjs.map +2 -2
- package/dist/mjs/package.json +1 -1
- package/dist/types/connection.d.ts +1 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/types.d.ts +15 -0
- package/package.json +1 -1
package/dist/cjs/connection.cjs
CHANGED
|
@@ -42,6 +42,7 @@ var __export = (target, all) => {
|
|
|
42
42
|
// packages/isolate-client/src/connection.ts
|
|
43
43
|
var exports_connection = {};
|
|
44
44
|
__export(exports_connection, {
|
|
45
|
+
isBenignDisposeError: () => isBenignDisposeError,
|
|
45
46
|
connect: () => connect
|
|
46
47
|
});
|
|
47
48
|
module.exports = __toCommonJS(exports_connection);
|
|
@@ -49,11 +50,10 @@ var import_node_net = require("node:net");
|
|
|
49
50
|
var import_node_path = __toESM(require("node:path"));
|
|
50
51
|
var import_isolate_protocol = require("@ricsam/isolate-protocol");
|
|
51
52
|
var import_client = require("@ricsam/isolate-playwright/client");
|
|
52
|
-
var DEFAULT_TIMEOUT = 30000;
|
|
53
|
-
var TEST_REQUEST_TIMEOUT_BUFFER_MS = 1000;
|
|
54
53
|
var isolateWsCallbacks = new Map;
|
|
55
54
|
var isolateClientWebSockets = new Map;
|
|
56
55
|
var isolateWebSocketCallbacks = new Map;
|
|
56
|
+
var isolateEventListeners = new Map;
|
|
57
57
|
async function connect(options = {}) {
|
|
58
58
|
const socket = await createSocket(options);
|
|
59
59
|
const state = {
|
|
@@ -68,47 +68,142 @@ async function connect(options = {}) {
|
|
|
68
68
|
streamResponses: new Map,
|
|
69
69
|
uploadStreams: new Map,
|
|
70
70
|
moduleSourceCache: new Map,
|
|
71
|
-
callbackStreamReaders: new Map
|
|
71
|
+
callbackStreamReaders: new Map,
|
|
72
|
+
closing: false,
|
|
73
|
+
namespacedRuntimes: new Map
|
|
72
74
|
};
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
function setupSocket(sock) {
|
|
76
|
+
const parser = import_isolate_protocol.createFrameParser();
|
|
77
|
+
sock.on("data", (data) => {
|
|
78
|
+
try {
|
|
79
|
+
for (const frame of parser.feed(new Uint8Array(data))) {
|
|
80
|
+
handleMessage(frame.message, state);
|
|
81
|
+
}
|
|
82
|
+
} catch (err) {
|
|
83
|
+
console.error("Error parsing frame:", err);
|
|
78
84
|
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
state.connected = false;
|
|
85
|
-
for (const [, pending] of state.pendingRequests) {
|
|
86
|
-
if (pending.timeoutId) {
|
|
87
|
-
clearTimeout(pending.timeoutId);
|
|
85
|
+
});
|
|
86
|
+
sock.on("close", () => {
|
|
87
|
+
state.connected = false;
|
|
88
|
+
for (const [, pending] of state.pendingRequests) {
|
|
89
|
+
pending.reject(new Error("Connection closed"));
|
|
88
90
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
resolver();
|
|
91
|
+
state.pendingRequests.clear();
|
|
92
|
+
for (const [, receiver] of state.streamResponses) {
|
|
93
|
+
receiver.state = "errored";
|
|
94
|
+
receiver.error = new Error("Connection closed");
|
|
95
|
+
const resolvers = receiver.pullResolvers.splice(0);
|
|
96
|
+
for (const resolver of resolvers) {
|
|
97
|
+
resolver();
|
|
98
|
+
}
|
|
98
99
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
100
|
+
state.streamResponses.clear();
|
|
101
|
+
for (const [, session] of state.uploadStreams) {
|
|
102
|
+
session.state = "closed";
|
|
103
|
+
if (session.creditResolver) {
|
|
104
|
+
session.creditResolver();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
state.uploadStreams.clear();
|
|
108
|
+
if (!state.closing && state.namespacedRuntimes.size > 0) {
|
|
109
|
+
state.reconnecting = reconnect(state, options).catch(() => {
|
|
110
|
+
state.namespacedRuntimes.clear();
|
|
111
|
+
state.reconnecting = undefined;
|
|
112
|
+
});
|
|
105
113
|
}
|
|
114
|
+
});
|
|
115
|
+
sock.on("error", (err) => {
|
|
116
|
+
if (!state.closing && state.namespacedRuntimes.size > 0)
|
|
117
|
+
return;
|
|
118
|
+
console.error("Socket error:", err);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
setupSocket(socket);
|
|
122
|
+
async function reconnect(st, opts) {
|
|
123
|
+
try {
|
|
124
|
+
const newSocket = await createSocket(opts);
|
|
125
|
+
st.socket = newSocket;
|
|
126
|
+
st.connected = true;
|
|
127
|
+
setupSocket(newSocket);
|
|
128
|
+
for (const [namespaceId, descriptor] of st.namespacedRuntimes) {
|
|
129
|
+
const runtimeOptions = descriptor.runtimeOptions;
|
|
130
|
+
const callbacks = {};
|
|
131
|
+
if (runtimeOptions.console) {
|
|
132
|
+
callbacks.console = registerConsoleCallbacks(st, runtimeOptions.console);
|
|
133
|
+
}
|
|
134
|
+
if (runtimeOptions.fetch) {
|
|
135
|
+
callbacks.fetch = registerFetchCallback(st, runtimeOptions.fetch);
|
|
136
|
+
}
|
|
137
|
+
if (runtimeOptions.fs) {
|
|
138
|
+
callbacks.fs = registerFsCallbacks(st, runtimeOptions.fs);
|
|
139
|
+
}
|
|
140
|
+
if (runtimeOptions.moduleLoader) {
|
|
141
|
+
callbacks.moduleLoader = registerModuleLoaderCallback(st, runtimeOptions.moduleLoader);
|
|
142
|
+
}
|
|
143
|
+
if (runtimeOptions.customFunctions) {
|
|
144
|
+
callbacks.custom = registerCustomFunctions(st, runtimeOptions.customFunctions);
|
|
145
|
+
}
|
|
146
|
+
if (runtimeOptions.playwright) {
|
|
147
|
+
const playwrightHandler = runtimeOptions.playwright.handler;
|
|
148
|
+
if (playwrightHandler) {
|
|
149
|
+
const handlerCallbackId = st.nextCallbackId++;
|
|
150
|
+
st.callbacks.set(handlerCallbackId, async (opJson) => {
|
|
151
|
+
const op = JSON.parse(opJson);
|
|
152
|
+
const result2 = await playwrightHandler(op);
|
|
153
|
+
return JSON.stringify(result2);
|
|
154
|
+
});
|
|
155
|
+
callbacks.playwright = {
|
|
156
|
+
handlerCallbackId,
|
|
157
|
+
console: runtimeOptions.playwright.console && !runtimeOptions.console?.onEntry
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
let testEnvironmentOption;
|
|
162
|
+
if (runtimeOptions.testEnvironment) {
|
|
163
|
+
if (typeof runtimeOptions.testEnvironment === "object") {
|
|
164
|
+
const testEnvOptions = runtimeOptions.testEnvironment;
|
|
165
|
+
const testEnvCallbacks = {};
|
|
166
|
+
if (testEnvOptions.onEvent) {
|
|
167
|
+
const userOnEvent = testEnvOptions.onEvent;
|
|
168
|
+
const onEventCallbackId = registerEventCallback(st, (eventJson) => {
|
|
169
|
+
const event = JSON.parse(eventJson);
|
|
170
|
+
userOnEvent(event);
|
|
171
|
+
});
|
|
172
|
+
testEnvCallbacks.onEvent = {
|
|
173
|
+
callbackId: onEventCallbackId,
|
|
174
|
+
name: "testEnvironment.onEvent",
|
|
175
|
+
type: "sync"
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
testEnvironmentOption = {
|
|
179
|
+
callbacks: testEnvCallbacks,
|
|
180
|
+
testTimeout: testEnvOptions.testTimeout
|
|
181
|
+
};
|
|
182
|
+
} else {
|
|
183
|
+
testEnvironmentOption = true;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
const requestId = st.nextRequestId++;
|
|
187
|
+
const request = {
|
|
188
|
+
type: import_isolate_protocol.MessageType.CREATE_RUNTIME,
|
|
189
|
+
requestId,
|
|
190
|
+
options: {
|
|
191
|
+
memoryLimitMB: runtimeOptions.memoryLimitMB,
|
|
192
|
+
cwd: runtimeOptions.cwd,
|
|
193
|
+
callbacks,
|
|
194
|
+
testEnvironment: testEnvironmentOption,
|
|
195
|
+
namespaceId
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
const result = await sendRequest(st, request);
|
|
199
|
+
descriptor.isolateId = result.isolateId;
|
|
200
|
+
}
|
|
201
|
+
st.reconnecting = undefined;
|
|
202
|
+
} catch {
|
|
203
|
+
st.reconnecting = undefined;
|
|
204
|
+
throw new Error("Failed to reconnect to daemon");
|
|
106
205
|
}
|
|
107
|
-
|
|
108
|
-
});
|
|
109
|
-
socket.on("error", (err) => {
|
|
110
|
-
console.error("Socket error:", err);
|
|
111
|
-
});
|
|
206
|
+
}
|
|
112
207
|
return {
|
|
113
208
|
createRuntime: (runtimeOptions) => createRuntime(state, runtimeOptions),
|
|
114
209
|
createNamespace: (id) => ({
|
|
@@ -116,15 +211,16 @@ async function connect(options = {}) {
|
|
|
116
211
|
createRuntime: (runtimeOptions) => createRuntime(state, runtimeOptions, id)
|
|
117
212
|
}),
|
|
118
213
|
close: async () => {
|
|
214
|
+
state.closing = true;
|
|
119
215
|
state.connected = false;
|
|
120
|
-
socket.destroy();
|
|
216
|
+
state.socket.destroy();
|
|
121
217
|
},
|
|
122
218
|
isConnected: () => state.connected
|
|
123
219
|
};
|
|
124
220
|
}
|
|
125
221
|
function createSocket(options) {
|
|
126
222
|
return new Promise((resolve, reject) => {
|
|
127
|
-
const timeout = options.timeout
|
|
223
|
+
const timeout = options.timeout;
|
|
128
224
|
let socket;
|
|
129
225
|
const onError = (err) => {
|
|
130
226
|
reject(err);
|
|
@@ -139,13 +235,15 @@ function createSocket(options) {
|
|
|
139
235
|
socket = import_node_net.connect(options.port ?? 47891, options.host ?? "127.0.0.1", onConnect);
|
|
140
236
|
}
|
|
141
237
|
socket.on("error", onError);
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
238
|
+
if (timeout && timeout > 0) {
|
|
239
|
+
const timeoutId = setTimeout(() => {
|
|
240
|
+
socket.destroy();
|
|
241
|
+
reject(new Error("Connection timeout"));
|
|
242
|
+
}, timeout);
|
|
243
|
+
socket.once("connect", () => {
|
|
244
|
+
clearTimeout(timeoutId);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
149
247
|
});
|
|
150
248
|
}
|
|
151
249
|
function handleMessage(message, state) {
|
|
@@ -155,8 +253,6 @@ function handleMessage(message, state) {
|
|
|
155
253
|
const pending = state.pendingRequests.get(response.requestId);
|
|
156
254
|
if (pending) {
|
|
157
255
|
state.pendingRequests.delete(response.requestId);
|
|
158
|
-
if (pending.timeoutId)
|
|
159
|
-
clearTimeout(pending.timeoutId);
|
|
160
256
|
pending.resolve(response.data);
|
|
161
257
|
}
|
|
162
258
|
break;
|
|
@@ -166,8 +262,6 @@ function handleMessage(message, state) {
|
|
|
166
262
|
const pending = state.pendingRequests.get(response.requestId);
|
|
167
263
|
if (pending) {
|
|
168
264
|
state.pendingRequests.delete(response.requestId);
|
|
169
|
-
if (pending.timeoutId)
|
|
170
|
-
clearTimeout(pending.timeoutId);
|
|
171
265
|
const error = new Error(response.message);
|
|
172
266
|
if (response.details) {
|
|
173
267
|
error.name = response.details.name;
|
|
@@ -194,42 +288,9 @@ function handleMessage(message, state) {
|
|
|
194
288
|
}
|
|
195
289
|
break;
|
|
196
290
|
}
|
|
197
|
-
case import_isolate_protocol.MessageType.
|
|
198
|
-
const msg = message;
|
|
199
|
-
const callbacks = isolateWsCallbacks.get(msg.isolateId);
|
|
200
|
-
if (callbacks) {
|
|
201
|
-
let data;
|
|
202
|
-
if (msg.command.data instanceof Uint8Array) {
|
|
203
|
-
data = msg.command.data.buffer.slice(msg.command.data.byteOffset, msg.command.data.byteOffset + msg.command.data.byteLength);
|
|
204
|
-
} else {
|
|
205
|
-
data = msg.command.data;
|
|
206
|
-
}
|
|
207
|
-
const cmd = {
|
|
208
|
-
type: msg.command.type,
|
|
209
|
-
connectionId: msg.command.connectionId,
|
|
210
|
-
data,
|
|
211
|
-
code: msg.command.code,
|
|
212
|
-
reason: msg.command.reason
|
|
213
|
-
};
|
|
214
|
-
for (const cb of callbacks) {
|
|
215
|
-
cb(cmd);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
break;
|
|
219
|
-
}
|
|
220
|
-
case import_isolate_protocol.MessageType.CLIENT_WS_CONNECT: {
|
|
221
|
-
const msg = message;
|
|
222
|
-
handleClientWsConnect(msg, state);
|
|
223
|
-
break;
|
|
224
|
-
}
|
|
225
|
-
case import_isolate_protocol.MessageType.CLIENT_WS_SEND: {
|
|
291
|
+
case import_isolate_protocol.MessageType.ISOLATE_EVENT: {
|
|
226
292
|
const msg = message;
|
|
227
|
-
|
|
228
|
-
break;
|
|
229
|
-
}
|
|
230
|
-
case import_isolate_protocol.MessageType.CLIENT_WS_CLOSE: {
|
|
231
|
-
const msg = message;
|
|
232
|
-
handleClientWsClose(msg, state);
|
|
293
|
+
handleIsolateEvent(msg, state);
|
|
233
294
|
break;
|
|
234
295
|
}
|
|
235
296
|
case import_isolate_protocol.MessageType.RESPONSE_STREAM_START: {
|
|
@@ -299,8 +360,6 @@ function handleMessage(message, state) {
|
|
|
299
360
|
const pending = state.pendingRequests.get(msg.requestId);
|
|
300
361
|
if (pending) {
|
|
301
362
|
state.pendingRequests.delete(msg.requestId);
|
|
302
|
-
if (pending.timeoutId)
|
|
303
|
-
clearTimeout(pending.timeoutId);
|
|
304
363
|
const response = new Response(readableStream, {
|
|
305
364
|
status: msg.metadata?.status ?? 200,
|
|
306
365
|
statusText: msg.metadata?.statusText ?? "OK",
|
|
@@ -425,25 +484,24 @@ function sendMessage(socket, message) {
|
|
|
425
484
|
const frame = import_isolate_protocol.buildFrame(message);
|
|
426
485
|
socket.write(frame);
|
|
427
486
|
}
|
|
428
|
-
function sendRequest(state, message
|
|
487
|
+
function sendRequest(state, message) {
|
|
429
488
|
return new Promise((resolve, reject) => {
|
|
430
489
|
if (!state.connected) {
|
|
431
490
|
reject(new Error("Not connected"));
|
|
432
491
|
return;
|
|
433
492
|
}
|
|
434
493
|
const requestId = message.requestId;
|
|
435
|
-
const timeoutId = setTimeout(() => {
|
|
436
|
-
state.pendingRequests.delete(requestId);
|
|
437
|
-
reject(new Error("Request timeout"));
|
|
438
|
-
}, timeout);
|
|
439
494
|
state.pendingRequests.set(requestId, {
|
|
440
495
|
resolve,
|
|
441
|
-
reject
|
|
442
|
-
timeoutId
|
|
496
|
+
reject
|
|
443
497
|
});
|
|
444
498
|
sendMessage(state.socket, message);
|
|
445
499
|
});
|
|
446
500
|
}
|
|
501
|
+
function isBenignDisposeError(error) {
|
|
502
|
+
const message = error instanceof Error ? error.message : String(error ?? "");
|
|
503
|
+
return /isolate not owned by this connection|isolate not found|not connected|connection closed/i.test(message);
|
|
504
|
+
}
|
|
447
505
|
async function createRuntime(state, options = {}, namespaceId) {
|
|
448
506
|
const callbacks = {};
|
|
449
507
|
if (options.console) {
|
|
@@ -582,13 +640,26 @@ async function createRuntime(state, options = {}, namespaceId) {
|
|
|
582
640
|
const result = await sendRequest(state, request);
|
|
583
641
|
const isolateId = result.isolateId;
|
|
584
642
|
const reused = result.reused ?? false;
|
|
643
|
+
if (namespaceId != null) {
|
|
644
|
+
state.namespacedRuntimes.set(namespaceId, {
|
|
645
|
+
isolateId,
|
|
646
|
+
runtimeOptions: options
|
|
647
|
+
});
|
|
648
|
+
}
|
|
585
649
|
const wsCommandCallbacks = new Set;
|
|
586
650
|
isolateWsCallbacks.set(isolateId, wsCommandCallbacks);
|
|
651
|
+
if (options.onWebSocketCommand) {
|
|
652
|
+
wsCommandCallbacks.add(options.onWebSocketCommand);
|
|
653
|
+
}
|
|
587
654
|
if (options.webSocket) {
|
|
588
655
|
isolateWebSocketCallbacks.set(isolateId, options.webSocket);
|
|
589
656
|
}
|
|
590
657
|
const fetchHandle = {
|
|
591
658
|
async dispatchRequest(req, opts) {
|
|
659
|
+
const signal = opts?.signal;
|
|
660
|
+
if (signal?.aborted) {
|
|
661
|
+
throw new DOMException("The operation was aborted", "AbortError");
|
|
662
|
+
}
|
|
592
663
|
const reqId = state.nextRequestId++;
|
|
593
664
|
const serialized = await serializeRequestWithStreaming(state, req);
|
|
594
665
|
const { bodyStream, ...serializableRequest } = serialized;
|
|
@@ -596,24 +667,40 @@ async function createRuntime(state, options = {}, namespaceId) {
|
|
|
596
667
|
type: import_isolate_protocol.MessageType.DISPATCH_REQUEST,
|
|
597
668
|
requestId: reqId,
|
|
598
669
|
isolateId,
|
|
599
|
-
request: serializableRequest
|
|
600
|
-
options: opts
|
|
670
|
+
request: serializableRequest
|
|
601
671
|
};
|
|
602
672
|
const handleResponse = (res) => {
|
|
603
673
|
if (res.__streaming && res.response instanceof Response) {
|
|
604
674
|
return res.response;
|
|
605
675
|
}
|
|
606
|
-
return deserializeResponse(res.response);
|
|
676
|
+
return import_isolate_protocol.deserializeResponse(res.response);
|
|
607
677
|
};
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
678
|
+
let onAbort;
|
|
679
|
+
if (signal) {
|
|
680
|
+
onAbort = () => {
|
|
681
|
+
const pending = state.pendingRequests.get(reqId);
|
|
682
|
+
if (pending) {
|
|
683
|
+
state.pendingRequests.delete(reqId);
|
|
684
|
+
pending.reject(new DOMException("The operation was aborted", "AbortError"));
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
688
|
+
}
|
|
689
|
+
try {
|
|
690
|
+
if (serialized.bodyStreamId !== undefined && bodyStream) {
|
|
691
|
+
const streamId = serialized.bodyStreamId;
|
|
692
|
+
const responsePromise = sendRequest(state, request2);
|
|
693
|
+
await sendBodyStream(state, streamId, bodyStream);
|
|
694
|
+
const res = await responsePromise;
|
|
695
|
+
return handleResponse(res);
|
|
696
|
+
} else {
|
|
697
|
+
const res = await sendRequest(state, request2);
|
|
698
|
+
return handleResponse(res);
|
|
699
|
+
}
|
|
700
|
+
} finally {
|
|
701
|
+
if (signal && onAbort) {
|
|
702
|
+
signal.removeEventListener("abort", onAbort);
|
|
703
|
+
}
|
|
617
704
|
}
|
|
618
705
|
},
|
|
619
706
|
async getUpgradeRequest() {
|
|
@@ -760,8 +847,22 @@ async function createRuntime(state, options = {}, namespaceId) {
|
|
|
760
847
|
isolateId,
|
|
761
848
|
timeout
|
|
762
849
|
};
|
|
763
|
-
|
|
764
|
-
|
|
850
|
+
try {
|
|
851
|
+
return await sendRequest(state, req);
|
|
852
|
+
} catch (err) {
|
|
853
|
+
if (err instanceof Error && /connection closed|not connected/i.test(err.message) && state.reconnecting) {
|
|
854
|
+
await state.reconnecting;
|
|
855
|
+
const retryReqId = state.nextRequestId++;
|
|
856
|
+
const retryReq = {
|
|
857
|
+
type: import_isolate_protocol.MessageType.RUN_TESTS,
|
|
858
|
+
requestId: retryReqId,
|
|
859
|
+
isolateId,
|
|
860
|
+
timeout
|
|
861
|
+
};
|
|
862
|
+
return sendRequest(state, retryReq);
|
|
863
|
+
}
|
|
864
|
+
throw err;
|
|
865
|
+
}
|
|
765
866
|
},
|
|
766
867
|
async hasTests() {
|
|
767
868
|
if (!testEnvironmentEnabled) {
|
|
@@ -836,17 +937,47 @@ async function createRuntime(state, options = {}, namespaceId) {
|
|
|
836
937
|
requestId: reqId,
|
|
837
938
|
isolateId,
|
|
838
939
|
code,
|
|
839
|
-
filename: options2?.filename
|
|
840
|
-
maxExecutionMs: options2?.maxExecutionMs
|
|
940
|
+
filename: options2?.filename
|
|
841
941
|
};
|
|
842
942
|
await sendRequest(state, req);
|
|
843
943
|
},
|
|
944
|
+
on(event, callback) {
|
|
945
|
+
let listeners = isolateEventListeners.get(isolateId);
|
|
946
|
+
if (!listeners) {
|
|
947
|
+
listeners = new Map;
|
|
948
|
+
isolateEventListeners.set(isolateId, listeners);
|
|
949
|
+
}
|
|
950
|
+
let eventListeners = listeners.get(event);
|
|
951
|
+
if (!eventListeners) {
|
|
952
|
+
eventListeners = new Set;
|
|
953
|
+
listeners.set(event, eventListeners);
|
|
954
|
+
}
|
|
955
|
+
eventListeners.add(callback);
|
|
956
|
+
return () => {
|
|
957
|
+
eventListeners.delete(callback);
|
|
958
|
+
if (eventListeners.size === 0) {
|
|
959
|
+
listeners.delete(event);
|
|
960
|
+
if (listeners.size === 0) {
|
|
961
|
+
isolateEventListeners.delete(isolateId);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
};
|
|
965
|
+
},
|
|
966
|
+
emit(event, payload) {
|
|
967
|
+
sendMessage(state.socket, {
|
|
968
|
+
type: import_isolate_protocol.MessageType.CLIENT_EVENT,
|
|
969
|
+
isolateId,
|
|
970
|
+
event,
|
|
971
|
+
payload
|
|
972
|
+
});
|
|
973
|
+
},
|
|
844
974
|
dispose: async () => {
|
|
845
975
|
for (const cleanup of pageListenerCleanups) {
|
|
846
976
|
cleanup();
|
|
847
977
|
}
|
|
848
978
|
isolateWsCallbacks.delete(isolateId);
|
|
849
979
|
isolateWebSocketCallbacks.delete(isolateId);
|
|
980
|
+
isolateEventListeners.delete(isolateId);
|
|
850
981
|
const clientSockets = isolateClientWebSockets.get(isolateId);
|
|
851
982
|
if (clientSockets) {
|
|
852
983
|
for (const ws of clientSockets.values()) {
|
|
@@ -856,13 +987,22 @@ async function createRuntime(state, options = {}, namespaceId) {
|
|
|
856
987
|
}
|
|
857
988
|
isolateClientWebSockets.delete(isolateId);
|
|
858
989
|
}
|
|
990
|
+
if (namespaceId != null) {
|
|
991
|
+
state.namespacedRuntimes.delete(namespaceId);
|
|
992
|
+
}
|
|
859
993
|
const reqId = state.nextRequestId++;
|
|
860
994
|
const req = {
|
|
861
995
|
type: import_isolate_protocol.MessageType.DISPOSE_RUNTIME,
|
|
862
996
|
requestId: reqId,
|
|
863
997
|
isolateId
|
|
864
998
|
};
|
|
865
|
-
|
|
999
|
+
try {
|
|
1000
|
+
await sendRequest(state, req);
|
|
1001
|
+
} catch (error) {
|
|
1002
|
+
if (!isBenignDisposeError(error)) {
|
|
1003
|
+
throw error;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
866
1006
|
}
|
|
867
1007
|
};
|
|
868
1008
|
}
|
|
@@ -894,8 +1034,8 @@ function registerFetchCallback(state, callback) {
|
|
|
894
1034
|
const init = {
|
|
895
1035
|
method: data.method,
|
|
896
1036
|
headers: data.headers,
|
|
897
|
-
rawBody: data.body,
|
|
898
|
-
body: data.body,
|
|
1037
|
+
rawBody: data.body ?? null,
|
|
1038
|
+
body: data.body ?? null,
|
|
899
1039
|
signal: new AbortController().signal
|
|
900
1040
|
};
|
|
901
1041
|
const response = await callback(data.url, init);
|
|
@@ -923,7 +1063,7 @@ function registerFetchCallback(state, callback) {
|
|
|
923
1063
|
streamCallbackResponseBody(state, streamId, requestId, response.body);
|
|
924
1064
|
return { __callbackStreaming: true, streamId };
|
|
925
1065
|
}
|
|
926
|
-
return serializeResponse(response);
|
|
1066
|
+
return import_isolate_protocol.serializeResponse(response);
|
|
927
1067
|
});
|
|
928
1068
|
return { callbackId, name: "fetch", type: "async" };
|
|
929
1069
|
}
|
|
@@ -1041,7 +1181,7 @@ function registerModuleLoaderCallback(state, callback) {
|
|
|
1041
1181
|
const specifier = moduleName;
|
|
1042
1182
|
const importerInfo = importer;
|
|
1043
1183
|
const result = await callback(specifier, importerInfo);
|
|
1044
|
-
const resolvedPath = import_node_path.default.posix.join(result.resolveDir,
|
|
1184
|
+
const resolvedPath = import_node_path.default.posix.join(result.resolveDir, result.filename);
|
|
1045
1185
|
state.moduleSourceCache.set(resolvedPath, result.code);
|
|
1046
1186
|
return result;
|
|
1047
1187
|
});
|
|
@@ -1051,12 +1191,6 @@ var clientIteratorSessions = new Map;
|
|
|
1051
1191
|
var nextClientIteratorId = 1;
|
|
1052
1192
|
var returnedPromiseRegistry = new Map;
|
|
1053
1193
|
var returnedIteratorRegistry = new Map;
|
|
1054
|
-
function isPromiseRef(value) {
|
|
1055
|
-
return typeof value === "object" && value !== null && value.__type === "PromiseRef";
|
|
1056
|
-
}
|
|
1057
|
-
function isAsyncIteratorRef(value) {
|
|
1058
|
-
return typeof value === "object" && value !== null && value.__type === "AsyncIteratorRef";
|
|
1059
|
-
}
|
|
1060
1194
|
function registerCustomFunctions(state, customFunctions) {
|
|
1061
1195
|
const registrations = {};
|
|
1062
1196
|
for (const [name, def] of Object.entries(customFunctions)) {
|
|
@@ -1139,7 +1273,7 @@ function registerCustomFunctions(state, customFunctions) {
|
|
|
1139
1273
|
if (value === null || typeof value !== "object") {
|
|
1140
1274
|
return value;
|
|
1141
1275
|
}
|
|
1142
|
-
if (isPromiseRef(value)) {
|
|
1276
|
+
if (import_isolate_protocol.isPromiseRef(value)) {
|
|
1143
1277
|
const resolveCallbackId = state.nextCallbackId++;
|
|
1144
1278
|
state.callbacks.set(resolveCallbackId, async (...args2) => {
|
|
1145
1279
|
const promiseId = args2[0];
|
|
@@ -1157,7 +1291,7 @@ function registerCustomFunctions(state, customFunctions) {
|
|
|
1157
1291
|
__resolveCallbackId: resolveCallbackId
|
|
1158
1292
|
};
|
|
1159
1293
|
}
|
|
1160
|
-
if (isAsyncIteratorRef(value)) {
|
|
1294
|
+
if (import_isolate_protocol.isAsyncIteratorRef(value)) {
|
|
1161
1295
|
const nextCallbackId = state.nextCallbackId++;
|
|
1162
1296
|
state.callbacks.set(nextCallbackId, async (...args2) => {
|
|
1163
1297
|
const iteratorId = args2[0];
|
|
@@ -1240,29 +1374,6 @@ function registerCustomFunctions(state, customFunctions) {
|
|
|
1240
1374
|
}
|
|
1241
1375
|
return registrations;
|
|
1242
1376
|
}
|
|
1243
|
-
async function serializeResponse(response) {
|
|
1244
|
-
const headers = [];
|
|
1245
|
-
response.headers.forEach((value, key) => {
|
|
1246
|
-
headers.push([key, value]);
|
|
1247
|
-
});
|
|
1248
|
-
let body = null;
|
|
1249
|
-
if (response.body) {
|
|
1250
|
-
body = new Uint8Array(await response.arrayBuffer());
|
|
1251
|
-
}
|
|
1252
|
-
return {
|
|
1253
|
-
status: response.status,
|
|
1254
|
-
statusText: response.statusText,
|
|
1255
|
-
headers,
|
|
1256
|
-
body
|
|
1257
|
-
};
|
|
1258
|
-
}
|
|
1259
|
-
function deserializeResponse(data) {
|
|
1260
|
-
return new Response(data.body, {
|
|
1261
|
-
status: data.status,
|
|
1262
|
-
statusText: data.statusText,
|
|
1263
|
-
headers: data.headers
|
|
1264
|
-
});
|
|
1265
|
-
}
|
|
1266
1377
|
async function serializeRequestWithStreaming(state, request) {
|
|
1267
1378
|
const headers = [];
|
|
1268
1379
|
request.headers.forEach((value, key) => {
|
|
@@ -1361,8 +1472,62 @@ async function sendBodyStream(state, streamId, body) {
|
|
|
1361
1472
|
state.uploadStreams.delete(streamId);
|
|
1362
1473
|
}
|
|
1363
1474
|
}
|
|
1364
|
-
function
|
|
1365
|
-
|
|
1475
|
+
function handleIsolateEvent(message, state) {
|
|
1476
|
+
switch (message.event) {
|
|
1477
|
+
case import_isolate_protocol.IsolateEvents.WS_COMMAND: {
|
|
1478
|
+
const payload = message.payload;
|
|
1479
|
+
const callbacks = isolateWsCallbacks.get(message.isolateId);
|
|
1480
|
+
if (callbacks) {
|
|
1481
|
+
let data;
|
|
1482
|
+
if (payload.data instanceof Uint8Array) {
|
|
1483
|
+
data = payload.data.buffer.slice(payload.data.byteOffset, payload.data.byteOffset + payload.data.byteLength);
|
|
1484
|
+
} else {
|
|
1485
|
+
data = payload.data;
|
|
1486
|
+
}
|
|
1487
|
+
const cmd = {
|
|
1488
|
+
type: payload.type,
|
|
1489
|
+
connectionId: payload.connectionId,
|
|
1490
|
+
data,
|
|
1491
|
+
code: payload.code,
|
|
1492
|
+
reason: payload.reason
|
|
1493
|
+
};
|
|
1494
|
+
for (const cb of callbacks) {
|
|
1495
|
+
cb(cmd);
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
break;
|
|
1499
|
+
}
|
|
1500
|
+
case import_isolate_protocol.IsolateEvents.WS_CLIENT_CONNECT: {
|
|
1501
|
+
const payload = message.payload;
|
|
1502
|
+
handleClientWsConnect(message.isolateId, payload, state);
|
|
1503
|
+
break;
|
|
1504
|
+
}
|
|
1505
|
+
case import_isolate_protocol.IsolateEvents.WS_CLIENT_SEND: {
|
|
1506
|
+
const payload = message.payload;
|
|
1507
|
+
handleClientWsSend(message.isolateId, payload, state);
|
|
1508
|
+
break;
|
|
1509
|
+
}
|
|
1510
|
+
case import_isolate_protocol.IsolateEvents.WS_CLIENT_CLOSE: {
|
|
1511
|
+
const payload = message.payload;
|
|
1512
|
+
handleClientWsClose(message.isolateId, payload, state);
|
|
1513
|
+
break;
|
|
1514
|
+
}
|
|
1515
|
+
default: {
|
|
1516
|
+
const listeners = isolateEventListeners.get(message.isolateId);
|
|
1517
|
+
if (listeners) {
|
|
1518
|
+
const eventListeners = listeners.get(message.event);
|
|
1519
|
+
if (eventListeners) {
|
|
1520
|
+
for (const cb of eventListeners) {
|
|
1521
|
+
cb(message.payload);
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
break;
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
function handleClientWsConnect(isolateId, payload, state) {
|
|
1530
|
+
const { socketId, url, protocols } = payload;
|
|
1366
1531
|
let sockets = isolateClientWebSockets.get(isolateId);
|
|
1367
1532
|
if (!sockets) {
|
|
1368
1533
|
sockets = new Map;
|
|
@@ -1371,14 +1536,12 @@ function handleClientWsConnect(message, state) {
|
|
|
1371
1536
|
const setupWebSocket = (ws) => {
|
|
1372
1537
|
sockets.set(socketId, ws);
|
|
1373
1538
|
ws.onopen = () => {
|
|
1374
|
-
|
|
1375
|
-
type: import_isolate_protocol.MessageType.
|
|
1539
|
+
sendMessage(state.socket, {
|
|
1540
|
+
type: import_isolate_protocol.MessageType.CLIENT_EVENT,
|
|
1376
1541
|
isolateId,
|
|
1377
|
-
|
|
1378
|
-
protocol: ws.protocol || "",
|
|
1379
|
-
|
|
1380
|
-
};
|
|
1381
|
-
sendMessage(state.socket, msg);
|
|
1542
|
+
event: import_isolate_protocol.ClientEvents.WS_CLIENT_OPENED,
|
|
1543
|
+
payload: { socketId, protocol: ws.protocol || "", extensions: ws.extensions || "" }
|
|
1544
|
+
});
|
|
1382
1545
|
};
|
|
1383
1546
|
ws.onmessage = (event) => {
|
|
1384
1547
|
let data;
|
|
@@ -1388,44 +1551,39 @@ function handleClientWsConnect(message, state) {
|
|
|
1388
1551
|
data = new Uint8Array(event.data);
|
|
1389
1552
|
} else if (event.data instanceof Blob) {
|
|
1390
1553
|
event.data.arrayBuffer().then((buffer) => {
|
|
1391
|
-
|
|
1392
|
-
type: import_isolate_protocol.MessageType.
|
|
1554
|
+
sendMessage(state.socket, {
|
|
1555
|
+
type: import_isolate_protocol.MessageType.CLIENT_EVENT,
|
|
1393
1556
|
isolateId,
|
|
1394
|
-
|
|
1395
|
-
data: new Uint8Array(buffer)
|
|
1396
|
-
};
|
|
1397
|
-
sendMessage(state.socket, msg2);
|
|
1557
|
+
event: import_isolate_protocol.ClientEvents.WS_CLIENT_MESSAGE,
|
|
1558
|
+
payload: { socketId, data: new Uint8Array(buffer) }
|
|
1559
|
+
});
|
|
1398
1560
|
});
|
|
1399
1561
|
return;
|
|
1400
1562
|
} else {
|
|
1401
1563
|
data = String(event.data);
|
|
1402
1564
|
}
|
|
1403
|
-
|
|
1404
|
-
type: import_isolate_protocol.MessageType.
|
|
1565
|
+
sendMessage(state.socket, {
|
|
1566
|
+
type: import_isolate_protocol.MessageType.CLIENT_EVENT,
|
|
1405
1567
|
isolateId,
|
|
1406
|
-
|
|
1407
|
-
data
|
|
1408
|
-
};
|
|
1409
|
-
sendMessage(state.socket, msg);
|
|
1568
|
+
event: import_isolate_protocol.ClientEvents.WS_CLIENT_MESSAGE,
|
|
1569
|
+
payload: { socketId, data }
|
|
1570
|
+
});
|
|
1410
1571
|
};
|
|
1411
1572
|
ws.onerror = () => {
|
|
1412
|
-
|
|
1413
|
-
type: import_isolate_protocol.MessageType.
|
|
1573
|
+
sendMessage(state.socket, {
|
|
1574
|
+
type: import_isolate_protocol.MessageType.CLIENT_EVENT,
|
|
1414
1575
|
isolateId,
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1576
|
+
event: import_isolate_protocol.ClientEvents.WS_CLIENT_ERROR,
|
|
1577
|
+
payload: { socketId }
|
|
1578
|
+
});
|
|
1418
1579
|
};
|
|
1419
1580
|
ws.onclose = (event) => {
|
|
1420
|
-
|
|
1421
|
-
type: import_isolate_protocol.MessageType.
|
|
1581
|
+
sendMessage(state.socket, {
|
|
1582
|
+
type: import_isolate_protocol.MessageType.CLIENT_EVENT,
|
|
1422
1583
|
isolateId,
|
|
1423
|
-
|
|
1424
|
-
code: event.code,
|
|
1425
|
-
|
|
1426
|
-
wasClean: event.wasClean
|
|
1427
|
-
};
|
|
1428
|
-
sendMessage(state.socket, msg);
|
|
1584
|
+
event: import_isolate_protocol.ClientEvents.WS_CLIENT_CLOSED,
|
|
1585
|
+
payload: { socketId, code: event.code, reason: event.reason, wasClean: event.wasClean }
|
|
1586
|
+
});
|
|
1429
1587
|
sockets?.delete(socketId);
|
|
1430
1588
|
if (sockets?.size === 0) {
|
|
1431
1589
|
isolateClientWebSockets.delete(isolateId);
|
|
@@ -1433,21 +1591,18 @@ function handleClientWsConnect(message, state) {
|
|
|
1433
1591
|
};
|
|
1434
1592
|
};
|
|
1435
1593
|
const sendConnectionFailed = (reason) => {
|
|
1436
|
-
|
|
1437
|
-
type: import_isolate_protocol.MessageType.
|
|
1594
|
+
sendMessage(state.socket, {
|
|
1595
|
+
type: import_isolate_protocol.MessageType.CLIENT_EVENT,
|
|
1438
1596
|
isolateId,
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
type: import_isolate_protocol.MessageType.
|
|
1597
|
+
event: import_isolate_protocol.ClientEvents.WS_CLIENT_ERROR,
|
|
1598
|
+
payload: { socketId }
|
|
1599
|
+
});
|
|
1600
|
+
sendMessage(state.socket, {
|
|
1601
|
+
type: import_isolate_protocol.MessageType.CLIENT_EVENT,
|
|
1444
1602
|
isolateId,
|
|
1445
|
-
|
|
1446
|
-
code: 1006,
|
|
1447
|
-
|
|
1448
|
-
wasClean: false
|
|
1449
|
-
};
|
|
1450
|
-
sendMessage(state.socket, closeMsg);
|
|
1603
|
+
event: import_isolate_protocol.ClientEvents.WS_CLIENT_CLOSED,
|
|
1604
|
+
payload: { socketId, code: 1006, reason, wasClean: false }
|
|
1605
|
+
});
|
|
1451
1606
|
};
|
|
1452
1607
|
const callback = isolateWebSocketCallbacks.get(isolateId);
|
|
1453
1608
|
if (callback) {
|
|
@@ -1480,8 +1635,8 @@ function handleClientWsConnect(message, state) {
|
|
|
1480
1635
|
}
|
|
1481
1636
|
}
|
|
1482
1637
|
}
|
|
1483
|
-
function handleClientWsSend(
|
|
1484
|
-
const {
|
|
1638
|
+
function handleClientWsSend(isolateId, payload, state) {
|
|
1639
|
+
const { socketId, data } = payload;
|
|
1485
1640
|
const sockets = isolateClientWebSockets.get(isolateId);
|
|
1486
1641
|
const ws = sockets?.get(socketId);
|
|
1487
1642
|
if (!ws || ws.readyState !== WebSocket.OPEN) {
|
|
@@ -1492,13 +1647,13 @@ function handleClientWsSend(message, state) {
|
|
|
1492
1647
|
const binary = Buffer.from(base64, "base64");
|
|
1493
1648
|
ws.send(binary);
|
|
1494
1649
|
} else if (data instanceof Uint8Array) {
|
|
1495
|
-
ws.send(data);
|
|
1650
|
+
ws.send(Buffer.from(data));
|
|
1496
1651
|
} else {
|
|
1497
1652
|
ws.send(data);
|
|
1498
1653
|
}
|
|
1499
1654
|
}
|
|
1500
|
-
function handleClientWsClose(
|
|
1501
|
-
const {
|
|
1655
|
+
function handleClientWsClose(isolateId, payload, state) {
|
|
1656
|
+
const { socketId, code, reason } = payload;
|
|
1502
1657
|
const sockets = isolateClientWebSockets.get(isolateId);
|
|
1503
1658
|
const ws = sockets?.get(socketId);
|
|
1504
1659
|
if (!ws) {
|
|
@@ -1509,4 +1664,4 @@ function handleClientWsClose(message, state) {
|
|
|
1509
1664
|
}
|
|
1510
1665
|
}
|
|
1511
1666
|
|
|
1512
|
-
//# debugId=
|
|
1667
|
+
//# debugId=BB5A27475A32C8E264756E2164756E21
|