Skip to content

Commit 916f275

Browse files
committed
review: update readme
1 parent fc7ab87 commit 916f275

1 file changed

Lines changed: 145 additions & 6 deletions

File tree

server/lib/cdpmonitor/README.md

Lines changed: 145 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ Chrome can restart independently of the monitor. When that happens, `UpstreamPro
1010

1111
## Event taxonomy
1212

13-
**CDP-derived** (1-to-1 with a CDP notification): `console_log`, `console_error`, `network_request`, `network_response`, `network_loading_failed`, `navigation`, `dom_content_loaded`, `page_load`, `layout_shift`
13+
**CDP-derived** (1-to-1 with a CDP notification): `console_log`, `console_error`, `network_request`, `network_response`, `network_loading_failed`, `page_tab_opened`, `page_navigation`, `page_dom_content_loaded`, `page_load`, `page_layout_shift`
1414

15-
**Computed** (inferred from sequences of CDP events): `network_idle` (fires when in-flight requests drop to zero), `layout_settled` (1 s after `page_load` with no intervening layout shifts), `navigation_settled` (fires once `dom_content_loaded`, `network_idle`, and `layout_settled` have all fired for the same navigation).
15+
**Computed** (inferred from sequences of CDP events): `network_idle` (fires when in-flight requests drop to zero), `page_layout_settled` (1 s after `page_load` with no intervening layout shifts), `page_navigation_settled` (fires once `page_dom_content_loaded`, `network_idle`, and `page_layout_settled` have all fired for the same navigation).
1616

17-
**Interaction** (fired by `interaction.js` via `Runtime.bindingCalled`): `interaction_click`, `interaction_key`, `scroll_settled`
17+
**Interaction** (fired by `interaction.js` via `Runtime.bindingCalled`): `interaction_click`, `interaction_key`, `interaction_scroll_settled`
1818

19-
**Monitor lifecycle** (emitted by the monitor itself, not by Chrome): `screenshot`, `monitor_disconnected`, `monitor_reconnected`, `monitor_reconnect_failed`, `monitor_init_failed`
19+
**Monitor lifecycle** (emitted by the monitor itself, not by Chrome): `monitor_screenshot`, `monitor_disconnected`, `monitor_reconnected`, `monitor_reconnect_failed`, `monitor_init_failed`
2020

2121
## Responsibilities
2222

@@ -70,7 +70,7 @@ restartMu -> lifeMu -> sessionsMu
7070
| `restartMu` | Serializes `handleUpstreamRestart` to prevent overlapping reconnects from rapid Chrome restarts |
7171
| `lifeMu` | `conn`, `lifecycleCtx`, `cancel`, `done`, `readReady` -- all fields that change during Start / Stop / reconnect |
7272
| `pendReqMu` | `pendingRequests` (requestId -> `networkReqState`): in-flight network requests accumulating request/response metadata until `loadingFinished` |
73-
| `computed.mu` | All `computedState` fields: counters and timers for the `network_idle`, `layout_settled`, and `navigation_settled` state machines |
73+
| `computed.mu` | All `computedState` fields: counters and timers for the `network_idle`, `page_layout_settled`, and `page_navigation_settled` state machines |
7474
| `pendMu` | `pending` (id -> reply channel): in-flight CDP commands waiting for a response from Chrome |
7575
| `sessionsMu` | `sessions` (sessionID -> `targetInfo`): the set of currently attached CDP targets (tabs, iframes, workers) |
7676
| `bindingRateMu` | `bindingLastSeen` (sessionID:eventType -> time): rate-limit state for `__kernelEvent` binding calls |
@@ -79,4 +79,143 @@ Fields that need no mutex use `sync/atomic`: `nextID`, `mainSessionID`, `running
7979

8080
### WebSocket concurrency
8181

82-
`coder/websocket` guarantees one concurrent `Read` and one concurrent `Write` are safe on the same connection. `readLoop` is the sole reader. All writes go through `send`, which calls `conn.Write` directly -- `conn.Write` is internally serialized by the library, so no external write mutex is needed.
82+
`coder/websocket` guarantees one concurrent `Read` and one concurrent `Write` are safe on the same connection. `readLoop` is the sole reader. All writes go through `send`, which calls `conn.Write` directly -- `conn.Write` is internally serialized by the library, so no external write mutex is needed.
83+
84+
## Event data model
85+
86+
### Envelope and top-level fields
87+
88+
Every event arrives as an `Envelope`:
89+
90+
```json
91+
{
92+
"capture_session_id": "cs_abc123",
93+
"seq": 42,
94+
"event": {
95+
"ts": 1746123456789000,
96+
"type": "network_request",
97+
"category": "network",
98+
"source": { ... },
99+
"data": { ... },
100+
"truncated": false
101+
}
102+
}
103+
```
104+
105+
| Field | Type | Description |
106+
| --- | --- | --- |
107+
| `capture_session_id` | string | Pipeline-assigned ID for the capture session (not a CDP concept). |
108+
| `seq` | uint64 | Monotonically increasing per-capture-session sequence number. |
109+
| `event.ts` | int64 | Wall-clock time the monitor emitted the event, as **Unix microseconds** (µs since epoch). |
110+
| `event.type` | string | See [Event taxonomy](#event-taxonomy). |
111+
| `event.category` | string | One of: `console`, `network`, `page`, `interaction`, `system`. |
112+
| `event.truncated` | bool | `true` if `data` was nulled to fit the 1 MB pipeline limit. |
113+
114+
### Source object
115+
116+
```json
117+
"source": {
118+
"kind": "cdp",
119+
"event": "Network.requestWillBeSent",
120+
"metadata": {
121+
"cdp_session_id": "...",
122+
"target_id": "...",
123+
"target_type": "page"
124+
}
125+
}
126+
```
127+
128+
| Field | Description |
129+
| --- | --- |
130+
| `event` | The raw CDP method that triggered the event (e.g. `Network.requestWillBeSent`). Empty for computed events. |
131+
| `metadata.cdp_session_id` | The CDP WebSocket session multiplexer ID for this target. Changes if Chrome restarts. |
132+
| `metadata.target_id` | Stable identifier for the browser target (tab/window). Survives navigations within the same tab. |
133+
| `metadata.target_type` | Target type as reported by Chrome: `page`, `iframe`, `worker`, etc. |
134+
135+
### CDP identity primer
136+
137+
Five IDs appear across events. Understanding how they nest prevents confusion:
138+
139+
```
140+
target_id <- one per tab/window; stable across navigations
141+
└── cdp_session_id <- WebSocket multiplexer channel to that target; resets on Chrome restart
142+
└── frame_id <- one per frame (top-level or iframe); changes on navigation
143+
└── loader_id <- one per document load; links a navigation to its network requests
144+
└── request_id <- one per request (stable across redirects in a chain)
145+
```
146+
147+
| ID | Where it appears | What it identifies |
148+
| --- | --- | --- |
149+
| `target_id` | `source.metadata`, most `data` objects | The browser tab. Use this to group all events from one tab session. |
150+
| `cdp_session_id` | `source.metadata` | The WebSocket sub-channel. Not stable across reconnects. |
151+
| `frame_id` | `page_navigation`, `network_request`, `network_response`, `network_loading_failed` | The frame the request or navigation belongs to. Top-level frame has no `parent_frame_id`. |
152+
| `source_frame_id` | `page_layout_shift` | The frame where the layout shift occurred. Distinct from the nav context `frame_id`, which is always the top-level navigated frame. |
153+
| `loader_id` | `page_navigation`, `network_request`, `network_response` | The document load that owns a request. Join `network_request.loader_id` to `page_navigation.loader_id` to correlate requests with the navigation that triggered them. |
154+
| `request_id` | `network_request`, `network_response`, `network_loading_failed` | A single request chain (including redirects). Links request to its eventual response or failure. |
155+
156+
### Navigation context fields
157+
158+
Most event `data` objects include a nav context block stamped at the last `page_navigation`. These fields reflect the top-level frame most recently navigated in the session:
159+
160+
| Field | Description |
161+
| --- | --- |
162+
| `session_id` | Same as `source.metadata.cdp_session_id`. Repeated for data-only consumers. |
163+
| `frame_id` | Frame ID of the navigated top-level frame. |
164+
| `loader_id` | Loader ID of the current document. |
165+
| `url` | URL of the current page at the time of the last navigation. |
166+
| `nav_seq` | Monotonically increasing counter, incremented on each `page_navigation`. Use it to detect that the page has navigated between two events in the same session. |
167+
168+
### Per-event data fields
169+
170+
Fields below are the unique additions per event type. Unless otherwise noted, events also include the nav context fields described above. Network events are the exception: they carry their own `loader_id` and `frame_id` directly and do not include nav context.
171+
172+
#### Console events
173+
174+
| Event | Unique fields |
175+
| --- | --- |
176+
| `console_log` | `level` (CDP type string), `text` (first arg), `args` (all args as strings), `stack_trace` |
177+
| `console_error` | Same as `console_log` when `source.event` is `Runtime.consoleAPICalled`. When `source.event` is `Runtime.exceptionThrown`: `text`, `line`, `column`, `source_url` (script file URL, not page URL), `stack_trace`. |
178+
179+
#### Network events
180+
181+
| Event | Fields |
182+
| --- | --- |
183+
| `network_request` | `request_id`, `loader_id`, `frame_id`, `document_url`, `method`, `url`, `headers`, `initiator_type`. Optional: `post_data`, `resource_type`, `is_redirect` + `redirect_url`. |
184+
| `network_response` | `request_id`, `loader_id`, `frame_id`, `method`, `url`, `status`, `headers`. Optional: `status_text`, `mime_type`, `resource_type`, `body` (truncated text body for textual MIME types). |
185+
| `network_loading_failed` | `request_id`, `error_text`, `canceled`. Optional (absent when the request record was not found): `url`, `loader_id`, `frame_id`, `resource_type`. |
186+
187+
#### Page events
188+
189+
| Event | Unique fields |
190+
| --- | --- |
191+
| `page_tab_opened` | `target_id`, `target_type`, `url`, `opener_id`, `title`. Emitted before the first navigation; no nav context. |
192+
| `page_navigation` | `session_id`, `target_id`, `target_type`, `url`, `frame_id`, `parent_frame_id` (absent for top-level frames), `loader_id`. This event establishes the nav context stamped on all subsequent events for the session. |
193+
| `page_dom_content_loaded` | Nav context + `cdp_timestamp` (CDP monotonic seconds; not a wall-clock timestamp -- use `event.ts` for ordering). |
194+
| `page_load` | Nav context + `cdp_timestamp` (CDP monotonic seconds). |
195+
| `page_layout_shift` | Nav context + `source_frame_id`, `time`, `duration`. Optional `layout_shift_details` object: `score`, `had_recent_input`. Optional `lcp_details` object: `render_time`, `load_time`, `size`, `element_id`, `url`, `node_id`. Chrome multiplexes LCP candidate data through the same `PerformanceTimeline.timelineEventAdded` notification, so both may appear on a single event. |
196+
197+
#### Computed events
198+
199+
`network_idle`, `page_layout_settled`, and `page_navigation_settled` carry nav context fields only.
200+
201+
#### Interaction events
202+
203+
All interaction events include nav context plus the fields below.
204+
205+
| Event | Unique fields |
206+
| --- | --- |
207+
| `interaction_click` | `x`, `y` (viewport coords), `selector` (CSS selector of clicked element), `tag`, `text` (element text; empty for sensitive inputs). |
208+
| `interaction_key` | `key` (key name), `selector`, `tag`. Not emitted for sensitive input fields. |
209+
| `interaction_scroll_settled` | `from_x`, `from_y`, `to_x`, `to_y` (scroll positions in px), `target_selector`. |
210+
211+
#### Monitor lifecycle events
212+
213+
Lifecycle events use `source.kind = "local_process"` and carry no nav context, except `monitor_screenshot` which includes nav context alongside the image payload.
214+
215+
| Event | Fields |
216+
| --- | --- |
217+
| `monitor_screenshot` | Nav context + `png` (base64-encoded PNG). |
218+
| `monitor_disconnected` | `reason: "chrome_restarted"`. |
219+
| `monitor_reconnected` | `reconnect_duration_ms`. |
220+
| `monitor_reconnect_failed` | `reason: "reconnect_exhausted"`. |
221+
| `monitor_init_failed` | `step` (name of the init step that failed, e.g. `"Target.setAutoAttach"`). |

0 commit comments

Comments
 (0)