@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.
@@ -42,6 +42,7 @@ var __export = (target, all) => {
42
42
  // packages/isolate-client/src/connection.ts
43
43
  var exports_connection = {};
44
44
  __export(exports_connection, {
45
+ isBenignDisposeError: () => isBenignDisposeError,
45
46
  connect: () => connect
46
47
  });
47
48
  module.exports = __toCommonJS(exports_connection);
@@ -49,8 +50,10 @@ var import_node_net = require("node:net");
49
50
  var import_node_path = __toESM(require("node:path"));
50
51
  var import_isolate_protocol = require("@ricsam/isolate-protocol");
51
52
  var import_client = require("@ricsam/isolate-playwright/client");
52
- var DEFAULT_TIMEOUT = 30000;
53
53
  var isolateWsCallbacks = new Map;
54
+ var isolateClientWebSockets = new Map;
55
+ var isolateWebSocketCallbacks = new Map;
56
+ var isolateEventListeners = new Map;
54
57
  async function connect(options = {}) {
55
58
  const socket = await createSocket(options);
56
59
  const state = {
@@ -80,9 +83,6 @@ async function connect(options = {}) {
80
83
  socket.on("close", () => {
81
84
  state.connected = false;
82
85
  for (const [, pending] of state.pendingRequests) {
83
- if (pending.timeoutId) {
84
- clearTimeout(pending.timeoutId);
85
- }
86
86
  pending.reject(new Error("Connection closed"));
87
87
  }
88
88
  state.pendingRequests.clear();
@@ -121,7 +121,7 @@ async function connect(options = {}) {
121
121
  }
122
122
  function createSocket(options) {
123
123
  return new Promise((resolve, reject) => {
124
- const timeout = options.timeout ?? DEFAULT_TIMEOUT;
124
+ const timeout = options.timeout;
125
125
  let socket;
126
126
  const onError = (err) => {
127
127
  reject(err);
@@ -136,13 +136,15 @@ function createSocket(options) {
136
136
  socket = import_node_net.connect(options.port ?? 47891, options.host ?? "127.0.0.1", onConnect);
137
137
  }
138
138
  socket.on("error", onError);
139
- const timeoutId = setTimeout(() => {
140
- socket.destroy();
141
- reject(new Error("Connection timeout"));
142
- }, timeout);
143
- socket.once("connect", () => {
144
- clearTimeout(timeoutId);
145
- });
139
+ if (timeout && timeout > 0) {
140
+ const timeoutId = setTimeout(() => {
141
+ socket.destroy();
142
+ reject(new Error("Connection timeout"));
143
+ }, timeout);
144
+ socket.once("connect", () => {
145
+ clearTimeout(timeoutId);
146
+ });
147
+ }
146
148
  });
147
149
  }
148
150
  function handleMessage(message, state) {
@@ -152,8 +154,6 @@ function handleMessage(message, state) {
152
154
  const pending = state.pendingRequests.get(response.requestId);
153
155
  if (pending) {
154
156
  state.pendingRequests.delete(response.requestId);
155
- if (pending.timeoutId)
156
- clearTimeout(pending.timeoutId);
157
157
  pending.resolve(response.data);
158
158
  }
159
159
  break;
@@ -163,8 +163,6 @@ function handleMessage(message, state) {
163
163
  const pending = state.pendingRequests.get(response.requestId);
164
164
  if (pending) {
165
165
  state.pendingRequests.delete(response.requestId);
166
- if (pending.timeoutId)
167
- clearTimeout(pending.timeoutId);
168
166
  const error = new Error(response.message);
169
167
  if (response.details) {
170
168
  error.name = response.details.name;
@@ -191,27 +189,9 @@ function handleMessage(message, state) {
191
189
  }
192
190
  break;
193
191
  }
194
- case import_isolate_protocol.MessageType.WS_COMMAND: {
192
+ case import_isolate_protocol.MessageType.ISOLATE_EVENT: {
195
193
  const msg = message;
196
- const callbacks = isolateWsCallbacks.get(msg.isolateId);
197
- if (callbacks) {
198
- let data;
199
- if (msg.command.data instanceof Uint8Array) {
200
- data = msg.command.data.buffer.slice(msg.command.data.byteOffset, msg.command.data.byteOffset + msg.command.data.byteLength);
201
- } else {
202
- data = msg.command.data;
203
- }
204
- const cmd = {
205
- type: msg.command.type,
206
- connectionId: msg.command.connectionId,
207
- data,
208
- code: msg.command.code,
209
- reason: msg.command.reason
210
- };
211
- for (const cb of callbacks) {
212
- cb(cmd);
213
- }
214
- }
194
+ handleIsolateEvent(msg, state);
215
195
  break;
216
196
  }
217
197
  case import_isolate_protocol.MessageType.RESPONSE_STREAM_START: {
@@ -281,8 +261,6 @@ function handleMessage(message, state) {
281
261
  const pending = state.pendingRequests.get(msg.requestId);
282
262
  if (pending) {
283
263
  state.pendingRequests.delete(msg.requestId);
284
- if (pending.timeoutId)
285
- clearTimeout(pending.timeoutId);
286
264
  const response = new Response(readableStream, {
287
265
  status: msg.metadata?.status ?? 200,
288
266
  statusText: msg.metadata?.statusText ?? "OK",
@@ -407,25 +385,24 @@ function sendMessage(socket, message) {
407
385
  const frame = import_isolate_protocol.buildFrame(message);
408
386
  socket.write(frame);
409
387
  }
410
- function sendRequest(state, message, timeout = DEFAULT_TIMEOUT) {
388
+ function sendRequest(state, message) {
411
389
  return new Promise((resolve, reject) => {
412
390
  if (!state.connected) {
413
391
  reject(new Error("Not connected"));
414
392
  return;
415
393
  }
416
394
  const requestId = message.requestId;
417
- const timeoutId = setTimeout(() => {
418
- state.pendingRequests.delete(requestId);
419
- reject(new Error("Request timeout"));
420
- }, timeout);
421
395
  state.pendingRequests.set(requestId, {
422
396
  resolve,
423
- reject,
424
- timeoutId
397
+ reject
425
398
  });
426
399
  sendMessage(state.socket, message);
427
400
  });
428
401
  }
402
+ function isBenignDisposeError(error) {
403
+ const message = error instanceof Error ? error.message : String(error ?? "");
404
+ return /isolate not owned by this connection|isolate not found|not connected|connection closed/i.test(message);
405
+ }
429
406
  async function createRuntime(state, options = {}, namespaceId) {
430
407
  const callbacks = {};
431
408
  if (options.console) {
@@ -449,73 +426,76 @@ async function createRuntime(state, options = {}, namespaceId) {
449
426
  const networkResponses = [];
450
427
  const pageListenerCleanups = [];
451
428
  if (options.playwright) {
452
- playwrightHandler = import_client.createPlaywrightHandler(options.playwright.page, {
453
- timeout: options.playwright.timeout
454
- });
429
+ playwrightHandler = options.playwright.handler;
430
+ if (!playwrightHandler) {
431
+ throw new Error("playwright.handler is required when using playwright options");
432
+ }
433
+ const page = import_client.getDefaultPlaywrightHandlerMetadata(playwrightHandler)?.page;
455
434
  const handlerCallbackId = state.nextCallbackId++;
456
435
  state.callbacks.set(handlerCallbackId, async (opJson) => {
457
436
  const op = JSON.parse(opJson);
458
437
  const result2 = await playwrightHandler(op);
459
438
  return JSON.stringify(result2);
460
439
  });
461
- const page = options.playwright.page;
462
- const onConsole = (msg) => {
463
- const entry = {
464
- level: msg.type(),
465
- stdout: msg.text(),
466
- timestamp: Date.now()
440
+ if (page) {
441
+ const onConsole = (msg) => {
442
+ const entry = {
443
+ level: msg.type(),
444
+ stdout: msg.text(),
445
+ timestamp: Date.now()
446
+ };
447
+ browserConsoleLogs.push(entry);
448
+ if (options.playwright.onEvent) {
449
+ options.playwright.onEvent({
450
+ type: "browserConsoleLog",
451
+ ...entry
452
+ });
453
+ }
454
+ if (options.playwright.console && options.console?.onEntry) {
455
+ options.console.onEntry({
456
+ type: "browserOutput",
457
+ ...entry
458
+ });
459
+ } else if (options.playwright.console) {
460
+ const prefix = entry.level === "error" ? "[browser:error]" : "[browser]";
461
+ console.log(prefix, entry.stdout);
462
+ }
467
463
  };
468
- browserConsoleLogs.push(entry);
469
- if (options.playwright.onEvent) {
470
- options.playwright.onEvent({
471
- type: "browserConsoleLog",
472
- ...entry
473
- });
474
- }
475
- if (options.playwright.console && options.console?.onEntry) {
476
- options.console.onEntry({
477
- type: "browserOutput",
478
- ...entry
479
- });
480
- } else if (options.playwright.console) {
481
- const prefix = entry.level === "error" ? "[browser:error]" : "[browser]";
482
- console.log(prefix, entry.stdout);
483
- }
484
- };
485
- const onRequest = (request2) => {
486
- const info = {
487
- url: request2.url(),
488
- method: request2.method(),
489
- headers: request2.headers(),
490
- timestamp: Date.now()
464
+ const onRequest = (request2) => {
465
+ const info = {
466
+ url: request2.url(),
467
+ method: request2.method(),
468
+ headers: request2.headers(),
469
+ timestamp: Date.now()
470
+ };
471
+ networkRequests.push(info);
472
+ if (options.playwright.onEvent) {
473
+ options.playwright.onEvent({
474
+ type: "networkRequest",
475
+ ...info
476
+ });
477
+ }
491
478
  };
492
- networkRequests.push(info);
493
- if (options.playwright.onEvent) {
494
- options.playwright.onEvent({
495
- type: "networkRequest",
496
- ...info
497
- });
498
- }
499
- };
500
- const onResponse = (response) => {
501
- const info = {
502
- url: response.url(),
503
- status: response.status(),
504
- headers: response.headers(),
505
- timestamp: Date.now()
479
+ const onResponse = (response) => {
480
+ const info = {
481
+ url: response.url(),
482
+ status: response.status(),
483
+ headers: response.headers(),
484
+ timestamp: Date.now()
485
+ };
486
+ networkResponses.push(info);
487
+ if (options.playwright.onEvent) {
488
+ options.playwright.onEvent({
489
+ type: "networkResponse",
490
+ ...info
491
+ });
492
+ }
506
493
  };
507
- networkResponses.push(info);
508
- if (options.playwright.onEvent) {
509
- options.playwright.onEvent({
510
- type: "networkResponse",
511
- ...info
512
- });
513
- }
514
- };
515
- page.on("console", onConsole);
516
- page.on("request", onRequest);
517
- page.on("response", onResponse);
518
- pageListenerCleanups.push(() => page.removeListener("console", onConsole), () => page.removeListener("request", onRequest), () => page.removeListener("response", onResponse));
494
+ page.on("console", onConsole);
495
+ page.on("request", onRequest);
496
+ page.on("response", onResponse);
497
+ pageListenerCleanups.push(() => page.removeListener("console", onConsole), () => page.removeListener("request", onRequest), () => page.removeListener("response", onResponse));
498
+ }
519
499
  callbacks.playwright = {
520
500
  handlerCallbackId,
521
501
  console: options.playwright.console && !options.console?.onEntry
@@ -563,8 +543,18 @@ async function createRuntime(state, options = {}, namespaceId) {
563
543
  const reused = result.reused ?? false;
564
544
  const wsCommandCallbacks = new Set;
565
545
  isolateWsCallbacks.set(isolateId, wsCommandCallbacks);
546
+ if (options.onWebSocketCommand) {
547
+ wsCommandCallbacks.add(options.onWebSocketCommand);
548
+ }
549
+ if (options.webSocket) {
550
+ isolateWebSocketCallbacks.set(isolateId, options.webSocket);
551
+ }
566
552
  const fetchHandle = {
567
553
  async dispatchRequest(req, opts) {
554
+ const signal = opts?.signal;
555
+ if (signal?.aborted) {
556
+ throw new DOMException("The operation was aborted", "AbortError");
557
+ }
568
558
  const reqId = state.nextRequestId++;
569
559
  const serialized = await serializeRequestWithStreaming(state, req);
570
560
  const { bodyStream, ...serializableRequest } = serialized;
@@ -572,24 +562,40 @@ async function createRuntime(state, options = {}, namespaceId) {
572
562
  type: import_isolate_protocol.MessageType.DISPATCH_REQUEST,
573
563
  requestId: reqId,
574
564
  isolateId,
575
- request: serializableRequest,
576
- options: opts
565
+ request: serializableRequest
577
566
  };
578
567
  const handleResponse = (res) => {
579
568
  if (res.__streaming && res.response instanceof Response) {
580
569
  return res.response;
581
570
  }
582
- return deserializeResponse(res.response);
571
+ return import_isolate_protocol.deserializeResponse(res.response);
583
572
  };
584
- if (serialized.bodyStreamId !== undefined && bodyStream) {
585
- const streamId = serialized.bodyStreamId;
586
- const responsePromise = sendRequest(state, request2, opts?.timeout ?? DEFAULT_TIMEOUT);
587
- await sendBodyStream(state, streamId, bodyStream);
588
- const res = await responsePromise;
589
- return handleResponse(res);
590
- } else {
591
- const res = await sendRequest(state, request2, opts?.timeout ?? DEFAULT_TIMEOUT);
592
- return handleResponse(res);
573
+ let onAbort;
574
+ if (signal) {
575
+ onAbort = () => {
576
+ const pending = state.pendingRequests.get(reqId);
577
+ if (pending) {
578
+ state.pendingRequests.delete(reqId);
579
+ pending.reject(new DOMException("The operation was aborted", "AbortError"));
580
+ }
581
+ };
582
+ signal.addEventListener("abort", onAbort, { once: true });
583
+ }
584
+ try {
585
+ if (serialized.bodyStreamId !== undefined && bodyStream) {
586
+ const streamId = serialized.bodyStreamId;
587
+ const responsePromise = sendRequest(state, request2);
588
+ await sendBodyStream(state, streamId, bodyStream);
589
+ const res = await responsePromise;
590
+ return handleResponse(res);
591
+ } else {
592
+ const res = await sendRequest(state, request2);
593
+ return handleResponse(res);
594
+ }
595
+ } finally {
596
+ if (signal && onAbort) {
597
+ signal.removeEventListener("abort", onAbort);
598
+ }
593
599
  }
594
600
  },
595
601
  async getUpgradeRequest() {
@@ -736,7 +742,7 @@ async function createRuntime(state, options = {}, namespaceId) {
736
742
  isolateId,
737
743
  timeout
738
744
  };
739
- return sendRequest(state, req, timeout ?? DEFAULT_TIMEOUT);
745
+ return sendRequest(state, req);
740
746
  },
741
747
  async hasTests() {
742
748
  if (!testEnvironmentEnabled) {
@@ -778,7 +784,7 @@ async function createRuntime(state, options = {}, namespaceId) {
778
784
  const playwrightHandle = {
779
785
  getCollectedData() {
780
786
  if (!playwrightEnabled) {
781
- throw new Error("Playwright not configured. Provide playwright.page in createRuntime options.");
787
+ throw new Error("Playwright not configured. Provide playwright.handler in createRuntime options.");
782
788
  }
783
789
  return {
784
790
  browserConsoleLogs: [...browserConsoleLogs],
@@ -788,7 +794,7 @@ async function createRuntime(state, options = {}, namespaceId) {
788
794
  },
789
795
  clearCollectedData() {
790
796
  if (!playwrightEnabled) {
791
- throw new Error("Playwright not configured. Provide playwright.page in createRuntime options.");
797
+ throw new Error("Playwright not configured. Provide playwright.handler in createRuntime options.");
792
798
  }
793
799
  browserConsoleLogs.length = 0;
794
800
  networkRequests.length = 0;
@@ -797,7 +803,6 @@ async function createRuntime(state, options = {}, namespaceId) {
797
803
  };
798
804
  return {
799
805
  id: isolateId,
800
- isolateId,
801
806
  reused,
802
807
  fetch: fetchHandle,
803
808
  timers: timersHandle,
@@ -812,24 +817,69 @@ async function createRuntime(state, options = {}, namespaceId) {
812
817
  requestId: reqId,
813
818
  isolateId,
814
819
  code,
815
- filename: options2?.filename,
816
- maxExecutionMs: options2?.maxExecutionMs,
817
- module: true
820
+ filename: options2?.filename
818
821
  };
819
822
  await sendRequest(state, req);
820
823
  },
824
+ on(event, callback) {
825
+ let listeners = isolateEventListeners.get(isolateId);
826
+ if (!listeners) {
827
+ listeners = new Map;
828
+ isolateEventListeners.set(isolateId, listeners);
829
+ }
830
+ let eventListeners = listeners.get(event);
831
+ if (!eventListeners) {
832
+ eventListeners = new Set;
833
+ listeners.set(event, eventListeners);
834
+ }
835
+ eventListeners.add(callback);
836
+ return () => {
837
+ eventListeners.delete(callback);
838
+ if (eventListeners.size === 0) {
839
+ listeners.delete(event);
840
+ if (listeners.size === 0) {
841
+ isolateEventListeners.delete(isolateId);
842
+ }
843
+ }
844
+ };
845
+ },
846
+ emit(event, payload) {
847
+ sendMessage(state.socket, {
848
+ type: import_isolate_protocol.MessageType.CLIENT_EVENT,
849
+ isolateId,
850
+ event,
851
+ payload
852
+ });
853
+ },
821
854
  dispose: async () => {
822
855
  for (const cleanup of pageListenerCleanups) {
823
856
  cleanup();
824
857
  }
825
858
  isolateWsCallbacks.delete(isolateId);
859
+ isolateWebSocketCallbacks.delete(isolateId);
860
+ isolateEventListeners.delete(isolateId);
861
+ const clientSockets = isolateClientWebSockets.get(isolateId);
862
+ if (clientSockets) {
863
+ for (const ws of clientSockets.values()) {
864
+ if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {
865
+ ws.close(1000, "Isolate disposed");
866
+ }
867
+ }
868
+ isolateClientWebSockets.delete(isolateId);
869
+ }
826
870
  const reqId = state.nextRequestId++;
827
871
  const req = {
828
872
  type: import_isolate_protocol.MessageType.DISPOSE_RUNTIME,
829
873
  requestId: reqId,
830
874
  isolateId
831
875
  };
832
- await sendRequest(state, req);
876
+ try {
877
+ await sendRequest(state, req);
878
+ } catch (error) {
879
+ if (!isBenignDisposeError(error)) {
880
+ throw error;
881
+ }
882
+ }
833
883
  }
834
884
  };
835
885
  }
@@ -857,8 +907,15 @@ function registerFetchCallback(state, callback) {
857
907
  const callbackId = state.nextCallbackId++;
858
908
  state.callbacksNeedingRequestId.add(callbackId);
859
909
  state.callbacks.set(callbackId, async (serialized, requestId) => {
860
- const request = deserializeRequest(serialized);
861
- const response = await callback(request);
910
+ const data = serialized;
911
+ const init = {
912
+ method: data.method,
913
+ headers: data.headers,
914
+ rawBody: data.body ?? null,
915
+ body: data.body ?? null,
916
+ signal: new AbortController().signal
917
+ };
918
+ const response = await callback(data.url, init);
862
919
  const contentLength = response.headers.get("content-length");
863
920
  const knownSize = contentLength ? parseInt(contentLength, 10) : null;
864
921
  const isNetworkResponse = response.url && (response.url.startsWith("http://") || response.url.startsWith("https://"));
@@ -883,7 +940,7 @@ function registerFetchCallback(state, callback) {
883
940
  streamCallbackResponseBody(state, streamId, requestId, response.body);
884
941
  return { __callbackStreaming: true, streamId };
885
942
  }
886
- return serializeResponse(response);
943
+ return import_isolate_protocol.serializeResponse(response);
887
944
  });
888
945
  return { callbackId, name: "fetch", type: "async" };
889
946
  }
@@ -1011,12 +1068,6 @@ var clientIteratorSessions = new Map;
1011
1068
  var nextClientIteratorId = 1;
1012
1069
  var returnedPromiseRegistry = new Map;
1013
1070
  var returnedIteratorRegistry = new Map;
1014
- function isPromiseRef(value) {
1015
- return typeof value === "object" && value !== null && value.__type === "PromiseRef";
1016
- }
1017
- function isAsyncIteratorRef(value) {
1018
- return typeof value === "object" && value !== null && value.__type === "AsyncIteratorRef";
1019
- }
1020
1071
  function registerCustomFunctions(state, customFunctions) {
1021
1072
  const registrations = {};
1022
1073
  for (const [name, def] of Object.entries(customFunctions)) {
@@ -1099,7 +1150,7 @@ function registerCustomFunctions(state, customFunctions) {
1099
1150
  if (value === null || typeof value !== "object") {
1100
1151
  return value;
1101
1152
  }
1102
- if (isPromiseRef(value)) {
1153
+ if (import_isolate_protocol.isPromiseRef(value)) {
1103
1154
  const resolveCallbackId = state.nextCallbackId++;
1104
1155
  state.callbacks.set(resolveCallbackId, async (...args2) => {
1105
1156
  const promiseId = args2[0];
@@ -1117,7 +1168,7 @@ function registerCustomFunctions(state, customFunctions) {
1117
1168
  __resolveCallbackId: resolveCallbackId
1118
1169
  };
1119
1170
  }
1120
- if (isAsyncIteratorRef(value)) {
1171
+ if (import_isolate_protocol.isAsyncIteratorRef(value)) {
1121
1172
  const nextCallbackId = state.nextCallbackId++;
1122
1173
  state.callbacks.set(nextCallbackId, async (...args2) => {
1123
1174
  const iteratorId = args2[0];
@@ -1200,36 +1251,6 @@ function registerCustomFunctions(state, customFunctions) {
1200
1251
  }
1201
1252
  return registrations;
1202
1253
  }
1203
- async function serializeResponse(response) {
1204
- const headers = [];
1205
- response.headers.forEach((value, key) => {
1206
- headers.push([key, value]);
1207
- });
1208
- let body = null;
1209
- if (response.body) {
1210
- body = new Uint8Array(await response.arrayBuffer());
1211
- }
1212
- return {
1213
- status: response.status,
1214
- statusText: response.statusText,
1215
- headers,
1216
- body
1217
- };
1218
- }
1219
- function deserializeRequest(data) {
1220
- return new Request(data.url, {
1221
- method: data.method,
1222
- headers: data.headers,
1223
- body: data.body
1224
- });
1225
- }
1226
- function deserializeResponse(data) {
1227
- return new Response(data.body, {
1228
- status: data.status,
1229
- statusText: data.statusText,
1230
- headers: data.headers
1231
- });
1232
- }
1233
1254
  async function serializeRequestWithStreaming(state, request) {
1234
1255
  const headers = [];
1235
1256
  request.headers.forEach((value, key) => {
@@ -1328,5 +1349,196 @@ async function sendBodyStream(state, streamId, body) {
1328
1349
  state.uploadStreams.delete(streamId);
1329
1350
  }
1330
1351
  }
1352
+ function handleIsolateEvent(message, state) {
1353
+ switch (message.event) {
1354
+ case import_isolate_protocol.IsolateEvents.WS_COMMAND: {
1355
+ const payload = message.payload;
1356
+ const callbacks = isolateWsCallbacks.get(message.isolateId);
1357
+ if (callbacks) {
1358
+ let data;
1359
+ if (payload.data instanceof Uint8Array) {
1360
+ data = payload.data.buffer.slice(payload.data.byteOffset, payload.data.byteOffset + payload.data.byteLength);
1361
+ } else {
1362
+ data = payload.data;
1363
+ }
1364
+ const cmd = {
1365
+ type: payload.type,
1366
+ connectionId: payload.connectionId,
1367
+ data,
1368
+ code: payload.code,
1369
+ reason: payload.reason
1370
+ };
1371
+ for (const cb of callbacks) {
1372
+ cb(cmd);
1373
+ }
1374
+ }
1375
+ break;
1376
+ }
1377
+ case import_isolate_protocol.IsolateEvents.WS_CLIENT_CONNECT: {
1378
+ const payload = message.payload;
1379
+ handleClientWsConnect(message.isolateId, payload, state);
1380
+ break;
1381
+ }
1382
+ case import_isolate_protocol.IsolateEvents.WS_CLIENT_SEND: {
1383
+ const payload = message.payload;
1384
+ handleClientWsSend(message.isolateId, payload, state);
1385
+ break;
1386
+ }
1387
+ case import_isolate_protocol.IsolateEvents.WS_CLIENT_CLOSE: {
1388
+ const payload = message.payload;
1389
+ handleClientWsClose(message.isolateId, payload, state);
1390
+ break;
1391
+ }
1392
+ default: {
1393
+ const listeners = isolateEventListeners.get(message.isolateId);
1394
+ if (listeners) {
1395
+ const eventListeners = listeners.get(message.event);
1396
+ if (eventListeners) {
1397
+ for (const cb of eventListeners) {
1398
+ cb(message.payload);
1399
+ }
1400
+ }
1401
+ }
1402
+ break;
1403
+ }
1404
+ }
1405
+ }
1406
+ function handleClientWsConnect(isolateId, payload, state) {
1407
+ const { socketId, url, protocols } = payload;
1408
+ let sockets = isolateClientWebSockets.get(isolateId);
1409
+ if (!sockets) {
1410
+ sockets = new Map;
1411
+ isolateClientWebSockets.set(isolateId, sockets);
1412
+ }
1413
+ const setupWebSocket = (ws) => {
1414
+ sockets.set(socketId, ws);
1415
+ ws.onopen = () => {
1416
+ sendMessage(state.socket, {
1417
+ type: import_isolate_protocol.MessageType.CLIENT_EVENT,
1418
+ isolateId,
1419
+ event: import_isolate_protocol.ClientEvents.WS_CLIENT_OPENED,
1420
+ payload: { socketId, protocol: ws.protocol || "", extensions: ws.extensions || "" }
1421
+ });
1422
+ };
1423
+ ws.onmessage = (event) => {
1424
+ let data;
1425
+ if (typeof event.data === "string") {
1426
+ data = event.data;
1427
+ } else if (event.data instanceof ArrayBuffer) {
1428
+ data = new Uint8Array(event.data);
1429
+ } else if (event.data instanceof Blob) {
1430
+ event.data.arrayBuffer().then((buffer) => {
1431
+ sendMessage(state.socket, {
1432
+ type: import_isolate_protocol.MessageType.CLIENT_EVENT,
1433
+ isolateId,
1434
+ event: import_isolate_protocol.ClientEvents.WS_CLIENT_MESSAGE,
1435
+ payload: { socketId, data: new Uint8Array(buffer) }
1436
+ });
1437
+ });
1438
+ return;
1439
+ } else {
1440
+ data = String(event.data);
1441
+ }
1442
+ sendMessage(state.socket, {
1443
+ type: import_isolate_protocol.MessageType.CLIENT_EVENT,
1444
+ isolateId,
1445
+ event: import_isolate_protocol.ClientEvents.WS_CLIENT_MESSAGE,
1446
+ payload: { socketId, data }
1447
+ });
1448
+ };
1449
+ ws.onerror = () => {
1450
+ sendMessage(state.socket, {
1451
+ type: import_isolate_protocol.MessageType.CLIENT_EVENT,
1452
+ isolateId,
1453
+ event: import_isolate_protocol.ClientEvents.WS_CLIENT_ERROR,
1454
+ payload: { socketId }
1455
+ });
1456
+ };
1457
+ ws.onclose = (event) => {
1458
+ sendMessage(state.socket, {
1459
+ type: import_isolate_protocol.MessageType.CLIENT_EVENT,
1460
+ isolateId,
1461
+ event: import_isolate_protocol.ClientEvents.WS_CLIENT_CLOSED,
1462
+ payload: { socketId, code: event.code, reason: event.reason, wasClean: event.wasClean }
1463
+ });
1464
+ sockets?.delete(socketId);
1465
+ if (sockets?.size === 0) {
1466
+ isolateClientWebSockets.delete(isolateId);
1467
+ }
1468
+ };
1469
+ };
1470
+ const sendConnectionFailed = (reason) => {
1471
+ sendMessage(state.socket, {
1472
+ type: import_isolate_protocol.MessageType.CLIENT_EVENT,
1473
+ isolateId,
1474
+ event: import_isolate_protocol.ClientEvents.WS_CLIENT_ERROR,
1475
+ payload: { socketId }
1476
+ });
1477
+ sendMessage(state.socket, {
1478
+ type: import_isolate_protocol.MessageType.CLIENT_EVENT,
1479
+ isolateId,
1480
+ event: import_isolate_protocol.ClientEvents.WS_CLIENT_CLOSED,
1481
+ payload: { socketId, code: 1006, reason, wasClean: false }
1482
+ });
1483
+ };
1484
+ const callback = isolateWebSocketCallbacks.get(isolateId);
1485
+ if (callback) {
1486
+ try {
1487
+ const result = callback(url, protocols || []);
1488
+ if (result instanceof Promise) {
1489
+ result.then((ws) => {
1490
+ if (ws === null) {
1491
+ sendConnectionFailed("Connection blocked");
1492
+ } else {
1493
+ setupWebSocket(ws);
1494
+ }
1495
+ }).catch(() => {
1496
+ sendConnectionFailed("Callback error");
1497
+ });
1498
+ } else if (result === null) {
1499
+ sendConnectionFailed("Connection blocked");
1500
+ } else {
1501
+ setupWebSocket(result);
1502
+ }
1503
+ } catch {
1504
+ sendConnectionFailed("Callback error");
1505
+ }
1506
+ } else {
1507
+ try {
1508
+ const ws = protocols && protocols.length > 0 ? new WebSocket(url, protocols) : new WebSocket(url);
1509
+ setupWebSocket(ws);
1510
+ } catch {
1511
+ sendConnectionFailed("Connection failed");
1512
+ }
1513
+ }
1514
+ }
1515
+ function handleClientWsSend(isolateId, payload, state) {
1516
+ const { socketId, data } = payload;
1517
+ const sockets = isolateClientWebSockets.get(isolateId);
1518
+ const ws = sockets?.get(socketId);
1519
+ if (!ws || ws.readyState !== WebSocket.OPEN) {
1520
+ return;
1521
+ }
1522
+ if (typeof data === "string" && data.startsWith("__BINARY__")) {
1523
+ const base64 = data.slice(10);
1524
+ const binary = Buffer.from(base64, "base64");
1525
+ ws.send(binary);
1526
+ } else if (data instanceof Uint8Array) {
1527
+ ws.send(data);
1528
+ } else {
1529
+ ws.send(data);
1530
+ }
1531
+ }
1532
+ function handleClientWsClose(isolateId, payload, state) {
1533
+ const { socketId, code, reason } = payload;
1534
+ const sockets = isolateClientWebSockets.get(isolateId);
1535
+ const ws = sockets?.get(socketId);
1536
+ if (!ws) {
1537
+ return;
1538
+ }
1539
+ if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {
1540
+ ws.close(code ?? 1000, reason ?? "");
1541
+ }
1542
+ }
1331
1543
 
1332
- //# debugId=1C20082A75E8BCB364756E2164756E21
1544
+ //# debugId=1DAE4D8C13C4D6B364756E2164756E21