@orkestrel/browser 0.0.26 → 0.0.27
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 +23 -13
- package/dist/bin/main.js +11 -9
- package/dist/bin/main.js.map +1 -1
- package/dist/src/browser/index.d.ts +6 -184
- package/dist/src/browser/index.js +145 -119
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/core/index.cjs +2324 -1991
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +672 -1366
- package/dist/src/core/index.d.ts +672 -1366
- package/dist/src/core/index.js +2287 -1941
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +202 -211
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +65 -166
- package/dist/src/server/index.d.ts +65 -166
- package/dist/src/server/index.js +201 -205
- package/dist/src/server/index.js.map +1 -1
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
# @orkestrel/browser
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
>
|
|
5
|
-
> and
|
|
6
|
-
> and a Node runtime that finds, launches, and connects to the browser itself.
|
|
3
|
+
> The browser runtime for the `@orkestrel` line: a `Browser` that finds, launches, or attaches
|
|
4
|
+
> to Chromium; its contexts and pages; the elements and readings a page yields; and the toolset
|
|
5
|
+
> and journeys that hand a page to an agent.
|
|
7
6
|
|
|
8
|
-
Connect to a running browser or launch one with the `createBrowser` function, open a page, and drive it through stable element references and trusted input. Read the whole captured page as Markdown or plain text in bounded slices, and hand the whole vocabulary to an agent as `@orkestrel/tool` tools with `createBrowserToolset`. Inside a page, `
|
|
7
|
+
Connect to a running browser or launch one with the `createBrowser` function, open a page, and drive it through stable element references and trusted input. Read the whole captured page as Markdown or plain text in bounded slices, and hand the whole vocabulary to an agent as `@orkestrel/tool` tools with `createBrowserToolset`. Inside a page, `createBrowserToolset(createBrowserDOMView(options))` drives a DOM document with native APIs, and `createSocketCDPTransport` carries the core client over the browser's own `WebSocket`. Record a journey, one user intent kept as JSON, from a model's tool calls or a person's gestures on a page, then list, edit, replay, and forget it through the seven journey tools, or compile it with `compileBrowserJourney` into a module a developer runs and customizes. Part of the `@orkestrel` line.
|
|
9
8
|
|
|
10
9
|
## Install
|
|
11
10
|
|
|
@@ -32,7 +31,12 @@ import { createBrowser } from '@orkestrel/browser/server'
|
|
|
32
31
|
|
|
33
32
|
const browser = createBrowser({ headless: true })
|
|
34
33
|
await browser.connect()
|
|
35
|
-
const
|
|
34
|
+
const url =
|
|
35
|
+
'data:text/html,' +
|
|
36
|
+
encodeURIComponent(
|
|
37
|
+
'<label>Email<input aria-label="Email"></label><button onclick="document.body.append("Saved")">Save</button>',
|
|
38
|
+
)
|
|
39
|
+
const page = await browser.create({ url })
|
|
36
40
|
const outline = await page.elements.outline() // the page's text and elements, with references such as e4
|
|
37
41
|
const [email] = await page.elements.find({ role: 'textbox', name: 'Email' })
|
|
38
42
|
await email?.fill('sam@example.test')
|
|
@@ -54,9 +58,13 @@ import { createToolManager } from '@orkestrel/tool'
|
|
|
54
58
|
|
|
55
59
|
const toolset = createBrowserToolset(page, { tools: createToolManager() })
|
|
56
60
|
await toolset.start()
|
|
57
|
-
await toolset.tools.execute({ id: '1', name: '
|
|
58
|
-
await toolset.tools.execute({ id: '2', name: 'read', arguments: { search: 'delivery' } })
|
|
59
|
-
await toolset.tools.execute({
|
|
61
|
+
await toolset.tools.execute({ id: '1', name: 'read', arguments: { from: 1, search: 'Email' } })
|
|
62
|
+
await toolset.tools.execute({ id: '2', name: 'read', arguments: { from: 1, search: 'delivery' } })
|
|
63
|
+
await toolset.tools.execute({
|
|
64
|
+
id: '3',
|
|
65
|
+
name: 'read',
|
|
66
|
+
arguments: { from: 1, search: 'confirmation' },
|
|
67
|
+
})
|
|
60
68
|
await toolset.destroy()
|
|
61
69
|
```
|
|
62
70
|
|
|
@@ -71,9 +79,11 @@ const result = await client.send('Page.navigate', { url: 'https://example.com' }
|
|
|
71
79
|
await client.close()
|
|
72
80
|
```
|
|
73
81
|
|
|
82
|
+
Context wrapping uses `BrowserContextOptions`; `browser.isolate` uses `BrowserIsolateOptions` and assigns the context id. The stable `page.recorder` reports `active` and starts explicitly. Network `apply` retains omitted or undefined settings; `clear()` resets headers, offline mode, and credentials. Cookie `remove` requires a nonempty filter; `clear()` removes all cookies.
|
|
83
|
+
|
|
74
84
|
## Browse binary
|
|
75
85
|
|
|
76
|
-
The package ships the `browse` binary, which serves the browser vocabulary and the journey tools over MCP on stdio and starts Chromium when the server starts, before the client's first request, keeping journeys and runs under `tmp/browsers`. Register it for a checkout with `claude mcp add --scope project browse -- node node_modules/@orkestrel/browser/dist/bin/main.js`, which writes the `browse` entry of the project's `.mcp.json`, then start `claude` in the checkout and approve the server; `BROWSE_ROOT`, `BROWSE_HEADLESS`, `BROWSE_EXECUTABLE`, `BROWSE_READONLY`, and `BROWSE_POOL` configure it. See [Register the browse binary with Claude Code](guides/browser.md#register-the-browse-binary-with-claude-code) for the entry, the approval, the startup and recovery behavior, and
|
|
86
|
+
The package ships the `browse` binary, which serves the browser vocabulary and the journey tools over MCP on stdio and starts Chromium when the server starts, before the client's first request, keeping journeys and runs under `tmp/browsers`. Register it for a checkout with `claude mcp add --scope project browse -- node node_modules/@orkestrel/browser/dist/bin/main.js`, which writes the `browse` entry of the project's `.mcp.json`, then start `claude` in the checkout and approve the server; `BROWSE_ROOT`, `BROWSE_HEADLESS`, `BROWSE_EXECUTABLE`, `BROWSE_READONLY`, and `BROWSE_POOL` configure it. See [Register the browse binary with Claude Code](guides/browser.md#register-the-browse-binary-with-claude-code) for the entry, the approval, the startup and recovery behavior, and an illustrative exchange.
|
|
77
87
|
|
|
78
88
|
## Guide
|
|
79
89
|
|
|
@@ -83,9 +93,9 @@ For the full surface of the three faces, the method tables, the toolset vocabula
|
|
|
83
93
|
|
|
84
94
|
The `exports` field in `package.json` names three entry points:
|
|
85
95
|
|
|
86
|
-
- `.`, the
|
|
87
|
-
- `./browser`, the in-page face: `BrowserDOMView`, `
|
|
88
|
-
- `./server`, the Node runtime: `Browser`, `WebSocketCDPTransport`, `FileBrowserWriter`, the file journey and run stores, `BrowserMCPServer`, and the factories `createBrowser`, `
|
|
96
|
+
- `.`, the core: context and page contracts, elements and readings, the toolset, recorder, replay, memory stores, journey compiler, and their factories. Owners construct pages, frames, elements, input devices, and managers and return their public interfaces; `createBrowserContext` constructs a context over an injected CDP client.
|
|
97
|
+
- `./browser`, the in-page face: `BrowserDOMView`, `BrowserDOMWait`, `SocketCDPTransport`, `createBrowserDOMView`, and `createSocketCDPTransport`. Compose the view with the core's `createBrowserToolset`.
|
|
98
|
+
- `./server`, the Node runtime: `Browser`, `WebSocketCDPTransport`, `FileBrowserWriter`, the file journey and run stores, `BrowserMCPServer`, and the factories `createBrowser`, `createWebSocketCDPTransport`, `createFileBrowserWriter`, `createFileBrowserJourneyStore`, `createFileBrowserRunStore`, and `createBrowserMCPServer`.
|
|
89
99
|
|
|
90
100
|
The `bin` field names `browse`, which runs `dist/bin/main.js`.
|
|
91
101
|
|
package/dist/bin/main.js
CHANGED
|
@@ -21,32 +21,34 @@ try {
|
|
|
21
21
|
"BROWSE_READONLY",
|
|
22
22
|
BROWSE_READONLY,
|
|
23
23
|
readonly
|
|
24
|
-
]]) if (value !== void 0 && value !== "" && parsed === void 0) throw new BrowserError(`${name} must be true, false, 1, or 0, not ${JSON.stringify(value)}`,
|
|
24
|
+
]]) if (value !== void 0 && value !== "" && parsed === void 0) throw new BrowserError("SERVER_ENVIRONMENT", `${name} must be true, false, 1, or 0, not ${JSON.stringify(value)}`, {
|
|
25
25
|
name,
|
|
26
26
|
value
|
|
27
27
|
});
|
|
28
|
-
if (BROWSE_POOL !== void 0 && BROWSE_POOL !== "" && size === void 0) throw new BrowserError(`BROWSE_POOL must be an integer, not ${JSON.stringify(BROWSE_POOL)}`,
|
|
28
|
+
if (BROWSE_POOL !== void 0 && BROWSE_POOL !== "" && size === void 0) throw new BrowserError("SERVER_ENVIRONMENT", `BROWSE_POOL must be an integer, not ${JSON.stringify(BROWSE_POOL)}`, {
|
|
29
29
|
name: "BROWSE_POOL",
|
|
30
30
|
value: BROWSE_POOL
|
|
31
31
|
});
|
|
32
|
-
if (BROWSE_VIEWPORT !== void 0 && BROWSE_VIEWPORT !== "" && viewport === void 0) throw new BrowserError(`BROWSE_VIEWPORT must be positive integers in WIDTHxHEIGHT form, not ${JSON.stringify(BROWSE_VIEWPORT)}`,
|
|
32
|
+
if (BROWSE_VIEWPORT !== void 0 && BROWSE_VIEWPORT !== "" && viewport === void 0) throw new BrowserError("SERVER_ENVIRONMENT", `BROWSE_VIEWPORT must be positive integers in WIDTHxHEIGHT form, not ${JSON.stringify(BROWSE_VIEWPORT)}`, {
|
|
33
33
|
name: "BROWSE_VIEWPORT",
|
|
34
34
|
value: BROWSE_VIEWPORT
|
|
35
35
|
});
|
|
36
|
-
if (BROWSE_CONTEXTS !== void 0 && BROWSE_CONTEXTS !== "" && contexts === void 0) throw new BrowserError(`BROWSE_CONTEXTS must be an integer, not ${JSON.stringify(BROWSE_CONTEXTS)}`,
|
|
36
|
+
if (BROWSE_CONTEXTS !== void 0 && BROWSE_CONTEXTS !== "" && contexts === void 0) throw new BrowserError("SERVER_ENVIRONMENT", `BROWSE_CONTEXTS must be an integer, not ${JSON.stringify(BROWSE_CONTEXTS)}`, {
|
|
37
37
|
name: "BROWSE_CONTEXTS",
|
|
38
38
|
value: BROWSE_CONTEXTS
|
|
39
39
|
});
|
|
40
40
|
await createBrowserMCPServer({
|
|
41
41
|
...BROWSE_ROOT === void 0 || BROWSE_ROOT === "" ? {} : { root: BROWSE_ROOT },
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
browser: {
|
|
43
|
+
...headless === void 0 ? {} : { headless },
|
|
44
|
+
...BROWSE_EXECUTABLE === void 0 || BROWSE_EXECUTABLE === "" ? {} : { executable: BROWSE_EXECUTABLE },
|
|
45
|
+
...viewport === void 0 ? {} : { viewport }
|
|
46
|
+
},
|
|
47
|
+
journeys: { ...readonly === void 0 ? {} : { readonly } },
|
|
45
48
|
pool: {
|
|
46
49
|
...size === void 0 ? {} : { size },
|
|
47
50
|
...contexts === void 0 ? {} : { contexts }
|
|
48
|
-
}
|
|
49
|
-
...viewport === void 0 ? {} : { viewport }
|
|
51
|
+
}
|
|
50
52
|
}).start();
|
|
51
53
|
} catch (error) {
|
|
52
54
|
if (!isBrowserError(error)) throw error;
|
package/dist/bin/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","names":[],"sources":["../../src/bin/main.ts"],"sourcesContent":["import { parseBoolean, parseInteger } from '@orkestrel/contract'\nimport { BrowserError, isBrowserError } from '@src/core'\nimport { createBrowserMCPServer, parseBrowserViewport } from '@src/server'\n\n// The entry owns stderr; a closed reader must not interrupt the server's teardown barrier.\nprocess.stderr.on('error', () => {\n\tprocess.exitCode = 1\n})\n\ntry {\n\tconst {\n\t\tBROWSE_ROOT,\n\t\tBROWSE_HEADLESS,\n\t\tBROWSE_EXECUTABLE,\n\t\tBROWSE_READONLY,\n\t\tBROWSE_POOL,\n\t\tBROWSE_CONTEXTS,\n\t\tBROWSE_VIEWPORT,\n\t} = process.env\n\tconst headless = parseBoolean(BROWSE_HEADLESS)\n\tconst readonly = parseBoolean(BROWSE_READONLY)\n\tconst size = parseInteger(BROWSE_POOL)\n\tconst contexts = parseInteger(BROWSE_CONTEXTS)\n\tconst viewport = parseBrowserViewport(BROWSE_VIEWPORT)\n\t// An empty variable counts as unset, as a shell's `NAME=` leaves it.\n\tfor (const [name, value, parsed] of [\n\t\t['BROWSE_HEADLESS', BROWSE_HEADLESS, headless],\n\t\t['BROWSE_READONLY', BROWSE_READONLY, readonly],\n\t] as const) {\n\t\tif (value !== undefined && value !== '' && parsed === undefined) {\n\t\t\tthrow new BrowserError(\n\t\t\t\t`${name} must be true, false, 1, or 0, not ${JSON.stringify(value)}`,\n\t\t\t\t
|
|
1
|
+
{"version":3,"file":"main.js","names":[],"sources":["../../src/bin/main.ts"],"sourcesContent":["import { parseBoolean, parseInteger } from '@orkestrel/contract'\nimport { BrowserError, isBrowserError } from '@src/core'\nimport { createBrowserMCPServer, parseBrowserViewport } from '@src/server'\n\n// The entry owns stderr; a closed reader must not interrupt the server's teardown barrier.\nprocess.stderr.on('error', () => {\n\tprocess.exitCode = 1\n})\n\ntry {\n\tconst {\n\t\tBROWSE_ROOT,\n\t\tBROWSE_HEADLESS,\n\t\tBROWSE_EXECUTABLE,\n\t\tBROWSE_READONLY,\n\t\tBROWSE_POOL,\n\t\tBROWSE_CONTEXTS,\n\t\tBROWSE_VIEWPORT,\n\t} = process.env\n\tconst headless = parseBoolean(BROWSE_HEADLESS)\n\tconst readonly = parseBoolean(BROWSE_READONLY)\n\tconst size = parseInteger(BROWSE_POOL)\n\tconst contexts = parseInteger(BROWSE_CONTEXTS)\n\tconst viewport = parseBrowserViewport(BROWSE_VIEWPORT)\n\t// An empty variable counts as unset, as a shell's `NAME=` leaves it.\n\tfor (const [name, value, parsed] of [\n\t\t['BROWSE_HEADLESS', BROWSE_HEADLESS, headless],\n\t\t['BROWSE_READONLY', BROWSE_READONLY, readonly],\n\t] as const) {\n\t\tif (value !== undefined && value !== '' && parsed === undefined) {\n\t\t\tthrow new BrowserError(\n\t\t\t\t'SERVER_ENVIRONMENT',\n\t\t\t\t`${name} must be true, false, 1, or 0, not ${JSON.stringify(value)}`,\n\t\t\t\t{ name, value },\n\t\t\t)\n\t\t}\n\t}\n\tif (BROWSE_POOL !== undefined && BROWSE_POOL !== '' && size === undefined)\n\t\tthrow new BrowserError(\n\t\t\t'SERVER_ENVIRONMENT',\n\t\t\t`BROWSE_POOL must be an integer, not ${JSON.stringify(BROWSE_POOL)}`,\n\t\t\t{ name: 'BROWSE_POOL', value: BROWSE_POOL },\n\t\t)\n\tif (BROWSE_VIEWPORT !== undefined && BROWSE_VIEWPORT !== '' && viewport === undefined)\n\t\tthrow new BrowserError(\n\t\t\t'SERVER_ENVIRONMENT',\n\t\t\t`BROWSE_VIEWPORT must be positive integers in WIDTHxHEIGHT form, not ${JSON.stringify(BROWSE_VIEWPORT)}`,\n\t\t\t{ name: 'BROWSE_VIEWPORT', value: BROWSE_VIEWPORT },\n\t\t)\n\tif (BROWSE_CONTEXTS !== undefined && BROWSE_CONTEXTS !== '' && contexts === undefined)\n\t\tthrow new BrowserError(\n\t\t\t'SERVER_ENVIRONMENT',\n\t\t\t`BROWSE_CONTEXTS must be an integer, not ${JSON.stringify(BROWSE_CONTEXTS)}`,\n\t\t\t{ name: 'BROWSE_CONTEXTS', value: BROWSE_CONTEXTS },\n\t\t)\n\tawait createBrowserMCPServer({\n\t\t...(BROWSE_ROOT === undefined || BROWSE_ROOT === '' ? {} : { root: BROWSE_ROOT }),\n\t\tbrowser: {\n\t\t\t...(headless === undefined ? {} : { headless }),\n\t\t\t...(BROWSE_EXECUTABLE === undefined || BROWSE_EXECUTABLE === ''\n\t\t\t\t? {}\n\t\t\t\t: { executable: BROWSE_EXECUTABLE }),\n\t\t\t...(viewport === undefined ? {} : { viewport }),\n\t\t},\n\t\tjourneys: { ...(readonly === undefined ? {} : { readonly }) },\n\t\tpool: {\n\t\t\t...(size === undefined ? {} : { size }),\n\t\t\t...(contexts === undefined ? {} : { contexts }),\n\t\t},\n\t}).start()\n} catch (error) {\n\tif (!isBrowserError(error)) throw error\n\tconsole.error(`browse: ${error.code}: ${error.message.split(/\\r\\n|\\n/u).join(' ')}`)\n\tprocess.exitCode = 1\n}\n"],"mappings":";;;;;AAKA,QAAQ,OAAO,GAAG,eAAe;CAChC,QAAQ,WAAW;AACpB,CAAC;AAED,IAAI;CACH,MAAM,EACL,aACA,iBACA,mBACA,iBACA,aACA,iBACA,oBACG,QAAQ;CACZ,MAAM,WAAW,aAAa,eAAe;CAC7C,MAAM,WAAW,aAAa,eAAe;CAC7C,MAAM,OAAO,aAAa,WAAW;CACrC,MAAM,WAAW,aAAa,eAAe;CAC7C,MAAM,WAAW,qBAAqB,eAAe;CAErD,KAAK,MAAM,CAAC,MAAM,OAAO,WAAW,CACnC;EAAC;EAAmB;EAAiB;CAAQ,GAC7C;EAAC;EAAmB;EAAiB;CAAQ,CAC9C,GACC,IAAI,UAAU,KAAA,KAAa,UAAU,MAAM,WAAW,KAAA,GACrD,MAAM,IAAI,aACT,sBACA,GAAG,KAAK,qCAAqC,KAAK,UAAU,KAAK,KACjE;EAAE;EAAM;CAAM,CACf;CAGF,IAAI,gBAAgB,KAAA,KAAa,gBAAgB,MAAM,SAAS,KAAA,GAC/D,MAAM,IAAI,aACT,sBACA,uCAAuC,KAAK,UAAU,WAAW,KACjE;EAAE,MAAM;EAAe,OAAO;CAAY,CAC3C;CACD,IAAI,oBAAoB,KAAA,KAAa,oBAAoB,MAAM,aAAa,KAAA,GAC3E,MAAM,IAAI,aACT,sBACA,uEAAuE,KAAK,UAAU,eAAe,KACrG;EAAE,MAAM;EAAmB,OAAO;CAAgB,CACnD;CACD,IAAI,oBAAoB,KAAA,KAAa,oBAAoB,MAAM,aAAa,KAAA,GAC3E,MAAM,IAAI,aACT,sBACA,2CAA2C,KAAK,UAAU,eAAe,KACzE;EAAE,MAAM;EAAmB,OAAO;CAAgB,CACnD;CACD,MAAM,uBAAuB;EAC5B,GAAI,gBAAgB,KAAA,KAAa,gBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,YAAY;EAC/E,SAAS;GACR,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS;GAC7C,GAAI,sBAAsB,KAAA,KAAa,sBAAsB,KAC1D,CAAC,IACD,EAAE,YAAY,kBAAkB;GACnC,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS;EAC9C;EACA,UAAU,EAAE,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,EAAG;EAC5D,MAAM;GACL,GAAI,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,KAAK;GACrC,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS;EAC9C;CACD,CAAC,CAAC,CAAC,MAAM;AACV,SAAS,OAAO;CACf,IAAI,CAAC,eAAe,KAAK,GAAG,MAAM;CAClC,QAAQ,MAAM,WAAW,MAAM,KAAK,IAAI,MAAM,QAAQ,MAAM,UAAU,CAAC,CAAC,KAAK,GAAG,GAAG;CACnF,QAAQ,WAAW;AACpB"}
|
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import type { BrowserCallOptions } from '@orkestrel/browser';
|
|
2
2
|
import type { BrowserElementInterface } from '@orkestrel/browser';
|
|
3
3
|
import type { BrowserElementManagerInterface } from '@orkestrel/browser';
|
|
4
|
-
import type { BrowserElementQuery } from '@orkestrel/browser';
|
|
5
|
-
import type { BrowserEpochFunction } from '@orkestrel/browser';
|
|
6
|
-
import type { BrowserOutline } from '@orkestrel/browser';
|
|
7
|
-
import type { BrowserOutlineOptions } from '@orkestrel/browser';
|
|
8
4
|
import type { BrowserReadingInput } from '@orkestrel/browser';
|
|
9
5
|
import type { BrowserReadingInterface } from '@orkestrel/browser';
|
|
10
|
-
import type { BrowserToolsetInterface } from '@orkestrel/browser';
|
|
11
|
-
import type { BrowserToolsetOptions } from '@orkestrel/browser';
|
|
12
6
|
import type { BrowserViewInterface } from '@orkestrel/browser';
|
|
13
7
|
import type { BrowserWaitOptions } from '@orkestrel/browser';
|
|
14
8
|
import type { CDPTransportEventMap } from '@orkestrel/browser';
|
|
@@ -77,82 +71,6 @@ export declare const BROWSER_SELECTED_ROLES: ReadonlySet<string>;
|
|
|
77
71
|
/** Names the `input` type states whose value an untrusted `fill` sets as typed text. */
|
|
78
72
|
export declare const BROWSER_TYPED_INPUTS: ReadonlySet<string>;
|
|
79
73
|
|
|
80
|
-
/**
|
|
81
|
-
* Configures a toolset that drives one browser document.
|
|
82
|
-
*
|
|
83
|
-
* @remarks
|
|
84
|
-
* - `document` and `own` — the driven document and the admission of the realm's own document, as
|
|
85
|
-
* {@link BrowserDOMViewOptions} describes them
|
|
86
|
-
* - `source` — a source of page tools, such as `@orkestrel/mcp`'s model context bridge; the
|
|
87
|
-
* toolset adopts its tools and re-adopts on its `change`. Default: no page tools
|
|
88
|
-
* - `tools`, `limit`, `journeys`, `on`, and `error` — as {@link BrowserToolsetOptions}
|
|
89
|
-
* describes them
|
|
90
|
-
*/
|
|
91
|
-
export declare interface BrowserDocumentToolsetOptions extends BrowserDOMViewOptions, Pick<BrowserToolsetOptions, 'on' | 'error' | 'tools' | 'source' | 'limit' | 'journeys'> {
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Drives a referenced element of a DOM document without trusted input.
|
|
96
|
-
*
|
|
97
|
-
* @remarks
|
|
98
|
-
* `click` runs `HTMLElement.click()`; `fill` and `select` set the control through its native
|
|
99
|
-
* prototype setter and dispatch `input` and `change`, and `fill` refuses `UNKNOWN` an element
|
|
100
|
-
* that is not a text control and a read-only one; `submit` runs `form.requestSubmit()` and
|
|
101
|
-
* observes the outcome through a `submit` listener registered across the call. Each action
|
|
102
|
-
* refuses with a `BrowserElementError` naming the reason: `DISABLED` for a disabled control,
|
|
103
|
-
* `HIDDEN` for an element that does not render, and `UNTRUSTED` for what an untrusted event
|
|
104
|
-
* cannot do, which is a click or submission that opens another browsing context, a click that
|
|
105
|
-
* opens a file chooser, and typing into a contenteditable element. A click that activates a
|
|
106
|
-
* `label`, on the label itself or on a descendant that `matchesBrowserActivation` admits, is
|
|
107
|
-
* judged by the label's control as well: a disabled control refuses `DISABLED`, and a file input
|
|
108
|
-
* refuses `UNTRUSTED` as a direct click on it does. A click on an interactive descendant of a
|
|
109
|
-
* label keeps only its own checks. `role` and `name` read the description the latest outline or
|
|
110
|
-
* query that encountered the element captured, so a change to the element shows after the next
|
|
111
|
-
* capture, and a dropped reference keeps its last capture. Every action on an element removed
|
|
112
|
-
* from its document, collected, or held across a navigation reports `GONE`.
|
|
113
|
-
*
|
|
114
|
-
* @example
|
|
115
|
-
* ```ts
|
|
116
|
-
* const view = createBrowserDOMView({ document: frame.contentDocument })
|
|
117
|
-
* await view.elements.outline()
|
|
118
|
-
* await view.elements.element('e1')?.click()
|
|
119
|
-
* ```
|
|
120
|
-
*/
|
|
121
|
-
export declare class BrowserDOMElement implements BrowserDOMElementInterface {
|
|
122
|
-
#private;
|
|
123
|
-
constructor(input: BrowserDOMElementInput);
|
|
124
|
-
get reference(): string;
|
|
125
|
-
get role(): string;
|
|
126
|
-
get name(): string;
|
|
127
|
-
click(options?: BrowserCallOptions): Promise<void>;
|
|
128
|
-
fill(value: string, options?: BrowserCallOptions): Promise<void>;
|
|
129
|
-
select(values: readonly string[], options?: BrowserCallOptions): Promise<void>;
|
|
130
|
-
focus(options?: BrowserCallOptions): Promise<void>;
|
|
131
|
-
read(options?: BrowserCallOptions): Promise<BrowserReadingInterface>;
|
|
132
|
-
submit(options?: BrowserCallOptions): Promise<void>;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Binds a DOM element to its reference and the manager that minted it.
|
|
137
|
-
*
|
|
138
|
-
* @remarks
|
|
139
|
-
* - `reference` — the reference the manager minted for the element
|
|
140
|
-
* - `description` — returns the role and accessible name the latest capture that encountered
|
|
141
|
-
* the element recorded; after the manager drops the reference it keeps returning that capture
|
|
142
|
-
* - `node` — a weak reference to the element the reference names, so a removed element can be
|
|
143
|
-
* collected; an element that no longer dereferences reports `GONE`
|
|
144
|
-
* - `current` — true while the manager still holds the reference; false otherwise
|
|
145
|
-
* - `navigation` — reads the epoch of the element's own document, which every reading records;
|
|
146
|
-
* it advances when that document or the view's document navigates
|
|
147
|
-
*/
|
|
148
|
-
export declare interface BrowserDOMElementInput {
|
|
149
|
-
readonly reference: string;
|
|
150
|
-
readonly description: () => Pick<BrowserElementInterface, 'role' | 'name'>;
|
|
151
|
-
readonly node: WeakRef<Element>;
|
|
152
|
-
readonly current: () => boolean;
|
|
153
|
-
readonly navigation: BrowserEpochFunction;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
74
|
/**
|
|
157
75
|
* Provides DOM actions through a stable element reference, without trusted input.
|
|
158
76
|
*
|
|
@@ -165,71 +83,6 @@ export declare interface BrowserDOMElementInput {
|
|
|
165
83
|
export declare interface BrowserDOMElementInterface extends BrowserElementInterface {
|
|
166
84
|
}
|
|
167
85
|
|
|
168
|
-
/**
|
|
169
|
-
* Outlines a DOM document from its elements and binds stable references to the interactive ones.
|
|
170
|
-
*
|
|
171
|
-
* @remarks
|
|
172
|
-
* Rows come in document order from a `TreeWalker` over the flat tree: an open shadow root
|
|
173
|
-
* contributes its rows in place of its host's children, a `slot` its assigned nodes, and a
|
|
174
|
-
* same-origin `iframe` its document's rows, while a cross-origin one renders
|
|
175
|
-
* `iframe "NAME" (cross-origin, not readable)`. An element that `matchesBrowserHidden` reports is
|
|
176
|
-
* omitted with its subtree, a scope root in such a subtree yields no row, and an element that
|
|
177
|
-
* `matchesBrowserInvisible` reports yields no row of its own. An element whose role
|
|
178
|
-
* `BROWSER_INTERACTIVE_ROLES` names receives a reference bound through a `WeakRef`, which never
|
|
179
|
-
* changes while the manager holds it, and a reference number is never reused. Every outline or
|
|
180
|
-
* query that encounters a bound element records its role and name afresh, and the element's
|
|
181
|
-
* wrapper reports that latest capture, also after the manager drops the reference. A reference
|
|
182
|
-
* and a reading from any walked document record that document's epoch, which advances on its own
|
|
183
|
-
* navigation events and on the view's; that document's `pagehide` drops its references. A form
|
|
184
|
-
* carrying a `toolname` attribute renders `[tool=NAME]` after its role and name. A row carries
|
|
185
|
-
* `focused` when its element is the active element of its own document or shadow root. Rows carry
|
|
186
|
-
* pressed, expanded, and selected states through the Chromium mapping in `readBrowserStates`.
|
|
187
|
-
* A `select` row is followed by one `option` row per option, named by its label. Whitespace between two texts of
|
|
188
|
-
* one block renders as one space, as a rendered `br` between them does, and texts with neither
|
|
189
|
-
* between them stay joined. A CSS query
|
|
190
|
-
* searches the document the view drives, not its child documents or shadow trees. After the
|
|
191
|
-
* input's `signal` aborts, `outline`, `find`, and `wait` reject with its reason.
|
|
192
|
-
*
|
|
193
|
-
* `wait` parks a `BrowserDOMWait` bound to the view's lifetime over every root that
|
|
194
|
-
* `collectBrowserRoots` reaches from its scope, reconciled at every observed mutation and frame
|
|
195
|
-
* `load`. A shadow root attached after the wait began is a declared limit: the wait discovers it
|
|
196
|
-
* at the next observed mutation or `load`, so a match inserted there with no other observed
|
|
197
|
-
* change is not seen before the deadline.
|
|
198
|
-
*
|
|
199
|
-
* @example
|
|
200
|
-
* ```ts
|
|
201
|
-
* const view = createBrowserDOMView({ document: frame.contentDocument })
|
|
202
|
-
* const outline = await view.elements.outline()
|
|
203
|
-
* const [save] = await view.elements.find({ role: 'button', name: 'save' })
|
|
204
|
-
* ```
|
|
205
|
-
*/
|
|
206
|
-
export declare class BrowserDOMElementManager implements BrowserElementManagerInterface<BrowserDOMElementInterface> {
|
|
207
|
-
#private;
|
|
208
|
-
constructor(input: BrowserDOMElementManagerInput);
|
|
209
|
-
outline(options?: BrowserOutlineOptions): Promise<BrowserOutline>;
|
|
210
|
-
find(query: BrowserElementQuery, options?: BrowserCallOptions): Promise<readonly BrowserDOMElementInterface[]>;
|
|
211
|
-
wait(query: BrowserElementQuery, options?: BrowserWaitOptions): Promise<readonly BrowserDOMElementInterface[]>;
|
|
212
|
-
element(reference: string): BrowserDOMElementInterface | undefined;
|
|
213
|
-
elements(): readonly BrowserDOMElementInterface[];
|
|
214
|
-
clear(): void;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Binds a DOM element manager to the view that owns it.
|
|
219
|
-
*
|
|
220
|
-
* @remarks
|
|
221
|
-
* - `document` — returns the document the view drives at the moment of the call
|
|
222
|
-
* - `navigation` — reads the view's navigation epoch, which every reading records
|
|
223
|
-
* - `signal` — the view's lifetime; it aborts when the view is destroyed, every wait and
|
|
224
|
-
* navigation listener the manager starts ends with it, and after it aborts `outline`, `find`,
|
|
225
|
-
* and `wait` reject with its reason
|
|
226
|
-
*/
|
|
227
|
-
export declare interface BrowserDOMElementManagerInput {
|
|
228
|
-
readonly document: () => Document;
|
|
229
|
-
readonly navigation: BrowserEpochFunction;
|
|
230
|
-
readonly signal: AbortSignal;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
86
|
/**
|
|
234
87
|
* Reads and drives a DOM document from a realm that can reach it, without trusted input.
|
|
235
88
|
*
|
|
@@ -242,7 +95,7 @@ export declare interface BrowserDOMElementManagerInput {
|
|
|
242
95
|
* fires none of those events, so a reading there stays current across it. A cross-document
|
|
243
96
|
* navigation also clears every element reference. `destroy()` releases the listeners and every
|
|
244
97
|
* reference, and fails every pending wait with a `BrowserError` coded
|
|
245
|
-
* `
|
|
98
|
+
* `DOCUMENT_DESTROYED`; after it, `title()`, `read()`, `wait()`, and the element manager's
|
|
246
99
|
* `outline()`, `find()`, and `wait()` reject with that error, and a second `destroy()` does
|
|
247
100
|
* nothing more. `trusted` is `false`: no action grants user activation, and
|
|
248
101
|
* every event the view's actions dispatch themselves carries `isTrusted` `false`. The `submit`
|
|
@@ -302,7 +155,7 @@ export declare interface BrowserDOMViewOptions {
|
|
|
302
155
|
* again after every subscription, and no check runs once the deadline, counted from `start`, has
|
|
303
156
|
* passed, which the wait reads again after `roots` returns. The wait settles one time: on the
|
|
304
157
|
* check's first value, on the signal's abort with its reason, at the deadline with
|
|
305
|
-
* `
|
|
158
|
+
* `TIMEOUT`, on a `pagehide` in the first root's window with `GONE`, or with whatever
|
|
306
159
|
* the check or the roots function throws. A signal that aborts while `check` or `roots` runs
|
|
307
160
|
* settles the wait with its reason, and wins over a value that same check returns. Settlement
|
|
308
161
|
* disconnects every observer and removes every listener synchronously, so a mutation queued
|
|
@@ -506,8 +359,8 @@ export declare function computeBrowserText(root: Element | ShadowRoot, context?:
|
|
|
506
359
|
* @param options - The driven document, and `own` to admit the realm's own document
|
|
507
360
|
* @returns A {@link BrowserDOMViewInterface} over the document's window
|
|
508
361
|
* @throws Thrown when `document` is not a document attached to a window, with the code
|
|
509
|
-
* `
|
|
510
|
-
* `
|
|
362
|
+
* `DOCUMENT`, and when it is `globalThis.document` without `own: true`, with the code
|
|
363
|
+
* `DOCUMENT_OWN`.
|
|
511
364
|
*
|
|
512
365
|
* @example
|
|
513
366
|
* ```ts
|
|
@@ -519,37 +372,6 @@ export declare function computeBrowserText(root: Element | ShadowRoot, context?:
|
|
|
519
372
|
*/
|
|
520
373
|
export declare function createBrowserDOMView(options: BrowserDOMViewOptions): BrowserDOMViewInterface;
|
|
521
374
|
|
|
522
|
-
/**
|
|
523
|
-
* Creates a `BrowserToolsetInterface` that publishes the five view tools over a DOM document and
|
|
524
|
-
* adopts a source's page tools beside them.
|
|
525
|
-
*
|
|
526
|
-
* @remarks
|
|
527
|
-
* The toolset runs over a view {@link createBrowserDOMView} creates for `document`, so it
|
|
528
|
-
* advertises `look`, `read`, `plain`, `click`, `type`, and `wait`, and a click or type receipt ends with
|
|
529
|
-
* ` (untrusted event)`. `source` supplies page tools, which the toolset adopts during `start()`
|
|
530
|
-
* and again on every `change`; `toolset.native` never includes them, so publishing it to a
|
|
531
|
-
* registry leaves that registry's own tools alone. The view belongs to the toolset: `destroy()`
|
|
532
|
-
* removes the toolset's tools, then destroys the view, which releases its listeners and fails
|
|
533
|
-
* its pending waits, and a construction that throws destroys the view before it rethrows.
|
|
534
|
-
* `journeys` adds `record`, `save`, `journeys`, `edit`, and `replay` at construction; a replay
|
|
535
|
-
* runs the steps the document placement executes.
|
|
536
|
-
*
|
|
537
|
-
* @param options - The driven document, `own`, the page-tool source, the manager, the bound, the
|
|
538
|
-
* journey stores, and the emitter hooks
|
|
539
|
-
* @returns A {@link BrowserToolsetInterface} whose `view` drives the document
|
|
540
|
-
* @throws Thrown when `document` is not a document attached to a window, with the code
|
|
541
|
-
* `BROWSER_DOCUMENT`, when it is `globalThis.document` without `own: true`, with the code
|
|
542
|
-
* `BROWSER_DOCUMENT_OWN`, and when `limit` is not a positive integer.
|
|
543
|
-
*
|
|
544
|
-
* @example
|
|
545
|
-
* ```ts
|
|
546
|
-
* const toolset = createDocumentToolset({ document: frame.contentDocument, source: bridge })
|
|
547
|
-
* await toolset.start()
|
|
548
|
-
* await toolset.tools.execute({ id: '1', name: 'look', arguments: { search: 'form' } })
|
|
549
|
-
* ```
|
|
550
|
-
*/
|
|
551
|
-
export declare function createDocumentToolset(options: BrowserDocumentToolsetOptions): BrowserToolsetInterface;
|
|
552
|
-
|
|
553
375
|
/**
|
|
554
376
|
* Creates a CDP transport over the browser's native `WebSocket`.
|
|
555
377
|
*
|
|
@@ -752,7 +574,7 @@ export declare function readBrowserBlock(element: Element | null, root: Node): N
|
|
|
752
574
|
* @param node - The root whose rendered markup is captured; its owner document supplies `URL`
|
|
753
575
|
* and `title`
|
|
754
576
|
* @returns The capture's `url`, `title`, and `html`
|
|
755
|
-
* @throws Thrown as a `
|
|
577
|
+
* @throws Thrown as a `BrowserError` when the serialized capture is longer than
|
|
756
578
|
* `BROWSER_RESULT_LIMIT` characters, with `length` and `limit` in its context.
|
|
757
579
|
*/
|
|
758
580
|
export declare function readBrowserCapture(node: Element): BrowserReadingInput;
|
|
@@ -855,7 +677,7 @@ export declare function skipBrowserSubtree(walker: TreeWalker): Node | null;
|
|
|
855
677
|
* Provides a raw CDP text transport over the browser's native `WebSocket`.
|
|
856
678
|
*
|
|
857
679
|
* @remarks
|
|
858
|
-
* `start()` resolves on the socket's `open` event and rejects with a `
|
|
680
|
+
* `start()` resolves on the socket's `open` event and rejects with a `BrowserError`
|
|
859
681
|
* carrying `url` for a URL whose scheme is not `ws:` or `wss:`, for a URL the `WebSocket`
|
|
860
682
|
* constructor refuses (one with a fragment), for a socket that fails or closes before it opens,
|
|
861
683
|
* and at the `timeout` deadline. Concurrent and repeated `start()` and `close()`
|