@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.
@@ -8,16 +8,21 @@ import {
8
8
  STREAM_THRESHOLD,
9
9
  STREAM_CHUNK_SIZE,
10
10
  STREAM_DEFAULT_CREDIT,
11
- marshalValue
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
- const parser = createFrameParser();
38
- socket.on("data", (data) => {
39
- try {
40
- for (const frame of parser.feed(new Uint8Array(data))) {
41
- 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);
42
53
  }
43
- } catch (err) {
44
- console.error("Error parsing frame:", err);
45
- }
46
- });
47
- socket.on("close", () => {
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
- pending.reject(new Error("Connection closed"));
54
- }
55
- state.pendingRequests.clear();
56
- for (const [, receiver] of state.streamResponses) {
57
- receiver.state = "errored";
58
- receiver.error = new Error("Connection closed");
59
- const resolvers = receiver.pullResolvers.splice(0);
60
- for (const resolver of resolvers) {
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
- state.streamResponses.clear();
65
- for (const [, session] of state.uploadStreams) {
66
- session.state = "closed";
67
- if (session.creditResolver) {
68
- session.creditResolver();
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
- state.uploadStreams.clear();
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 ?? DEFAULT_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
- const timeoutId = setTimeout(() => {
107
- socket.destroy();
108
- reject(new Error("Connection timeout"));
109
- }, timeout);
110
- socket.once("connect", () => {
111
- clearTimeout(timeoutId);
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.WS_COMMAND: {
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
- handleClientWsSend(msg, state);
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, timeout = DEFAULT_TIMEOUT) {
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
- if (serialized.bodyStreamId !== undefined && bodyStream) {
573
- const streamId = serialized.bodyStreamId;
574
- const responsePromise = sendRequest(state, request2, opts?.timeout ?? DEFAULT_TIMEOUT);
575
- await sendBodyStream(state, streamId, bodyStream);
576
- const res = await responsePromise;
577
- return handleResponse(res);
578
- } else {
579
- const res = await sendRequest(state, request2, opts?.timeout ?? DEFAULT_TIMEOUT);
580
- return handleResponse(res);
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
- const requestTimeout = timeout === undefined ? DEFAULT_TIMEOUT : Math.max(timeout + TEST_REQUEST_TIMEOUT_BUFFER_MS, DEFAULT_TIMEOUT);
728
- return sendRequest(state, req, requestTimeout);
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
- await sendRequest(state, req);
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, path.posix.basename(specifier));
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 handleClientWsConnect(message, state) {
1329
- const { isolateId, socketId, url, protocols } = message;
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
- const msg = {
1339
- type: MessageType.CLIENT_WS_OPENED,
1508
+ sendMessage(state.socket, {
1509
+ type: MessageType.CLIENT_EVENT,
1340
1510
  isolateId,
1341
- socketId,
1342
- protocol: ws.protocol || "",
1343
- extensions: ws.extensions || ""
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
- const msg2 = {
1356
- type: MessageType.CLIENT_WS_MESSAGE,
1523
+ sendMessage(state.socket, {
1524
+ type: MessageType.CLIENT_EVENT,
1357
1525
  isolateId,
1358
- socketId,
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
- const msg = {
1368
- type: MessageType.CLIENT_WS_MESSAGE,
1534
+ sendMessage(state.socket, {
1535
+ type: MessageType.CLIENT_EVENT,
1369
1536
  isolateId,
1370
- socketId,
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
- const msg = {
1377
- type: MessageType.CLIENT_WS_ERROR,
1542
+ sendMessage(state.socket, {
1543
+ type: MessageType.CLIENT_EVENT,
1378
1544
  isolateId,
1379
- socketId
1380
- };
1381
- sendMessage(state.socket, msg);
1545
+ event: ClientEvents.WS_CLIENT_ERROR,
1546
+ payload: { socketId }
1547
+ });
1382
1548
  };
1383
1549
  ws.onclose = (event) => {
1384
- const msg = {
1385
- type: MessageType.CLIENT_WS_CLOSED,
1550
+ sendMessage(state.socket, {
1551
+ type: MessageType.CLIENT_EVENT,
1386
1552
  isolateId,
1387
- socketId,
1388
- code: event.code,
1389
- reason: event.reason,
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
- const errorMsg = {
1401
- type: MessageType.CLIENT_WS_ERROR,
1563
+ sendMessage(state.socket, {
1564
+ type: MessageType.CLIENT_EVENT,
1402
1565
  isolateId,
1403
- socketId
1404
- };
1405
- sendMessage(state.socket, errorMsg);
1406
- const closeMsg = {
1407
- type: MessageType.CLIENT_WS_CLOSED,
1566
+ event: ClientEvents.WS_CLIENT_ERROR,
1567
+ payload: { socketId }
1568
+ });
1569
+ sendMessage(state.socket, {
1570
+ type: MessageType.CLIENT_EVENT,
1408
1571
  isolateId,
1409
- socketId,
1410
- code: 1006,
1411
- reason,
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(message, state) {
1448
- const { isolateId, socketId, data } = message;
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(message, state) {
1465
- const { isolateId, socketId, code, reason } = message;
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=D4986DB48143DFE264756E2164756E21
1640
+ //# debugId=C1D8CA9472E6C2F664756E2164756E21