@ricsam/isolate-client 0.1.0 → 0.1.4

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