@olimsaidov/icdp 0.2.1 → 0.3.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/README.md +4 -117
- package/dist/frame/index.mjs +24320 -6
- package/dist/host/index.d.mts +1 -1
- package/dist/protocol-CZthc7CO.d.mts +121 -0
- package/dist/protocol.d.mts +1 -120
- package/dist/relay/core.d.mts +1 -1
- package/package.json +7 -1
- package/dist/frame/ax-tree.mjs +0 -2186
package/README.md
CHANGED
|
@@ -1,124 +1,11 @@
|
|
|
1
1
|
# icdp
|
|
2
2
|
|
|
3
|
-
Chrome DevTools Protocol over an iframe boundary
|
|
3
|
+
Chrome DevTools Protocol over an iframe boundary — drive and inspect an embedded, even **cross-origin**, app with CDP tools, without a real browser debugging session.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
agent-browser / CDP client
|
|
7
|
-
│ WebSocket (standard CDP, flat sessions)
|
|
8
|
-
▼
|
|
9
|
-
Relay ← @olimsaidov/icdp/relay (+ /relay/node) server
|
|
10
|
-
│ WebSocket (bridge protocol)
|
|
11
|
-
▼
|
|
12
|
-
Host ← @olimsaidov/icdp/host parent window
|
|
13
|
-
│ MessagePort (per iframe)
|
|
14
|
-
▼
|
|
15
|
-
Frame Agent ← @olimsaidov/icdp/frame inside the iframe'd app
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
See `CONTEXT.md` for the project language (Frame Agent, Host, Relay, Client, Target, Pairing) and `docs/adr/` for architectural decisions.
|
|
19
|
-
|
|
20
|
-
## The three pieces
|
|
21
|
-
|
|
22
|
-
### Frame Agent — in the embedded app
|
|
23
|
-
|
|
24
|
-
The app under automation includes the agent itself (cooperative embedding — the Host never injects):
|
|
25
|
-
|
|
26
|
-
```ts
|
|
27
|
-
import { startFrameAgent } from "@olimsaidov/icdp/frame";
|
|
28
|
-
|
|
29
|
-
startFrameAgent({ allowedParents: ["https://shell.example.com"] });
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
The agent announces itself to the parent on boot and stays dormant unless the parent's origin is allowlisted. `allowedParents: "*"` hands DOM read/write/eval to **any** embedder — only for sandboxed or throwaway pages.
|
|
33
|
-
|
|
34
|
-
### Host — in the parent window
|
|
35
|
-
|
|
36
|
-
```ts
|
|
37
|
-
import { IcdpHost } from "@olimsaidov/icdp/host";
|
|
38
|
-
|
|
39
|
-
const host = new IcdpHost();
|
|
40
|
-
host.pair(iframeElement, { targetId: "preview", origins: ["https://app.example.com"] });
|
|
41
|
-
|
|
42
|
-
// Local consumption — no server needed (e.g. a console panel):
|
|
43
|
-
const session = host.attach("preview");
|
|
44
|
-
session.onEvent((method, params) => {
|
|
45
|
-
/* Runtime.consoleAPICalled, ... */
|
|
46
|
-
});
|
|
47
|
-
await session.send("Runtime.enable");
|
|
48
|
-
|
|
49
|
-
// Forward everything to a Relay so external tools can connect:
|
|
50
|
-
const disconnect = host.connectRelay({ url: "ws://localhost:9222/icdp/host" });
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Target identity belongs to the Pairing: reloads and navigations keep the same `targetId` (Clients see `Page.frameNavigated`); commands in flight when a document dies fail fast with `-32000`. The Relay uplink is just another consumer of the same hub — events broadcast to all attached sessions, domain enables are ref-counted.
|
|
54
|
-
|
|
55
|
-
#### Client-driven target lifecycle (optional)
|
|
56
|
-
|
|
57
|
-
By default only the Host creates Targets (via `pair()`), so a Client's `Target.createTarget` is rejected and `Target.closeTarget` is a no-op. Pass `onCreateTarget` / `onCloseTarget` to let a Client open and close Targets itself:
|
|
58
|
-
|
|
59
|
-
```ts
|
|
60
|
-
const host = new IcdpHost({
|
|
61
|
-
onCreateTarget: ({ url }) => {
|
|
62
|
-
const iframe = document.createElement("iframe");
|
|
63
|
-
iframe.src = url ?? "about:blank";
|
|
64
|
-
document.body.append(iframe);
|
|
65
|
-
const targetId = crypto.randomUUID();
|
|
66
|
-
host.pair(iframe, { targetId, origins: ["https://app.example.com"] });
|
|
67
|
-
return targetId; // string | Promise<string>
|
|
68
|
-
},
|
|
69
|
-
onCloseTarget: (targetId) => host.unpair(targetId), // + remove the iframe you made
|
|
70
|
-
});
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
The Host advertises which of these it handles, so the Relay forwards only those and keeps its defaults for any hook you leave unset (existing Hosts are unaffected). `createTarget` resolves **only once the new Target completes its handshake**, so the Client's first command can't race the not-connected gate; a Target that never connects (timeout or early destroy) is torn down rather than left as a zombie. A bare `new IcdpHost(window)` is still accepted for back-compat.
|
|
74
|
-
|
|
75
|
-
### Relay — the server
|
|
76
|
-
|
|
77
|
-
```ts
|
|
78
|
-
import { serveRelay } from "@olimsaidov/icdp/relay/node";
|
|
79
|
-
|
|
80
|
-
const relay = await serveRelay({ port: 9222 });
|
|
81
|
-
console.log(relay.browserWsUrl); // ws://127.0.0.1:9222/devtools/browser ← CDP clients
|
|
82
|
-
console.log(relay.hostWsUrl); // ws://127.0.0.1:9222/icdp/host ← Host uplink
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
The Node adapter is built on `node:http` + `ws`. The runtime-agnostic core (`@olimsaidov/icdp/relay` → `RelayCore`) takes plain `{ send, close }` sockets, so other runtimes only need a thin adapter. HTTP discovery: `/json/version`, `/json/list`, `/icdp/status`.
|
|
86
|
-
|
|
87
|
-
One Host per Relay, new-wins: a newly connecting Host replaces a stale one, with `targetDestroyed`/`targetCreated` churn surfaced to attached Clients.
|
|
88
|
-
|
|
89
|
-
## Protocol shape
|
|
90
|
-
|
|
91
|
-
- **Flat sessions only.** Clients connect to the single browser-level endpoint and use `Target.getTargets` / `Target.attachToTarget` (or `Target.setAutoAttach`) + `sessionId` routing. There are no per-target WebSocket URLs. Session-scoped `Target.*`/`Browser.*` housekeeping (e.g. agent-browser's session-scoped `Target.setAutoAttach`) is answered by the Relay; the Frame Agent never sees it. Registry methods (`getTargets`/`attachToTarget`/`setAutoAttach`) are always Relay-owned; only the `Target.createTarget`/`Target.closeTarget` lifecycle can be delegated to the Host (see [Client-driven target lifecycle](#client-driven-target-lifecycle-optional)).
|
|
92
|
-
- **Compatibility bar: agent-browser.** The supported command surface is the prior art's support matrix (AX-tree snapshots, semantic locators, click/fill/type, eval, waits, console, SPA history). Screenshots, PDF, file uploads, drag-and-drop, dialogs, and real network interception are intentionally out — page JavaScript cannot provide them. Raw Playwright over `connectOverCDP` is best-effort, not promised.
|
|
93
|
-
|
|
94
|
-
## Driving an icdp target with agent-browser
|
|
95
|
-
|
|
96
|
-
Use the per-command `--cdp <relay port>` flag, and issue one `wait` first to sync agent-browser's page model from the live target:
|
|
97
|
-
|
|
98
|
-
```sh
|
|
99
|
-
agent-browser --cdp 9222 wait --text "My App" # first command: syncs the model
|
|
100
|
-
agent-browser --cdp 9222 snapshot -i
|
|
101
|
-
agent-browser --cdp 9222 find role button click --name "Save"
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
Do not use `agent-browser connect <ws-url>`: as of agent-browser 0.27.x the session-bound connect no longer routes follow-up commands over the connection (this reproduces against real Chrome too, both browser and page endpoints — it is not an icdp limitation).
|
|
105
|
-
|
|
106
|
-
## Playground
|
|
107
|
-
|
|
108
|
-
`npm run playground` starts a runnable demo of the full topology — see [playground/README.md](./playground/README.md).
|
|
109
|
-
|
|
110
|
-
## Development
|
|
111
|
-
|
|
112
|
-
Node ≥22, VoidZero tooling (Vitest, oxlint, oxfmt, tsdown/Rolldown):
|
|
5
|
+
**📖 [Documentation](https://olimsaidov.github.io/icdp/)** · [npm](https://www.npmjs.com/package/@olimsaidov/icdp)
|
|
113
6
|
|
|
114
7
|
```sh
|
|
115
|
-
npm install
|
|
116
|
-
npm test # unit + in-process integration (vitest)
|
|
117
|
-
npm run test:e2e # conformance suite (needs agent-browser CLI + Chrome, ~90s)
|
|
118
|
-
npm run test:all # everything
|
|
119
|
-
npm run check # tsc + oxlint + oxfmt --check
|
|
120
|
-
npm run fmt # oxfmt
|
|
121
|
-
npm run build # tsdown -> dist/
|
|
8
|
+
npm install @olimsaidov/icdp
|
|
122
9
|
```
|
|
123
10
|
|
|
124
|
-
|
|
11
|
+
MIT
|