@ricsam/isolate 0.1.10 → 0.1.12

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.
Files changed (140) hide show
  1. package/README.md +257 -18
  2. package/dist/cjs/bridge/diagnostics.cjs +37 -2
  3. package/dist/cjs/bridge/diagnostics.cjs.map +3 -3
  4. package/dist/cjs/bridge/runtime-bindings.cjs +230 -51
  5. package/dist/cjs/bridge/runtime-bindings.cjs.map +3 -3
  6. package/dist/cjs/bridge/sandbox-isolate.cjs +464 -0
  7. package/dist/cjs/bridge/sandbox-isolate.cjs.map +10 -0
  8. package/dist/cjs/host/create-isolate-host.cjs +130 -25
  9. package/dist/cjs/host/create-isolate-host.cjs.map +3 -3
  10. package/dist/cjs/host/nested-host-controller.cjs +369 -0
  11. package/dist/cjs/host/nested-host-controller.cjs.map +10 -0
  12. package/dist/cjs/index.cjs.map +1 -1
  13. package/dist/cjs/internal/browser-source.cjs +102 -0
  14. package/dist/cjs/internal/browser-source.cjs.map +10 -0
  15. package/dist/cjs/internal/client/connection.cjs +163 -172
  16. package/dist/cjs/internal/client/connection.cjs.map +3 -3
  17. package/dist/cjs/internal/daemon/callback-fs-handler.cjs +3 -3
  18. package/dist/cjs/internal/daemon/callback-fs-handler.cjs.map +3 -3
  19. package/dist/cjs/internal/daemon/connection.cjs +156 -13
  20. package/dist/cjs/internal/daemon/connection.cjs.map +3 -3
  21. package/dist/cjs/internal/playwright/client.cjs +4 -2
  22. package/dist/cjs/internal/playwright/client.cjs.map +3 -3
  23. package/dist/cjs/internal/playwright/handler.cjs +298 -25
  24. package/dist/cjs/internal/playwright/handler.cjs.map +3 -3
  25. package/dist/cjs/internal/playwright/index.cjs +54 -8
  26. package/dist/cjs/internal/playwright/index.cjs.map +3 -3
  27. package/dist/cjs/internal/playwright/types.cjs +3 -1
  28. package/dist/cjs/internal/playwright/types.cjs.map +3 -3
  29. package/dist/cjs/internal/protocol/codec.cjs +16 -5
  30. package/dist/cjs/internal/protocol/codec.cjs.map +3 -3
  31. package/dist/cjs/internal/protocol/marshalValue.cjs +37 -6
  32. package/dist/cjs/internal/protocol/marshalValue.cjs.map +3 -3
  33. package/dist/cjs/internal/protocol/types.cjs +2 -1
  34. package/dist/cjs/internal/protocol/types.cjs.map +3 -3
  35. package/dist/cjs/internal/runtime/index.cjs +377 -22
  36. package/dist/cjs/internal/runtime/index.cjs.map +3 -3
  37. package/dist/cjs/internal/typecheck/index.cjs +2 -1
  38. package/dist/cjs/internal/typecheck/index.cjs.map +3 -3
  39. package/dist/cjs/internal/typecheck/isolate-types.cjs +218 -13
  40. package/dist/cjs/internal/typecheck/isolate-types.cjs.map +3 -3
  41. package/dist/cjs/internal/typecheck/typecheck.cjs +2 -3
  42. package/dist/cjs/internal/typecheck/typecheck.cjs.map +3 -3
  43. package/dist/cjs/package.json +1 -1
  44. package/dist/cjs/playwright.cjs +76 -0
  45. package/dist/cjs/playwright.cjs.map +10 -0
  46. package/dist/cjs/runtime/namespaced-runtime.cjs +181 -0
  47. package/dist/cjs/runtime/namespaced-runtime.cjs.map +10 -0
  48. package/dist/cjs/runtime/script-runtime.cjs +14 -12
  49. package/dist/cjs/runtime/script-runtime.cjs.map +3 -3
  50. package/dist/cjs/runtime/test-runtime.cjs +113 -0
  51. package/dist/cjs/runtime/test-runtime.cjs.map +10 -0
  52. package/dist/cjs/server/app-server.cjs +16 -9
  53. package/dist/cjs/server/app-server.cjs.map +3 -3
  54. package/dist/cjs/typecheck/index.cjs +2 -1
  55. package/dist/cjs/typecheck/index.cjs.map +3 -3
  56. package/dist/mjs/bridge/diagnostics.mjs +37 -2
  57. package/dist/mjs/bridge/diagnostics.mjs.map +3 -3
  58. package/dist/mjs/bridge/runtime-bindings.mjs +233 -51
  59. package/dist/mjs/bridge/runtime-bindings.mjs.map +3 -3
  60. package/dist/mjs/bridge/sandbox-isolate.mjs +424 -0
  61. package/dist/mjs/bridge/sandbox-isolate.mjs.map +10 -0
  62. package/dist/mjs/host/create-isolate-host.mjs +132 -25
  63. package/dist/mjs/host/create-isolate-host.mjs.map +3 -3
  64. package/dist/mjs/host/nested-host-controller.mjs +333 -0
  65. package/dist/mjs/host/nested-host-controller.mjs.map +10 -0
  66. package/dist/mjs/index.mjs.map +1 -1
  67. package/dist/mjs/internal/browser-source.mjs +62 -0
  68. package/dist/mjs/internal/browser-source.mjs.map +10 -0
  69. package/dist/mjs/internal/client/connection.mjs +165 -173
  70. package/dist/mjs/internal/client/connection.mjs.map +3 -3
  71. package/dist/mjs/internal/daemon/callback-fs-handler.mjs +3 -3
  72. package/dist/mjs/internal/daemon/callback-fs-handler.mjs.map +3 -3
  73. package/dist/mjs/internal/daemon/connection.mjs +156 -13
  74. package/dist/mjs/internal/daemon/connection.mjs.map +3 -3
  75. package/dist/mjs/internal/playwright/client.mjs +7 -3
  76. package/dist/mjs/internal/playwright/client.mjs.map +3 -3
  77. package/dist/mjs/internal/playwright/handler.mjs +300 -26
  78. package/dist/mjs/internal/playwright/handler.mjs.map +3 -3
  79. package/dist/mjs/internal/playwright/index.mjs +59 -9
  80. package/dist/mjs/internal/playwright/index.mjs.map +3 -3
  81. package/dist/mjs/internal/playwright/types.mjs +3 -1
  82. package/dist/mjs/internal/playwright/types.mjs.map +3 -3
  83. package/dist/mjs/internal/protocol/codec.mjs +16 -5
  84. package/dist/mjs/internal/protocol/codec.mjs.map +3 -3
  85. package/dist/mjs/internal/protocol/marshalValue.mjs +38 -6
  86. package/dist/mjs/internal/protocol/marshalValue.mjs.map +3 -3
  87. package/dist/mjs/internal/protocol/types.mjs +2 -1
  88. package/dist/mjs/internal/protocol/types.mjs.map +3 -3
  89. package/dist/mjs/internal/runtime/index.mjs +377 -22
  90. package/dist/mjs/internal/runtime/index.mjs.map +3 -3
  91. package/dist/mjs/internal/typecheck/index.mjs +3 -1
  92. package/dist/mjs/internal/typecheck/index.mjs.map +3 -3
  93. package/dist/mjs/internal/typecheck/isolate-types.mjs +218 -13
  94. package/dist/mjs/internal/typecheck/isolate-types.mjs.map +3 -3
  95. package/dist/mjs/internal/typecheck/typecheck.mjs +2 -3
  96. package/dist/mjs/internal/typecheck/typecheck.mjs.map +3 -3
  97. package/dist/mjs/package.json +1 -1
  98. package/dist/mjs/playwright.mjs +47 -0
  99. package/dist/mjs/playwright.mjs.map +10 -0
  100. package/dist/mjs/runtime/namespaced-runtime.mjs +143 -0
  101. package/dist/mjs/runtime/namespaced-runtime.mjs.map +10 -0
  102. package/dist/mjs/runtime/script-runtime.mjs +16 -12
  103. package/dist/mjs/runtime/script-runtime.mjs.map +3 -3
  104. package/dist/mjs/runtime/test-runtime.mjs +78 -0
  105. package/dist/mjs/runtime/test-runtime.mjs.map +10 -0
  106. package/dist/mjs/server/app-server.mjs +23 -11
  107. package/dist/mjs/server/app-server.mjs.map +3 -3
  108. package/dist/mjs/typecheck/index.mjs +2 -1
  109. package/dist/mjs/typecheck/index.mjs.map +3 -3
  110. package/dist/types/bridge/diagnostics.d.ts +6 -1
  111. package/dist/types/bridge/runtime-bindings.d.ts +5 -1
  112. package/dist/types/bridge/sandbox-isolate.d.ts +21 -0
  113. package/dist/types/host/nested-host-controller.d.ts +15 -0
  114. package/dist/types/index.d.ts +1 -1
  115. package/dist/types/internal/browser-source.d.ts +10 -0
  116. package/dist/types/internal/client/types.d.ts +9 -0
  117. package/dist/types/internal/daemon/types.d.ts +0 -2
  118. package/dist/types/internal/playwright/client.d.ts +2 -2
  119. package/dist/types/internal/playwright/handler.d.ts +27 -4
  120. package/dist/types/internal/playwright/index.d.ts +2 -2
  121. package/dist/types/internal/playwright/types.d.ts +33 -1
  122. package/dist/types/internal/protocol/codec.d.ts +12 -2
  123. package/dist/types/internal/protocol/marshalValue.d.ts +3 -2
  124. package/dist/types/internal/protocol/types.d.ts +33 -2
  125. package/dist/types/internal/runtime/index.d.ts +5 -0
  126. package/dist/types/internal/typecheck/index.d.ts +1 -1
  127. package/dist/types/internal/typecheck/isolate-types.d.ts +6 -4
  128. package/dist/types/internal/typecheck/typecheck.d.ts +1 -1
  129. package/dist/types/playwright.d.ts +26 -0
  130. package/dist/types/runtime/namespaced-runtime.d.ts +11 -0
  131. package/dist/types/runtime/script-runtime.d.ts +2 -1
  132. package/dist/types/runtime/test-runtime.d.ts +4 -0
  133. package/dist/types/server/app-server.d.ts +2 -1
  134. package/dist/types/types.d.ts +75 -33
  135. package/package.json +8 -3
  136. package/dist/cjs/browser/browser-runtime.cjs +0 -157
  137. package/dist/cjs/browser/browser-runtime.cjs.map +0 -10
  138. package/dist/mjs/browser/browser-runtime.mjs +0 -93
  139. package/dist/mjs/browser/browser-runtime.mjs.map +0 -10
  140. package/dist/types/browser/browser-runtime.d.ts +0 -3
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @ricsam/isolate
2
2
 
3
- `@ricsam/isolate` is a runtime-centric JavaScript sandbox built on an async-context-enabled [`@ricsam/isolated-vm`](https://github.com/ricsam/isolated-vm) engine build. It gives you a single host API for running isolated code with web-style capabilities such as `fetch`, files, streams, server handlers, module loading, and Playwright-backed browser tests.
3
+ `@ricsam/isolate` is a runtime-centric JavaScript sandbox built on an async-context-enabled [`@ricsam/isolated-vm`](https://github.com/ricsam/isolated-vm) engine build. It gives you a single host API for running isolated code with web-style capabilities such as `fetch`, files, streams, server handlers, nested sandboxes, module loading, and Playwright-backed browser tests.
4
4
 
5
5
  ## Installation
6
6
 
@@ -10,7 +10,7 @@ npm add @ricsam/isolate @ricsam/isolated-vm
10
10
 
11
11
  The `@ricsam/isolated-vm` peer includes the `createContext({ asyncContext: true })` support required by this repo. Upstream `isolated-vm` will fail fast during runtime boot with a clear AsyncContext error.
12
12
 
13
- Install Playwright when you want browser runtimes:
13
+ Install Playwright when you want browser-enabled runtimes or test runtimes:
14
14
 
15
15
  ```bash
16
16
  npm add playwright
@@ -24,12 +24,16 @@ npm add playwright
24
24
  - `createModuleResolver()` to provide virtual modules, source trees, mounted `node_modules`, and fallback resolution
25
25
  - `createFileBindings()` to expose a rooted file API to sandboxed code
26
26
  - `getTypeProfile()`, `typecheck()`, and `formatTypecheckErrors()` for sandbox-aware TypeScript tooling
27
+ - `@ricsam/isolate/playwright` to build handler-first Playwright sessions without importing internals
27
28
 
28
29
  The host can create three runtime styles:
29
30
 
30
31
  - `host.createRuntime()` for scripts, agents, and ad hoc execution
31
32
  - `host.createAppServer()` for `serve()`-based request handlers
32
- - `host.createBrowserRuntime()` for Playwright-backed execution
33
+ - `host.createTestRuntime()` for test suites with optional Playwright-backed browser access
34
+ - `host.getNamespacedRuntime()` for persistent mixed script/test/browser sessions keyed by namespace
35
+
36
+ Inside sandbox code, `@ricsam/isolate` is also available as a synthetic module. It exports a sandbox-only `createIsolateHost()` that lets a runtime create nested runtimes, app servers, and test runtimes without exposing daemon configuration to the sandbox.
33
37
 
34
38
  ## Host Bindings
35
39
 
@@ -40,9 +44,19 @@ Each runtime is configured through `bindings`, which describe how sandboxed code
40
44
  - `files` exposes a safe, root-scoped filesystem
41
45
  - `modules` resolves virtual modules, source trees, and mounted packages
42
46
  - `tools` exposes async host functions and async iterators
47
+ - `browser` exposes a Playwright-like browser surface backed either by a stable handler or by host `createContext()` and `createPage()` callbacks
43
48
 
44
49
  Every host callback receives a `HostCallContext` with an `AbortSignal`, runtime identity, resource identity, and request metadata.
45
50
 
51
+ `bindings.browser` is intentionally smaller than a full Playwright browser. It injects a global `browser` object with `browser.newContext()` and `browser.contexts()`, and returned contexts expose `context.newPage()` and `context.pages()`. Browser-level shutdown stays on the host side, while the sandbox can still close pages and contexts that it created.
52
+
53
+ Choose exactly one browser mode per runtime:
54
+
55
+ - factory-first: provide `createContext()` and optionally `createPage()`, `readFile()`, and `writeFile()`
56
+ - handler-first: provide `handler`, usually from `createPlaywrightSessionHandler(...)`
57
+
58
+ Do not mix `handler` with `createContext()` / `createPage()` / `readFile()` / `writeFile()` in the same binding.
59
+
46
60
  ## Async Context
47
61
 
48
62
  Runtimes created by `@ricsam/isolate` enable the TC39 proposal-style `AsyncContext` global inside the sandbox. This is an experimental surface for now, and the proposal API is used to implement the `node:async_hooks` shim exported to sandboxed code.
@@ -145,6 +159,51 @@ try {
145
159
  }
146
160
  ```
147
161
 
162
+ ## Nested Hosts Inside The Sandbox
163
+
164
+ Sandbox code can import `@ricsam/isolate` and create child runtimes against the same top-level host connection.
165
+
166
+ ```ts
167
+ const runtime = await host.createRuntime({
168
+ bindings: {
169
+ console: {
170
+ onEntry(entry) {
171
+ if (entry.type === "output") {
172
+ console.log(entry.stdout);
173
+ }
174
+ },
175
+ },
176
+ },
177
+ });
178
+
179
+ await runtime.eval(`
180
+ import { createIsolateHost } from "@ricsam/isolate";
181
+
182
+ const nestedHost = createIsolateHost();
183
+ const child = await nestedHost.createRuntime({
184
+ bindings: {
185
+ tools: {
186
+ greet: async (name) => "hello " + name,
187
+ },
188
+ },
189
+ });
190
+
191
+ await child.eval('console.log(await greet("nested"))');
192
+ await child.dispose();
193
+ await nestedHost.close();
194
+ `);
195
+ ```
196
+
197
+ Nested hosts support:
198
+
199
+ - `createRuntime()`
200
+ - `createAppServer()`
201
+ - `createTestRuntime()`
202
+ - `diagnostics()`
203
+ - `close()`
204
+
205
+ Child runtimes can reuse the same binding shapes as top-level runtimes. That includes isolate-authored callbacks, async iterators, module resolvers, file bindings, and browser handles.
206
+
148
207
  ## App Servers
149
208
 
150
209
  `createAppServer()` is the long-lived server-oriented API. It boots a runtime around an entry module that calls `serve()` and then lets the host dispatch requests into it.
@@ -183,51 +242,227 @@ await host.close();
183
242
 
184
243
  `server.handle()` returns either a normal HTTP response or WebSocket upgrade metadata. The `server.ws` helpers let the host continue an upgraded connection by sending open, message, close, and error events back into the runtime.
185
244
 
186
- ## Browser Runtimes
245
+ ## Browser Bindings In Script And Server Runtimes
246
+
247
+ ## Namespaced Sessions
248
+
249
+ `host.getNamespacedRuntime(key, options)` is the public persistent-session API. It is the supported way to reuse one underlying runtime across multiple calls while refreshing host bindings on each acquire.
250
+
251
+ Use it when you want patterns like:
187
252
 
188
- `createBrowserRuntime()` runs sandboxed code against a Playwright page while keeping the host in control of file access, diagnostics, and browser event collection.
253
+ - script calls that keep module state or globals between runs
254
+ - Playwright browser contexts/pages that stay alive behind one stable handler
255
+ - later `runTests(code)` calls that should see existing `browser.contexts()`
256
+
257
+ Normal `session.dispose()` is a soft dispose for that namespace. The next acquire of the same key reuses the cached runtime. `host.disposeNamespace(key)` is the hard-delete path for active or pooled namespaces and invalidates any live handles in the current process.
189
258
 
190
259
  ```ts
191
260
  import { chromium } from "playwright";
192
261
  import { createIsolateHost } from "@ricsam/isolate";
262
+ import { createPlaywrightSessionHandler } from "@ricsam/isolate/playwright";
193
263
 
194
264
  const browser = await chromium.launch();
195
- const context = await browser.newContext();
196
- const page = await context.newPage();
265
+ const host = await createIsolateHost();
266
+ const playwright = createPlaywrightSessionHandler({
267
+ createContext: async (options) =>
268
+ await browser.newContext(options ?? undefined),
269
+ createPage: async (context) =>
270
+ await context.newPage(),
271
+ });
272
+
273
+ const session = await host.getNamespacedRuntime("playwright:preview:session", {
274
+ bindings: {
275
+ browser: {
276
+ handler: playwright.handler,
277
+ },
278
+ },
279
+ });
280
+
281
+ await session.eval(`
282
+ globalThis.ctx = await browser.newContext();
283
+ globalThis.page = await globalThis.ctx.newPage();
284
+ await globalThis.page.goto("https://example.com");
285
+ `);
286
+
287
+ await session.dispose();
288
+
289
+ const reused = await host.getNamespacedRuntime("playwright:preview:session", {
290
+ bindings: {
291
+ browser: {
292
+ handler: playwright.handler,
293
+ },
294
+ },
295
+ });
296
+
297
+ const results = await reused.runTests(`
298
+ test("sees the existing browser state", async () => {
299
+ const contexts = await browser.contexts();
300
+ expect(contexts.length).toBe(1);
301
+ const pages = await contexts[0].pages();
302
+ expect(pages.length).toBe(1);
303
+ });
304
+ `);
305
+
306
+ console.log(results.success);
307
+
308
+ await host.disposeNamespace("playwright:preview:session");
309
+ await browser.close();
310
+ await host.close();
311
+ ```
312
+
313
+ Lifecycle notes:
314
+
315
+ - only one live handle per namespace is allowed at a time
316
+ - `runTests(code)` resets test registration before loading and running the provided suite
317
+ - runtime globals, module state, and Playwright resources are preserved across soft dispose and reacquire
318
+ - browser shutdown stays host-owned; page/context shutdown stays sandbox-owned
319
+ - preview URL rewriting remains host-specific and stays outside isolate
197
320
 
321
+ ## Browser Bindings In Script And Server Runtimes
322
+
323
+ If you provide `bindings.browser`, script and app runtimes get a global `browser` factory even when they are not full Playwright browser runtimes.
324
+
325
+ ```ts
326
+ import { chromium } from "playwright";
327
+ import { createIsolateHost } from "@ricsam/isolate";
328
+
329
+ const browser = await chromium.launch();
330
+ const host = await createIsolateHost();
331
+
332
+ const runtime = await host.createRuntime({
333
+ bindings: {
334
+ browser: {
335
+ createContext: async (options) =>
336
+ await browser.newContext(options ?? undefined),
337
+ createPage: async (contextInstance) =>
338
+ await contextInstance.newPage(),
339
+ },
340
+ },
341
+ });
342
+
343
+ await runtime.eval(`
344
+ const ctx = await browser.newContext({
345
+ viewport: { width: 1280, height: 720 },
346
+ });
347
+ const page = await ctx.newPage();
348
+
349
+ await page.goto("https://example.com");
350
+ console.log(await page.title());
351
+ console.log(typeof browser.close);
352
+
353
+ await page.close();
354
+ await ctx.close();
355
+ `);
356
+
357
+ await runtime.dispose();
358
+ await browser.close();
359
+ await host.close();
360
+ ```
361
+
362
+ In these runtimes:
363
+
364
+ - `browser.newContext()` is available
365
+ - `browser.contexts()` is available
366
+ - `context.newPage()` is available
367
+ - `context.pages()` is available
368
+ - `page.close()` and `context.close()` are available
369
+ - `browser.close()` is not exposed inside the sandbox
370
+ - `page` and `context` are never injected as implicit globals
371
+
372
+ ## Test Runtimes
373
+
374
+ `createTestRuntime()` enables `describe`, `test`/`it`, hooks, and `expect`. If you also provide `bindings.browser`, the same test runtime gets Playwright-style browser access and matcher support, but you are responsible for explicit page/context lifecycle inside the suite.
375
+
376
+ ```ts
377
+ import { chromium } from "playwright";
378
+ import { createIsolateHost } from "@ricsam/isolate";
379
+
380
+ const browser = await chromium.launch();
198
381
  const host = await createIsolateHost();
199
- const runtime = await host.createBrowserRuntime({
200
- key: "example/browser",
201
- bindings: {},
202
- features: { tests: true },
203
- browser: {
204
- page,
205
- captureConsole: true,
382
+ const runtime = await host.createTestRuntime({
383
+ key: "example/browser-test",
384
+ bindings: {
385
+ browser: {
386
+ captureConsole: true,
387
+ createContext: async (options) =>
388
+ await browser.newContext(options ?? undefined),
389
+ createPage: async (contextInstance) =>
390
+ await contextInstance.newPage(),
391
+ },
206
392
  },
207
393
  });
208
394
 
209
395
  const result = await runtime.run(
210
396
  `
397
+ let ctx;
398
+ let page;
399
+
400
+ beforeAll(async () => {
401
+ ctx = await browser.newContext();
402
+ page = await ctx.newPage();
403
+ });
404
+
405
+ afterAll(async () => {
406
+ await ctx.close();
407
+ });
408
+
211
409
  test("loads a page", async () => {
212
- await page.goto("https://example.com");
410
+ expect((await browser.contexts()).length).toBe(1);
411
+ expect((await ctx.pages()).length).toBe(1);
412
+ await page.goto("https://example.com", {
413
+ waitUntil: "domcontentloaded",
414
+ });
213
415
  await expect(page).toHaveTitle(/Example Domain/);
214
416
  });
215
417
  `,
216
418
  {
217
419
  filename: "/browser-test.ts",
218
- asTestSuite: true,
219
420
  timeoutMs: 10_000,
220
421
  },
221
422
  );
222
423
 
223
- console.log(result.tests);
424
+ console.log(result);
224
425
 
225
426
  await runtime.dispose();
226
- await context.close();
227
427
  await browser.close();
228
428
  await host.close();
229
429
  ```
230
430
 
431
+ From inside another sandbox, `nestedHost.createTestRuntime()` can reuse the sandbox `browser` handle:
432
+
433
+ ```ts
434
+ import { createIsolateHost } from "@ricsam/isolate";
435
+
436
+ const nestedHost = createIsolateHost();
437
+ const child = await nestedHost.createTestRuntime({
438
+ bindings: {
439
+ browser,
440
+ },
441
+ });
442
+
443
+ await child.run(`
444
+ let ctx;
445
+ let page;
446
+
447
+ beforeAll(async () => {
448
+ ctx = await browser.newContext();
449
+ page = await ctx.newPage();
450
+ });
451
+
452
+ afterAll(async () => {
453
+ await ctx.close();
454
+ });
455
+
456
+ test("loads a nested page", async () => {
457
+ await page.goto("https://example.com");
458
+ await expect(page).toHaveTitle(/Example Domain/);
459
+ });
460
+ `);
461
+
462
+ await child.dispose();
463
+ await nestedHost.close();
464
+ ```
465
+
231
466
  ## Module Resolution
232
467
 
233
468
  `createModuleResolver()` is a fluent builder. You can mix and match:
@@ -278,6 +513,10 @@ Built-in profiles:
278
513
 
279
514
  Capabilities can extend a profile with `fetch`, `files`, `tests`, `browser`, `tools`, `console`, `encoding`, and `timers`.
280
515
 
516
+ - Use `browser` when sandbox code should typecheck `browser.newContext()`, `browser.contexts()`, `context.newPage()`, and `context.pages()`
517
+ - The browser test profile does not assume implicit global `page` or `context`
518
+ - The synthetic sandbox import `import { createIsolateHost } from "@ricsam/isolate"` is included in all type profiles
519
+
281
520
  ## Daemon CLI
282
521
 
283
522
  The package also exposes an `isolate-daemon` binary:
@@ -39,7 +39,8 @@ var __export = (target, all) => {
39
39
  // src/bridge/diagnostics.ts
40
40
  var exports_diagnostics = {};
41
41
  __export(exports_diagnostics, {
42
- createRuntimeDiagnostics: () => createRuntimeDiagnostics
42
+ createRuntimeDiagnostics: () => createRuntimeDiagnostics,
43
+ createBrowserDiagnostics: () => createBrowserDiagnostics
43
44
  });
44
45
  module.exports = __toCommonJS(exports_diagnostics);
45
46
  function createRuntimeDiagnostics() {
@@ -54,5 +55,39 @@ function createRuntimeDiagnostics() {
54
55
  lifecycleState: "idle"
55
56
  };
56
57
  }
58
+ function createBrowserDiagnostics(collectedData, trackedResources) {
59
+ const contextIds = new Set;
60
+ const pageIds = new Set;
61
+ for (const entry of collectedData.browserConsoleLogs) {
62
+ contextIds.add(entry.contextId);
63
+ pageIds.add(entry.pageId);
64
+ }
65
+ for (const entry of collectedData.pageErrors) {
66
+ contextIds.add(entry.contextId);
67
+ pageIds.add(entry.pageId);
68
+ }
69
+ for (const entry of collectedData.networkRequests) {
70
+ contextIds.add(entry.contextId);
71
+ pageIds.add(entry.pageId);
72
+ }
73
+ for (const entry of collectedData.networkResponses) {
74
+ contextIds.add(entry.contextId);
75
+ pageIds.add(entry.pageId);
76
+ }
77
+ for (const entry of collectedData.requestFailures) {
78
+ contextIds.add(entry.contextId);
79
+ pageIds.add(entry.pageId);
80
+ }
81
+ return {
82
+ contexts: trackedResources?.contexts.length ?? contextIds.size,
83
+ pages: trackedResources?.pages.length ?? pageIds.size,
84
+ browserConsoleLogs: collectedData.browserConsoleLogs.length,
85
+ networkRequests: collectedData.networkRequests.length,
86
+ networkResponses: collectedData.networkResponses.length,
87
+ pageErrors: collectedData.pageErrors.length,
88
+ requestFailures: collectedData.requestFailures.length,
89
+ collectedData
90
+ };
91
+ }
57
92
 
58
- //# debugId=40FF8D24B6369A0D64756E2164756E21
93
+ //# debugId=8BF2916FF62F72B164756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../src/bridge/diagnostics.ts"],
4
4
  "sourcesContent": [
5
- "import type { RuntimeDiagnostics } from \"../types.cjs\";\n\nexport interface MutableRuntimeDiagnostics extends RuntimeDiagnostics {\n activeRequests: number;\n activeResources: number;\n pendingFiles: number;\n pendingFetches: number;\n pendingModules: number;\n pendingTools: number;\n streamCount: number;\n lifecycleState: \"idle\" | \"active\" | \"reloading\" | \"disposing\";\n}\n\nexport function createRuntimeDiagnostics(): MutableRuntimeDiagnostics {\n return {\n activeRequests: 0,\n activeResources: 0,\n pendingFiles: 0,\n pendingFetches: 0,\n pendingModules: 0,\n pendingTools: 0,\n streamCount: 0,\n lifecycleState: \"idle\",\n };\n}\n"
5
+ "import type { CollectedData } from \"../internal/client/index.cjs\";\nimport type { BrowserDiagnostics, RuntimeDiagnostics } from \"../types.cjs\";\n\nexport interface MutableRuntimeDiagnostics extends RuntimeDiagnostics {\n activeRequests: number;\n activeResources: number;\n pendingFiles: number;\n pendingFetches: number;\n pendingModules: number;\n pendingTools: number;\n streamCount: number;\n lifecycleState: \"idle\" | \"active\" | \"reloading\" | \"disposing\";\n}\n\nexport function createRuntimeDiagnostics(): MutableRuntimeDiagnostics {\n return {\n activeRequests: 0,\n activeResources: 0,\n pendingFiles: 0,\n pendingFetches: 0,\n pendingModules: 0,\n pendingTools: 0,\n streamCount: 0,\n lifecycleState: \"idle\",\n };\n}\n\nexport function createBrowserDiagnostics(\n collectedData: CollectedData,\n trackedResources?: { contexts: string[]; pages: string[] },\n): BrowserDiagnostics {\n const contextIds = new Set<string>();\n const pageIds = new Set<string>();\n for (const entry of collectedData.browserConsoleLogs) {\n contextIds.add(entry.contextId);\n pageIds.add(entry.pageId);\n }\n for (const entry of collectedData.pageErrors) {\n contextIds.add(entry.contextId);\n pageIds.add(entry.pageId);\n }\n for (const entry of collectedData.networkRequests) {\n contextIds.add(entry.contextId);\n pageIds.add(entry.pageId);\n }\n for (const entry of collectedData.networkResponses) {\n contextIds.add(entry.contextId);\n pageIds.add(entry.pageId);\n }\n for (const entry of collectedData.requestFailures) {\n contextIds.add(entry.contextId);\n pageIds.add(entry.pageId);\n }\n\n return {\n contexts: trackedResources?.contexts.length ?? contextIds.size,\n pages: trackedResources?.pages.length ?? pageIds.size,\n browserConsoleLogs: collectedData.browserConsoleLogs.length,\n networkRequests: collectedData.networkRequests.length,\n networkResponses: collectedData.networkResponses.length,\n pageErrors: collectedData.pageErrors.length,\n requestFailures: collectedData.requestFailures.length,\n collectedData,\n };\n}\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAaO,SAAS,wBAAwB,GAA8B;AAAA,EACpE,OAAO;AAAA,IACL,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,aAAa;AAAA,IACb,gBAAgB;AAAA,EAClB;AAAA;",
8
- "debugId": "40FF8D24B6369A0D64756E2164756E21",
7
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAcO,SAAS,wBAAwB,GAA8B;AAAA,EACpE,OAAO;AAAA,IACL,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,aAAa;AAAA,IACb,gBAAgB;AAAA,EAClB;AAAA;AAGK,SAAS,wBAAwB,CACtC,eACA,kBACoB;AAAA,EACpB,MAAM,aAAa,IAAI;AAAA,EACvB,MAAM,UAAU,IAAI;AAAA,EACpB,WAAW,SAAS,cAAc,oBAAoB;AAAA,IACpD,WAAW,IAAI,MAAM,SAAS;AAAA,IAC9B,QAAQ,IAAI,MAAM,MAAM;AAAA,EAC1B;AAAA,EACA,WAAW,SAAS,cAAc,YAAY;AAAA,IAC5C,WAAW,IAAI,MAAM,SAAS;AAAA,IAC9B,QAAQ,IAAI,MAAM,MAAM;AAAA,EAC1B;AAAA,EACA,WAAW,SAAS,cAAc,iBAAiB;AAAA,IACjD,WAAW,IAAI,MAAM,SAAS;AAAA,IAC9B,QAAQ,IAAI,MAAM,MAAM;AAAA,EAC1B;AAAA,EACA,WAAW,SAAS,cAAc,kBAAkB;AAAA,IAClD,WAAW,IAAI,MAAM,SAAS;AAAA,IAC9B,QAAQ,IAAI,MAAM,MAAM;AAAA,EAC1B;AAAA,EACA,WAAW,SAAS,cAAc,iBAAiB;AAAA,IACjD,WAAW,IAAI,MAAM,SAAS;AAAA,IAC9B,QAAQ,IAAI,MAAM,MAAM;AAAA,EAC1B;AAAA,EAEA,OAAO;AAAA,IACL,UAAU,kBAAkB,SAAS,UAAU,WAAW;AAAA,IAC1D,OAAO,kBAAkB,MAAM,UAAU,QAAQ;AAAA,IACjD,oBAAoB,cAAc,mBAAmB;AAAA,IACrD,iBAAiB,cAAc,gBAAgB;AAAA,IAC/C,kBAAkB,cAAc,iBAAiB;AAAA,IACjD,YAAY,cAAc,WAAW;AAAA,IACrC,iBAAiB,cAAc,gBAAgB;AAAA,IAC/C;AAAA,EACF;AAAA;",
8
+ "debugId": "8BF2916FF62F72B164756E2164756E21",
9
9
  "names": []
10
10
  }