@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.
@@ -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
- const parser = import_isolate_protocol.createFrameParser();
74
- socket.on("data", (data) => {
75
- try {
76
- for (const frame of parser.feed(new Uint8Array(data))) {
77
- handleMessage(frame.message, state);
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
- } catch (err) {
80
- console.error("Error parsing frame:", err);
81
- }
82
- });
83
- socket.on("close", () => {
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
- state.streamResponses.clear();
98
- for (const [, session] of state.uploadStreams) {
99
- session.state = "closed";
100
- if (session.creditResolver) {
101
- session.creditResolver();
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
- state.uploadStreams.clear();
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
- return sendRequest(state, req);
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: new AbortController().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, import_node_path.default.posix.basename(specifier));
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=1DAE4D8C13C4D6B364756E2164756E21
1694
+ //# debugId=E397D9CA05CE94DB64756E2164756E21