@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.
- package/README.md +257 -18
- package/dist/cjs/bridge/diagnostics.cjs +37 -2
- package/dist/cjs/bridge/diagnostics.cjs.map +3 -3
- package/dist/cjs/bridge/runtime-bindings.cjs +230 -51
- package/dist/cjs/bridge/runtime-bindings.cjs.map +3 -3
- package/dist/cjs/bridge/sandbox-isolate.cjs +464 -0
- package/dist/cjs/bridge/sandbox-isolate.cjs.map +10 -0
- package/dist/cjs/host/create-isolate-host.cjs +130 -25
- package/dist/cjs/host/create-isolate-host.cjs.map +3 -3
- package/dist/cjs/host/nested-host-controller.cjs +369 -0
- package/dist/cjs/host/nested-host-controller.cjs.map +10 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/internal/browser-source.cjs +102 -0
- package/dist/cjs/internal/browser-source.cjs.map +10 -0
- package/dist/cjs/internal/client/connection.cjs +163 -172
- package/dist/cjs/internal/client/connection.cjs.map +3 -3
- package/dist/cjs/internal/daemon/callback-fs-handler.cjs +3 -3
- package/dist/cjs/internal/daemon/callback-fs-handler.cjs.map +3 -3
- package/dist/cjs/internal/daemon/connection.cjs +156 -13
- package/dist/cjs/internal/daemon/connection.cjs.map +3 -3
- package/dist/cjs/internal/playwright/client.cjs +4 -2
- package/dist/cjs/internal/playwright/client.cjs.map +3 -3
- package/dist/cjs/internal/playwright/handler.cjs +298 -25
- package/dist/cjs/internal/playwright/handler.cjs.map +3 -3
- package/dist/cjs/internal/playwright/index.cjs +54 -8
- package/dist/cjs/internal/playwright/index.cjs.map +3 -3
- package/dist/cjs/internal/playwright/types.cjs +3 -1
- package/dist/cjs/internal/playwright/types.cjs.map +3 -3
- package/dist/cjs/internal/protocol/codec.cjs +16 -5
- package/dist/cjs/internal/protocol/codec.cjs.map +3 -3
- package/dist/cjs/internal/protocol/marshalValue.cjs +37 -6
- package/dist/cjs/internal/protocol/marshalValue.cjs.map +3 -3
- package/dist/cjs/internal/protocol/types.cjs +2 -1
- package/dist/cjs/internal/protocol/types.cjs.map +3 -3
- package/dist/cjs/internal/runtime/index.cjs +377 -22
- package/dist/cjs/internal/runtime/index.cjs.map +3 -3
- package/dist/cjs/internal/typecheck/index.cjs +2 -1
- package/dist/cjs/internal/typecheck/index.cjs.map +3 -3
- package/dist/cjs/internal/typecheck/isolate-types.cjs +218 -13
- package/dist/cjs/internal/typecheck/isolate-types.cjs.map +3 -3
- package/dist/cjs/internal/typecheck/typecheck.cjs +2 -3
- package/dist/cjs/internal/typecheck/typecheck.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/playwright.cjs +76 -0
- package/dist/cjs/playwright.cjs.map +10 -0
- package/dist/cjs/runtime/namespaced-runtime.cjs +181 -0
- package/dist/cjs/runtime/namespaced-runtime.cjs.map +10 -0
- package/dist/cjs/runtime/script-runtime.cjs +14 -12
- package/dist/cjs/runtime/script-runtime.cjs.map +3 -3
- package/dist/cjs/runtime/test-runtime.cjs +113 -0
- package/dist/cjs/runtime/test-runtime.cjs.map +10 -0
- package/dist/cjs/server/app-server.cjs +16 -9
- package/dist/cjs/server/app-server.cjs.map +3 -3
- package/dist/cjs/typecheck/index.cjs +2 -1
- package/dist/cjs/typecheck/index.cjs.map +3 -3
- package/dist/mjs/bridge/diagnostics.mjs +37 -2
- package/dist/mjs/bridge/diagnostics.mjs.map +3 -3
- package/dist/mjs/bridge/runtime-bindings.mjs +233 -51
- package/dist/mjs/bridge/runtime-bindings.mjs.map +3 -3
- package/dist/mjs/bridge/sandbox-isolate.mjs +424 -0
- package/dist/mjs/bridge/sandbox-isolate.mjs.map +10 -0
- package/dist/mjs/host/create-isolate-host.mjs +132 -25
- package/dist/mjs/host/create-isolate-host.mjs.map +3 -3
- package/dist/mjs/host/nested-host-controller.mjs +333 -0
- package/dist/mjs/host/nested-host-controller.mjs.map +10 -0
- package/dist/mjs/index.mjs.map +1 -1
- package/dist/mjs/internal/browser-source.mjs +62 -0
- package/dist/mjs/internal/browser-source.mjs.map +10 -0
- package/dist/mjs/internal/client/connection.mjs +165 -173
- package/dist/mjs/internal/client/connection.mjs.map +3 -3
- package/dist/mjs/internal/daemon/callback-fs-handler.mjs +3 -3
- package/dist/mjs/internal/daemon/callback-fs-handler.mjs.map +3 -3
- package/dist/mjs/internal/daemon/connection.mjs +156 -13
- package/dist/mjs/internal/daemon/connection.mjs.map +3 -3
- package/dist/mjs/internal/playwright/client.mjs +7 -3
- package/dist/mjs/internal/playwright/client.mjs.map +3 -3
- package/dist/mjs/internal/playwright/handler.mjs +300 -26
- package/dist/mjs/internal/playwright/handler.mjs.map +3 -3
- package/dist/mjs/internal/playwright/index.mjs +59 -9
- package/dist/mjs/internal/playwright/index.mjs.map +3 -3
- package/dist/mjs/internal/playwright/types.mjs +3 -1
- package/dist/mjs/internal/playwright/types.mjs.map +3 -3
- package/dist/mjs/internal/protocol/codec.mjs +16 -5
- package/dist/mjs/internal/protocol/codec.mjs.map +3 -3
- package/dist/mjs/internal/protocol/marshalValue.mjs +38 -6
- package/dist/mjs/internal/protocol/marshalValue.mjs.map +3 -3
- package/dist/mjs/internal/protocol/types.mjs +2 -1
- package/dist/mjs/internal/protocol/types.mjs.map +3 -3
- package/dist/mjs/internal/runtime/index.mjs +377 -22
- package/dist/mjs/internal/runtime/index.mjs.map +3 -3
- package/dist/mjs/internal/typecheck/index.mjs +3 -1
- package/dist/mjs/internal/typecheck/index.mjs.map +3 -3
- package/dist/mjs/internal/typecheck/isolate-types.mjs +218 -13
- package/dist/mjs/internal/typecheck/isolate-types.mjs.map +3 -3
- package/dist/mjs/internal/typecheck/typecheck.mjs +2 -3
- package/dist/mjs/internal/typecheck/typecheck.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/playwright.mjs +47 -0
- package/dist/mjs/playwright.mjs.map +10 -0
- package/dist/mjs/runtime/namespaced-runtime.mjs +143 -0
- package/dist/mjs/runtime/namespaced-runtime.mjs.map +10 -0
- package/dist/mjs/runtime/script-runtime.mjs +16 -12
- package/dist/mjs/runtime/script-runtime.mjs.map +3 -3
- package/dist/mjs/runtime/test-runtime.mjs +78 -0
- package/dist/mjs/runtime/test-runtime.mjs.map +10 -0
- package/dist/mjs/server/app-server.mjs +23 -11
- package/dist/mjs/server/app-server.mjs.map +3 -3
- package/dist/mjs/typecheck/index.mjs +2 -1
- package/dist/mjs/typecheck/index.mjs.map +3 -3
- package/dist/types/bridge/diagnostics.d.ts +6 -1
- package/dist/types/bridge/runtime-bindings.d.ts +5 -1
- package/dist/types/bridge/sandbox-isolate.d.ts +21 -0
- package/dist/types/host/nested-host-controller.d.ts +15 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/internal/browser-source.d.ts +10 -0
- package/dist/types/internal/client/types.d.ts +9 -0
- package/dist/types/internal/daemon/types.d.ts +0 -2
- package/dist/types/internal/playwright/client.d.ts +2 -2
- package/dist/types/internal/playwright/handler.d.ts +27 -4
- package/dist/types/internal/playwright/index.d.ts +2 -2
- package/dist/types/internal/playwright/types.d.ts +33 -1
- package/dist/types/internal/protocol/codec.d.ts +12 -2
- package/dist/types/internal/protocol/marshalValue.d.ts +3 -2
- package/dist/types/internal/protocol/types.d.ts +33 -2
- package/dist/types/internal/runtime/index.d.ts +5 -0
- package/dist/types/internal/typecheck/index.d.ts +1 -1
- package/dist/types/internal/typecheck/isolate-types.d.ts +6 -4
- package/dist/types/internal/typecheck/typecheck.d.ts +1 -1
- package/dist/types/playwright.d.ts +26 -0
- package/dist/types/runtime/namespaced-runtime.d.ts +11 -0
- package/dist/types/runtime/script-runtime.d.ts +2 -1
- package/dist/types/runtime/test-runtime.d.ts +4 -0
- package/dist/types/server/app-server.d.ts +2 -1
- package/dist/types/types.d.ts +75 -33
- package/package.json +8 -3
- package/dist/cjs/browser/browser-runtime.cjs +0 -157
- package/dist/cjs/browser/browser-runtime.cjs.map +0 -10
- package/dist/mjs/browser/browser-runtime.mjs +0 -93
- package/dist/mjs/browser/browser-runtime.mjs.map +0 -10
- 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.
|
|
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
|
-
|
|
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
|
|
196
|
-
const
|
|
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.
|
|
200
|
-
key: "example/browser",
|
|
201
|
-
bindings: {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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
|
|
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
|
|
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=
|
|
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": "
|
|
8
|
-
"debugId": "
|
|
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
|
}
|