@ricsam/isolate-client 0.1.1 → 0.1.5

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.
@@ -4,9 +4,15 @@ import { connect as netConnect } from "net";
4
4
  import {
5
5
  createFrameParser,
6
6
  buildFrame,
7
- MessageType
7
+ MessageType,
8
+ STREAM_THRESHOLD,
9
+ STREAM_CHUNK_SIZE,
10
+ STREAM_DEFAULT_CREDIT,
11
+ marshalValue
8
12
  } from "@ricsam/isolate-protocol";
13
+ import { createPlaywrightHandler } from "@ricsam/isolate-playwright/client";
9
14
  var DEFAULT_TIMEOUT = 30000;
15
+ var isolateWsCallbacks = new Map;
10
16
  async function connect(options = {}) {
11
17
  const socket = await createSocket(options);
12
18
  const state = {
@@ -15,8 +21,10 @@ async function connect(options = {}) {
15
21
  callbacks: new Map,
16
22
  nextRequestId: 1,
17
23
  nextCallbackId: 1,
24
+ nextStreamId: 1,
18
25
  connected: true,
19
- playwrightEventHandlers: new Map
26
+ streamResponses: new Map,
27
+ uploadStreams: new Map
20
28
  };
21
29
  const parser = createFrameParser();
22
30
  socket.on("data", (data) => {
@@ -111,21 +119,157 @@ function handleMessage(message, state) {
111
119
  }
112
120
  case MessageType.PONG:
113
121
  break;
114
- case MessageType.PLAYWRIGHT_EVENT: {
115
- const event = message;
116
- const handler = state.playwrightEventHandlers.get(event.isolateId);
117
- if (handler) {
118
- switch (event.eventType) {
119
- case "consoleLog":
120
- handler.onConsoleLog?.(event.payload);
121
- break;
122
- case "networkRequest":
123
- handler.onNetworkRequest?.(event.payload);
124
- break;
125
- case "networkResponse":
126
- handler.onNetworkResponse?.(event.payload);
127
- break;
122
+ case MessageType.WS_COMMAND: {
123
+ const msg = message;
124
+ const callbacks = isolateWsCallbacks.get(msg.isolateId);
125
+ if (callbacks) {
126
+ let data;
127
+ if (msg.command.data instanceof Uint8Array) {
128
+ data = msg.command.data.buffer.slice(msg.command.data.byteOffset, msg.command.data.byteOffset + msg.command.data.byteLength);
129
+ } else {
130
+ data = msg.command.data;
128
131
  }
132
+ const cmd = {
133
+ type: msg.command.type,
134
+ connectionId: msg.command.connectionId,
135
+ data,
136
+ code: msg.command.code,
137
+ reason: msg.command.reason
138
+ };
139
+ for (const cb of callbacks) {
140
+ cb(cmd);
141
+ }
142
+ }
143
+ break;
144
+ }
145
+ case MessageType.RESPONSE_STREAM_START: {
146
+ const msg = message;
147
+ const receiver = {
148
+ streamId: msg.streamId,
149
+ requestId: msg.requestId,
150
+ metadata: msg.metadata,
151
+ controller: null,
152
+ state: "active",
153
+ pendingChunks: []
154
+ };
155
+ const readableStream = new ReadableStream({
156
+ start(controller) {
157
+ receiver.controller = controller;
158
+ },
159
+ pull(_controller) {
160
+ while (receiver.pendingChunks.length > 0) {
161
+ const chunk = receiver.pendingChunks.shift();
162
+ receiver.controller.enqueue(chunk);
163
+ }
164
+ if (receiver.state === "closed") {
165
+ receiver.controller.close();
166
+ return;
167
+ }
168
+ if (receiver.state === "errored") {
169
+ return;
170
+ }
171
+ sendMessage(state.socket, {
172
+ type: MessageType.STREAM_PULL,
173
+ streamId: msg.streamId,
174
+ maxBytes: STREAM_DEFAULT_CREDIT
175
+ });
176
+ return new Promise((resolve) => {
177
+ receiver.pullResolver = resolve;
178
+ });
179
+ },
180
+ cancel(_reason) {
181
+ receiver.state = "errored";
182
+ sendMessage(state.socket, {
183
+ type: MessageType.STREAM_ERROR,
184
+ streamId: msg.streamId,
185
+ error: "Stream cancelled by consumer"
186
+ });
187
+ state.streamResponses.delete(msg.streamId);
188
+ }
189
+ });
190
+ state.streamResponses.set(msg.streamId, receiver);
191
+ const pending = state.pendingRequests.get(msg.requestId);
192
+ if (pending) {
193
+ state.pendingRequests.delete(msg.requestId);
194
+ if (pending.timeoutId)
195
+ clearTimeout(pending.timeoutId);
196
+ const response = new Response(readableStream, {
197
+ status: msg.metadata?.status ?? 200,
198
+ statusText: msg.metadata?.statusText ?? "OK",
199
+ headers: msg.metadata?.headers
200
+ });
201
+ pending.resolve({ response, __streaming: true });
202
+ }
203
+ sendMessage(state.socket, {
204
+ type: MessageType.STREAM_PULL,
205
+ streamId: msg.streamId,
206
+ maxBytes: STREAM_DEFAULT_CREDIT
207
+ });
208
+ break;
209
+ }
210
+ case MessageType.RESPONSE_STREAM_CHUNK: {
211
+ const msg = message;
212
+ const receiver = state.streamResponses.get(msg.streamId);
213
+ if (receiver && receiver.state === "active") {
214
+ if (receiver.pullResolver) {
215
+ receiver.controller.enqueue(msg.chunk);
216
+ const resolver = receiver.pullResolver;
217
+ receiver.pullResolver = undefined;
218
+ resolver();
219
+ } else {
220
+ receiver.pendingChunks.push(msg.chunk);
221
+ }
222
+ }
223
+ break;
224
+ }
225
+ case MessageType.RESPONSE_STREAM_END: {
226
+ const msg = message;
227
+ const receiver = state.streamResponses.get(msg.streamId);
228
+ if (receiver) {
229
+ receiver.state = "closed";
230
+ while (receiver.pendingChunks.length > 0) {
231
+ const chunk = receiver.pendingChunks.shift();
232
+ receiver.controller.enqueue(chunk);
233
+ }
234
+ receiver.controller.close();
235
+ if (receiver.pullResolver) {
236
+ const resolver = receiver.pullResolver;
237
+ receiver.pullResolver = undefined;
238
+ resolver();
239
+ }
240
+ state.streamResponses.delete(msg.streamId);
241
+ }
242
+ break;
243
+ }
244
+ case MessageType.STREAM_PULL: {
245
+ const msg = message;
246
+ const session = state.uploadStreams.get(msg.streamId);
247
+ if (session) {
248
+ session.credit += msg.maxBytes;
249
+ if (session.creditResolver) {
250
+ session.creditResolver();
251
+ session.creditResolver = undefined;
252
+ }
253
+ }
254
+ break;
255
+ }
256
+ case MessageType.STREAM_ERROR: {
257
+ const msg = message;
258
+ const uploadSession = state.uploadStreams.get(msg.streamId);
259
+ if (uploadSession) {
260
+ uploadSession.state = "closed";
261
+ state.uploadStreams.delete(msg.streamId);
262
+ }
263
+ const receiver = state.streamResponses.get(msg.streamId);
264
+ if (receiver) {
265
+ receiver.state = "errored";
266
+ receiver.controller.error(new Error(msg.error));
267
+ if (receiver.pullResolver) {
268
+ const resolver = receiver.pullResolver;
269
+ receiver.pullResolver = undefined;
270
+ resolver();
271
+ }
272
+ state.streamResponses.delete(msg.streamId);
129
273
  }
130
274
  break;
131
275
  }
@@ -193,64 +337,291 @@ async function createRuntime(state, options = {}) {
193
337
  if (options.fs) {
194
338
  callbacks.fs = registerFsCallbacks(state, options.fs);
195
339
  }
340
+ if (options.moduleLoader) {
341
+ callbacks.moduleLoader = registerModuleLoaderCallback(state, options.moduleLoader);
342
+ }
343
+ if (options.customFunctions) {
344
+ callbacks.custom = registerCustomFunctions(state, options.customFunctions);
345
+ }
346
+ let playwrightHandler;
347
+ if (options.playwright) {
348
+ playwrightHandler = createPlaywrightHandler(options.playwright.page, {
349
+ timeout: options.playwright.timeout,
350
+ baseUrl: options.playwright.baseUrl
351
+ });
352
+ const handlerCallbackId = state.nextCallbackId++;
353
+ state.callbacks.set(handlerCallbackId, async (opJson) => {
354
+ const op = JSON.parse(opJson);
355
+ const result2 = await playwrightHandler(op);
356
+ return JSON.stringify(result2);
357
+ });
358
+ const hasOnEvent = !!options.playwright.onEvent;
359
+ const hasConsoleHandler = options.playwright.console && options.console?.onEntry;
360
+ let browserConsoleLogCallbackId;
361
+ if (hasOnEvent || hasConsoleHandler) {
362
+ browserConsoleLogCallbackId = registerEventCallback(state, (entry) => {
363
+ const browserEntry = entry;
364
+ if (options.playwright.onEvent) {
365
+ options.playwright.onEvent({
366
+ type: "browserConsoleLog",
367
+ level: browserEntry.level,
368
+ args: browserEntry.args,
369
+ timestamp: browserEntry.timestamp
370
+ });
371
+ }
372
+ if (options.playwright.console && options.console?.onEntry) {
373
+ options.console.onEntry({
374
+ type: "browserOutput",
375
+ level: browserEntry.level,
376
+ args: browserEntry.args,
377
+ timestamp: browserEntry.timestamp
378
+ });
379
+ }
380
+ });
381
+ }
382
+ let networkRequestCallbackId;
383
+ if (hasOnEvent) {
384
+ networkRequestCallbackId = registerEventCallback(state, (info) => {
385
+ const reqInfo = info;
386
+ options.playwright.onEvent({
387
+ type: "networkRequest",
388
+ url: reqInfo.url,
389
+ method: reqInfo.method,
390
+ headers: reqInfo.headers,
391
+ postData: reqInfo.postData,
392
+ resourceType: reqInfo.resourceType,
393
+ timestamp: reqInfo.timestamp
394
+ });
395
+ });
396
+ }
397
+ let networkResponseCallbackId;
398
+ if (hasOnEvent) {
399
+ networkResponseCallbackId = registerEventCallback(state, (info) => {
400
+ const resInfo = info;
401
+ options.playwright.onEvent({
402
+ type: "networkResponse",
403
+ url: resInfo.url,
404
+ status: resInfo.status,
405
+ statusText: resInfo.statusText,
406
+ headers: resInfo.headers,
407
+ timestamp: resInfo.timestamp
408
+ });
409
+ });
410
+ }
411
+ callbacks.playwright = {
412
+ handlerCallbackId,
413
+ console: options.playwright.console && !options.console?.onEntry,
414
+ onBrowserConsoleLogCallbackId: browserConsoleLogCallbackId,
415
+ onNetworkRequestCallbackId: networkRequestCallbackId,
416
+ onNetworkResponseCallbackId: networkResponseCallbackId
417
+ };
418
+ }
419
+ let testEnvironmentOption;
420
+ if (options.testEnvironment) {
421
+ if (typeof options.testEnvironment === "object") {
422
+ const testEnvOptions = options.testEnvironment;
423
+ const testEnvCallbacks = {};
424
+ if (testEnvOptions.onEvent) {
425
+ const userOnEvent = testEnvOptions.onEvent;
426
+ const onEventCallbackId = registerEventCallback(state, (eventJson) => {
427
+ const event = JSON.parse(eventJson);
428
+ userOnEvent(event);
429
+ });
430
+ testEnvCallbacks.onEvent = {
431
+ callbackId: onEventCallbackId,
432
+ name: "testEnvironment.onEvent",
433
+ type: "sync"
434
+ };
435
+ }
436
+ testEnvironmentOption = {
437
+ callbacks: testEnvCallbacks,
438
+ testTimeout: testEnvOptions.testTimeout
439
+ };
440
+ } else {
441
+ testEnvironmentOption = true;
442
+ }
443
+ }
196
444
  const requestId = state.nextRequestId++;
197
445
  const request = {
198
446
  type: MessageType.CREATE_RUNTIME,
199
447
  requestId,
200
448
  options: {
201
- memoryLimit: options.memoryLimit,
202
- callbacks
449
+ memoryLimitMB: options.memoryLimitMB,
450
+ cwd: options.cwd,
451
+ callbacks,
452
+ testEnvironment: testEnvironmentOption
203
453
  }
204
454
  };
205
455
  const result = await sendRequest(state, request);
206
456
  const isolateId = result.isolateId;
207
- return {
208
- isolateId,
209
- eval: async (code, filename) => {
457
+ const wsCommandCallbacks = new Set;
458
+ isolateWsCallbacks.set(isolateId, wsCommandCallbacks);
459
+ const fetchHandle = {
460
+ async dispatchRequest(req, opts) {
461
+ const reqId = state.nextRequestId++;
462
+ const serialized = await serializeRequestWithStreaming(state, req);
463
+ const { bodyStream, ...serializableRequest } = serialized;
464
+ const request2 = {
465
+ type: MessageType.DISPATCH_REQUEST,
466
+ requestId: reqId,
467
+ isolateId,
468
+ request: serializableRequest,
469
+ options: opts
470
+ };
471
+ const handleResponse = (res) => {
472
+ if (res.__streaming && res.response instanceof Response) {
473
+ return res.response;
474
+ }
475
+ return deserializeResponse(res.response);
476
+ };
477
+ if (serialized.bodyStreamId !== undefined && bodyStream) {
478
+ const streamId = serialized.bodyStreamId;
479
+ const responsePromise = sendRequest(state, request2, opts?.timeout ?? DEFAULT_TIMEOUT);
480
+ await sendBodyStream(state, streamId, bodyStream);
481
+ const res = await responsePromise;
482
+ return handleResponse(res);
483
+ } else {
484
+ const res = await sendRequest(state, request2, opts?.timeout ?? DEFAULT_TIMEOUT);
485
+ return handleResponse(res);
486
+ }
487
+ },
488
+ async getUpgradeRequest() {
210
489
  const reqId = state.nextRequestId++;
211
490
  const req = {
212
- type: MessageType.EVAL,
491
+ type: MessageType.FETCH_GET_UPGRADE_REQUEST,
492
+ requestId: reqId,
493
+ isolateId
494
+ };
495
+ return sendRequest(state, req);
496
+ },
497
+ async dispatchWebSocketOpen(connectionId) {
498
+ const reqId = state.nextRequestId++;
499
+ const req = {
500
+ type: MessageType.WS_OPEN,
213
501
  requestId: reqId,
214
502
  isolateId,
215
- code,
216
- filename
503
+ connectionId
217
504
  };
218
- const res = await sendRequest(state, req);
219
- return res.value;
505
+ await sendRequest(state, req);
220
506
  },
221
- dispatchRequest: async (request2, dispatchOptions) => {
507
+ async dispatchWebSocketMessage(connectionId, message) {
222
508
  const reqId = state.nextRequestId++;
223
- const serialized = await serializeRequest(request2);
509
+ const data = message instanceof ArrayBuffer ? new Uint8Array(message) : message;
224
510
  const req = {
225
- type: MessageType.DISPATCH_REQUEST,
511
+ type: MessageType.WS_MESSAGE,
512
+ requestId: reqId,
513
+ isolateId,
514
+ connectionId,
515
+ data
516
+ };
517
+ await sendRequest(state, req);
518
+ },
519
+ async dispatchWebSocketClose(connectionId, code, reason) {
520
+ const reqId = state.nextRequestId++;
521
+ const req = {
522
+ type: MessageType.WS_CLOSE,
226
523
  requestId: reqId,
227
524
  isolateId,
228
- request: serialized,
229
- options: dispatchOptions
525
+ connectionId,
526
+ code,
527
+ reason
230
528
  };
231
- const res = await sendRequest(state, req, dispatchOptions?.timeout ?? DEFAULT_TIMEOUT);
232
- return deserializeResponse(res.response);
529
+ await sendRequest(state, req);
233
530
  },
234
- tick: async (ms) => {
531
+ async dispatchWebSocketError(connectionId, error) {
235
532
  const reqId = state.nextRequestId++;
236
533
  const req = {
237
- type: MessageType.TICK,
534
+ type: MessageType.FETCH_WS_ERROR,
238
535
  requestId: reqId,
239
536
  isolateId,
240
- ms
537
+ connectionId,
538
+ error: error.message
241
539
  };
242
540
  await sendRequest(state, req);
243
541
  },
244
- setupTestEnvironment: async () => {
542
+ onWebSocketCommand(callback) {
543
+ wsCommandCallbacks.add(callback);
544
+ return () => {
545
+ wsCommandCallbacks.delete(callback);
546
+ };
547
+ },
548
+ async hasServeHandler() {
549
+ const reqId = state.nextRequestId++;
550
+ const req = {
551
+ type: MessageType.FETCH_HAS_SERVE_HANDLER,
552
+ requestId: reqId,
553
+ isolateId
554
+ };
555
+ return sendRequest(state, req);
556
+ },
557
+ async hasActiveConnections() {
558
+ const reqId = state.nextRequestId++;
559
+ const req = {
560
+ type: MessageType.FETCH_HAS_ACTIVE_CONNECTIONS,
561
+ requestId: reqId,
562
+ isolateId
563
+ };
564
+ return sendRequest(state, req);
565
+ }
566
+ };
567
+ const timersHandle = {
568
+ async clearAll() {
569
+ const reqId = state.nextRequestId++;
570
+ const req = {
571
+ type: MessageType.TIMERS_CLEAR_ALL,
572
+ requestId: reqId,
573
+ isolateId
574
+ };
575
+ await sendRequest(state, req);
576
+ }
577
+ };
578
+ const consoleHandle = {
579
+ async reset() {
245
580
  const reqId = state.nextRequestId++;
246
581
  const req = {
247
- type: MessageType.SETUP_TEST_ENV,
582
+ type: MessageType.CONSOLE_RESET,
248
583
  requestId: reqId,
249
584
  isolateId
250
585
  };
251
586
  await sendRequest(state, req);
252
587
  },
253
- runTests: async (timeout) => {
588
+ async getTimers() {
589
+ const reqId = state.nextRequestId++;
590
+ const req = {
591
+ type: MessageType.CONSOLE_GET_TIMERS,
592
+ requestId: reqId,
593
+ isolateId
594
+ };
595
+ const result2 = await sendRequest(state, req);
596
+ return new Map(Object.entries(result2));
597
+ },
598
+ async getCounters() {
599
+ const reqId = state.nextRequestId++;
600
+ const req = {
601
+ type: MessageType.CONSOLE_GET_COUNTERS,
602
+ requestId: reqId,
603
+ isolateId
604
+ };
605
+ const result2 = await sendRequest(state, req);
606
+ return new Map(Object.entries(result2));
607
+ },
608
+ async getGroupDepth() {
609
+ const reqId = state.nextRequestId++;
610
+ const req = {
611
+ type: MessageType.CONSOLE_GET_GROUP_DEPTH,
612
+ requestId: reqId,
613
+ isolateId
614
+ };
615
+ return sendRequest(state, req);
616
+ }
617
+ };
618
+ const testEnvironmentEnabled = !!options.testEnvironment;
619
+ const playwrightEnabled = !!options.playwright;
620
+ const testEnvironmentHandle = {
621
+ async runTests(timeout) {
622
+ if (!testEnvironmentEnabled) {
623
+ throw new Error("Test environment not enabled. Set testEnvironment: true in createRuntime options.");
624
+ }
254
625
  const reqId = state.nextRequestId++;
255
626
  const req = {
256
627
  type: MessageType.RUN_TESTS,
@@ -260,47 +631,48 @@ async function createRuntime(state, options = {}) {
260
631
  };
261
632
  return sendRequest(state, req, timeout ?? DEFAULT_TIMEOUT);
262
633
  },
263
- setupPlaywright: async (playwrightOptions) => {
634
+ async hasTests() {
635
+ if (!testEnvironmentEnabled) {
636
+ throw new Error("Test environment not enabled. Set testEnvironment: true in createRuntime options.");
637
+ }
264
638
  const reqId = state.nextRequestId++;
265
639
  const req = {
266
- type: MessageType.SETUP_PLAYWRIGHT,
640
+ type: MessageType.HAS_TESTS,
267
641
  requestId: reqId,
268
- isolateId,
269
- options: {
270
- browserType: playwrightOptions?.browserType,
271
- headless: playwrightOptions?.headless,
272
- baseURL: playwrightOptions?.baseURL
273
- }
642
+ isolateId
274
643
  };
275
- if (playwrightOptions?.onConsoleLog || playwrightOptions?.onNetworkRequest || playwrightOptions?.onNetworkResponse) {
276
- state.playwrightEventHandlers.set(isolateId, {
277
- onConsoleLog: playwrightOptions.onConsoleLog,
278
- onNetworkRequest: playwrightOptions.onNetworkRequest,
279
- onNetworkResponse: playwrightOptions.onNetworkResponse
280
- });
281
- }
282
- await sendRequest(state, req);
644
+ return sendRequest(state, req);
283
645
  },
284
- runPlaywrightTests: async (timeout) => {
646
+ async getTestCount() {
647
+ if (!testEnvironmentEnabled) {
648
+ throw new Error("Test environment not enabled. Set testEnvironment: true in createRuntime options.");
649
+ }
285
650
  const reqId = state.nextRequestId++;
286
651
  const req = {
287
- type: MessageType.RUN_PLAYWRIGHT_TESTS,
652
+ type: MessageType.GET_TEST_COUNT,
288
653
  requestId: reqId,
289
- isolateId,
290
- timeout
654
+ isolateId
291
655
  };
292
- return sendRequest(state, req, timeout ?? DEFAULT_TIMEOUT);
656
+ return sendRequest(state, req);
293
657
  },
294
- resetPlaywrightTests: async () => {
658
+ async reset() {
659
+ if (!testEnvironmentEnabled) {
660
+ throw new Error("Test environment not enabled. Set testEnvironment: true in createRuntime options.");
661
+ }
295
662
  const reqId = state.nextRequestId++;
296
663
  const req = {
297
- type: MessageType.RESET_PLAYWRIGHT_TESTS,
664
+ type: MessageType.RESET_TEST_ENV,
298
665
  requestId: reqId,
299
666
  isolateId
300
667
  };
301
668
  await sendRequest(state, req);
302
- },
303
- getCollectedData: async () => {
669
+ }
670
+ };
671
+ const playwrightHandle = {
672
+ async getCollectedData() {
673
+ if (!playwrightEnabled) {
674
+ throw new Error("Playwright not configured. Provide playwright.page in createRuntime options.");
675
+ }
304
676
  const reqId = state.nextRequestId++;
305
677
  const req = {
306
678
  type: MessageType.GET_COLLECTED_DATA,
@@ -309,8 +681,43 @@ async function createRuntime(state, options = {}) {
309
681
  };
310
682
  return sendRequest(state, req);
311
683
  },
684
+ async clearCollectedData() {
685
+ if (!playwrightEnabled) {
686
+ throw new Error("Playwright not configured. Provide playwright.page in createRuntime options.");
687
+ }
688
+ const reqId = state.nextRequestId++;
689
+ const req = {
690
+ type: MessageType.CLEAR_COLLECTED_DATA,
691
+ requestId: reqId,
692
+ isolateId
693
+ };
694
+ await sendRequest(state, req);
695
+ }
696
+ };
697
+ return {
698
+ id: isolateId,
699
+ isolateId,
700
+ fetch: fetchHandle,
701
+ timers: timersHandle,
702
+ console: consoleHandle,
703
+ testEnvironment: testEnvironmentHandle,
704
+ playwright: playwrightHandle,
705
+ eval: async (code, filenameOrOptions) => {
706
+ const reqId = state.nextRequestId++;
707
+ const options2 = typeof filenameOrOptions === "string" ? { filename: filenameOrOptions } : filenameOrOptions;
708
+ const req = {
709
+ type: MessageType.EVAL,
710
+ requestId: reqId,
711
+ isolateId,
712
+ code,
713
+ filename: options2?.filename,
714
+ maxExecutionMs: options2?.maxExecutionMs,
715
+ module: true
716
+ };
717
+ await sendRequest(state, req);
718
+ },
312
719
  dispose: async () => {
313
- state.playwrightEventHandlers.delete(isolateId);
720
+ isolateWsCallbacks.delete(isolateId);
314
721
  const reqId = state.nextRequestId++;
315
722
  const req = {
316
723
  type: MessageType.DISPOSE_RUNTIME,
@@ -321,27 +728,23 @@ async function createRuntime(state, options = {}) {
321
728
  }
322
729
  };
323
730
  }
731
+ function registerEventCallback(state, handler) {
732
+ const callbackId = state.nextCallbackId++;
733
+ state.callbacks.set(callbackId, (data) => {
734
+ handler(data);
735
+ return;
736
+ });
737
+ return callbackId;
738
+ }
324
739
  function registerConsoleCallbacks(state, callbacks) {
325
740
  const registrations = {};
326
- const register = (name, fn) => {
741
+ if (callbacks.onEntry) {
327
742
  const callbackId = state.nextCallbackId++;
328
- state.callbacks.set(callbackId, (_level, ...args) => {
329
- fn(...args);
743
+ state.callbacks.set(callbackId, (entry) => {
744
+ callbacks.onEntry(entry);
330
745
  });
331
- registrations[name] = { callbackId, name, async: false };
332
- };
333
- if (callbacks.log)
334
- register("log", callbacks.log);
335
- if (callbacks.warn)
336
- register("warn", callbacks.warn);
337
- if (callbacks.error)
338
- register("error", callbacks.error);
339
- if (callbacks.info)
340
- register("info", callbacks.info);
341
- if (callbacks.debug)
342
- register("debug", callbacks.debug);
343
- if (callbacks.dir)
344
- register("dir", callbacks.dir);
746
+ registrations.onEntry = { callbackId, name: "onEntry", type: "sync" };
747
+ }
345
748
  return registrations;
346
749
  }
347
750
  function registerFetchCallback(state, callback) {
@@ -351,7 +754,7 @@ function registerFetchCallback(state, callback) {
351
754
  const response = await callback(request);
352
755
  return serializeResponse(response);
353
756
  });
354
- return { callbackId, name: "fetch", async: true };
757
+ return { callbackId, name: "fetch", type: "async" };
355
758
  }
356
759
  function registerFsCallbacks(state, callbacks) {
357
760
  const registrations = {};
@@ -361,7 +764,7 @@ function registerFsCallbacks(state, callbacks) {
361
764
  const result = await callbacks.readFile(path);
362
765
  return new Uint8Array(result);
363
766
  });
364
- registrations.readFile = { callbackId, name: "readFile", async: true };
767
+ registrations.readFile = { callbackId, name: "readFile", type: "async" };
365
768
  }
366
769
  if (callbacks.writeFile) {
367
770
  const callbackId = state.nextCallbackId++;
@@ -378,67 +781,251 @@ function registerFsCallbacks(state, callbacks) {
378
781
  }
379
782
  await callbacks.writeFile(path, buffer);
380
783
  });
381
- registrations.writeFile = { callbackId, name: "writeFile", async: true };
784
+ registrations.writeFile = { callbackId, name: "writeFile", type: "async" };
382
785
  }
383
786
  if (callbacks.unlink) {
384
787
  const callbackId = state.nextCallbackId++;
385
788
  state.callbacks.set(callbackId, async (path) => {
386
789
  await callbacks.unlink(path);
387
790
  });
388
- registrations.unlink = { callbackId, name: "unlink", async: true };
791
+ registrations.unlink = { callbackId, name: "unlink", type: "async" };
389
792
  }
390
793
  if (callbacks.readdir) {
391
794
  const callbackId = state.nextCallbackId++;
392
795
  state.callbacks.set(callbackId, async (path) => {
393
796
  return callbacks.readdir(path);
394
797
  });
395
- registrations.readdir = { callbackId, name: "readdir", async: true };
798
+ registrations.readdir = { callbackId, name: "readdir", type: "async" };
396
799
  }
397
800
  if (callbacks.mkdir) {
398
801
  const callbackId = state.nextCallbackId++;
399
802
  state.callbacks.set(callbackId, async (path, options) => {
400
803
  await callbacks.mkdir(path, options);
401
804
  });
402
- registrations.mkdir = { callbackId, name: "mkdir", async: true };
805
+ registrations.mkdir = { callbackId, name: "mkdir", type: "async" };
403
806
  }
404
807
  if (callbacks.rmdir) {
405
808
  const callbackId = state.nextCallbackId++;
406
809
  state.callbacks.set(callbackId, async (path) => {
407
810
  await callbacks.rmdir(path);
408
811
  });
409
- registrations.rmdir = { callbackId, name: "rmdir", async: true };
812
+ registrations.rmdir = { callbackId, name: "rmdir", type: "async" };
410
813
  }
411
814
  if (callbacks.stat) {
412
815
  const callbackId = state.nextCallbackId++;
413
816
  state.callbacks.set(callbackId, async (path) => {
414
817
  return callbacks.stat(path);
415
818
  });
416
- registrations.stat = { callbackId, name: "stat", async: true };
819
+ registrations.stat = { callbackId, name: "stat", type: "async" };
417
820
  }
418
821
  if (callbacks.rename) {
419
822
  const callbackId = state.nextCallbackId++;
420
823
  state.callbacks.set(callbackId, async (from, to) => {
421
824
  await callbacks.rename(from, to);
422
825
  });
423
- registrations.rename = { callbackId, name: "rename", async: true };
826
+ registrations.rename = { callbackId, name: "rename", type: "async" };
424
827
  }
425
828
  return registrations;
426
829
  }
427
- async function serializeRequest(request) {
428
- const headers = [];
429
- request.headers.forEach((value, key) => {
430
- headers.push([key, value]);
830
+ function registerModuleLoaderCallback(state, callback) {
831
+ const callbackId = state.nextCallbackId++;
832
+ state.callbacks.set(callbackId, async (moduleName) => {
833
+ return callback(moduleName);
431
834
  });
432
- let body = null;
433
- if (request.body) {
434
- body = new Uint8Array(await request.arrayBuffer());
835
+ return { callbackId, name: "moduleLoader", type: "async" };
836
+ }
837
+ var clientIteratorSessions = new Map;
838
+ var nextClientIteratorId = 1;
839
+ var returnedPromiseRegistry = new Map;
840
+ var returnedIteratorRegistry = new Map;
841
+ function isPromiseRef(value) {
842
+ return typeof value === "object" && value !== null && value.__type === "PromiseRef";
843
+ }
844
+ function isAsyncIteratorRef(value) {
845
+ return typeof value === "object" && value !== null && value.__type === "AsyncIteratorRef";
846
+ }
847
+ function registerCustomFunctions(state, customFunctions) {
848
+ const registrations = {};
849
+ for (const [name, def] of Object.entries(customFunctions)) {
850
+ if (def.type === "asyncIterator") {
851
+ const startCallbackId = state.nextCallbackId++;
852
+ state.callbacks.set(startCallbackId, async (...args) => {
853
+ try {
854
+ const fn = def.fn;
855
+ const iterator = fn(...args);
856
+ const iteratorId = nextClientIteratorId++;
857
+ clientIteratorSessions.set(iteratorId, { iterator });
858
+ return { iteratorId };
859
+ } catch (error) {
860
+ throw error;
861
+ }
862
+ });
863
+ const nextCallbackId = state.nextCallbackId++;
864
+ state.callbacks.set(nextCallbackId, async (iteratorId) => {
865
+ const session = clientIteratorSessions.get(iteratorId);
866
+ if (!session) {
867
+ throw new Error(`Iterator session ${iteratorId} not found`);
868
+ }
869
+ try {
870
+ const result = await session.iterator.next();
871
+ if (result.done) {
872
+ clientIteratorSessions.delete(iteratorId);
873
+ }
874
+ return { done: result.done, value: await marshalValue(result.value) };
875
+ } catch (error) {
876
+ clientIteratorSessions.delete(iteratorId);
877
+ throw error;
878
+ }
879
+ });
880
+ const returnCallbackId = state.nextCallbackId++;
881
+ state.callbacks.set(returnCallbackId, async (iteratorId, value) => {
882
+ const session = clientIteratorSessions.get(iteratorId);
883
+ if (!session) {
884
+ return { done: true, value: await marshalValue(undefined) };
885
+ }
886
+ try {
887
+ const result = await session.iterator.return?.(value);
888
+ clientIteratorSessions.delete(iteratorId);
889
+ return { done: true, value: await marshalValue(result?.value) };
890
+ } catch (error) {
891
+ clientIteratorSessions.delete(iteratorId);
892
+ throw error;
893
+ }
894
+ });
895
+ const throwCallbackId = state.nextCallbackId++;
896
+ state.callbacks.set(throwCallbackId, async (iteratorId, errorData) => {
897
+ const session = clientIteratorSessions.get(iteratorId);
898
+ if (!session) {
899
+ throw new Error(`Iterator session ${iteratorId} not found`);
900
+ }
901
+ try {
902
+ const errInfo = errorData;
903
+ const error = Object.assign(new Error(errInfo.message), { name: errInfo.name });
904
+ const result = await session.iterator.throw?.(error);
905
+ clientIteratorSessions.delete(iteratorId);
906
+ return { done: result?.done ?? true, value: await marshalValue(result?.value) };
907
+ } catch (error) {
908
+ clientIteratorSessions.delete(iteratorId);
909
+ throw error;
910
+ }
911
+ });
912
+ registrations[`${name}:start`] = { callbackId: startCallbackId, name: `${name}:start`, type: "async" };
913
+ registrations[`${name}:next`] = { callbackId: nextCallbackId, name: `${name}:next`, type: "async" };
914
+ registrations[`${name}:return`] = { callbackId: returnCallbackId, name: `${name}:return`, type: "async" };
915
+ registrations[`${name}:throw`] = { callbackId: throwCallbackId, name: `${name}:throw`, type: "async" };
916
+ registrations[name] = {
917
+ callbackId: startCallbackId,
918
+ name,
919
+ type: "asyncIterator"
920
+ };
921
+ } else {
922
+ const callbackId = state.nextCallbackId++;
923
+ state.callbacks.set(callbackId, async (...args) => {
924
+ const result = await def.fn(...args);
925
+ const addCallbackIdsToRefs = (value) => {
926
+ if (value === null || typeof value !== "object") {
927
+ return value;
928
+ }
929
+ if (isPromiseRef(value)) {
930
+ const resolveCallbackId = state.nextCallbackId++;
931
+ state.callbacks.set(resolveCallbackId, async (...args2) => {
932
+ const promiseId = args2[0];
933
+ const promise = returnedPromiseRegistry.get(promiseId);
934
+ if (!promise) {
935
+ throw new Error(`Promise ${promiseId} not found`);
936
+ }
937
+ const promiseResult = await promise;
938
+ returnedPromiseRegistry.delete(promiseId);
939
+ const marshalledResult = await marshalValue(promiseResult, marshalCtx);
940
+ return addCallbackIdsToRefs(marshalledResult);
941
+ });
942
+ return {
943
+ ...value,
944
+ __resolveCallbackId: resolveCallbackId
945
+ };
946
+ }
947
+ if (isAsyncIteratorRef(value)) {
948
+ const nextCallbackId = state.nextCallbackId++;
949
+ state.callbacks.set(nextCallbackId, async (...args2) => {
950
+ const iteratorId = args2[0];
951
+ const iterator = returnedIteratorRegistry.get(iteratorId);
952
+ if (!iterator) {
953
+ throw new Error(`Iterator ${iteratorId} not found`);
954
+ }
955
+ const iterResult = await iterator.next();
956
+ if (iterResult.done) {
957
+ returnedIteratorRegistry.delete(iteratorId);
958
+ }
959
+ const marshalledValue = await marshalValue(iterResult.value, marshalCtx);
960
+ return {
961
+ done: iterResult.done,
962
+ value: addCallbackIdsToRefs(marshalledValue)
963
+ };
964
+ });
965
+ const returnCallbackId = state.nextCallbackId++;
966
+ state.callbacks.set(returnCallbackId, async (...args2) => {
967
+ const iteratorId = args2[0];
968
+ const returnValue = args2[1];
969
+ const iterator = returnedIteratorRegistry.get(iteratorId);
970
+ returnedIteratorRegistry.delete(iteratorId);
971
+ if (!iterator || !iterator.return) {
972
+ return { done: true, value: undefined };
973
+ }
974
+ const iterResult = await iterator.return(returnValue);
975
+ const marshalledValue = await marshalValue(iterResult.value, marshalCtx);
976
+ return {
977
+ done: true,
978
+ value: addCallbackIdsToRefs(marshalledValue)
979
+ };
980
+ });
981
+ return {
982
+ ...value,
983
+ __nextCallbackId: nextCallbackId,
984
+ __returnCallbackId: returnCallbackId
985
+ };
986
+ }
987
+ if (Array.isArray(value)) {
988
+ return value.map((item) => addCallbackIdsToRefs(item));
989
+ }
990
+ const objResult = {};
991
+ for (const key of Object.keys(value)) {
992
+ objResult[key] = addCallbackIdsToRefs(value[key]);
993
+ }
994
+ return objResult;
995
+ };
996
+ const marshalCtx = {
997
+ registerCallback: (fn) => {
998
+ const returnedCallbackId = state.nextCallbackId++;
999
+ state.callbacks.set(returnedCallbackId, async (...args2) => {
1000
+ const fnResult = await fn(...args2);
1001
+ const marshalledResult = await marshalValue(fnResult, marshalCtx);
1002
+ return addCallbackIdsToRefs(marshalledResult);
1003
+ });
1004
+ return returnedCallbackId;
1005
+ },
1006
+ registerPromise: (promise) => {
1007
+ const promiseId = state.nextCallbackId++;
1008
+ returnedPromiseRegistry.set(promiseId, promise);
1009
+ return promiseId;
1010
+ },
1011
+ registerIterator: (iterator) => {
1012
+ const iteratorId = state.nextCallbackId++;
1013
+ returnedIteratorRegistry.set(iteratorId, iterator);
1014
+ return iteratorId;
1015
+ }
1016
+ };
1017
+ const marshalled = await marshalValue(result, marshalCtx);
1018
+ const withCallbackIds = addCallbackIdsToRefs(marshalled);
1019
+ return withCallbackIds;
1020
+ });
1021
+ registrations[name] = {
1022
+ callbackId,
1023
+ name,
1024
+ type: def.type
1025
+ };
1026
+ }
435
1027
  }
436
- return {
437
- method: request.method,
438
- url: request.url,
439
- headers,
440
- body
441
- };
1028
+ return registrations;
442
1029
  }
443
1030
  async function serializeResponse(response) {
444
1031
  const headers = [];
@@ -470,8 +1057,106 @@ function deserializeResponse(data) {
470
1057
  headers: data.headers
471
1058
  });
472
1059
  }
1060
+ async function serializeRequestWithStreaming(state, request) {
1061
+ const headers = [];
1062
+ request.headers.forEach((value, key) => {
1063
+ headers.push([key, value]);
1064
+ });
1065
+ let body = null;
1066
+ let bodyStreamId;
1067
+ let bodyStream;
1068
+ if (request.body) {
1069
+ const contentLength = request.headers.get("content-length");
1070
+ const knownSize = contentLength ? parseInt(contentLength, 10) : null;
1071
+ if (knownSize !== null && knownSize > STREAM_THRESHOLD) {
1072
+ bodyStreamId = state.nextStreamId++;
1073
+ bodyStream = request.body;
1074
+ } else {
1075
+ const clonedRequest = request.clone();
1076
+ try {
1077
+ body = new Uint8Array(await request.arrayBuffer());
1078
+ if (body.length > STREAM_THRESHOLD) {
1079
+ bodyStreamId = state.nextStreamId++;
1080
+ bodyStream = clonedRequest.body;
1081
+ body = null;
1082
+ }
1083
+ } catch {
1084
+ bodyStreamId = state.nextStreamId++;
1085
+ bodyStream = clonedRequest.body;
1086
+ }
1087
+ }
1088
+ }
1089
+ const result = {
1090
+ method: request.method,
1091
+ url: request.url,
1092
+ headers,
1093
+ body
1094
+ };
1095
+ if (bodyStreamId !== undefined) {
1096
+ result.bodyStreamId = bodyStreamId;
1097
+ result.bodyStream = bodyStream;
1098
+ }
1099
+ return result;
1100
+ }
1101
+ function waitForUploadCredit(session) {
1102
+ return new Promise((resolve) => {
1103
+ session.creditResolver = resolve;
1104
+ });
1105
+ }
1106
+ async function sendBodyStream(state, streamId, body) {
1107
+ const session = {
1108
+ streamId,
1109
+ requestId: 0,
1110
+ state: "active",
1111
+ bytesTransferred: 0,
1112
+ credit: 0
1113
+ };
1114
+ state.uploadStreams.set(streamId, session);
1115
+ const reader = body.getReader();
1116
+ try {
1117
+ while (true) {
1118
+ if (session.state !== "active") {
1119
+ throw new Error("Stream cancelled");
1120
+ }
1121
+ while (session.credit < STREAM_CHUNK_SIZE && session.state === "active") {
1122
+ await waitForUploadCredit(session);
1123
+ }
1124
+ if (session.state !== "active") {
1125
+ throw new Error("Stream cancelled");
1126
+ }
1127
+ const { done, value } = await reader.read();
1128
+ if (done) {
1129
+ sendMessage(state.socket, {
1130
+ type: MessageType.STREAM_CLOSE,
1131
+ streamId
1132
+ });
1133
+ break;
1134
+ }
1135
+ for (let offset = 0;offset < value.length; offset += STREAM_CHUNK_SIZE) {
1136
+ const chunk = value.slice(offset, offset + STREAM_CHUNK_SIZE);
1137
+ sendMessage(state.socket, {
1138
+ type: MessageType.STREAM_PUSH,
1139
+ streamId,
1140
+ chunk
1141
+ });
1142
+ session.credit -= chunk.length;
1143
+ session.bytesTransferred += chunk.length;
1144
+ }
1145
+ }
1146
+ } catch (err) {
1147
+ sendMessage(state.socket, {
1148
+ type: MessageType.STREAM_ERROR,
1149
+ streamId,
1150
+ error: err.message
1151
+ });
1152
+ throw err;
1153
+ } finally {
1154
+ reader.releaseLock();
1155
+ state.uploadStreams.delete(streamId);
1156
+ }
1157
+ }
473
1158
  export {
474
1159
  connect
475
1160
  };
476
1161
 
477
- //# debugId=944ECBC62DEB63FB64756E2164756E21
1162
+ //# debugId=2BAB1C12EE66984164756E2164756E21