@ap3x/browser 0.1.0
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/LICENSE +21 -0
- package/README.md +30 -0
- package/dist/cdp/connection.d.ts +53 -0
- package/dist/cdp/connection.d.ts.map +1 -0
- package/dist/cdp/endpoint.d.ts +18 -0
- package/dist/cdp/endpoint.d.ts.map +1 -0
- package/dist/cdp/reconnect.d.ts +22 -0
- package/dist/cdp/reconnect.d.ts.map +1 -0
- package/dist/chunk-DXCP25KX.js +77 -0
- package/dist/config.d.ts +91 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/dialogs/handler.d.ts +43 -0
- package/dist/dialogs/handler.d.ts.map +1 -0
- package/dist/dom/clickability.d.ts +4 -0
- package/dist/dom/clickability.d.ts.map +1 -0
- package/dist/dom/compound.d.ts +4 -0
- package/dist/dom/compound.d.ts.map +1 -0
- package/dist/dom/constants.d.ts +28 -0
- package/dist/dom/constants.d.ts.map +1 -0
- package/dist/dom/dom-service.d.ts +65 -0
- package/dist/dom/dom-service.d.ts.map +1 -0
- package/dist/dom/enhanced-tree.d.ts +52 -0
- package/dist/dom/enhanced-tree.d.ts.map +1 -0
- package/dist/dom/hashing.d.ts +21 -0
- package/dist/dom/hashing.d.ts.map +1 -0
- package/dist/dom/node.d.ts +43 -0
- package/dist/dom/node.d.ts.map +1 -0
- package/dist/dom/overlay.d.ts +11 -0
- package/dist/dom/overlay.d.ts.map +1 -0
- package/dist/dom/paint-order.d.ts +25 -0
- package/dist/dom/paint-order.d.ts.map +1 -0
- package/dist/dom/serialize-text.d.ts +16 -0
- package/dist/dom/serialize-text.d.ts.map +1 -0
- package/dist/dom/serializer.d.ts +33 -0
- package/dist/dom/serializer.d.ts.map +1 -0
- package/dist/dom/snapshot.d.ts +37 -0
- package/dist/dom/snapshot.d.ts.map +1 -0
- package/dist/dom/types.d.ts +178 -0
- package/dist/dom/types.d.ts.map +1 -0
- package/dist/downloads/sanitize.d.ts +13 -0
- package/dist/downloads/sanitize.d.ts.map +1 -0
- package/dist/driver.d.ts +88 -0
- package/dist/driver.d.ts.map +1 -0
- package/dist/errors.d.ts +71 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/events.d.ts +8 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5066 -0
- package/dist/input/dispatcher.d.ts +196 -0
- package/dist/input/dispatcher.d.ts.map +1 -0
- package/dist/input/keys.d.ts +20 -0
- package/dist/input/keys.d.ts.map +1 -0
- package/dist/launch/discovery.d.ts +14 -0
- package/dist/launch/discovery.d.ts.map +1 -0
- package/dist/launch/local-browser.d.ts +59 -0
- package/dist/launch/local-browser.d.ts.map +1 -0
- package/dist/navigation/navigator.d.ts +37 -0
- package/dist/navigation/navigator.d.ts.map +1 -0
- package/dist/navigation/policy.d.ts +61 -0
- package/dist/navigation/policy.d.ts.map +1 -0
- package/dist/providers/cloak.d.ts +26 -0
- package/dist/providers/cloak.d.ts.map +1 -0
- package/dist/providers/factory.d.ts +17 -0
- package/dist/providers/factory.d.ts.map +1 -0
- package/dist/providers/index.d.ts +5 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/local.d.ts +13 -0
- package/dist/providers/local.d.ts.map +1 -0
- package/dist/providers/types.d.ts +8 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/recording/har.d.ts +94 -0
- package/dist/recording/har.d.ts.map +1 -0
- package/dist/recording/screencast.d.ts +40 -0
- package/dist/recording/screencast.d.ts.map +1 -0
- package/dist/screenshot/service.d.ts +34 -0
- package/dist/screenshot/service.d.ts.map +1 -0
- package/dist/session.d.ts +130 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/targets/registry.d.ts +99 -0
- package/dist/targets/registry.d.ts.map +1 -0
- package/dist/testing.d.ts +53 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +8 -0
- package/dist/types.d.ts +88 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +42 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AP3X
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# @ap3x/browser
|
|
2
|
+
|
|
3
|
+
Primitives for driving Chromium over the Chrome DevTools Protocol: sessions, navigation, DOM extraction, input, screenshots, and recording.
|
|
4
|
+
|
|
5
|
+
Part of [AP3X](https://github.com/AP3X-Dev/AP3X) — a TypeScript multi-agent framework.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @ap3x/browser
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## What's inside
|
|
14
|
+
|
|
15
|
+
- **`openBrowserSession(config)`** — the entry point; resolves to a local launch or a remote CDP endpoint.
|
|
16
|
+
- **CDP transport** — typed protocol access with a target registry and reconnect handling.
|
|
17
|
+
- **DOM** — extraction, serialization, clickability and paint-order analysis, and stable element hashing.
|
|
18
|
+
- **Navigation** — a navigation policy with domain allow-lists and IP-blocking rules.
|
|
19
|
+
- **Input** — human-like input dispatch with dialog resilience.
|
|
20
|
+
- **Capture** — screenshots, HAR recording, and screencast.
|
|
21
|
+
|
|
22
|
+
The agent that drives these lives in [`@ap3x/browser-agent`](https://www.npmjs.com/package/@ap3x/browser-agent).
|
|
23
|
+
|
|
24
|
+
## Documentation
|
|
25
|
+
|
|
26
|
+
See the [AP3X repository](https://github.com/AP3X-Dev/AP3X) for architecture notes, the full package map, and examples.
|
|
27
|
+
|
|
28
|
+
## License
|
|
29
|
+
|
|
30
|
+
MIT
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { CdpConnectionError } from "../errors";
|
|
2
|
+
import type { CdpCommand, CdpCommandParams, CdpCommandReturn, CdpEventListener, CdpEventName, CdpSendOptions, CdpTransport } from "../types";
|
|
3
|
+
/**
|
|
4
|
+
* The minimal socket surface {@link CdpConnection} needs. `ws` is adapted to it
|
|
5
|
+
* by {@link openWebSocket}; tests inject a fake so no real browser is required.
|
|
6
|
+
*/
|
|
7
|
+
export interface CdpSocket {
|
|
8
|
+
send(data: string): void;
|
|
9
|
+
close(): void;
|
|
10
|
+
onMessage(cb: (data: string) => void): void;
|
|
11
|
+
onClose(cb: () => void): void;
|
|
12
|
+
onError(cb: (err: Error) => void): void;
|
|
13
|
+
}
|
|
14
|
+
export interface OpenWebSocketOptions {
|
|
15
|
+
headers?: Record<string, string>;
|
|
16
|
+
maxPayload?: number;
|
|
17
|
+
signal?: AbortSignal;
|
|
18
|
+
}
|
|
19
|
+
/** Open a real `ws` WebSocket and adapt it to {@link CdpSocket}. */
|
|
20
|
+
export declare function openWebSocket(url: string, options?: OpenWebSocketOptions): Promise<CdpSocket>;
|
|
21
|
+
export interface CdpConnectionOptions {
|
|
22
|
+
/** Default per-request timeout in ms (default 60000). */
|
|
23
|
+
defaultTimeoutMs?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Debug-level diagnostic sink (e.g. a dropped malformed frame). Default:
|
|
26
|
+
* silent — this is a library, not a host; callers opt in.
|
|
27
|
+
*/
|
|
28
|
+
onDebug?: (message: string, fields?: Record<string, unknown>) => void;
|
|
29
|
+
}
|
|
30
|
+
export declare class CdpConnection implements CdpTransport {
|
|
31
|
+
private readonly socket;
|
|
32
|
+
private nextId;
|
|
33
|
+
private readonly pending;
|
|
34
|
+
private readonly registrations;
|
|
35
|
+
private readonly disconnectListeners;
|
|
36
|
+
private readonly defaultTimeoutMs;
|
|
37
|
+
private readonly onDebug;
|
|
38
|
+
private closedError;
|
|
39
|
+
private intentional;
|
|
40
|
+
constructor(socket: CdpSocket, options?: CdpConnectionOptions);
|
|
41
|
+
/** Open a live connection to a `ws://` DevTools endpoint. */
|
|
42
|
+
static connect(wsUrl: string, options?: CdpConnectionOptions & OpenWebSocketOptions): Promise<CdpConnection>;
|
|
43
|
+
get isClosed(): boolean;
|
|
44
|
+
/** Fired once when the socket drops unexpectedly (not on {@link close}). */
|
|
45
|
+
onDisconnect(cb: (err: CdpConnectionError) => void): () => void;
|
|
46
|
+
send<T extends CdpCommand>(method: T, params?: CdpCommandParams<T>, options?: CdpSendOptions): Promise<CdpCommandReturn<T>>;
|
|
47
|
+
on<M extends CdpEventName>(method: M, listener: CdpEventListener<M>, sessionId?: string): () => void;
|
|
48
|
+
close(): Promise<void>;
|
|
49
|
+
private handleMessage;
|
|
50
|
+
private dispatchEvent;
|
|
51
|
+
private handleClose;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=connection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/cdp/connection.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,KAAK,EACV,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,cAAc,EACd,YAAY,EACb,MAAM,UAAU,CAAC;AAMlB;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,IAAI,IAAI,CAAC;IACd,SAAS,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC5C,OAAO,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC9B,OAAO,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;CACzC;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,oEAAoE;AACpE,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,SAAS,CAAC,CAiC7F;AAaD,MAAM,WAAW,oBAAoB;IACnC,yDAAyD;IACzD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CACvE;AAED,qBAAa,aAAc,YAAW,YAAY;IAW9C,OAAO,CAAC,QAAQ,CAAC,MAAM;IAVzB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;IAC7D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAwC;IACtE,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAgD;IACpF,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8D;IACtF,OAAO,CAAC,WAAW,CAAiC;IACpD,OAAO,CAAC,WAAW,CAAS;gBAGT,MAAM,EAAE,SAAS,EAClC,OAAO,CAAC,EAAE,oBAAoB;IAUhC,6DAA6D;WAChD,OAAO,CAClB,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,oBAAoB,GAAG,oBAAoB,GACpD,OAAO,CAAC,aAAa,CAAC;IAKzB,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,4EAA4E;IAC5E,YAAY,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,kBAAkB,KAAK,IAAI,GAAG,MAAM,IAAI;IAOzD,IAAI,CAAC,CAAC,SAAS,UAAU,EAC7B,MAAM,EAAE,CAAC,EACT,MAAM,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC5B,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;IA4C/B,EAAE,CAAC,CAAC,SAAS,YAAY,EACvB,MAAM,EAAE,CAAC,EACT,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC7B,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,IAAI;IAiBP,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAU5B,OAAO,CAAC,aAAa;IA0DrB,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,WAAW;CAapB"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface ResolveCdpOptions {
|
|
2
|
+
/** Injected fetch (tests / proxy control). Defaults to the global fetch. */
|
|
3
|
+
fetch?: typeof fetch;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Resolve a CDP endpoint to a `ws(s)://` debugger url.
|
|
7
|
+
*
|
|
8
|
+
* - `ws://` / `wss://` → returned as-is.
|
|
9
|
+
* - `http://` / `https://` → fetch `<base>/json/version` and read
|
|
10
|
+
* `webSocketDebuggerUrl`.
|
|
11
|
+
*
|
|
12
|
+
* localhost DevTools is proxy-exempt (design §7.3.1 `trust_env=False`): Node's
|
|
13
|
+
* global fetch (undici) does not honour HTTP(S)_PROXY env by default, so no
|
|
14
|
+
* proxy stripping is needed for 127.0.0.1/localhost/::1.
|
|
15
|
+
* ponytail: revisit only if a global undici ProxyAgent is ever installed.
|
|
16
|
+
*/
|
|
17
|
+
export declare function resolveCdpWebSocketUrl(url: string, options?: ResolveCdpOptions): Promise<string>;
|
|
18
|
+
//# sourceMappingURL=endpoint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint.d.ts","sourceRoot":"","sources":["../../src/cdp/endpoint.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,iBAAiB;IAChC,4EAA4E;IAC5E,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAMD;;;;;;;;;;;GAWG;AACH,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,MAAM,CAAC,CAsDjB"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CdpConnectionError } from "../errors";
|
|
2
|
+
import type { CdpConnection } from "./connection";
|
|
3
|
+
export interface ReconnectEvents {
|
|
4
|
+
onReconnecting?: (attempt: number, max: number) => void;
|
|
5
|
+
onReconnected?: (connection: CdpConnection) => void;
|
|
6
|
+
onFailed?: (err: CdpConnectionError) => void;
|
|
7
|
+
}
|
|
8
|
+
export interface ReconnectOptions {
|
|
9
|
+
/** Number of attempts (default 3). */
|
|
10
|
+
attempts?: number;
|
|
11
|
+
/** Backoff before attempts 2..N (default [1000, 2000, 4000] ms). */
|
|
12
|
+
delaysMs?: number[];
|
|
13
|
+
/** Per-attempt timeout (default 15000 ms). */
|
|
14
|
+
attemptTimeoutMs?: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Rebuild a connection with bounded retries. `connect` receives an AbortSignal
|
|
18
|
+
* that fires when the per-attempt budget is exceeded. Resolves with the first
|
|
19
|
+
* successful connection or throws a `reconnect_failed` {@link CdpConnectionError}.
|
|
20
|
+
*/
|
|
21
|
+
export declare function reconnectWithBackoff(connect: (signal: AbortSignal) => Promise<CdpConnection>, events?: ReconnectEvents, options?: ReconnectOptions): Promise<CdpConnection>;
|
|
22
|
+
//# sourceMappingURL=reconnect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconnect.d.ts","sourceRoot":"","sources":["../../src/cdp/reconnect.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,MAAM,WAAW,eAAe;IAC9B,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACxD,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,aAAa,KAAK,IAAI,CAAC;IACpD,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,kBAAkB,KAAK,IAAI,CAAC;CAC9C;AAED,MAAM,WAAW,gBAAgB;IAC/B,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,8CAA8C;IAC9C,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAiBD;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,aAAa,CAAC,EACxD,MAAM,CAAC,EAAE,eAAe,EACxB,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,aAAa,CAAC,CA2BxB"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// src/testing.ts
|
|
2
|
+
var FakeCdpTransport = class {
|
|
3
|
+
constructor(responses = /* @__PURE__ */ new Map()) {
|
|
4
|
+
this.responses = responses;
|
|
5
|
+
}
|
|
6
|
+
responses;
|
|
7
|
+
/** Every `send` in order, for assertions. */
|
|
8
|
+
calls = [];
|
|
9
|
+
registrations = /* @__PURE__ */ new Map();
|
|
10
|
+
disconnectListeners = /* @__PURE__ */ new Set();
|
|
11
|
+
async send(method, params, options) {
|
|
12
|
+
this.calls.push({ method, params, sessionId: options?.sessionId });
|
|
13
|
+
const responder = this.responses.get(method);
|
|
14
|
+
const value = typeof responder === "function" ? responder(params, options?.sessionId) : responder;
|
|
15
|
+
return value ?? {};
|
|
16
|
+
}
|
|
17
|
+
on(method, listener, sessionId) {
|
|
18
|
+
const key = method;
|
|
19
|
+
let set = this.registrations.get(key);
|
|
20
|
+
if (!set) {
|
|
21
|
+
set = /* @__PURE__ */ new Set();
|
|
22
|
+
this.registrations.set(key, set);
|
|
23
|
+
}
|
|
24
|
+
const registration = {
|
|
25
|
+
listener,
|
|
26
|
+
sessionId
|
|
27
|
+
};
|
|
28
|
+
set.add(registration);
|
|
29
|
+
return () => {
|
|
30
|
+
set.delete(registration);
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/** Push a canned CDP event to matching subscribers. */
|
|
34
|
+
emitEvent(method, params, sessionId) {
|
|
35
|
+
const set = this.registrations.get(method);
|
|
36
|
+
if (!set) return;
|
|
37
|
+
for (const registration of [...set]) {
|
|
38
|
+
if (registration.sessionId === void 0 || registration.sessionId === sessionId) {
|
|
39
|
+
registration.listener(params, sessionId);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
onDisconnect(cb) {
|
|
44
|
+
this.disconnectListeners.add(cb);
|
|
45
|
+
return () => {
|
|
46
|
+
this.disconnectListeners.delete(cb);
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/** Simulate an unexpected socket drop for tests. */
|
|
50
|
+
emitDisconnect(err) {
|
|
51
|
+
for (const cb of [...this.disconnectListeners]) cb(err);
|
|
52
|
+
}
|
|
53
|
+
/** Number of `send`s recorded for a method. */
|
|
54
|
+
sendCount(method) {
|
|
55
|
+
return this.calls.filter((c) => c.method === method).length;
|
|
56
|
+
}
|
|
57
|
+
async close() {
|
|
58
|
+
this.registrations.clear();
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
function groundTruth(session) {
|
|
62
|
+
return {
|
|
63
|
+
/** Evaluate an arbitrary expression in the page and return the JSON value. */
|
|
64
|
+
evalInPage: (expression) => session.evaluate(expression),
|
|
65
|
+
/** `window.getClickCount()` — the golden-fixture click-counter contract (design/08-09 §9.3). */
|
|
66
|
+
clickCount: () => session.evaluate("window.getClickCount()"),
|
|
67
|
+
/** The live `.value` of the element matched by `selector`. */
|
|
68
|
+
inputValue: (selector) => session.evaluate(`document.querySelector(${JSON.stringify(selector)}).value`),
|
|
69
|
+
/** The live `.checked` of the element matched by `selector`. */
|
|
70
|
+
checked: (selector) => session.evaluate(`document.querySelector(${JSON.stringify(selector)}).checked`)
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export {
|
|
75
|
+
FakeCdpTransport,
|
|
76
|
+
groundTruth
|
|
77
|
+
};
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/** Cloak (CloakBrowser / cloakserve) connection settings. All optional here — the
|
|
2
|
+
* factory requires `endpoint` before building a {@link CloakProvider}. */
|
|
3
|
+
export interface CloakConfig {
|
|
4
|
+
/** cloakserve base URL or a launched CloakBrowser CDP url (http(s):// or ws(s)://). */
|
|
5
|
+
readonly endpoint?: string;
|
|
6
|
+
/** Fingerprint seed (cloakserve `fingerprint`). */
|
|
7
|
+
readonly fingerprint?: string;
|
|
8
|
+
/** Fingerprint platform (cloakserve `fingerprint-platform`). */
|
|
9
|
+
readonly platform?: "windows" | "macos";
|
|
10
|
+
/** Upstream proxy (cloakserve `proxy`). */
|
|
11
|
+
readonly proxy?: string;
|
|
12
|
+
/** Derive geo from the proxy IP (cloakserve `geoip`). */
|
|
13
|
+
readonly geoip?: string;
|
|
14
|
+
/** Humanize input timing (cloakserve `humanize`). */
|
|
15
|
+
readonly humanize?: boolean;
|
|
16
|
+
/** Spoofed timezone (cloakserve `timezone`). */
|
|
17
|
+
readonly timezone?: string;
|
|
18
|
+
/** Spoofed locale (cloakserve `locale`). */
|
|
19
|
+
readonly locale?: string;
|
|
20
|
+
}
|
|
21
|
+
/** The frozen configuration a {@link BrowserSession} is built from. */
|
|
22
|
+
export interface ResolvedBrowserConfig {
|
|
23
|
+
/** Which provider yields the session — stock local Chrome or a stealth CloakBrowser. */
|
|
24
|
+
readonly provider: "local" | "cloak";
|
|
25
|
+
/** Cloak connection settings (only used when `provider === "cloak"`). */
|
|
26
|
+
readonly cloak: CloakConfig;
|
|
27
|
+
/** Launch headless (only relevant to the launch path). */
|
|
28
|
+
readonly headless: boolean;
|
|
29
|
+
/** CDP endpoint to connect to (the connect path / CloakBrowser seam). */
|
|
30
|
+
readonly cdpUrl?: string;
|
|
31
|
+
/** Allow-list for navigation (empty = open). */
|
|
32
|
+
readonly allowedDomains: readonly string[];
|
|
33
|
+
/** Deny-list for navigation. */
|
|
34
|
+
readonly prohibitedDomains: readonly string[];
|
|
35
|
+
/** Block navigation to raw IP addresses (SSRF guard). */
|
|
36
|
+
readonly blockIpAddresses: boolean;
|
|
37
|
+
/** Opt-in (W27): permit `file://` navigation, otherwise unconditionally
|
|
38
|
+
* blocked by NavigationPolicy. Default-deny — reads local disk. */
|
|
39
|
+
readonly allowFileUrls: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* C3 global dialog override: force-accept (true) or force-dismiss (false)
|
|
42
|
+
* ALL dialog types. When undefined (the default), each type uses its own
|
|
43
|
+
* per-type default (prompt→dismiss, others→accept).
|
|
44
|
+
*/
|
|
45
|
+
readonly dialogAccept?: boolean;
|
|
46
|
+
/** Text for accepted `prompt()` dialogs. */
|
|
47
|
+
readonly dialogPromptText?: string;
|
|
48
|
+
/** Draw the numbered highlight overlay before screenshots (M5). */
|
|
49
|
+
readonly highlightElements: boolean;
|
|
50
|
+
/** Descend cross-origin (out-of-process) iframes during DOM capture. */
|
|
51
|
+
readonly crossOriginIframes: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* The five DomServiceOptions perception knobs. Undefined (the default at
|
|
54
|
+
* every level) means DomService's own default stays authoritative — config
|
|
55
|
+
* never hardcodes a value that could drift from it.
|
|
56
|
+
*/
|
|
57
|
+
readonly maxIframeDepth?: number;
|
|
58
|
+
readonly viewportThreshold?: number | null;
|
|
59
|
+
readonly includeAttributes?: readonly string[];
|
|
60
|
+
readonly paintOrderFiltering?: boolean;
|
|
61
|
+
readonly enableBboxFiltering?: boolean;
|
|
62
|
+
}
|
|
63
|
+
/** Overrides accepted by {@link resolveBrowserConfig} (all optional). */
|
|
64
|
+
export type BrowserConfigOverrides = Partial<{
|
|
65
|
+
provider: "local" | "cloak";
|
|
66
|
+
cloak: CloakConfig;
|
|
67
|
+
headless: boolean;
|
|
68
|
+
cdpUrl: string;
|
|
69
|
+
allowedDomains: readonly string[];
|
|
70
|
+
prohibitedDomains: readonly string[];
|
|
71
|
+
blockIpAddresses: boolean;
|
|
72
|
+
allowFileUrls: boolean;
|
|
73
|
+
dialogAccept: boolean;
|
|
74
|
+
dialogPromptText: string;
|
|
75
|
+
highlightElements: boolean;
|
|
76
|
+
crossOriginIframes: boolean;
|
|
77
|
+
maxIframeDepth: number;
|
|
78
|
+
viewportThreshold: number | null;
|
|
79
|
+
includeAttributes: readonly string[];
|
|
80
|
+
paintOrderFiltering: boolean;
|
|
81
|
+
enableBboxFiltering: boolean;
|
|
82
|
+
}>;
|
|
83
|
+
/** The env source read by {@link resolveBrowserConfig} (a subset of process.env). */
|
|
84
|
+
export type EnvSource = Record<string, string | undefined>;
|
|
85
|
+
/**
|
|
86
|
+
* Merge overrides over the `AP3X_BROWSER_*` environment over the defaults and
|
|
87
|
+
* freeze the result. Call once per session; the object never re-reads env. The
|
|
88
|
+
* env source is injectable (defaults to `process.env`) for pure testing.
|
|
89
|
+
*/
|
|
90
|
+
export declare function resolveBrowserConfig(overrides?: BrowserConfigOverrides, source?: EnvSource): ResolvedBrowserConfig;
|
|
91
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { TypedEmitter } from "../events";
|
|
2
|
+
import type { CdpTransport } from "../types";
|
|
3
|
+
/** A dialog that opened and was auto-answered. */
|
|
4
|
+
export interface DialogNotification {
|
|
5
|
+
type: string;
|
|
6
|
+
message: string;
|
|
7
|
+
accepted: boolean;
|
|
8
|
+
sessionId?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface DialogHandlerEvents {
|
|
11
|
+
dialog: DialogNotification;
|
|
12
|
+
}
|
|
13
|
+
export interface DialogHandlerOptions {
|
|
14
|
+
/**
|
|
15
|
+
* C3 global override: force-accept (true) or force-dismiss (false) EVERY
|
|
16
|
+
* dialog type. When undefined (the default), each type uses its own per-type
|
|
17
|
+
* default — see {@link DialogHandler.policyFor}.
|
|
18
|
+
*/
|
|
19
|
+
accept?: boolean;
|
|
20
|
+
/** Text supplied to `prompt()` dialogs when accepting. */
|
|
21
|
+
promptText?: string;
|
|
22
|
+
}
|
|
23
|
+
export declare class DialogHandler {
|
|
24
|
+
private readonly transport;
|
|
25
|
+
readonly events: TypedEmitter<DialogHandlerEvents>;
|
|
26
|
+
private readonly accept?;
|
|
27
|
+
private readonly promptText?;
|
|
28
|
+
private unsubscribe?;
|
|
29
|
+
constructor(transport: CdpTransport, options?: DialogHandlerOptions);
|
|
30
|
+
/**
|
|
31
|
+
* The accept/dismiss decision for a dialog type. The C3 global override wins
|
|
32
|
+
* when set; otherwise the per-type default applies: `prompt` is
|
|
33
|
+
* dismissed (accepting would send "" instead of null — no input available),
|
|
34
|
+
* everything else (alert / confirm / beforeunload) is accepted.
|
|
35
|
+
*/
|
|
36
|
+
private policyFor;
|
|
37
|
+
/** Begin auto-answering dialogs across all sessions. Idempotent. */
|
|
38
|
+
start(): void;
|
|
39
|
+
/** Stop auto-answering. */
|
|
40
|
+
stop(): void;
|
|
41
|
+
private handle;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/dialogs/handler.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,kDAAkD;AAClD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,kBAAkB,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,aAAa;IAOtB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAN5B,QAAQ,CAAC,MAAM,oCAA2C;IAC1D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAS;IACrC,OAAO,CAAC,WAAW,CAAC,CAAa;gBAGd,SAAS,EAAE,YAAY,EACxC,OAAO,GAAE,oBAAyB;IAMpC;;;;;OAKG;IACH,OAAO,CAAC,SAAS;IAKjB,oEAAoE;IACpE,KAAK,IAAI,IAAI;IAOb,2BAA2B;IAC3B,IAAI,IAAI,IAAI;YAKE,MAAM;CAoBrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clickability.d.ts","sourceRoot":"","sources":["../../src/dom/clickability.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,mBAAmB,EAAY,MAAM,SAAS,CAAC;AAwE7D,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAiHhE"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type EnhancedDOMTreeNode, type SimplifiedNode } from "./types";
|
|
2
|
+
/** Append compound sub-components to `node.compoundChildren`; mark `simplified`. */
|
|
3
|
+
export declare function addCompoundComponents(simplified: SimplifiedNode, node: EnhancedDOMTreeNode): void;
|
|
4
|
+
//# sourceMappingURL=compound.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compound.d.ts","sourceRoot":"","sources":["../../src/dom/compound.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,KAAK,mBAAmB,EAExB,KAAK,cAAc,EACpB,MAAM,SAAS,CAAC;AA+FjB,oFAAoF;AACpF,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,cAAc,EAAE,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAsGjG"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ~55 attributes the serializer surfaces to the LLM by default, in the
|
|
3
|
+
* order they are emitted. Mixes HTML attributes, synthetic format hints, and
|
|
4
|
+
* AX-derived properties (see design/04a §4.25). `class` is intentionally omitted
|
|
5
|
+
* (deliberately omitted, to force structural rather than class-name reasoning).
|
|
6
|
+
*/
|
|
7
|
+
export declare const DEFAULT_INCLUDE_ATTRIBUTES: readonly string[];
|
|
8
|
+
/** Attributes considered identity-stable, fed into element hashing (design/05). */
|
|
9
|
+
export declare const STATIC_ATTRIBUTES: ReadonlySet<string>;
|
|
10
|
+
/** Substrings marking transient CSS-state classes, dropped from the stable hash. */
|
|
11
|
+
export declare const DYNAMIC_CLASS_PATTERNS: ReadonlySet<string>;
|
|
12
|
+
/**
|
|
13
|
+
* The 10 computed styles requested from `DOMSnapshot.captureSnapshot`, in order.
|
|
14
|
+
* The response returns style values positionally aligned to THIS list, so the
|
|
15
|
+
* order is load-bearing. Deliberately minimal: requesting more crashes Chrome on
|
|
16
|
+
* heavy pages (design/04a §4.26).
|
|
17
|
+
*/
|
|
18
|
+
export declare const REQUIRED_COMPUTED_STYLES: readonly string[];
|
|
19
|
+
/** Elements never serialized (no interaction / content value). */
|
|
20
|
+
export declare const DISABLED_ELEMENTS: ReadonlySet<string>;
|
|
21
|
+
/** SVG child elements skipped as decorative. */
|
|
22
|
+
export declare const SVG_ELEMENTS: ReadonlySet<string>;
|
|
23
|
+
/**
|
|
24
|
+
* AP3X's opt-out attribute — AP3X-branded, per Hard Constraint 1. An element whose
|
|
25
|
+
* value is "true" (case-insensitive) is dropped from serialization.
|
|
26
|
+
*/
|
|
27
|
+
export declare const EXCLUDE_ATTRIBUTE = "data-ap3x-exclude";
|
|
28
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/dom/constants.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,EAAE,SAAS,MAAM,EAyDvD,CAAC;AAEF,mFAAmF;AACnF,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,MAAM,CAkDhD,CAAC;AAEH,oFAAoF;AACpF,eAAO,MAAM,sBAAsB,EAAE,WAAW,CAAC,MAAM,CAqBrD,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,EAAE,SAAS,MAAM,EAWrD,CAAC;AAEF,kEAAkE;AAClE,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,MAAM,CAOhD,CAAC;AAEH,gDAAgD;AAChD,eAAO,MAAM,YAAY,EAAE,WAAW,CAAC,MAAM,CAiB3C,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,iBAAiB,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { CdpTransport } from "../types";
|
|
2
|
+
import type { BackendNodeId, TargetId } from "../types";
|
|
3
|
+
import { type SerializerOptions } from "./serializer";
|
|
4
|
+
import type { DomSelectorMap, EnhancedDOMTreeNode, TargetAllTrees } from "./types";
|
|
5
|
+
/** The serialized page state the agent consumes. */
|
|
6
|
+
export interface SerializedDom {
|
|
7
|
+
/** The numbered/indented text projection the LLM reads. */
|
|
8
|
+
serializedText: string;
|
|
9
|
+
/** backendNodeId → node. The `[N]` in `serializedText` == a key here. */
|
|
10
|
+
selectorMap: DomSelectorMap;
|
|
11
|
+
/** The raw merged tree root (kept for downstream geometry/coordinate needs). */
|
|
12
|
+
enhancedTree: EnhancedDOMTreeNode;
|
|
13
|
+
}
|
|
14
|
+
export interface SerializeFromSnapshotOptions extends SerializerOptions {
|
|
15
|
+
targetId: TargetId;
|
|
16
|
+
includeAttributes?: readonly string[];
|
|
17
|
+
viewportThreshold?: number | null;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Pure pipeline: raw trees → { serializedText, selectorMap, enhancedTree }. No
|
|
21
|
+
* CDP, no I/O. Handles same-origin iframe content and shadow roots inline (both
|
|
22
|
+
* present in the pierce:true capture). Cross-origin iframes must be pre-attached
|
|
23
|
+
* to the trees' DOM (the live orchestrator does this).
|
|
24
|
+
*/
|
|
25
|
+
export declare function serializeFromSnapshot(trees: TargetAllTrees, opts: SerializeFromSnapshotOptions): SerializedDom;
|
|
26
|
+
/** Resolves a cross-origin iframe's frame to its own CDP target/session. */
|
|
27
|
+
export type FrameTargetResolver = (frameId: string | undefined, src: string | undefined) => {
|
|
28
|
+
targetId: TargetId;
|
|
29
|
+
sessionId?: string;
|
|
30
|
+
} | undefined;
|
|
31
|
+
export interface DomServiceOptions {
|
|
32
|
+
/** Descend into out-of-process (cross-origin) iframes. Default false. */
|
|
33
|
+
crossOriginIframes?: boolean;
|
|
34
|
+
maxIframeDepth?: number;
|
|
35
|
+
viewportThreshold?: number | null;
|
|
36
|
+
includeAttributes?: readonly string[];
|
|
37
|
+
paintOrderFiltering?: boolean;
|
|
38
|
+
enableBboxFiltering?: boolean;
|
|
39
|
+
/** Required to descend OOPIFs when `crossOriginIframes` is on. */
|
|
40
|
+
resolveFrameTarget?: FrameTargetResolver;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Orchestrates the live capture + serialize for a focus target. Reuses one
|
|
44
|
+
* transport across steps. OOPIF descent recurses into child targets, threading
|
|
45
|
+
* the accumulated frame offset so child coordinates land in main-page space.
|
|
46
|
+
*/
|
|
47
|
+
export declare class DomService {
|
|
48
|
+
private readonly transport;
|
|
49
|
+
private readonly opts;
|
|
50
|
+
constructor(transport: CdpTransport, opts?: DomServiceOptions);
|
|
51
|
+
getSerializedDom(targetId: TargetId, sessionId: string | undefined, serializerOpts?: SerializerOptions, opts?: {
|
|
52
|
+
signal?: AbortSignal;
|
|
53
|
+
}): Promise<SerializedDom>;
|
|
54
|
+
/** Build the merged tree, descending OOPIFs (recursively — an OOPIF's own
|
|
55
|
+
* subtree may itself contain further OOPIFs) when enabled. Bounded by
|
|
56
|
+
* `maxIframeDepth` (default 5, via `buildEnhancedTree`'s own gate), so a
|
|
57
|
+
* cyclic frame graph cannot recurse forever. */
|
|
58
|
+
private buildWithOopif;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Resolve an element by its map key — the CDP backendNodeId, i.e. the `[N]` the
|
|
62
|
+
* LLM emitted. Same integer everywhere (design/10 gap #1).
|
|
63
|
+
*/
|
|
64
|
+
export declare function getElementByIndex(selectorMap: DomSelectorMap, index: BackendNodeId): EnhancedDOMTreeNode | undefined;
|
|
65
|
+
//# sourceMappingURL=dom-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom-service.d.ts","sourceRoot":"","sources":["../../src/dom/dom-service.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAIxD,OAAO,EAAiB,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAErE,OAAO,KAAK,EAAW,cAAc,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAI5F,oDAAoD;AACpD,MAAM,WAAW,aAAa;IAC5B,2DAA2D;IAC3D,cAAc,EAAE,MAAM,CAAC;IACvB,yEAAyE;IACzE,WAAW,EAAE,cAAc,CAAC;IAC5B,gFAAgF;IAChF,YAAY,EAAE,mBAAmB,CAAC;CACnC;AAED,MAAM,WAAW,4BAA6B,SAAQ,iBAAiB;IACrE,QAAQ,EAAE,QAAQ,CAAC;IACnB,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,cAAc,EACrB,IAAI,EAAE,4BAA4B,GACjC,aAAa,CAUf;AAED,4EAA4E;AAC5E,MAAM,MAAM,mBAAmB,GAAG,CAChC,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,GAAG,EAAE,MAAM,GAAG,SAAS,KACpB;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAAC;AAE5D,MAAM,WAAW,iBAAiB;IAChC,yEAAyE;IACzE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,kEAAkE;IAClE,kBAAkB,CAAC,EAAE,mBAAmB,CAAC;CAC1C;AAED;;;;GAIG;AACH,qBAAa,UAAU;IAEnB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,IAAI;gBADJ,SAAS,EAAE,YAAY,EACvB,IAAI,GAAE,iBAAsB;IAGzC,gBAAgB,CACpB,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,cAAc,GAAE,iBAAsB,EACtC,IAAI,GAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAO,GAClC,OAAO,CAAC,aAAa,CAAC;IAmBzB;;;oDAGgD;YAClC,cAAc;CA2C7B;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,cAAc,EAC3B,KAAK,EAAE,aAAa,GACnB,mBAAmB,GAAG,SAAS,CAEjC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { TargetId } from "../types";
|
|
2
|
+
import { type DOMRect, type EnhancedDOMTreeNode, type TargetAllTrees } from "./types";
|
|
3
|
+
export interface BuildTreeOptions {
|
|
4
|
+
targetId: TargetId;
|
|
5
|
+
viewportThreshold?: number | null;
|
|
6
|
+
crossOriginIframes?: boolean;
|
|
7
|
+
maxIframeDepth?: number;
|
|
8
|
+
iframeDepth?: number;
|
|
9
|
+
/** Carried into an OOPIF recursion so its coordinates land in main-page space. */
|
|
10
|
+
initialFrameOffset?: DOMRect;
|
|
11
|
+
/**
|
|
12
|
+
* The CDP session this capture was taken from. Stamped on every node built by
|
|
13
|
+
* this call so `InputDispatcher` routes a backendNodeId to the session that
|
|
14
|
+
* minted it (design §4.23) — required for OOPIF subtrees, which are captured
|
|
15
|
+
* against a different target/session than the main page. Leave unset for the
|
|
16
|
+
* main-page build; same-origin iframe content (arrives inline via
|
|
17
|
+
* `pierce:true`) legitimately belongs to the parent session.
|
|
18
|
+
*/
|
|
19
|
+
sessionId?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Seam for cross-origin (out-of-process) iframes: called for each IFRAME with
|
|
22
|
+
* no inline content document, passing the node and the accumulated frame
|
|
23
|
+
* offset. The orchestrator captures that frame's target and attaches the built
|
|
24
|
+
* subtree as `contentDocument`. Same-origin iframes never reach here (their
|
|
25
|
+
* content arrives inline via `pierce:true`).
|
|
26
|
+
*/
|
|
27
|
+
onOopifIframe?: (node: EnhancedDOMTreeNode, frameOffset: DOMRect) => void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Element visibility per its full frame chain. CSS excludes first
|
|
31
|
+
* (display/visibility/opacity), then a geometric viewport-intersection test at
|
|
32
|
+
* each ancestor HTML frame. `viewportThreshold === null` skips geometry
|
|
33
|
+
* (CSS-only mode). Faithful to design/04a §4.24.
|
|
34
|
+
*/
|
|
35
|
+
export declare function isElementVisibleAccordingToAllParents(node: EnhancedDOMTreeNode, htmlFrames: EnhancedDOMTreeNode[], viewportThreshold?: number | null): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Build the merged tree for one target's captures. Same-origin iframe content
|
|
38
|
+
* and shadow roots (both present in the `pierce:true` document) are recursed
|
|
39
|
+
* inline; cross-origin iframes are surfaced to `opts.onOopifIframe`.
|
|
40
|
+
*/
|
|
41
|
+
export declare function buildEnhancedTree(trees: TargetAllTrees, opts: BuildTreeOptions): EnhancedDOMTreeNode;
|
|
42
|
+
/**
|
|
43
|
+
* Annotate every IFRAME/FRAME node that has a content document with hints about
|
|
44
|
+
* interactive elements hidden below its viewport: `hiddenElementsInfo` (sorted by
|
|
45
|
+
* pages-down, capped at 10) and `hasHiddenContent` (set when no interactive
|
|
46
|
+
* element is hidden but some non-interactive content is). Run on the fully
|
|
47
|
+
* assembled tree, AFTER build (and OOPIF attach), BEFORE serialization — the
|
|
48
|
+
* serializer reads these off the iframe node to emit scroll hints. Faithful to
|
|
49
|
+
* design/04a §4.24 (hidden-element counting across iframes).
|
|
50
|
+
*/
|
|
51
|
+
export declare function countHiddenElementsInIframes(node: EnhancedDOMTreeNode): void;
|
|
52
|
+
//# sourceMappingURL=enhanced-tree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enhanced-tree.d.ts","sourceRoot":"","sources":["../../src/dom/enhanced-tree.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAIzC,OAAO,EACL,KAAK,OAAO,EAGZ,KAAK,mBAAmB,EAIxB,KAAK,cAAc,EACpB,MAAM,SAAS,CAAC;AAKjB,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,QAAQ,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kFAAkF;IAClF,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,mBAAmB,EAAE,WAAW,EAAE,OAAO,KAAK,IAAI,CAAC;CAC3E;AA+CD;;;;;GAKG;AACH,wBAAgB,qCAAqC,CACnD,IAAI,EAAE,mBAAmB,EACzB,UAAU,EAAE,mBAAmB,EAAE,EACjC,iBAAiB,GAAE,MAAM,GAAG,IAAiC,GAC5D,OAAO,CAyCT;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,cAAc,EACrB,IAAI,EAAE,gBAAgB,GACrB,mBAAmB,CAgJrB;AAmDD;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAoB5E"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type DOMInteractedElement, type EnhancedDOMTreeNode } from "./types";
|
|
2
|
+
/** Tag names of every ELEMENT ancestor, root → self. */
|
|
3
|
+
export declare function parentBranchPath(node: EnhancedDOMTreeNode): string[];
|
|
4
|
+
/**
|
|
5
|
+
* Drop transient CSS-state classes (any class whose lowercased form CONTAINS a
|
|
6
|
+
* dynamic pattern), then return the survivors sorted and space-joined — sorting
|
|
7
|
+
* makes the stable hash deterministic.
|
|
8
|
+
*/
|
|
9
|
+
export declare function filterDynamicClasses(classStr: string | undefined): string;
|
|
10
|
+
/** Exact hash (MatchLevel.Exact): full static attributes, unfiltered. */
|
|
11
|
+
export declare function elementHash(node: EnhancedDOMTreeNode): string;
|
|
12
|
+
/** Stable hash (MatchLevel.Stable): dynamic classes filtered — survives class churn. */
|
|
13
|
+
export declare function stableHash(node: EnhancedDOMTreeNode): string;
|
|
14
|
+
/** Parent-branch hash: structural identity only (no attributes/ax). */
|
|
15
|
+
export declare function parentBranchHash(node: EnhancedDOMTreeNode): string;
|
|
16
|
+
/**
|
|
17
|
+
* Snapshot a node into a persisted interaction record. Both hashes are captured
|
|
18
|
+
* here so replay has a single source of truth (design/05 invariant).
|
|
19
|
+
*/
|
|
20
|
+
export declare function buildInteractedElement(node: EnhancedDOMTreeNode): DOMInteractedElement;
|
|
21
|
+
//# sourceMappingURL=hashing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hashing.d.ts","sourceRoot":"","sources":["../../src/dom/hashing.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,KAAK,oBAAoB,EAAE,KAAK,mBAAmB,EAAY,MAAM,SAAS,CAAC;AAMxF,wDAAwD;AACxD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,EAAE,CASpE;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAWzE;AAuBD,yEAAyE;AACzE,wBAAgB,WAAW,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,CAG7D;AAED,wFAAwF;AACxF,wBAAgB,UAAU,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,CAG5D;AAED,uEAAuE;AACvE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,CAElE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,mBAAmB,GAAG,oBAAoB,CAgBtF"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type DOMRect, type EnhancedDOMTreeNode } from "./types";
|
|
2
|
+
/** Lower-cased tag name. */
|
|
3
|
+
export declare function tagName(node: EnhancedDOMTreeNode): string;
|
|
4
|
+
/** Real children (never the shared array). */
|
|
5
|
+
export declare function children(node: EnhancedDOMTreeNode): EnhancedDOMTreeNode[];
|
|
6
|
+
/** Children plus shadow roots — a fresh array, safe to iterate/mutate. */
|
|
7
|
+
export declare function childrenAndShadowRoots(node: EnhancedDOMTreeNode): EnhancedDOMTreeNode[];
|
|
8
|
+
/**
|
|
9
|
+
* Scroll detection combining CDP's flag with a CSS/geometry heuristic — catches
|
|
10
|
+
* scrollable containers CDP misses (common in iframes and dynamically-sized
|
|
11
|
+
* elements). Faithful to design/04a §4.25.
|
|
12
|
+
*/
|
|
13
|
+
export declare function isActuallyScrollable(node: EnhancedDOMTreeNode): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Whether to render scroll info for this node. Always for iframes; else the node
|
|
16
|
+
* must be scrollable and not nested inside another scrollable (avoids spam);
|
|
17
|
+
* always for iframe-content body/html.
|
|
18
|
+
*/
|
|
19
|
+
export declare function shouldShowScrollInfo(node: EnhancedDOMTreeNode): boolean;
|
|
20
|
+
interface ScrollInfo {
|
|
21
|
+
scrollableHeight: number;
|
|
22
|
+
scrollableWidth: number;
|
|
23
|
+
visibleHeight: number;
|
|
24
|
+
visibleWidth: number;
|
|
25
|
+
pagesAbove: number;
|
|
26
|
+
pagesBelow: number;
|
|
27
|
+
verticalScrollPct: number;
|
|
28
|
+
horizontalScrollPct: number;
|
|
29
|
+
}
|
|
30
|
+
/** Scroll geometry (pages above/below, percentages) or undefined if not scrollable. */
|
|
31
|
+
export declare function scrollInfo(node: EnhancedDOMTreeNode): ScrollInfo | undefined;
|
|
32
|
+
/** Human-readable scroll text, e.g. "1.0 pages above, 3.0 pages below". */
|
|
33
|
+
export declare function getScrollInfoText(node: EnhancedDOMTreeNode): string;
|
|
34
|
+
/**
|
|
35
|
+
* XPath for a node, passing THROUGH shadow roots and stopping AT iframe
|
|
36
|
+
* boundaries (xpath is per-document). Position `[n]` is 1-based and only emitted
|
|
37
|
+
* when there is more than one same-tag sibling.
|
|
38
|
+
*/
|
|
39
|
+
export declare function xpath(node: EnhancedDOMTreeNode): string;
|
|
40
|
+
/** Absolute bounds, if known. */
|
|
41
|
+
export declare function absoluteBounds(node: EnhancedDOMTreeNode): DOMRect | undefined;
|
|
42
|
+
export {};
|
|
43
|
+
//# sourceMappingURL=node.d.ts.map
|