@ricsam/isolate-client 0.1.14 → 0.1.16

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,11 +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
- import { createPlaywrightHandler } from "@ricsam/isolate-playwright/client";
14
- var DEFAULT_TIMEOUT = 30000;
19
+ import {
20
+ getDefaultPlaywrightHandlerMetadata
21
+ } from "@ricsam/isolate-playwright/client";
15
22
  var isolateWsCallbacks = new Map;
23
+ var isolateClientWebSockets = new Map;
24
+ var isolateWebSocketCallbacks = new Map;
25
+ var isolateEventListeners = new Map;
16
26
  async function connect(options = {}) {
17
27
  const socket = await createSocket(options);
18
28
  const state = {
@@ -42,9 +52,6 @@ async function connect(options = {}) {
42
52
  socket.on("close", () => {
43
53
  state.connected = false;
44
54
  for (const [, pending] of state.pendingRequests) {
45
- if (pending.timeoutId) {
46
- clearTimeout(pending.timeoutId);
47
- }
48
55
  pending.reject(new Error("Connection closed"));
49
56
  }
50
57
  state.pendingRequests.clear();
@@ -83,7 +90,7 @@ async function connect(options = {}) {
83
90
  }
84
91
  function createSocket(options) {
85
92
  return new Promise((resolve, reject) => {
86
- const timeout = options.timeout ?? DEFAULT_TIMEOUT;
93
+ const timeout = options.timeout;
87
94
  let socket;
88
95
  const onError = (err) => {
89
96
  reject(err);
@@ -98,13 +105,15 @@ function createSocket(options) {
98
105
  socket = netConnect(options.port ?? 47891, options.host ?? "127.0.0.1", onConnect);
99
106
  }
100
107
  socket.on("error", onError);
101
- const timeoutId = setTimeout(() => {
102
- socket.destroy();
103
- reject(new Error("Connection timeout"));
104
- }, timeout);
105
- socket.once("connect", () => {
106
- clearTimeout(timeoutId);
107
- });
108
+ if (timeout && timeout > 0) {
109
+ const timeoutId = setTimeout(() => {
110
+ socket.destroy();
111
+ reject(new Error("Connection timeout"));
112
+ }, timeout);
113
+ socket.once("connect", () => {
114
+ clearTimeout(timeoutId);
115
+ });
116
+ }
108
117
  });
109
118
  }
110
119
  function handleMessage(message, state) {
@@ -114,8 +123,6 @@ function handleMessage(message, state) {
114
123
  const pending = state.pendingRequests.get(response.requestId);
115
124
  if (pending) {
116
125
  state.pendingRequests.delete(response.requestId);
117
- if (pending.timeoutId)
118
- clearTimeout(pending.timeoutId);
119
126
  pending.resolve(response.data);
120
127
  }
121
128
  break;
@@ -125,8 +132,6 @@ function handleMessage(message, state) {
125
132
  const pending = state.pendingRequests.get(response.requestId);
126
133
  if (pending) {
127
134
  state.pendingRequests.delete(response.requestId);
128
- if (pending.timeoutId)
129
- clearTimeout(pending.timeoutId);
130
135
  const error = new Error(response.message);
131
136
  if (response.details) {
132
137
  error.name = response.details.name;
@@ -153,27 +158,9 @@ function handleMessage(message, state) {
153
158
  }
154
159
  break;
155
160
  }
156
- case MessageType.WS_COMMAND: {
161
+ case MessageType.ISOLATE_EVENT: {
157
162
  const msg = message;
158
- const callbacks = isolateWsCallbacks.get(msg.isolateId);
159
- if (callbacks) {
160
- let data;
161
- if (msg.command.data instanceof Uint8Array) {
162
- data = msg.command.data.buffer.slice(msg.command.data.byteOffset, msg.command.data.byteOffset + msg.command.data.byteLength);
163
- } else {
164
- data = msg.command.data;
165
- }
166
- const cmd = {
167
- type: msg.command.type,
168
- connectionId: msg.command.connectionId,
169
- data,
170
- code: msg.command.code,
171
- reason: msg.command.reason
172
- };
173
- for (const cb of callbacks) {
174
- cb(cmd);
175
- }
176
- }
163
+ handleIsolateEvent(msg, state);
177
164
  break;
178
165
  }
179
166
  case MessageType.RESPONSE_STREAM_START: {
@@ -243,8 +230,6 @@ function handleMessage(message, state) {
243
230
  const pending = state.pendingRequests.get(msg.requestId);
244
231
  if (pending) {
245
232
  state.pendingRequests.delete(msg.requestId);
246
- if (pending.timeoutId)
247
- clearTimeout(pending.timeoutId);
248
233
  const response = new Response(readableStream, {
249
234
  status: msg.metadata?.status ?? 200,
250
235
  statusText: msg.metadata?.statusText ?? "OK",
@@ -369,25 +354,24 @@ function sendMessage(socket, message) {
369
354
  const frame = buildFrame(message);
370
355
  socket.write(frame);
371
356
  }
372
- function sendRequest(state, message, timeout = DEFAULT_TIMEOUT) {
357
+ function sendRequest(state, message) {
373
358
  return new Promise((resolve, reject) => {
374
359
  if (!state.connected) {
375
360
  reject(new Error("Not connected"));
376
361
  return;
377
362
  }
378
363
  const requestId = message.requestId;
379
- const timeoutId = setTimeout(() => {
380
- state.pendingRequests.delete(requestId);
381
- reject(new Error("Request timeout"));
382
- }, timeout);
383
364
  state.pendingRequests.set(requestId, {
384
365
  resolve,
385
- reject,
386
- timeoutId
366
+ reject
387
367
  });
388
368
  sendMessage(state.socket, message);
389
369
  });
390
370
  }
371
+ function isBenignDisposeError(error) {
372
+ const message = error instanceof Error ? error.message : String(error ?? "");
373
+ return /isolate not owned by this connection|isolate not found|not connected|connection closed/i.test(message);
374
+ }
391
375
  async function createRuntime(state, options = {}, namespaceId) {
392
376
  const callbacks = {};
393
377
  if (options.console) {
@@ -411,73 +395,76 @@ async function createRuntime(state, options = {}, namespaceId) {
411
395
  const networkResponses = [];
412
396
  const pageListenerCleanups = [];
413
397
  if (options.playwright) {
414
- playwrightHandler = createPlaywrightHandler(options.playwright.page, {
415
- timeout: options.playwright.timeout
416
- });
398
+ playwrightHandler = options.playwright.handler;
399
+ if (!playwrightHandler) {
400
+ throw new Error("playwright.handler is required when using playwright options");
401
+ }
402
+ const page = getDefaultPlaywrightHandlerMetadata(playwrightHandler)?.page;
417
403
  const handlerCallbackId = state.nextCallbackId++;
418
404
  state.callbacks.set(handlerCallbackId, async (opJson) => {
419
405
  const op = JSON.parse(opJson);
420
406
  const result2 = await playwrightHandler(op);
421
407
  return JSON.stringify(result2);
422
408
  });
423
- const page = options.playwright.page;
424
- const onConsole = (msg) => {
425
- const entry = {
426
- level: msg.type(),
427
- stdout: msg.text(),
428
- timestamp: Date.now()
409
+ if (page) {
410
+ const onConsole = (msg) => {
411
+ const entry = {
412
+ level: msg.type(),
413
+ stdout: msg.text(),
414
+ timestamp: Date.now()
415
+ };
416
+ browserConsoleLogs.push(entry);
417
+ if (options.playwright.onEvent) {
418
+ options.playwright.onEvent({
419
+ type: "browserConsoleLog",
420
+ ...entry
421
+ });
422
+ }
423
+ if (options.playwright.console && options.console?.onEntry) {
424
+ options.console.onEntry({
425
+ type: "browserOutput",
426
+ ...entry
427
+ });
428
+ } else if (options.playwright.console) {
429
+ const prefix = entry.level === "error" ? "[browser:error]" : "[browser]";
430
+ console.log(prefix, entry.stdout);
431
+ }
429
432
  };
430
- browserConsoleLogs.push(entry);
431
- if (options.playwright.onEvent) {
432
- options.playwright.onEvent({
433
- type: "browserConsoleLog",
434
- ...entry
435
- });
436
- }
437
- if (options.playwright.console && options.console?.onEntry) {
438
- options.console.onEntry({
439
- type: "browserOutput",
440
- ...entry
441
- });
442
- } else if (options.playwright.console) {
443
- const prefix = entry.level === "error" ? "[browser:error]" : "[browser]";
444
- console.log(prefix, entry.stdout);
445
- }
446
- };
447
- const onRequest = (request2) => {
448
- const info = {
449
- url: request2.url(),
450
- method: request2.method(),
451
- headers: request2.headers(),
452
- timestamp: Date.now()
433
+ const onRequest = (request2) => {
434
+ const info = {
435
+ url: request2.url(),
436
+ method: request2.method(),
437
+ headers: request2.headers(),
438
+ timestamp: Date.now()
439
+ };
440
+ networkRequests.push(info);
441
+ if (options.playwright.onEvent) {
442
+ options.playwright.onEvent({
443
+ type: "networkRequest",
444
+ ...info
445
+ });
446
+ }
453
447
  };
454
- networkRequests.push(info);
455
- if (options.playwright.onEvent) {
456
- options.playwright.onEvent({
457
- type: "networkRequest",
458
- ...info
459
- });
460
- }
461
- };
462
- const onResponse = (response) => {
463
- const info = {
464
- url: response.url(),
465
- status: response.status(),
466
- headers: response.headers(),
467
- timestamp: Date.now()
448
+ const onResponse = (response) => {
449
+ const info = {
450
+ url: response.url(),
451
+ status: response.status(),
452
+ headers: response.headers(),
453
+ timestamp: Date.now()
454
+ };
455
+ networkResponses.push(info);
456
+ if (options.playwright.onEvent) {
457
+ options.playwright.onEvent({
458
+ type: "networkResponse",
459
+ ...info
460
+ });
461
+ }
468
462
  };
469
- networkResponses.push(info);
470
- if (options.playwright.onEvent) {
471
- options.playwright.onEvent({
472
- type: "networkResponse",
473
- ...info
474
- });
475
- }
476
- };
477
- page.on("console", onConsole);
478
- page.on("request", onRequest);
479
- page.on("response", onResponse);
480
- pageListenerCleanups.push(() => page.removeListener("console", onConsole), () => page.removeListener("request", onRequest), () => page.removeListener("response", onResponse));
463
+ page.on("console", onConsole);
464
+ page.on("request", onRequest);
465
+ page.on("response", onResponse);
466
+ pageListenerCleanups.push(() => page.removeListener("console", onConsole), () => page.removeListener("request", onRequest), () => page.removeListener("response", onResponse));
467
+ }
481
468
  callbacks.playwright = {
482
469
  handlerCallbackId,
483
470
  console: options.playwright.console && !options.console?.onEntry
@@ -525,8 +512,18 @@ async function createRuntime(state, options = {}, namespaceId) {
525
512
  const reused = result.reused ?? false;
526
513
  const wsCommandCallbacks = new Set;
527
514
  isolateWsCallbacks.set(isolateId, wsCommandCallbacks);
515
+ if (options.onWebSocketCommand) {
516
+ wsCommandCallbacks.add(options.onWebSocketCommand);
517
+ }
518
+ if (options.webSocket) {
519
+ isolateWebSocketCallbacks.set(isolateId, options.webSocket);
520
+ }
528
521
  const fetchHandle = {
529
522
  async dispatchRequest(req, opts) {
523
+ const signal = opts?.signal;
524
+ if (signal?.aborted) {
525
+ throw new DOMException("The operation was aborted", "AbortError");
526
+ }
530
527
  const reqId = state.nextRequestId++;
531
528
  const serialized = await serializeRequestWithStreaming(state, req);
532
529
  const { bodyStream, ...serializableRequest } = serialized;
@@ -534,8 +531,7 @@ async function createRuntime(state, options = {}, namespaceId) {
534
531
  type: MessageType.DISPATCH_REQUEST,
535
532
  requestId: reqId,
536
533
  isolateId,
537
- request: serializableRequest,
538
- options: opts
534
+ request: serializableRequest
539
535
  };
540
536
  const handleResponse = (res) => {
541
537
  if (res.__streaming && res.response instanceof Response) {
@@ -543,15 +539,32 @@ async function createRuntime(state, options = {}, namespaceId) {
543
539
  }
544
540
  return deserializeResponse(res.response);
545
541
  };
546
- if (serialized.bodyStreamId !== undefined && bodyStream) {
547
- const streamId = serialized.bodyStreamId;
548
- const responsePromise = sendRequest(state, request2, opts?.timeout ?? DEFAULT_TIMEOUT);
549
- await sendBodyStream(state, streamId, bodyStream);
550
- const res = await responsePromise;
551
- return handleResponse(res);
552
- } else {
553
- const res = await sendRequest(state, request2, opts?.timeout ?? DEFAULT_TIMEOUT);
554
- return handleResponse(res);
542
+ let onAbort;
543
+ if (signal) {
544
+ onAbort = () => {
545
+ const pending = state.pendingRequests.get(reqId);
546
+ if (pending) {
547
+ state.pendingRequests.delete(reqId);
548
+ pending.reject(new DOMException("The operation was aborted", "AbortError"));
549
+ }
550
+ };
551
+ signal.addEventListener("abort", onAbort, { once: true });
552
+ }
553
+ try {
554
+ if (serialized.bodyStreamId !== undefined && bodyStream) {
555
+ const streamId = serialized.bodyStreamId;
556
+ const responsePromise = sendRequest(state, request2);
557
+ await sendBodyStream(state, streamId, bodyStream);
558
+ const res = await responsePromise;
559
+ return handleResponse(res);
560
+ } else {
561
+ const res = await sendRequest(state, request2);
562
+ return handleResponse(res);
563
+ }
564
+ } finally {
565
+ if (signal && onAbort) {
566
+ signal.removeEventListener("abort", onAbort);
567
+ }
555
568
  }
556
569
  },
557
570
  async getUpgradeRequest() {
@@ -698,7 +711,7 @@ async function createRuntime(state, options = {}, namespaceId) {
698
711
  isolateId,
699
712
  timeout
700
713
  };
701
- return sendRequest(state, req, timeout ?? DEFAULT_TIMEOUT);
714
+ return sendRequest(state, req);
702
715
  },
703
716
  async hasTests() {
704
717
  if (!testEnvironmentEnabled) {
@@ -740,7 +753,7 @@ async function createRuntime(state, options = {}, namespaceId) {
740
753
  const playwrightHandle = {
741
754
  getCollectedData() {
742
755
  if (!playwrightEnabled) {
743
- throw new Error("Playwright not configured. Provide playwright.page in createRuntime options.");
756
+ throw new Error("Playwright not configured. Provide playwright.handler in createRuntime options.");
744
757
  }
745
758
  return {
746
759
  browserConsoleLogs: [...browserConsoleLogs],
@@ -750,7 +763,7 @@ async function createRuntime(state, options = {}, namespaceId) {
750
763
  },
751
764
  clearCollectedData() {
752
765
  if (!playwrightEnabled) {
753
- throw new Error("Playwright not configured. Provide playwright.page in createRuntime options.");
766
+ throw new Error("Playwright not configured. Provide playwright.handler in createRuntime options.");
754
767
  }
755
768
  browserConsoleLogs.length = 0;
756
769
  networkRequests.length = 0;
@@ -759,7 +772,6 @@ async function createRuntime(state, options = {}, namespaceId) {
759
772
  };
760
773
  return {
761
774
  id: isolateId,
762
- isolateId,
763
775
  reused,
764
776
  fetch: fetchHandle,
765
777
  timers: timersHandle,
@@ -774,24 +786,69 @@ async function createRuntime(state, options = {}, namespaceId) {
774
786
  requestId: reqId,
775
787
  isolateId,
776
788
  code,
777
- filename: options2?.filename,
778
- maxExecutionMs: options2?.maxExecutionMs,
779
- module: true
789
+ filename: options2?.filename
780
790
  };
781
791
  await sendRequest(state, req);
782
792
  },
793
+ on(event, callback) {
794
+ let listeners = isolateEventListeners.get(isolateId);
795
+ if (!listeners) {
796
+ listeners = new Map;
797
+ isolateEventListeners.set(isolateId, listeners);
798
+ }
799
+ let eventListeners = listeners.get(event);
800
+ if (!eventListeners) {
801
+ eventListeners = new Set;
802
+ listeners.set(event, eventListeners);
803
+ }
804
+ eventListeners.add(callback);
805
+ return () => {
806
+ eventListeners.delete(callback);
807
+ if (eventListeners.size === 0) {
808
+ listeners.delete(event);
809
+ if (listeners.size === 0) {
810
+ isolateEventListeners.delete(isolateId);
811
+ }
812
+ }
813
+ };
814
+ },
815
+ emit(event, payload) {
816
+ sendMessage(state.socket, {
817
+ type: MessageType.CLIENT_EVENT,
818
+ isolateId,
819
+ event,
820
+ payload
821
+ });
822
+ },
783
823
  dispose: async () => {
784
824
  for (const cleanup of pageListenerCleanups) {
785
825
  cleanup();
786
826
  }
787
827
  isolateWsCallbacks.delete(isolateId);
828
+ isolateWebSocketCallbacks.delete(isolateId);
829
+ isolateEventListeners.delete(isolateId);
830
+ const clientSockets = isolateClientWebSockets.get(isolateId);
831
+ if (clientSockets) {
832
+ for (const ws of clientSockets.values()) {
833
+ if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {
834
+ ws.close(1000, "Isolate disposed");
835
+ }
836
+ }
837
+ isolateClientWebSockets.delete(isolateId);
838
+ }
788
839
  const reqId = state.nextRequestId++;
789
840
  const req = {
790
841
  type: MessageType.DISPOSE_RUNTIME,
791
842
  requestId: reqId,
792
843
  isolateId
793
844
  };
794
- await sendRequest(state, req);
845
+ try {
846
+ await sendRequest(state, req);
847
+ } catch (error) {
848
+ if (!isBenignDisposeError(error)) {
849
+ throw error;
850
+ }
851
+ }
795
852
  }
796
853
  };
797
854
  }
@@ -819,8 +876,15 @@ function registerFetchCallback(state, callback) {
819
876
  const callbackId = state.nextCallbackId++;
820
877
  state.callbacksNeedingRequestId.add(callbackId);
821
878
  state.callbacks.set(callbackId, async (serialized, requestId) => {
822
- const request = deserializeRequest(serialized);
823
- const response = await callback(request);
879
+ const data = serialized;
880
+ const init = {
881
+ method: data.method,
882
+ headers: data.headers,
883
+ rawBody: data.body ?? null,
884
+ body: data.body ?? null,
885
+ signal: new AbortController().signal
886
+ };
887
+ const response = await callback(data.url, init);
824
888
  const contentLength = response.headers.get("content-length");
825
889
  const knownSize = contentLength ? parseInt(contentLength, 10) : null;
826
890
  const isNetworkResponse = response.url && (response.url.startsWith("http://") || response.url.startsWith("https://"));
@@ -973,12 +1037,6 @@ var clientIteratorSessions = new Map;
973
1037
  var nextClientIteratorId = 1;
974
1038
  var returnedPromiseRegistry = new Map;
975
1039
  var returnedIteratorRegistry = new Map;
976
- function isPromiseRef(value) {
977
- return typeof value === "object" && value !== null && value.__type === "PromiseRef";
978
- }
979
- function isAsyncIteratorRef(value) {
980
- return typeof value === "object" && value !== null && value.__type === "AsyncIteratorRef";
981
- }
982
1040
  function registerCustomFunctions(state, customFunctions) {
983
1041
  const registrations = {};
984
1042
  for (const [name, def] of Object.entries(customFunctions)) {
@@ -1162,36 +1220,6 @@ function registerCustomFunctions(state, customFunctions) {
1162
1220
  }
1163
1221
  return registrations;
1164
1222
  }
1165
- async function serializeResponse(response) {
1166
- const headers = [];
1167
- response.headers.forEach((value, key) => {
1168
- headers.push([key, value]);
1169
- });
1170
- let body = null;
1171
- if (response.body) {
1172
- body = new Uint8Array(await response.arrayBuffer());
1173
- }
1174
- return {
1175
- status: response.status,
1176
- statusText: response.statusText,
1177
- headers,
1178
- body
1179
- };
1180
- }
1181
- function deserializeRequest(data) {
1182
- return new Request(data.url, {
1183
- method: data.method,
1184
- headers: data.headers,
1185
- body: data.body
1186
- });
1187
- }
1188
- function deserializeResponse(data) {
1189
- return new Response(data.body, {
1190
- status: data.status,
1191
- statusText: data.statusText,
1192
- headers: data.headers
1193
- });
1194
- }
1195
1223
  async function serializeRequestWithStreaming(state, request) {
1196
1224
  const headers = [];
1197
1225
  request.headers.forEach((value, key) => {
@@ -1290,8 +1318,200 @@ async function sendBodyStream(state, streamId, body) {
1290
1318
  state.uploadStreams.delete(streamId);
1291
1319
  }
1292
1320
  }
1321
+ function handleIsolateEvent(message, state) {
1322
+ switch (message.event) {
1323
+ case IsolateEvents.WS_COMMAND: {
1324
+ const payload = message.payload;
1325
+ const callbacks = isolateWsCallbacks.get(message.isolateId);
1326
+ if (callbacks) {
1327
+ let data;
1328
+ if (payload.data instanceof Uint8Array) {
1329
+ data = payload.data.buffer.slice(payload.data.byteOffset, payload.data.byteOffset + payload.data.byteLength);
1330
+ } else {
1331
+ data = payload.data;
1332
+ }
1333
+ const cmd = {
1334
+ type: payload.type,
1335
+ connectionId: payload.connectionId,
1336
+ data,
1337
+ code: payload.code,
1338
+ reason: payload.reason
1339
+ };
1340
+ for (const cb of callbacks) {
1341
+ cb(cmd);
1342
+ }
1343
+ }
1344
+ break;
1345
+ }
1346
+ case IsolateEvents.WS_CLIENT_CONNECT: {
1347
+ const payload = message.payload;
1348
+ handleClientWsConnect(message.isolateId, payload, state);
1349
+ break;
1350
+ }
1351
+ case IsolateEvents.WS_CLIENT_SEND: {
1352
+ const payload = message.payload;
1353
+ handleClientWsSend(message.isolateId, payload, state);
1354
+ break;
1355
+ }
1356
+ case IsolateEvents.WS_CLIENT_CLOSE: {
1357
+ const payload = message.payload;
1358
+ handleClientWsClose(message.isolateId, payload, state);
1359
+ break;
1360
+ }
1361
+ default: {
1362
+ const listeners = isolateEventListeners.get(message.isolateId);
1363
+ if (listeners) {
1364
+ const eventListeners = listeners.get(message.event);
1365
+ if (eventListeners) {
1366
+ for (const cb of eventListeners) {
1367
+ cb(message.payload);
1368
+ }
1369
+ }
1370
+ }
1371
+ break;
1372
+ }
1373
+ }
1374
+ }
1375
+ function handleClientWsConnect(isolateId, payload, state) {
1376
+ const { socketId, url, protocols } = payload;
1377
+ let sockets = isolateClientWebSockets.get(isolateId);
1378
+ if (!sockets) {
1379
+ sockets = new Map;
1380
+ isolateClientWebSockets.set(isolateId, sockets);
1381
+ }
1382
+ const setupWebSocket = (ws) => {
1383
+ sockets.set(socketId, ws);
1384
+ ws.onopen = () => {
1385
+ sendMessage(state.socket, {
1386
+ type: MessageType.CLIENT_EVENT,
1387
+ isolateId,
1388
+ event: ClientEvents.WS_CLIENT_OPENED,
1389
+ payload: { socketId, protocol: ws.protocol || "", extensions: ws.extensions || "" }
1390
+ });
1391
+ };
1392
+ ws.onmessage = (event) => {
1393
+ let data;
1394
+ if (typeof event.data === "string") {
1395
+ data = event.data;
1396
+ } else if (event.data instanceof ArrayBuffer) {
1397
+ data = new Uint8Array(event.data);
1398
+ } else if (event.data instanceof Blob) {
1399
+ event.data.arrayBuffer().then((buffer) => {
1400
+ sendMessage(state.socket, {
1401
+ type: MessageType.CLIENT_EVENT,
1402
+ isolateId,
1403
+ event: ClientEvents.WS_CLIENT_MESSAGE,
1404
+ payload: { socketId, data: new Uint8Array(buffer) }
1405
+ });
1406
+ });
1407
+ return;
1408
+ } else {
1409
+ data = String(event.data);
1410
+ }
1411
+ sendMessage(state.socket, {
1412
+ type: MessageType.CLIENT_EVENT,
1413
+ isolateId,
1414
+ event: ClientEvents.WS_CLIENT_MESSAGE,
1415
+ payload: { socketId, data }
1416
+ });
1417
+ };
1418
+ ws.onerror = () => {
1419
+ sendMessage(state.socket, {
1420
+ type: MessageType.CLIENT_EVENT,
1421
+ isolateId,
1422
+ event: ClientEvents.WS_CLIENT_ERROR,
1423
+ payload: { socketId }
1424
+ });
1425
+ };
1426
+ ws.onclose = (event) => {
1427
+ sendMessage(state.socket, {
1428
+ type: MessageType.CLIENT_EVENT,
1429
+ isolateId,
1430
+ event: ClientEvents.WS_CLIENT_CLOSED,
1431
+ payload: { socketId, code: event.code, reason: event.reason, wasClean: event.wasClean }
1432
+ });
1433
+ sockets?.delete(socketId);
1434
+ if (sockets?.size === 0) {
1435
+ isolateClientWebSockets.delete(isolateId);
1436
+ }
1437
+ };
1438
+ };
1439
+ const sendConnectionFailed = (reason) => {
1440
+ sendMessage(state.socket, {
1441
+ type: MessageType.CLIENT_EVENT,
1442
+ isolateId,
1443
+ event: ClientEvents.WS_CLIENT_ERROR,
1444
+ payload: { socketId }
1445
+ });
1446
+ sendMessage(state.socket, {
1447
+ type: MessageType.CLIENT_EVENT,
1448
+ isolateId,
1449
+ event: ClientEvents.WS_CLIENT_CLOSED,
1450
+ payload: { socketId, code: 1006, reason, wasClean: false }
1451
+ });
1452
+ };
1453
+ const callback = isolateWebSocketCallbacks.get(isolateId);
1454
+ if (callback) {
1455
+ try {
1456
+ const result = callback(url, protocols || []);
1457
+ if (result instanceof Promise) {
1458
+ result.then((ws) => {
1459
+ if (ws === null) {
1460
+ sendConnectionFailed("Connection blocked");
1461
+ } else {
1462
+ setupWebSocket(ws);
1463
+ }
1464
+ }).catch(() => {
1465
+ sendConnectionFailed("Callback error");
1466
+ });
1467
+ } else if (result === null) {
1468
+ sendConnectionFailed("Connection blocked");
1469
+ } else {
1470
+ setupWebSocket(result);
1471
+ }
1472
+ } catch {
1473
+ sendConnectionFailed("Callback error");
1474
+ }
1475
+ } else {
1476
+ try {
1477
+ const ws = protocols && protocols.length > 0 ? new WebSocket(url, protocols) : new WebSocket(url);
1478
+ setupWebSocket(ws);
1479
+ } catch {
1480
+ sendConnectionFailed("Connection failed");
1481
+ }
1482
+ }
1483
+ }
1484
+ function handleClientWsSend(isolateId, payload, state) {
1485
+ const { socketId, data } = payload;
1486
+ const sockets = isolateClientWebSockets.get(isolateId);
1487
+ const ws = sockets?.get(socketId);
1488
+ if (!ws || ws.readyState !== WebSocket.OPEN) {
1489
+ return;
1490
+ }
1491
+ if (typeof data === "string" && data.startsWith("__BINARY__")) {
1492
+ const base64 = data.slice(10);
1493
+ const binary = Buffer.from(base64, "base64");
1494
+ ws.send(binary);
1495
+ } else if (data instanceof Uint8Array) {
1496
+ ws.send(data);
1497
+ } else {
1498
+ ws.send(data);
1499
+ }
1500
+ }
1501
+ function handleClientWsClose(isolateId, payload, state) {
1502
+ const { socketId, code, reason } = payload;
1503
+ const sockets = isolateClientWebSockets.get(isolateId);
1504
+ const ws = sockets?.get(socketId);
1505
+ if (!ws) {
1506
+ return;
1507
+ }
1508
+ if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {
1509
+ ws.close(code ?? 1000, reason ?? "");
1510
+ }
1511
+ }
1293
1512
  export {
1513
+ isBenignDisposeError,
1294
1514
  connect
1295
1515
  };
1296
1516
 
1297
- //# debugId=20BE24C415D52F0F64756E2164756E21
1517
+ //# debugId=A84790A2E8D5115464756E2164756E21