@ricsam/isolate-client 0.1.9 → 0.1.11

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.
package/README.md CHANGED
@@ -85,7 +85,10 @@ const namespace = client.createNamespace("tenant-123");
85
85
  // Create a runtime in this namespace
86
86
  const runtime = await namespace.createRuntime({
87
87
  memoryLimitMB: 128,
88
- moduleLoader: async (name) => loadModule(name),
88
+ moduleLoader: async (name, importer) => {
89
+ const code = loadModule(name);
90
+ return { code, resolveDir: importer.resolveDir };
91
+ },
89
92
  });
90
93
 
91
94
  console.log(runtime.reused); // false - first time
@@ -145,21 +148,29 @@ interface Namespace {
145
148
 
146
149
  ## Module Loader
147
150
 
148
- Register a custom module loader to handle dynamic `import()` calls:
151
+ Register a custom module loader to handle dynamic `import()` calls. The loader receives the module specifier and importer info, and returns an object with the source code and `resolveDir` (used to resolve nested relative imports):
149
152
 
150
153
  ```typescript
151
154
  const runtime = await client.createRuntime({
152
- moduleLoader: async (moduleName: string) => {
155
+ moduleLoader: async (moduleName: string, importer) => {
156
+ // importer.path = resolved path of importing module
157
+ // importer.resolveDir = directory for relative resolution
153
158
  if (moduleName === "@/db") {
154
- return `
155
- export async function getUser(id) {
156
- const response = await fetch("/api/users/" + id);
157
- return response.json();
158
- }
159
- `;
159
+ return {
160
+ code: `
161
+ export async function getUser(id) {
162
+ const response = await fetch("/api/users/" + id);
163
+ return response.json();
164
+ }
165
+ `,
166
+ resolveDir: "/modules",
167
+ };
160
168
  }
161
169
  if (moduleName === "@/config") {
162
- return `export const API_KEY = "sk-xxx";`;
170
+ return {
171
+ code: `export const API_KEY = "sk-xxx";`,
172
+ resolveDir: "/modules",
173
+ };
163
174
  }
164
175
  throw new Error(`Unknown module: ${moduleName}`);
165
176
  },
@@ -1,7 +1,20 @@
1
+ var __create = Object.create;
2
+ var __getProtoOf = Object.getPrototypeOf;
1
3
  var __defProp = Object.defineProperty;
2
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
3
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
5
18
  var __moduleCache = /* @__PURE__ */ new WeakMap;
6
19
  var __toCommonJS = (from) => {
7
20
  var entry = __moduleCache.get(from), desc;
@@ -33,6 +46,7 @@ __export(exports_connection, {
33
46
  });
34
47
  module.exports = __toCommonJS(exports_connection);
35
48
  var import_node_net = require("node:net");
49
+ var import_node_path = __toESM(require("node:path"));
36
50
  var import_isolate_protocol = require("@ricsam/isolate-protocol");
37
51
  var import_client = require("@ricsam/isolate-playwright/client");
38
52
  var DEFAULT_TIMEOUT = 30000;
@@ -421,6 +435,10 @@ async function createRuntime(state, options = {}, namespaceId) {
421
435
  callbacks.custom = registerCustomFunctions(state, options.customFunctions);
422
436
  }
423
437
  let playwrightHandler;
438
+ const browserConsoleLogs = [];
439
+ const networkRequests = [];
440
+ const networkResponses = [];
441
+ const pageListenerCleanups = [];
424
442
  if (options.playwright) {
425
443
  playwrightHandler = import_client.createPlaywrightHandler(options.playwright.page, {
426
444
  timeout: options.playwright.timeout,
@@ -432,65 +450,67 @@ async function createRuntime(state, options = {}, namespaceId) {
432
450
  const result2 = await playwrightHandler(op);
433
451
  return JSON.stringify(result2);
434
452
  });
435
- const hasOnEvent = !!options.playwright.onEvent;
436
- const hasConsoleHandler = options.playwright.console && options.console?.onEntry;
437
- let browserConsoleLogCallbackId;
438
- if (hasOnEvent || hasConsoleHandler) {
439
- browserConsoleLogCallbackId = registerEventCallback(state, (entry) => {
440
- const browserEntry = entry;
441
- if (options.playwright.onEvent) {
442
- options.playwright.onEvent({
443
- type: "browserConsoleLog",
444
- level: browserEntry.level,
445
- stdout: browserEntry.stdout,
446
- timestamp: browserEntry.timestamp
447
- });
448
- }
449
- if (options.playwright.console && options.console?.onEntry) {
450
- options.console.onEntry({
451
- type: "browserOutput",
452
- level: browserEntry.level,
453
- stdout: browserEntry.stdout,
454
- timestamp: browserEntry.timestamp
455
- });
456
- }
457
- });
458
- }
459
- let networkRequestCallbackId;
460
- if (hasOnEvent) {
461
- networkRequestCallbackId = registerEventCallback(state, (info) => {
462
- const reqInfo = info;
453
+ const page = options.playwright.page;
454
+ const onConsole = (msg) => {
455
+ const entry = {
456
+ level: msg.type(),
457
+ stdout: msg.text(),
458
+ timestamp: Date.now()
459
+ };
460
+ browserConsoleLogs.push(entry);
461
+ if (options.playwright.onEvent) {
462
+ options.playwright.onEvent({
463
+ type: "browserConsoleLog",
464
+ ...entry
465
+ });
466
+ }
467
+ if (options.playwright.console && options.console?.onEntry) {
468
+ options.console.onEntry({
469
+ type: "browserOutput",
470
+ ...entry
471
+ });
472
+ } else if (options.playwright.console) {
473
+ const prefix = entry.level === "error" ? "[browser:error]" : "[browser]";
474
+ console.log(prefix, entry.stdout);
475
+ }
476
+ };
477
+ const onRequest = (request2) => {
478
+ const info = {
479
+ url: request2.url(),
480
+ method: request2.method(),
481
+ headers: request2.headers(),
482
+ timestamp: Date.now()
483
+ };
484
+ networkRequests.push(info);
485
+ if (options.playwright.onEvent) {
463
486
  options.playwright.onEvent({
464
487
  type: "networkRequest",
465
- url: reqInfo.url,
466
- method: reqInfo.method,
467
- headers: reqInfo.headers,
468
- postData: reqInfo.postData,
469
- resourceType: reqInfo.resourceType,
470
- timestamp: reqInfo.timestamp
488
+ ...info
471
489
  });
472
- });
473
- }
474
- let networkResponseCallbackId;
475
- if (hasOnEvent) {
476
- networkResponseCallbackId = registerEventCallback(state, (info) => {
477
- const resInfo = info;
490
+ }
491
+ };
492
+ const onResponse = (response) => {
493
+ const info = {
494
+ url: response.url(),
495
+ status: response.status(),
496
+ headers: response.headers(),
497
+ timestamp: Date.now()
498
+ };
499
+ networkResponses.push(info);
500
+ if (options.playwright.onEvent) {
478
501
  options.playwright.onEvent({
479
502
  type: "networkResponse",
480
- url: resInfo.url,
481
- status: resInfo.status,
482
- statusText: resInfo.statusText,
483
- headers: resInfo.headers,
484
- timestamp: resInfo.timestamp
503
+ ...info
485
504
  });
486
- });
487
- }
505
+ }
506
+ };
507
+ page.on("console", onConsole);
508
+ page.on("request", onRequest);
509
+ page.on("response", onResponse);
510
+ pageListenerCleanups.push(() => page.removeListener("console", onConsole), () => page.removeListener("request", onRequest), () => page.removeListener("response", onResponse));
488
511
  callbacks.playwright = {
489
512
  handlerCallbackId,
490
- console: options.playwright.console && !options.console?.onEntry,
491
- onBrowserConsoleLogCallbackId: browserConsoleLogCallbackId,
492
- onNetworkRequestCallbackId: networkRequestCallbackId,
493
- onNetworkResponseCallbackId: networkResponseCallbackId
513
+ console: options.playwright.console && !options.console?.onEntry
494
514
  };
495
515
  }
496
516
  let testEnvironmentOption;
@@ -748,29 +768,23 @@ async function createRuntime(state, options = {}, namespaceId) {
748
768
  }
749
769
  };
750
770
  const playwrightHandle = {
751
- async getCollectedData() {
771
+ getCollectedData() {
752
772
  if (!playwrightEnabled) {
753
773
  throw new Error("Playwright not configured. Provide playwright.page in createRuntime options.");
754
774
  }
755
- const reqId = state.nextRequestId++;
756
- const req = {
757
- type: import_isolate_protocol.MessageType.GET_COLLECTED_DATA,
758
- requestId: reqId,
759
- isolateId
775
+ return {
776
+ browserConsoleLogs: [...browserConsoleLogs],
777
+ networkRequests: [...networkRequests],
778
+ networkResponses: [...networkResponses]
760
779
  };
761
- return sendRequest(state, req);
762
780
  },
763
- async clearCollectedData() {
781
+ clearCollectedData() {
764
782
  if (!playwrightEnabled) {
765
783
  throw new Error("Playwright not configured. Provide playwright.page in createRuntime options.");
766
784
  }
767
- const reqId = state.nextRequestId++;
768
- const req = {
769
- type: import_isolate_protocol.MessageType.CLEAR_COLLECTED_DATA,
770
- requestId: reqId,
771
- isolateId
772
- };
773
- await sendRequest(state, req);
785
+ browserConsoleLogs.length = 0;
786
+ networkRequests.length = 0;
787
+ networkResponses.length = 0;
774
788
  }
775
789
  };
776
790
  return {
@@ -797,6 +811,9 @@ async function createRuntime(state, options = {}, namespaceId) {
797
811
  await sendRequest(state, req);
798
812
  },
799
813
  dispose: async () => {
814
+ for (const cleanup of pageListenerCleanups) {
815
+ cleanup();
816
+ }
800
817
  isolateWsCallbacks.delete(isolateId);
801
818
  const reqId = state.nextRequestId++;
802
819
  const req = {
@@ -899,15 +916,15 @@ function registerFsCallbacks(state, callbacks) {
899
916
  const registrations = {};
900
917
  if (callbacks.readFile) {
901
918
  const callbackId = state.nextCallbackId++;
902
- state.callbacks.set(callbackId, async (path) => {
903
- const result = await callbacks.readFile(path);
919
+ state.callbacks.set(callbackId, async (path2) => {
920
+ const result = await callbacks.readFile(path2);
904
921
  return new Uint8Array(result);
905
922
  });
906
923
  registrations.readFile = { callbackId, name: "readFile", type: "async" };
907
924
  }
908
925
  if (callbacks.writeFile) {
909
926
  const callbackId = state.nextCallbackId++;
910
- state.callbacks.set(callbackId, async (path, data) => {
927
+ state.callbacks.set(callbackId, async (path2, data) => {
911
928
  let buffer;
912
929
  if (data instanceof Uint8Array) {
913
930
  buffer = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
@@ -918,42 +935,42 @@ function registerFsCallbacks(state, callbacks) {
918
935
  } else {
919
936
  buffer = new ArrayBuffer(0);
920
937
  }
921
- await callbacks.writeFile(path, buffer);
938
+ await callbacks.writeFile(path2, buffer);
922
939
  });
923
940
  registrations.writeFile = { callbackId, name: "writeFile", type: "async" };
924
941
  }
925
942
  if (callbacks.unlink) {
926
943
  const callbackId = state.nextCallbackId++;
927
- state.callbacks.set(callbackId, async (path) => {
928
- await callbacks.unlink(path);
944
+ state.callbacks.set(callbackId, async (path2) => {
945
+ await callbacks.unlink(path2);
929
946
  });
930
947
  registrations.unlink = { callbackId, name: "unlink", type: "async" };
931
948
  }
932
949
  if (callbacks.readdir) {
933
950
  const callbackId = state.nextCallbackId++;
934
- state.callbacks.set(callbackId, async (path) => {
935
- return callbacks.readdir(path);
951
+ state.callbacks.set(callbackId, async (path2) => {
952
+ return callbacks.readdir(path2);
936
953
  });
937
954
  registrations.readdir = { callbackId, name: "readdir", type: "async" };
938
955
  }
939
956
  if (callbacks.mkdir) {
940
957
  const callbackId = state.nextCallbackId++;
941
- state.callbacks.set(callbackId, async (path, options) => {
942
- await callbacks.mkdir(path, options);
958
+ state.callbacks.set(callbackId, async (path2, options) => {
959
+ await callbacks.mkdir(path2, options);
943
960
  });
944
961
  registrations.mkdir = { callbackId, name: "mkdir", type: "async" };
945
962
  }
946
963
  if (callbacks.rmdir) {
947
964
  const callbackId = state.nextCallbackId++;
948
- state.callbacks.set(callbackId, async (path) => {
949
- await callbacks.rmdir(path);
965
+ state.callbacks.set(callbackId, async (path2) => {
966
+ await callbacks.rmdir(path2);
950
967
  });
951
968
  registrations.rmdir = { callbackId, name: "rmdir", type: "async" };
952
969
  }
953
970
  if (callbacks.stat) {
954
971
  const callbackId = state.nextCallbackId++;
955
- state.callbacks.set(callbackId, async (path) => {
956
- return callbacks.stat(path);
972
+ state.callbacks.set(callbackId, async (path2) => {
973
+ return callbacks.stat(path2);
957
974
  });
958
975
  registrations.stat = { callbackId, name: "stat", type: "async" };
959
976
  }
@@ -968,15 +985,13 @@ function registerFsCallbacks(state, callbacks) {
968
985
  }
969
986
  function registerModuleLoaderCallback(state, callback) {
970
987
  const callbackId = state.nextCallbackId++;
971
- state.callbacks.set(callbackId, async (moduleName) => {
988
+ state.callbacks.set(callbackId, async (moduleName, importer) => {
972
989
  const specifier = moduleName;
973
- const cached = state.moduleSourceCache.get(specifier);
974
- if (cached !== undefined) {
975
- return cached;
976
- }
977
- const source = await callback(specifier);
978
- state.moduleSourceCache.set(specifier, source);
979
- return source;
990
+ const importerInfo = importer;
991
+ const result = await callback(specifier, importerInfo);
992
+ const resolvedPath = import_node_path.default.posix.join(result.resolveDir, import_node_path.default.posix.basename(specifier));
993
+ state.moduleSourceCache.set(resolvedPath, result.code);
994
+ return result;
980
995
  });
981
996
  return { callbackId, name: "moduleLoader", type: "async" };
982
997
  }
@@ -1302,4 +1317,4 @@ async function sendBodyStream(state, streamId, body) {
1302
1317
  }
1303
1318
  }
1304
1319
 
1305
- //# debugId=88982DC84A5B7DE464756E2164756E21
1320
+ //# debugId=F22B720CD1D2496764756E2164756E21