@ricsam/isolate-client 0.1.16 → 0.1.18
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/dist/cjs/connection.cjs +190 -40
- package/dist/cjs/connection.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/connection.mjs +190 -40
- package/dist/mjs/connection.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/package.json +1 -1
package/dist/cjs/connection.cjs
CHANGED
|
@@ -68,44 +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
|
-
pending.reject(new Error("Connection closed"));
|
|
87
|
-
}
|
|
88
|
-
state.pendingRequests.clear();
|
|
89
|
-
for (const [, receiver] of state.streamResponses) {
|
|
90
|
-
receiver.state = "errored";
|
|
91
|
-
receiver.error = new Error("Connection closed");
|
|
92
|
-
const resolvers = receiver.pullResolvers.splice(0);
|
|
93
|
-
for (const resolver of resolvers) {
|
|
94
|
-
resolver();
|
|
85
|
+
});
|
|
86
|
+
sock.on("close", () => {
|
|
87
|
+
state.connected = false;
|
|
88
|
+
for (const [, pending] of state.pendingRequests) {
|
|
89
|
+
pending.reject(new Error("Connection closed"));
|
|
95
90
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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
|
+
}
|
|
99
|
+
}
|
|
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
|
+
});
|
|
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;
|
|
102
200
|
}
|
|
201
|
+
st.reconnecting = undefined;
|
|
202
|
+
} catch {
|
|
203
|
+
st.reconnecting = undefined;
|
|
204
|
+
throw new Error("Failed to reconnect to daemon");
|
|
103
205
|
}
|
|
104
|
-
|
|
105
|
-
});
|
|
106
|
-
socket.on("error", (err) => {
|
|
107
|
-
console.error("Socket error:", err);
|
|
108
|
-
});
|
|
206
|
+
}
|
|
109
207
|
return {
|
|
110
208
|
createRuntime: (runtimeOptions) => createRuntime(state, runtimeOptions),
|
|
111
209
|
createNamespace: (id) => ({
|
|
@@ -113,8 +211,9 @@ async function connect(options = {}) {
|
|
|
113
211
|
createRuntime: (runtimeOptions) => createRuntime(state, runtimeOptions, id)
|
|
114
212
|
}),
|
|
115
213
|
close: async () => {
|
|
214
|
+
state.closing = true;
|
|
116
215
|
state.connected = false;
|
|
117
|
-
socket.destroy();
|
|
216
|
+
state.socket.destroy();
|
|
118
217
|
},
|
|
119
218
|
isConnected: () => state.connected
|
|
120
219
|
};
|
|
@@ -541,6 +640,12 @@ async function createRuntime(state, options = {}, namespaceId) {
|
|
|
541
640
|
const result = await sendRequest(state, request);
|
|
542
641
|
const isolateId = result.isolateId;
|
|
543
642
|
const reused = result.reused ?? false;
|
|
643
|
+
if (namespaceId != null) {
|
|
644
|
+
state.namespacedRuntimes.set(namespaceId, {
|
|
645
|
+
isolateId,
|
|
646
|
+
runtimeOptions: options
|
|
647
|
+
});
|
|
648
|
+
}
|
|
544
649
|
const wsCommandCallbacks = new Set;
|
|
545
650
|
isolateWsCallbacks.set(isolateId, wsCommandCallbacks);
|
|
546
651
|
if (options.onWebSocketCommand) {
|
|
@@ -555,6 +660,8 @@ async function createRuntime(state, options = {}, namespaceId) {
|
|
|
555
660
|
if (signal?.aborted) {
|
|
556
661
|
throw new DOMException("The operation was aborted", "AbortError");
|
|
557
662
|
}
|
|
663
|
+
const requestSignal = req.signal;
|
|
664
|
+
const requestSignalInitiallyAborted = requestSignal?.aborted ?? false;
|
|
558
665
|
const reqId = state.nextRequestId++;
|
|
559
666
|
const serialized = await serializeRequestWithStreaming(state, req);
|
|
560
667
|
const { bodyStream, ...serializableRequest } = serialized;
|
|
@@ -581,6 +688,23 @@ async function createRuntime(state, options = {}, namespaceId) {
|
|
|
581
688
|
};
|
|
582
689
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
583
690
|
}
|
|
691
|
+
let onRequestAbort;
|
|
692
|
+
if (requestSignal && !requestSignalInitiallyAborted) {
|
|
693
|
+
onRequestAbort = () => {
|
|
694
|
+
const abortMessage = {
|
|
695
|
+
type: import_isolate_protocol.MessageType.DISPATCH_REQUEST_ABORT,
|
|
696
|
+
isolateId,
|
|
697
|
+
targetRequestId: reqId
|
|
698
|
+
};
|
|
699
|
+
if (state.connected) {
|
|
700
|
+
sendMessage(state.socket, abortMessage);
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
requestSignal.addEventListener("abort", onRequestAbort, { once: true });
|
|
704
|
+
if (requestSignal.aborted) {
|
|
705
|
+
onRequestAbort();
|
|
706
|
+
}
|
|
707
|
+
}
|
|
584
708
|
try {
|
|
585
709
|
if (serialized.bodyStreamId !== undefined && bodyStream) {
|
|
586
710
|
const streamId = serialized.bodyStreamId;
|
|
@@ -596,6 +720,9 @@ async function createRuntime(state, options = {}, namespaceId) {
|
|
|
596
720
|
if (signal && onAbort) {
|
|
597
721
|
signal.removeEventListener("abort", onAbort);
|
|
598
722
|
}
|
|
723
|
+
if (requestSignal && onRequestAbort) {
|
|
724
|
+
requestSignal.removeEventListener("abort", onRequestAbort);
|
|
725
|
+
}
|
|
599
726
|
}
|
|
600
727
|
},
|
|
601
728
|
async getUpgradeRequest() {
|
|
@@ -742,7 +869,22 @@ async function createRuntime(state, options = {}, namespaceId) {
|
|
|
742
869
|
isolateId,
|
|
743
870
|
timeout
|
|
744
871
|
};
|
|
745
|
-
|
|
872
|
+
try {
|
|
873
|
+
return await sendRequest(state, req);
|
|
874
|
+
} catch (err) {
|
|
875
|
+
if (err instanceof Error && /connection closed|not connected/i.test(err.message) && state.reconnecting) {
|
|
876
|
+
await state.reconnecting;
|
|
877
|
+
const retryReqId = state.nextRequestId++;
|
|
878
|
+
const retryReq = {
|
|
879
|
+
type: import_isolate_protocol.MessageType.RUN_TESTS,
|
|
880
|
+
requestId: retryReqId,
|
|
881
|
+
isolateId,
|
|
882
|
+
timeout
|
|
883
|
+
};
|
|
884
|
+
return sendRequest(state, retryReq);
|
|
885
|
+
}
|
|
886
|
+
throw err;
|
|
887
|
+
}
|
|
746
888
|
},
|
|
747
889
|
async hasTests() {
|
|
748
890
|
if (!testEnvironmentEnabled) {
|
|
@@ -867,6 +1009,9 @@ async function createRuntime(state, options = {}, namespaceId) {
|
|
|
867
1009
|
}
|
|
868
1010
|
isolateClientWebSockets.delete(isolateId);
|
|
869
1011
|
}
|
|
1012
|
+
if (namespaceId != null) {
|
|
1013
|
+
state.namespacedRuntimes.delete(namespaceId);
|
|
1014
|
+
}
|
|
870
1015
|
const reqId = state.nextRequestId++;
|
|
871
1016
|
const req = {
|
|
872
1017
|
type: import_isolate_protocol.MessageType.DISPOSE_RUNTIME,
|
|
@@ -908,12 +1053,16 @@ function registerFetchCallback(state, callback) {
|
|
|
908
1053
|
state.callbacksNeedingRequestId.add(callbackId);
|
|
909
1054
|
state.callbacks.set(callbackId, async (serialized, requestId) => {
|
|
910
1055
|
const data = serialized;
|
|
1056
|
+
const signalController = new AbortController;
|
|
1057
|
+
if (data.signalAborted) {
|
|
1058
|
+
signalController.abort();
|
|
1059
|
+
}
|
|
911
1060
|
const init = {
|
|
912
1061
|
method: data.method,
|
|
913
1062
|
headers: data.headers,
|
|
914
1063
|
rawBody: data.body ?? null,
|
|
915
1064
|
body: data.body ?? null,
|
|
916
|
-
signal:
|
|
1065
|
+
signal: signalController.signal
|
|
917
1066
|
};
|
|
918
1067
|
const response = await callback(data.url, init);
|
|
919
1068
|
const contentLength = response.headers.get("content-length");
|
|
@@ -1058,7 +1207,7 @@ function registerModuleLoaderCallback(state, callback) {
|
|
|
1058
1207
|
const specifier = moduleName;
|
|
1059
1208
|
const importerInfo = importer;
|
|
1060
1209
|
const result = await callback(specifier, importerInfo);
|
|
1061
|
-
const resolvedPath = import_node_path.default.posix.join(result.resolveDir,
|
|
1210
|
+
const resolvedPath = import_node_path.default.posix.join(result.resolveDir, result.filename);
|
|
1062
1211
|
state.moduleSourceCache.set(resolvedPath, result.code);
|
|
1063
1212
|
return result;
|
|
1064
1213
|
});
|
|
@@ -1284,7 +1433,8 @@ async function serializeRequestWithStreaming(state, request) {
|
|
|
1284
1433
|
method: request.method,
|
|
1285
1434
|
url: request.url,
|
|
1286
1435
|
headers,
|
|
1287
|
-
body
|
|
1436
|
+
body,
|
|
1437
|
+
signalAborted: request.signal?.aborted ?? false
|
|
1288
1438
|
};
|
|
1289
1439
|
if (bodyStreamId !== undefined) {
|
|
1290
1440
|
result.bodyStreamId = bodyStreamId;
|
|
@@ -1524,7 +1674,7 @@ function handleClientWsSend(isolateId, payload, state) {
|
|
|
1524
1674
|
const binary = Buffer.from(base64, "base64");
|
|
1525
1675
|
ws.send(binary);
|
|
1526
1676
|
} else if (data instanceof Uint8Array) {
|
|
1527
|
-
ws.send(data);
|
|
1677
|
+
ws.send(Buffer.from(data));
|
|
1528
1678
|
} else {
|
|
1529
1679
|
ws.send(data);
|
|
1530
1680
|
}
|
|
@@ -1541,4 +1691,4 @@ function handleClientWsClose(isolateId, payload, state) {
|
|
|
1541
1691
|
}
|
|
1542
1692
|
}
|
|
1543
1693
|
|
|
1544
|
-
//# debugId=
|
|
1694
|
+
//# debugId=E397D9CA05CE94DB64756E2164756E21
|