@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.
@@ -37,44 +37,142 @@ async function connect(options = {}) {
37
37
  streamResponses: new Map,
38
38
  uploadStreams: new Map,
39
39
  moduleSourceCache: new Map,
40
- callbackStreamReaders: new Map
40
+ callbackStreamReaders: new Map,
41
+ closing: false,
42
+ namespacedRuntimes: new Map
41
43
  };
42
- const parser = createFrameParser();
43
- socket.on("data", (data) => {
44
- try {
45
- for (const frame of parser.feed(new Uint8Array(data))) {
46
- handleMessage(frame.message, state);
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);
47
53
  }
48
- } catch (err) {
49
- console.error("Error parsing frame:", err);
50
- }
51
- });
52
- socket.on("close", () => {
53
- state.connected = false;
54
- for (const [, pending] of state.pendingRequests) {
55
- pending.reject(new Error("Connection closed"));
56
- }
57
- state.pendingRequests.clear();
58
- for (const [, receiver] of state.streamResponses) {
59
- receiver.state = "errored";
60
- receiver.error = new Error("Connection closed");
61
- const resolvers = receiver.pullResolvers.splice(0);
62
- for (const resolver of resolvers) {
63
- resolver();
54
+ });
55
+ sock.on("close", () => {
56
+ state.connected = false;
57
+ for (const [, pending] of state.pendingRequests) {
58
+ pending.reject(new Error("Connection closed"));
64
59
  }
65
- }
66
- state.streamResponses.clear();
67
- for (const [, session] of state.uploadStreams) {
68
- session.state = "closed";
69
- if (session.creditResolver) {
70
- session.creditResolver();
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
+ }
71
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
+ });
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");
72
174
  }
73
- state.uploadStreams.clear();
74
- });
75
- socket.on("error", (err) => {
76
- console.error("Socket error:", err);
77
- });
175
+ }
78
176
  return {
79
177
  createRuntime: (runtimeOptions) => createRuntime(state, runtimeOptions),
80
178
  createNamespace: (id) => ({
@@ -82,8 +180,9 @@ async function connect(options = {}) {
82
180
  createRuntime: (runtimeOptions) => createRuntime(state, runtimeOptions, id)
83
181
  }),
84
182
  close: async () => {
183
+ state.closing = true;
85
184
  state.connected = false;
86
- socket.destroy();
185
+ state.socket.destroy();
87
186
  },
88
187
  isConnected: () => state.connected
89
188
  };
@@ -510,6 +609,12 @@ async function createRuntime(state, options = {}, namespaceId) {
510
609
  const result = await sendRequest(state, request);
511
610
  const isolateId = result.isolateId;
512
611
  const reused = result.reused ?? false;
612
+ if (namespaceId != null) {
613
+ state.namespacedRuntimes.set(namespaceId, {
614
+ isolateId,
615
+ runtimeOptions: options
616
+ });
617
+ }
513
618
  const wsCommandCallbacks = new Set;
514
619
  isolateWsCallbacks.set(isolateId, wsCommandCallbacks);
515
620
  if (options.onWebSocketCommand) {
@@ -711,7 +816,22 @@ async function createRuntime(state, options = {}, namespaceId) {
711
816
  isolateId,
712
817
  timeout
713
818
  };
714
- return sendRequest(state, req);
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
+ }
715
835
  },
716
836
  async hasTests() {
717
837
  if (!testEnvironmentEnabled) {
@@ -836,6 +956,9 @@ async function createRuntime(state, options = {}, namespaceId) {
836
956
  }
837
957
  isolateClientWebSockets.delete(isolateId);
838
958
  }
959
+ if (namespaceId != null) {
960
+ state.namespacedRuntimes.delete(namespaceId);
961
+ }
839
962
  const reqId = state.nextRequestId++;
840
963
  const req = {
841
964
  type: MessageType.DISPOSE_RUNTIME,
@@ -1027,7 +1150,7 @@ function registerModuleLoaderCallback(state, callback) {
1027
1150
  const specifier = moduleName;
1028
1151
  const importerInfo = importer;
1029
1152
  const result = await callback(specifier, importerInfo);
1030
- const resolvedPath = path.posix.join(result.resolveDir, path.posix.basename(specifier));
1153
+ const resolvedPath = path.posix.join(result.resolveDir, result.filename);
1031
1154
  state.moduleSourceCache.set(resolvedPath, result.code);
1032
1155
  return result;
1033
1156
  });
@@ -1493,7 +1616,7 @@ function handleClientWsSend(isolateId, payload, state) {
1493
1616
  const binary = Buffer.from(base64, "base64");
1494
1617
  ws.send(binary);
1495
1618
  } else if (data instanceof Uint8Array) {
1496
- ws.send(data);
1619
+ ws.send(Buffer.from(data));
1497
1620
  } else {
1498
1621
  ws.send(data);
1499
1622
  }
@@ -1514,4 +1637,4 @@ export {
1514
1637
  connect
1515
1638
  };
1516
1639
 
1517
- //# debugId=A84790A2E8D5115464756E2164756E21
1640
+ //# debugId=C1D8CA9472E6C2F664756E2164756E21