@ricsam/isolate-client 0.1.16 → 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.
@@ -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
+ }
102
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;
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) {
@@ -742,7 +847,22 @@ async function createRuntime(state, options = {}, namespaceId) {
742
847
  isolateId,
743
848
  timeout
744
849
  };
745
- return sendRequest(state, req);
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
+ }
746
866
  },
747
867
  async hasTests() {
748
868
  if (!testEnvironmentEnabled) {
@@ -867,6 +987,9 @@ async function createRuntime(state, options = {}, namespaceId) {
867
987
  }
868
988
  isolateClientWebSockets.delete(isolateId);
869
989
  }
990
+ if (namespaceId != null) {
991
+ state.namespacedRuntimes.delete(namespaceId);
992
+ }
870
993
  const reqId = state.nextRequestId++;
871
994
  const req = {
872
995
  type: import_isolate_protocol.MessageType.DISPOSE_RUNTIME,
@@ -1058,7 +1181,7 @@ function registerModuleLoaderCallback(state, callback) {
1058
1181
  const specifier = moduleName;
1059
1182
  const importerInfo = importer;
1060
1183
  const result = await callback(specifier, importerInfo);
1061
- const resolvedPath = import_node_path.default.posix.join(result.resolveDir, import_node_path.default.posix.basename(specifier));
1184
+ const resolvedPath = import_node_path.default.posix.join(result.resolveDir, result.filename);
1062
1185
  state.moduleSourceCache.set(resolvedPath, result.code);
1063
1186
  return result;
1064
1187
  });
@@ -1524,7 +1647,7 @@ function handleClientWsSend(isolateId, payload, state) {
1524
1647
  const binary = Buffer.from(base64, "base64");
1525
1648
  ws.send(binary);
1526
1649
  } else if (data instanceof Uint8Array) {
1527
- ws.send(data);
1650
+ ws.send(Buffer.from(data));
1528
1651
  } else {
1529
1652
  ws.send(data);
1530
1653
  }
@@ -1541,4 +1664,4 @@ function handleClientWsClose(isolateId, payload, state) {
1541
1664
  }
1542
1665
  }
1543
1666
 
1544
- //# debugId=1DAE4D8C13C4D6B364756E2164756E21
1667
+ //# debugId=BB5A27475A32C8E264756E2164756E21