@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/mjs/connection.mjs
CHANGED
|
@@ -8,16 +8,21 @@ import {
|
|
|
8
8
|
STREAM_THRESHOLD,
|
|
9
9
|
STREAM_CHUNK_SIZE,
|
|
10
10
|
STREAM_DEFAULT_CREDIT,
|
|
11
|
-
|
|
11
|
+
IsolateEvents,
|
|
12
|
+
ClientEvents,
|
|
13
|
+
marshalValue,
|
|
14
|
+
isPromiseRef,
|
|
15
|
+
isAsyncIteratorRef,
|
|
16
|
+
serializeResponse,
|
|
17
|
+
deserializeResponse
|
|
12
18
|
} from "@ricsam/isolate-protocol";
|
|
13
19
|
import {
|
|
14
20
|
getDefaultPlaywrightHandlerMetadata
|
|
15
21
|
} from "@ricsam/isolate-playwright/client";
|
|
16
|
-
var DEFAULT_TIMEOUT = 30000;
|
|
17
|
-
var TEST_REQUEST_TIMEOUT_BUFFER_MS = 1000;
|
|
18
22
|
var isolateWsCallbacks = new Map;
|
|
19
23
|
var isolateClientWebSockets = new Map;
|
|
20
24
|
var isolateWebSocketCallbacks = new Map;
|
|
25
|
+
var isolateEventListeners = new Map;
|
|
21
26
|
async function connect(options = {}) {
|
|
22
27
|
const socket = await createSocket(options);
|
|
23
28
|
const state = {
|
|
@@ -32,47 +37,142 @@ async function connect(options = {}) {
|
|
|
32
37
|
streamResponses: new Map,
|
|
33
38
|
uploadStreams: new Map,
|
|
34
39
|
moduleSourceCache: new Map,
|
|
35
|
-
callbackStreamReaders: new Map
|
|
40
|
+
callbackStreamReaders: new Map,
|
|
41
|
+
closing: false,
|
|
42
|
+
namespacedRuntimes: new Map
|
|
36
43
|
};
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
function setupSocket(sock) {
|
|
45
|
+
const parser = createFrameParser();
|
|
46
|
+
sock.on("data", (data) => {
|
|
47
|
+
try {
|
|
48
|
+
for (const frame of parser.feed(new Uint8Array(data))) {
|
|
49
|
+
handleMessage(frame.message, state);
|
|
50
|
+
}
|
|
51
|
+
} catch (err) {
|
|
52
|
+
console.error("Error parsing frame:", err);
|
|
42
53
|
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
state.connected = false;
|
|
49
|
-
for (const [, pending] of state.pendingRequests) {
|
|
50
|
-
if (pending.timeoutId) {
|
|
51
|
-
clearTimeout(pending.timeoutId);
|
|
54
|
+
});
|
|
55
|
+
sock.on("close", () => {
|
|
56
|
+
state.connected = false;
|
|
57
|
+
for (const [, pending] of state.pendingRequests) {
|
|
58
|
+
pending.reject(new Error("Connection closed"));
|
|
52
59
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
resolver();
|
|
60
|
+
state.pendingRequests.clear();
|
|
61
|
+
for (const [, receiver] of state.streamResponses) {
|
|
62
|
+
receiver.state = "errored";
|
|
63
|
+
receiver.error = new Error("Connection closed");
|
|
64
|
+
const resolvers = receiver.pullResolvers.splice(0);
|
|
65
|
+
for (const resolver of resolvers) {
|
|
66
|
+
resolver();
|
|
67
|
+
}
|
|
62
68
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
state.streamResponses.clear();
|
|
70
|
+
for (const [, session] of state.uploadStreams) {
|
|
71
|
+
session.state = "closed";
|
|
72
|
+
if (session.creditResolver) {
|
|
73
|
+
session.creditResolver();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
state.uploadStreams.clear();
|
|
77
|
+
if (!state.closing && state.namespacedRuntimes.size > 0) {
|
|
78
|
+
state.reconnecting = reconnect(state, options).catch(() => {
|
|
79
|
+
state.namespacedRuntimes.clear();
|
|
80
|
+
state.reconnecting = undefined;
|
|
81
|
+
});
|
|
69
82
|
}
|
|
83
|
+
});
|
|
84
|
+
sock.on("error", (err) => {
|
|
85
|
+
if (!state.closing && state.namespacedRuntimes.size > 0)
|
|
86
|
+
return;
|
|
87
|
+
console.error("Socket error:", err);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
setupSocket(socket);
|
|
91
|
+
async function reconnect(st, opts) {
|
|
92
|
+
try {
|
|
93
|
+
const newSocket = await createSocket(opts);
|
|
94
|
+
st.socket = newSocket;
|
|
95
|
+
st.connected = true;
|
|
96
|
+
setupSocket(newSocket);
|
|
97
|
+
for (const [namespaceId, descriptor] of st.namespacedRuntimes) {
|
|
98
|
+
const runtimeOptions = descriptor.runtimeOptions;
|
|
99
|
+
const callbacks = {};
|
|
100
|
+
if (runtimeOptions.console) {
|
|
101
|
+
callbacks.console = registerConsoleCallbacks(st, runtimeOptions.console);
|
|
102
|
+
}
|
|
103
|
+
if (runtimeOptions.fetch) {
|
|
104
|
+
callbacks.fetch = registerFetchCallback(st, runtimeOptions.fetch);
|
|
105
|
+
}
|
|
106
|
+
if (runtimeOptions.fs) {
|
|
107
|
+
callbacks.fs = registerFsCallbacks(st, runtimeOptions.fs);
|
|
108
|
+
}
|
|
109
|
+
if (runtimeOptions.moduleLoader) {
|
|
110
|
+
callbacks.moduleLoader = registerModuleLoaderCallback(st, runtimeOptions.moduleLoader);
|
|
111
|
+
}
|
|
112
|
+
if (runtimeOptions.customFunctions) {
|
|
113
|
+
callbacks.custom = registerCustomFunctions(st, runtimeOptions.customFunctions);
|
|
114
|
+
}
|
|
115
|
+
if (runtimeOptions.playwright) {
|
|
116
|
+
const playwrightHandler = runtimeOptions.playwright.handler;
|
|
117
|
+
if (playwrightHandler) {
|
|
118
|
+
const handlerCallbackId = st.nextCallbackId++;
|
|
119
|
+
st.callbacks.set(handlerCallbackId, async (opJson) => {
|
|
120
|
+
const op = JSON.parse(opJson);
|
|
121
|
+
const result2 = await playwrightHandler(op);
|
|
122
|
+
return JSON.stringify(result2);
|
|
123
|
+
});
|
|
124
|
+
callbacks.playwright = {
|
|
125
|
+
handlerCallbackId,
|
|
126
|
+
console: runtimeOptions.playwright.console && !runtimeOptions.console?.onEntry
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
let testEnvironmentOption;
|
|
131
|
+
if (runtimeOptions.testEnvironment) {
|
|
132
|
+
if (typeof runtimeOptions.testEnvironment === "object") {
|
|
133
|
+
const testEnvOptions = runtimeOptions.testEnvironment;
|
|
134
|
+
const testEnvCallbacks = {};
|
|
135
|
+
if (testEnvOptions.onEvent) {
|
|
136
|
+
const userOnEvent = testEnvOptions.onEvent;
|
|
137
|
+
const onEventCallbackId = registerEventCallback(st, (eventJson) => {
|
|
138
|
+
const event = JSON.parse(eventJson);
|
|
139
|
+
userOnEvent(event);
|
|
140
|
+
});
|
|
141
|
+
testEnvCallbacks.onEvent = {
|
|
142
|
+
callbackId: onEventCallbackId,
|
|
143
|
+
name: "testEnvironment.onEvent",
|
|
144
|
+
type: "sync"
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
testEnvironmentOption = {
|
|
148
|
+
callbacks: testEnvCallbacks,
|
|
149
|
+
testTimeout: testEnvOptions.testTimeout
|
|
150
|
+
};
|
|
151
|
+
} else {
|
|
152
|
+
testEnvironmentOption = true;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const requestId = st.nextRequestId++;
|
|
156
|
+
const request = {
|
|
157
|
+
type: MessageType.CREATE_RUNTIME,
|
|
158
|
+
requestId,
|
|
159
|
+
options: {
|
|
160
|
+
memoryLimitMB: runtimeOptions.memoryLimitMB,
|
|
161
|
+
cwd: runtimeOptions.cwd,
|
|
162
|
+
callbacks,
|
|
163
|
+
testEnvironment: testEnvironmentOption,
|
|
164
|
+
namespaceId
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
const result = await sendRequest(st, request);
|
|
168
|
+
descriptor.isolateId = result.isolateId;
|
|
169
|
+
}
|
|
170
|
+
st.reconnecting = undefined;
|
|
171
|
+
} catch {
|
|
172
|
+
st.reconnecting = undefined;
|
|
173
|
+
throw new Error("Failed to reconnect to daemon");
|
|
70
174
|
}
|
|
71
|
-
|
|
72
|
-
});
|
|
73
|
-
socket.on("error", (err) => {
|
|
74
|
-
console.error("Socket error:", err);
|
|
75
|
-
});
|
|
175
|
+
}
|
|
76
176
|
return {
|
|
77
177
|
createRuntime: (runtimeOptions) => createRuntime(state, runtimeOptions),
|
|
78
178
|
createNamespace: (id) => ({
|
|
@@ -80,15 +180,16 @@ async function connect(options = {}) {
|
|
|
80
180
|
createRuntime: (runtimeOptions) => createRuntime(state, runtimeOptions, id)
|
|
81
181
|
}),
|
|
82
182
|
close: async () => {
|
|
183
|
+
state.closing = true;
|
|
83
184
|
state.connected = false;
|
|
84
|
-
socket.destroy();
|
|
185
|
+
state.socket.destroy();
|
|
85
186
|
},
|
|
86
187
|
isConnected: () => state.connected
|
|
87
188
|
};
|
|
88
189
|
}
|
|
89
190
|
function createSocket(options) {
|
|
90
191
|
return new Promise((resolve, reject) => {
|
|
91
|
-
const timeout = options.timeout
|
|
192
|
+
const timeout = options.timeout;
|
|
92
193
|
let socket;
|
|
93
194
|
const onError = (err) => {
|
|
94
195
|
reject(err);
|
|
@@ -103,13 +204,15 @@ function createSocket(options) {
|
|
|
103
204
|
socket = netConnect(options.port ?? 47891, options.host ?? "127.0.0.1", onConnect);
|
|
104
205
|
}
|
|
105
206
|
socket.on("error", onError);
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
207
|
+
if (timeout && timeout > 0) {
|
|
208
|
+
const timeoutId = setTimeout(() => {
|
|
209
|
+
socket.destroy();
|
|
210
|
+
reject(new Error("Connection timeout"));
|
|
211
|
+
}, timeout);
|
|
212
|
+
socket.once("connect", () => {
|
|
213
|
+
clearTimeout(timeoutId);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
113
216
|
});
|
|
114
217
|
}
|
|
115
218
|
function handleMessage(message, state) {
|
|
@@ -119,8 +222,6 @@ function handleMessage(message, state) {
|
|
|
119
222
|
const pending = state.pendingRequests.get(response.requestId);
|
|
120
223
|
if (pending) {
|
|
121
224
|
state.pendingRequests.delete(response.requestId);
|
|
122
|
-
if (pending.timeoutId)
|
|
123
|
-
clearTimeout(pending.timeoutId);
|
|
124
225
|
pending.resolve(response.data);
|
|
125
226
|
}
|
|
126
227
|
break;
|
|
@@ -130,8 +231,6 @@ function handleMessage(message, state) {
|
|
|
130
231
|
const pending = state.pendingRequests.get(response.requestId);
|
|
131
232
|
if (pending) {
|
|
132
233
|
state.pendingRequests.delete(response.requestId);
|
|
133
|
-
if (pending.timeoutId)
|
|
134
|
-
clearTimeout(pending.timeoutId);
|
|
135
234
|
const error = new Error(response.message);
|
|
136
235
|
if (response.details) {
|
|
137
236
|
error.name = response.details.name;
|
|
@@ -158,42 +257,9 @@ function handleMessage(message, state) {
|
|
|
158
257
|
}
|
|
159
258
|
break;
|
|
160
259
|
}
|
|
161
|
-
case MessageType.
|
|
162
|
-
const msg = message;
|
|
163
|
-
const callbacks = isolateWsCallbacks.get(msg.isolateId);
|
|
164
|
-
if (callbacks) {
|
|
165
|
-
let data;
|
|
166
|
-
if (msg.command.data instanceof Uint8Array) {
|
|
167
|
-
data = msg.command.data.buffer.slice(msg.command.data.byteOffset, msg.command.data.byteOffset + msg.command.data.byteLength);
|
|
168
|
-
} else {
|
|
169
|
-
data = msg.command.data;
|
|
170
|
-
}
|
|
171
|
-
const cmd = {
|
|
172
|
-
type: msg.command.type,
|
|
173
|
-
connectionId: msg.command.connectionId,
|
|
174
|
-
data,
|
|
175
|
-
code: msg.command.code,
|
|
176
|
-
reason: msg.command.reason
|
|
177
|
-
};
|
|
178
|
-
for (const cb of callbacks) {
|
|
179
|
-
cb(cmd);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
break;
|
|
183
|
-
}
|
|
184
|
-
case MessageType.CLIENT_WS_CONNECT: {
|
|
185
|
-
const msg = message;
|
|
186
|
-
handleClientWsConnect(msg, state);
|
|
187
|
-
break;
|
|
188
|
-
}
|
|
189
|
-
case MessageType.CLIENT_WS_SEND: {
|
|
260
|
+
case MessageType.ISOLATE_EVENT: {
|
|
190
261
|
const msg = message;
|
|
191
|
-
|
|
192
|
-
break;
|
|
193
|
-
}
|
|
194
|
-
case MessageType.CLIENT_WS_CLOSE: {
|
|
195
|
-
const msg = message;
|
|
196
|
-
handleClientWsClose(msg, state);
|
|
262
|
+
handleIsolateEvent(msg, state);
|
|
197
263
|
break;
|
|
198
264
|
}
|
|
199
265
|
case MessageType.RESPONSE_STREAM_START: {
|
|
@@ -263,8 +329,6 @@ function handleMessage(message, state) {
|
|
|
263
329
|
const pending = state.pendingRequests.get(msg.requestId);
|
|
264
330
|
if (pending) {
|
|
265
331
|
state.pendingRequests.delete(msg.requestId);
|
|
266
|
-
if (pending.timeoutId)
|
|
267
|
-
clearTimeout(pending.timeoutId);
|
|
268
332
|
const response = new Response(readableStream, {
|
|
269
333
|
status: msg.metadata?.status ?? 200,
|
|
270
334
|
statusText: msg.metadata?.statusText ?? "OK",
|
|
@@ -389,25 +453,24 @@ function sendMessage(socket, message) {
|
|
|
389
453
|
const frame = buildFrame(message);
|
|
390
454
|
socket.write(frame);
|
|
391
455
|
}
|
|
392
|
-
function sendRequest(state, message
|
|
456
|
+
function sendRequest(state, message) {
|
|
393
457
|
return new Promise((resolve, reject) => {
|
|
394
458
|
if (!state.connected) {
|
|
395
459
|
reject(new Error("Not connected"));
|
|
396
460
|
return;
|
|
397
461
|
}
|
|
398
462
|
const requestId = message.requestId;
|
|
399
|
-
const timeoutId = setTimeout(() => {
|
|
400
|
-
state.pendingRequests.delete(requestId);
|
|
401
|
-
reject(new Error("Request timeout"));
|
|
402
|
-
}, timeout);
|
|
403
463
|
state.pendingRequests.set(requestId, {
|
|
404
464
|
resolve,
|
|
405
|
-
reject
|
|
406
|
-
timeoutId
|
|
465
|
+
reject
|
|
407
466
|
});
|
|
408
467
|
sendMessage(state.socket, message);
|
|
409
468
|
});
|
|
410
469
|
}
|
|
470
|
+
function isBenignDisposeError(error) {
|
|
471
|
+
const message = error instanceof Error ? error.message : String(error ?? "");
|
|
472
|
+
return /isolate not owned by this connection|isolate not found|not connected|connection closed/i.test(message);
|
|
473
|
+
}
|
|
411
474
|
async function createRuntime(state, options = {}, namespaceId) {
|
|
412
475
|
const callbacks = {};
|
|
413
476
|
if (options.console) {
|
|
@@ -546,13 +609,26 @@ async function createRuntime(state, options = {}, namespaceId) {
|
|
|
546
609
|
const result = await sendRequest(state, request);
|
|
547
610
|
const isolateId = result.isolateId;
|
|
548
611
|
const reused = result.reused ?? false;
|
|
612
|
+
if (namespaceId != null) {
|
|
613
|
+
state.namespacedRuntimes.set(namespaceId, {
|
|
614
|
+
isolateId,
|
|
615
|
+
runtimeOptions: options
|
|
616
|
+
});
|
|
617
|
+
}
|
|
549
618
|
const wsCommandCallbacks = new Set;
|
|
550
619
|
isolateWsCallbacks.set(isolateId, wsCommandCallbacks);
|
|
620
|
+
if (options.onWebSocketCommand) {
|
|
621
|
+
wsCommandCallbacks.add(options.onWebSocketCommand);
|
|
622
|
+
}
|
|
551
623
|
if (options.webSocket) {
|
|
552
624
|
isolateWebSocketCallbacks.set(isolateId, options.webSocket);
|
|
553
625
|
}
|
|
554
626
|
const fetchHandle = {
|
|
555
627
|
async dispatchRequest(req, opts) {
|
|
628
|
+
const signal = opts?.signal;
|
|
629
|
+
if (signal?.aborted) {
|
|
630
|
+
throw new DOMException("The operation was aborted", "AbortError");
|
|
631
|
+
}
|
|
556
632
|
const reqId = state.nextRequestId++;
|
|
557
633
|
const serialized = await serializeRequestWithStreaming(state, req);
|
|
558
634
|
const { bodyStream, ...serializableRequest } = serialized;
|
|
@@ -560,8 +636,7 @@ async function createRuntime(state, options = {}, namespaceId) {
|
|
|
560
636
|
type: MessageType.DISPATCH_REQUEST,
|
|
561
637
|
requestId: reqId,
|
|
562
638
|
isolateId,
|
|
563
|
-
request: serializableRequest
|
|
564
|
-
options: opts
|
|
639
|
+
request: serializableRequest
|
|
565
640
|
};
|
|
566
641
|
const handleResponse = (res) => {
|
|
567
642
|
if (res.__streaming && res.response instanceof Response) {
|
|
@@ -569,15 +644,32 @@ async function createRuntime(state, options = {}, namespaceId) {
|
|
|
569
644
|
}
|
|
570
645
|
return deserializeResponse(res.response);
|
|
571
646
|
};
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
647
|
+
let onAbort;
|
|
648
|
+
if (signal) {
|
|
649
|
+
onAbort = () => {
|
|
650
|
+
const pending = state.pendingRequests.get(reqId);
|
|
651
|
+
if (pending) {
|
|
652
|
+
state.pendingRequests.delete(reqId);
|
|
653
|
+
pending.reject(new DOMException("The operation was aborted", "AbortError"));
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
657
|
+
}
|
|
658
|
+
try {
|
|
659
|
+
if (serialized.bodyStreamId !== undefined && bodyStream) {
|
|
660
|
+
const streamId = serialized.bodyStreamId;
|
|
661
|
+
const responsePromise = sendRequest(state, request2);
|
|
662
|
+
await sendBodyStream(state, streamId, bodyStream);
|
|
663
|
+
const res = await responsePromise;
|
|
664
|
+
return handleResponse(res);
|
|
665
|
+
} else {
|
|
666
|
+
const res = await sendRequest(state, request2);
|
|
667
|
+
return handleResponse(res);
|
|
668
|
+
}
|
|
669
|
+
} finally {
|
|
670
|
+
if (signal && onAbort) {
|
|
671
|
+
signal.removeEventListener("abort", onAbort);
|
|
672
|
+
}
|
|
581
673
|
}
|
|
582
674
|
},
|
|
583
675
|
async getUpgradeRequest() {
|
|
@@ -724,8 +816,22 @@ async function createRuntime(state, options = {}, namespaceId) {
|
|
|
724
816
|
isolateId,
|
|
725
817
|
timeout
|
|
726
818
|
};
|
|
727
|
-
|
|
728
|
-
|
|
819
|
+
try {
|
|
820
|
+
return await sendRequest(state, req);
|
|
821
|
+
} catch (err) {
|
|
822
|
+
if (err instanceof Error && /connection closed|not connected/i.test(err.message) && state.reconnecting) {
|
|
823
|
+
await state.reconnecting;
|
|
824
|
+
const retryReqId = state.nextRequestId++;
|
|
825
|
+
const retryReq = {
|
|
826
|
+
type: MessageType.RUN_TESTS,
|
|
827
|
+
requestId: retryReqId,
|
|
828
|
+
isolateId,
|
|
829
|
+
timeout
|
|
830
|
+
};
|
|
831
|
+
return sendRequest(state, retryReq);
|
|
832
|
+
}
|
|
833
|
+
throw err;
|
|
834
|
+
}
|
|
729
835
|
},
|
|
730
836
|
async hasTests() {
|
|
731
837
|
if (!testEnvironmentEnabled) {
|
|
@@ -800,17 +906,47 @@ async function createRuntime(state, options = {}, namespaceId) {
|
|
|
800
906
|
requestId: reqId,
|
|
801
907
|
isolateId,
|
|
802
908
|
code,
|
|
803
|
-
filename: options2?.filename
|
|
804
|
-
maxExecutionMs: options2?.maxExecutionMs
|
|
909
|
+
filename: options2?.filename
|
|
805
910
|
};
|
|
806
911
|
await sendRequest(state, req);
|
|
807
912
|
},
|
|
913
|
+
on(event, callback) {
|
|
914
|
+
let listeners = isolateEventListeners.get(isolateId);
|
|
915
|
+
if (!listeners) {
|
|
916
|
+
listeners = new Map;
|
|
917
|
+
isolateEventListeners.set(isolateId, listeners);
|
|
918
|
+
}
|
|
919
|
+
let eventListeners = listeners.get(event);
|
|
920
|
+
if (!eventListeners) {
|
|
921
|
+
eventListeners = new Set;
|
|
922
|
+
listeners.set(event, eventListeners);
|
|
923
|
+
}
|
|
924
|
+
eventListeners.add(callback);
|
|
925
|
+
return () => {
|
|
926
|
+
eventListeners.delete(callback);
|
|
927
|
+
if (eventListeners.size === 0) {
|
|
928
|
+
listeners.delete(event);
|
|
929
|
+
if (listeners.size === 0) {
|
|
930
|
+
isolateEventListeners.delete(isolateId);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
},
|
|
935
|
+
emit(event, payload) {
|
|
936
|
+
sendMessage(state.socket, {
|
|
937
|
+
type: MessageType.CLIENT_EVENT,
|
|
938
|
+
isolateId,
|
|
939
|
+
event,
|
|
940
|
+
payload
|
|
941
|
+
});
|
|
942
|
+
},
|
|
808
943
|
dispose: async () => {
|
|
809
944
|
for (const cleanup of pageListenerCleanups) {
|
|
810
945
|
cleanup();
|
|
811
946
|
}
|
|
812
947
|
isolateWsCallbacks.delete(isolateId);
|
|
813
948
|
isolateWebSocketCallbacks.delete(isolateId);
|
|
949
|
+
isolateEventListeners.delete(isolateId);
|
|
814
950
|
const clientSockets = isolateClientWebSockets.get(isolateId);
|
|
815
951
|
if (clientSockets) {
|
|
816
952
|
for (const ws of clientSockets.values()) {
|
|
@@ -820,13 +956,22 @@ async function createRuntime(state, options = {}, namespaceId) {
|
|
|
820
956
|
}
|
|
821
957
|
isolateClientWebSockets.delete(isolateId);
|
|
822
958
|
}
|
|
959
|
+
if (namespaceId != null) {
|
|
960
|
+
state.namespacedRuntimes.delete(namespaceId);
|
|
961
|
+
}
|
|
823
962
|
const reqId = state.nextRequestId++;
|
|
824
963
|
const req = {
|
|
825
964
|
type: MessageType.DISPOSE_RUNTIME,
|
|
826
965
|
requestId: reqId,
|
|
827
966
|
isolateId
|
|
828
967
|
};
|
|
829
|
-
|
|
968
|
+
try {
|
|
969
|
+
await sendRequest(state, req);
|
|
970
|
+
} catch (error) {
|
|
971
|
+
if (!isBenignDisposeError(error)) {
|
|
972
|
+
throw error;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
830
975
|
}
|
|
831
976
|
};
|
|
832
977
|
}
|
|
@@ -858,8 +1003,8 @@ function registerFetchCallback(state, callback) {
|
|
|
858
1003
|
const init = {
|
|
859
1004
|
method: data.method,
|
|
860
1005
|
headers: data.headers,
|
|
861
|
-
rawBody: data.body,
|
|
862
|
-
body: data.body,
|
|
1006
|
+
rawBody: data.body ?? null,
|
|
1007
|
+
body: data.body ?? null,
|
|
863
1008
|
signal: new AbortController().signal
|
|
864
1009
|
};
|
|
865
1010
|
const response = await callback(data.url, init);
|
|
@@ -1005,7 +1150,7 @@ function registerModuleLoaderCallback(state, callback) {
|
|
|
1005
1150
|
const specifier = moduleName;
|
|
1006
1151
|
const importerInfo = importer;
|
|
1007
1152
|
const result = await callback(specifier, importerInfo);
|
|
1008
|
-
const resolvedPath = path.posix.join(result.resolveDir,
|
|
1153
|
+
const resolvedPath = path.posix.join(result.resolveDir, result.filename);
|
|
1009
1154
|
state.moduleSourceCache.set(resolvedPath, result.code);
|
|
1010
1155
|
return result;
|
|
1011
1156
|
});
|
|
@@ -1015,12 +1160,6 @@ var clientIteratorSessions = new Map;
|
|
|
1015
1160
|
var nextClientIteratorId = 1;
|
|
1016
1161
|
var returnedPromiseRegistry = new Map;
|
|
1017
1162
|
var returnedIteratorRegistry = new Map;
|
|
1018
|
-
function isPromiseRef(value) {
|
|
1019
|
-
return typeof value === "object" && value !== null && value.__type === "PromiseRef";
|
|
1020
|
-
}
|
|
1021
|
-
function isAsyncIteratorRef(value) {
|
|
1022
|
-
return typeof value === "object" && value !== null && value.__type === "AsyncIteratorRef";
|
|
1023
|
-
}
|
|
1024
1163
|
function registerCustomFunctions(state, customFunctions) {
|
|
1025
1164
|
const registrations = {};
|
|
1026
1165
|
for (const [name, def] of Object.entries(customFunctions)) {
|
|
@@ -1204,29 +1343,6 @@ function registerCustomFunctions(state, customFunctions) {
|
|
|
1204
1343
|
}
|
|
1205
1344
|
return registrations;
|
|
1206
1345
|
}
|
|
1207
|
-
async function serializeResponse(response) {
|
|
1208
|
-
const headers = [];
|
|
1209
|
-
response.headers.forEach((value, key) => {
|
|
1210
|
-
headers.push([key, value]);
|
|
1211
|
-
});
|
|
1212
|
-
let body = null;
|
|
1213
|
-
if (response.body) {
|
|
1214
|
-
body = new Uint8Array(await response.arrayBuffer());
|
|
1215
|
-
}
|
|
1216
|
-
return {
|
|
1217
|
-
status: response.status,
|
|
1218
|
-
statusText: response.statusText,
|
|
1219
|
-
headers,
|
|
1220
|
-
body
|
|
1221
|
-
};
|
|
1222
|
-
}
|
|
1223
|
-
function deserializeResponse(data) {
|
|
1224
|
-
return new Response(data.body, {
|
|
1225
|
-
status: data.status,
|
|
1226
|
-
statusText: data.statusText,
|
|
1227
|
-
headers: data.headers
|
|
1228
|
-
});
|
|
1229
|
-
}
|
|
1230
1346
|
async function serializeRequestWithStreaming(state, request) {
|
|
1231
1347
|
const headers = [];
|
|
1232
1348
|
request.headers.forEach((value, key) => {
|
|
@@ -1325,8 +1441,62 @@ async function sendBodyStream(state, streamId, body) {
|
|
|
1325
1441
|
state.uploadStreams.delete(streamId);
|
|
1326
1442
|
}
|
|
1327
1443
|
}
|
|
1328
|
-
function
|
|
1329
|
-
|
|
1444
|
+
function handleIsolateEvent(message, state) {
|
|
1445
|
+
switch (message.event) {
|
|
1446
|
+
case IsolateEvents.WS_COMMAND: {
|
|
1447
|
+
const payload = message.payload;
|
|
1448
|
+
const callbacks = isolateWsCallbacks.get(message.isolateId);
|
|
1449
|
+
if (callbacks) {
|
|
1450
|
+
let data;
|
|
1451
|
+
if (payload.data instanceof Uint8Array) {
|
|
1452
|
+
data = payload.data.buffer.slice(payload.data.byteOffset, payload.data.byteOffset + payload.data.byteLength);
|
|
1453
|
+
} else {
|
|
1454
|
+
data = payload.data;
|
|
1455
|
+
}
|
|
1456
|
+
const cmd = {
|
|
1457
|
+
type: payload.type,
|
|
1458
|
+
connectionId: payload.connectionId,
|
|
1459
|
+
data,
|
|
1460
|
+
code: payload.code,
|
|
1461
|
+
reason: payload.reason
|
|
1462
|
+
};
|
|
1463
|
+
for (const cb of callbacks) {
|
|
1464
|
+
cb(cmd);
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
break;
|
|
1468
|
+
}
|
|
1469
|
+
case IsolateEvents.WS_CLIENT_CONNECT: {
|
|
1470
|
+
const payload = message.payload;
|
|
1471
|
+
handleClientWsConnect(message.isolateId, payload, state);
|
|
1472
|
+
break;
|
|
1473
|
+
}
|
|
1474
|
+
case IsolateEvents.WS_CLIENT_SEND: {
|
|
1475
|
+
const payload = message.payload;
|
|
1476
|
+
handleClientWsSend(message.isolateId, payload, state);
|
|
1477
|
+
break;
|
|
1478
|
+
}
|
|
1479
|
+
case IsolateEvents.WS_CLIENT_CLOSE: {
|
|
1480
|
+
const payload = message.payload;
|
|
1481
|
+
handleClientWsClose(message.isolateId, payload, state);
|
|
1482
|
+
break;
|
|
1483
|
+
}
|
|
1484
|
+
default: {
|
|
1485
|
+
const listeners = isolateEventListeners.get(message.isolateId);
|
|
1486
|
+
if (listeners) {
|
|
1487
|
+
const eventListeners = listeners.get(message.event);
|
|
1488
|
+
if (eventListeners) {
|
|
1489
|
+
for (const cb of eventListeners) {
|
|
1490
|
+
cb(message.payload);
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
break;
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
function handleClientWsConnect(isolateId, payload, state) {
|
|
1499
|
+
const { socketId, url, protocols } = payload;
|
|
1330
1500
|
let sockets = isolateClientWebSockets.get(isolateId);
|
|
1331
1501
|
if (!sockets) {
|
|
1332
1502
|
sockets = new Map;
|
|
@@ -1335,14 +1505,12 @@ function handleClientWsConnect(message, state) {
|
|
|
1335
1505
|
const setupWebSocket = (ws) => {
|
|
1336
1506
|
sockets.set(socketId, ws);
|
|
1337
1507
|
ws.onopen = () => {
|
|
1338
|
-
|
|
1339
|
-
type: MessageType.
|
|
1508
|
+
sendMessage(state.socket, {
|
|
1509
|
+
type: MessageType.CLIENT_EVENT,
|
|
1340
1510
|
isolateId,
|
|
1341
|
-
|
|
1342
|
-
protocol: ws.protocol || "",
|
|
1343
|
-
|
|
1344
|
-
};
|
|
1345
|
-
sendMessage(state.socket, msg);
|
|
1511
|
+
event: ClientEvents.WS_CLIENT_OPENED,
|
|
1512
|
+
payload: { socketId, protocol: ws.protocol || "", extensions: ws.extensions || "" }
|
|
1513
|
+
});
|
|
1346
1514
|
};
|
|
1347
1515
|
ws.onmessage = (event) => {
|
|
1348
1516
|
let data;
|
|
@@ -1352,44 +1520,39 @@ function handleClientWsConnect(message, state) {
|
|
|
1352
1520
|
data = new Uint8Array(event.data);
|
|
1353
1521
|
} else if (event.data instanceof Blob) {
|
|
1354
1522
|
event.data.arrayBuffer().then((buffer) => {
|
|
1355
|
-
|
|
1356
|
-
type: MessageType.
|
|
1523
|
+
sendMessage(state.socket, {
|
|
1524
|
+
type: MessageType.CLIENT_EVENT,
|
|
1357
1525
|
isolateId,
|
|
1358
|
-
|
|
1359
|
-
data: new Uint8Array(buffer)
|
|
1360
|
-
};
|
|
1361
|
-
sendMessage(state.socket, msg2);
|
|
1526
|
+
event: ClientEvents.WS_CLIENT_MESSAGE,
|
|
1527
|
+
payload: { socketId, data: new Uint8Array(buffer) }
|
|
1528
|
+
});
|
|
1362
1529
|
});
|
|
1363
1530
|
return;
|
|
1364
1531
|
} else {
|
|
1365
1532
|
data = String(event.data);
|
|
1366
1533
|
}
|
|
1367
|
-
|
|
1368
|
-
type: MessageType.
|
|
1534
|
+
sendMessage(state.socket, {
|
|
1535
|
+
type: MessageType.CLIENT_EVENT,
|
|
1369
1536
|
isolateId,
|
|
1370
|
-
|
|
1371
|
-
data
|
|
1372
|
-
};
|
|
1373
|
-
sendMessage(state.socket, msg);
|
|
1537
|
+
event: ClientEvents.WS_CLIENT_MESSAGE,
|
|
1538
|
+
payload: { socketId, data }
|
|
1539
|
+
});
|
|
1374
1540
|
};
|
|
1375
1541
|
ws.onerror = () => {
|
|
1376
|
-
|
|
1377
|
-
type: MessageType.
|
|
1542
|
+
sendMessage(state.socket, {
|
|
1543
|
+
type: MessageType.CLIENT_EVENT,
|
|
1378
1544
|
isolateId,
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1545
|
+
event: ClientEvents.WS_CLIENT_ERROR,
|
|
1546
|
+
payload: { socketId }
|
|
1547
|
+
});
|
|
1382
1548
|
};
|
|
1383
1549
|
ws.onclose = (event) => {
|
|
1384
|
-
|
|
1385
|
-
type: MessageType.
|
|
1550
|
+
sendMessage(state.socket, {
|
|
1551
|
+
type: MessageType.CLIENT_EVENT,
|
|
1386
1552
|
isolateId,
|
|
1387
|
-
|
|
1388
|
-
code: event.code,
|
|
1389
|
-
|
|
1390
|
-
wasClean: event.wasClean
|
|
1391
|
-
};
|
|
1392
|
-
sendMessage(state.socket, msg);
|
|
1553
|
+
event: ClientEvents.WS_CLIENT_CLOSED,
|
|
1554
|
+
payload: { socketId, code: event.code, reason: event.reason, wasClean: event.wasClean }
|
|
1555
|
+
});
|
|
1393
1556
|
sockets?.delete(socketId);
|
|
1394
1557
|
if (sockets?.size === 0) {
|
|
1395
1558
|
isolateClientWebSockets.delete(isolateId);
|
|
@@ -1397,21 +1560,18 @@ function handleClientWsConnect(message, state) {
|
|
|
1397
1560
|
};
|
|
1398
1561
|
};
|
|
1399
1562
|
const sendConnectionFailed = (reason) => {
|
|
1400
|
-
|
|
1401
|
-
type: MessageType.
|
|
1563
|
+
sendMessage(state.socket, {
|
|
1564
|
+
type: MessageType.CLIENT_EVENT,
|
|
1402
1565
|
isolateId,
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
type: MessageType.
|
|
1566
|
+
event: ClientEvents.WS_CLIENT_ERROR,
|
|
1567
|
+
payload: { socketId }
|
|
1568
|
+
});
|
|
1569
|
+
sendMessage(state.socket, {
|
|
1570
|
+
type: MessageType.CLIENT_EVENT,
|
|
1408
1571
|
isolateId,
|
|
1409
|
-
|
|
1410
|
-
code: 1006,
|
|
1411
|
-
|
|
1412
|
-
wasClean: false
|
|
1413
|
-
};
|
|
1414
|
-
sendMessage(state.socket, closeMsg);
|
|
1572
|
+
event: ClientEvents.WS_CLIENT_CLOSED,
|
|
1573
|
+
payload: { socketId, code: 1006, reason, wasClean: false }
|
|
1574
|
+
});
|
|
1415
1575
|
};
|
|
1416
1576
|
const callback = isolateWebSocketCallbacks.get(isolateId);
|
|
1417
1577
|
if (callback) {
|
|
@@ -1444,8 +1604,8 @@ function handleClientWsConnect(message, state) {
|
|
|
1444
1604
|
}
|
|
1445
1605
|
}
|
|
1446
1606
|
}
|
|
1447
|
-
function handleClientWsSend(
|
|
1448
|
-
const {
|
|
1607
|
+
function handleClientWsSend(isolateId, payload, state) {
|
|
1608
|
+
const { socketId, data } = payload;
|
|
1449
1609
|
const sockets = isolateClientWebSockets.get(isolateId);
|
|
1450
1610
|
const ws = sockets?.get(socketId);
|
|
1451
1611
|
if (!ws || ws.readyState !== WebSocket.OPEN) {
|
|
@@ -1456,13 +1616,13 @@ function handleClientWsSend(message, state) {
|
|
|
1456
1616
|
const binary = Buffer.from(base64, "base64");
|
|
1457
1617
|
ws.send(binary);
|
|
1458
1618
|
} else if (data instanceof Uint8Array) {
|
|
1459
|
-
ws.send(data);
|
|
1619
|
+
ws.send(Buffer.from(data));
|
|
1460
1620
|
} else {
|
|
1461
1621
|
ws.send(data);
|
|
1462
1622
|
}
|
|
1463
1623
|
}
|
|
1464
|
-
function handleClientWsClose(
|
|
1465
|
-
const {
|
|
1624
|
+
function handleClientWsClose(isolateId, payload, state) {
|
|
1625
|
+
const { socketId, code, reason } = payload;
|
|
1466
1626
|
const sockets = isolateClientWebSockets.get(isolateId);
|
|
1467
1627
|
const ws = sockets?.get(socketId);
|
|
1468
1628
|
if (!ws) {
|
|
@@ -1473,7 +1633,8 @@ function handleClientWsClose(message, state) {
|
|
|
1473
1633
|
}
|
|
1474
1634
|
}
|
|
1475
1635
|
export {
|
|
1636
|
+
isBenignDisposeError,
|
|
1476
1637
|
connect
|
|
1477
1638
|
};
|
|
1478
1639
|
|
|
1479
|
-
//# debugId=
|
|
1640
|
+
//# debugId=C1D8CA9472E6C2F664756E2164756E21
|