browser-debug-mcp-bridge 1.5.0 → 1.9.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 +136 -26
- package/apps/mcp-server/dist/db/events-repository.js +296 -26
- package/apps/mcp-server/dist/db/events-repository.js.map +1 -1
- package/apps/mcp-server/dist/db/migrations.js +191 -1
- package/apps/mcp-server/dist/db/migrations.js.map +1 -1
- package/apps/mcp-server/dist/db/schema.js +35 -1
- package/apps/mcp-server/dist/db/schema.js.map +1 -1
- package/apps/mcp-server/dist/main.js +21 -4
- package/apps/mcp-server/dist/main.js.map +1 -1
- package/apps/mcp-server/dist/mcp/server.js +1148 -112
- package/apps/mcp-server/dist/mcp/server.js.map +1 -1
- package/apps/mcp-server/dist/retention.js +97 -8
- package/apps/mcp-server/dist/retention.js.map +1 -1
- package/apps/mcp-server/dist/websocket/messages.js +27 -0
- package/apps/mcp-server/dist/websocket/messages.js.map +1 -1
- package/apps/mcp-server/dist/websocket/websocket-server.js +20 -0
- package/apps/mcp-server/dist/websocket/websocket-server.js.map +1 -1
- package/apps/mcp-server/package.json +2 -2
- package/package.json +13 -6
- package/scripts/mcp-start.cjs +178 -18
package/README.md
CHANGED
|
@@ -9,6 +9,9 @@ It captures telemetry from an actual browser session (console, network, navigati
|
|
|
9
9
|
- Inspect real sessions instead of synthetic test runs
|
|
10
10
|
- Query recent errors, failed requests, and event timelines
|
|
11
11
|
- Run targeted live capture (DOM subtree/document, styles, layout)
|
|
12
|
+
- Pull live in-memory console logs with server-side filters (`url`, `tabId`, `levels`, `contains`)
|
|
13
|
+
- Query targeted API calls with optional sanitized request/response bodies
|
|
14
|
+
- Wait deterministically for the next matching API request during repro flows
|
|
12
15
|
- Correlate user actions with network/runtime failures
|
|
13
16
|
- Keep privacy controls enabled (safe mode, allowlist, redaction)
|
|
14
17
|
|
|
@@ -22,14 +25,47 @@ It captures telemetry from an actual browser session (console, network, navigati
|
|
|
22
25
|
## Requirements
|
|
23
26
|
|
|
24
27
|
- Node.js `>=20`
|
|
28
|
+
- npm (for no-repo quick mode)
|
|
25
29
|
- pnpm `>=9` (for local repo mode)
|
|
26
30
|
- Chrome (Developer Mode to load unpacked extension)
|
|
27
31
|
|
|
28
32
|
## Setup Modes
|
|
29
33
|
|
|
30
|
-
### Recommended
|
|
34
|
+
### Recommended for Most Users: No-Repo Quick Setup
|
|
31
35
|
|
|
32
|
-
Use this when you want
|
|
36
|
+
Use this when you want to install and run quickly without cloning this repository.
|
|
37
|
+
|
|
38
|
+
1. Install runtime globally:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm i -g browser-debug-mcp-bridge
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
1. Download the latest extension asset `chrome-extension-dist.tgz` from:
|
|
45
|
+
|
|
46
|
+
- `https://github.com/RobertoM80/browser-debug-mcp-bridge/releases/latest`
|
|
47
|
+
|
|
48
|
+
1. Extract the archive and load extension in Chrome:
|
|
49
|
+
|
|
50
|
+
1. Open `chrome://extensions`
|
|
51
|
+
1. Enable Developer mode
|
|
52
|
+
1. Click **Load unpacked**
|
|
53
|
+
1. Select the extracted extension folder
|
|
54
|
+
|
|
55
|
+
1. Configure MCP host with direct Node launch (recommended):
|
|
56
|
+
|
|
57
|
+
1. Find npm global root: `npm root -g`
|
|
58
|
+
1. Use script path: `<NPM_GLOBAL_ROOT>/browser-debug-mcp-bridge/scripts/mcp-start.cjs`
|
|
59
|
+
|
|
60
|
+
1. Alternative quick runtime (secondary):
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npx -y browser-debug-mcp-bridge
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Local Repo Setup (Contributors/Customization)
|
|
67
|
+
|
|
68
|
+
Use this when you need local development, customization, or source-level debugging.
|
|
33
69
|
|
|
34
70
|
```bash
|
|
35
71
|
git clone https://github.com/RobertoM80/browser-debug-mcp-bridge.git
|
|
@@ -52,28 +88,9 @@ Start MCP runtime:
|
|
|
52
88
|
node scripts/mcp-start.cjs
|
|
53
89
|
```
|
|
54
90
|
|
|
55
|
-
### Quick Runtime (MCP server launcher only)
|
|
56
|
-
|
|
57
|
-
If you already have extension/runtime assets aligned, you can launch from npm:
|
|
58
|
-
|
|
59
|
-
```bash
|
|
60
|
-
npx -y browser-debug-mcp-bridge
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
GitHub fallback (if npm registry package is unavailable):
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
npx -y --package=github:RobertoM80/browser-debug-mcp-bridge browser-debug-mcp-bridge
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
Important:
|
|
70
|
-
|
|
71
|
-
- This only starts the runtime.
|
|
72
|
-
- You still need a compatible extension connected to `127.0.0.1:8065`.
|
|
73
|
-
|
|
74
91
|
## MCP Client Configuration
|
|
75
92
|
|
|
76
|
-
|
|
93
|
+
If you are using local repo mode, generate ready-to-paste snippets:
|
|
77
94
|
|
|
78
95
|
```bash
|
|
79
96
|
pnpm mcp:print-config
|
|
@@ -81,15 +98,25 @@ pnpm mcp:print-config
|
|
|
81
98
|
|
|
82
99
|
### OpenAI (Codex CLI / Codex in VS Code)
|
|
83
100
|
|
|
101
|
+
Best-practice launch path: use direct `node` launch to the installed script path.
|
|
102
|
+
|
|
84
103
|
Edit `~/.codex/config.toml` (Windows: `C:\Users\<you>\.codex\config.toml`) and add:
|
|
85
104
|
|
|
105
|
+
```toml
|
|
106
|
+
[mcp_servers.browser_debug]
|
|
107
|
+
command = "node"
|
|
108
|
+
args = ["C:\\Users\\<you>\\AppData\\Roaming\\npm\\node_modules\\browser-debug-mcp-bridge\\scripts\\mcp-start.cjs"]
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
local repo mode alternative:
|
|
112
|
+
|
|
86
113
|
```toml
|
|
87
114
|
[mcp_servers.browser_debug]
|
|
88
115
|
command = "node"
|
|
89
116
|
args = ["C:\\ABSOLUTE\\PATH\\TO\\browser-debug-mcp-bridge\\scripts\\mcp-start.cjs"]
|
|
90
117
|
```
|
|
91
118
|
|
|
92
|
-
npm quick mode:
|
|
119
|
+
npm quick mode (secondary):
|
|
93
120
|
|
|
94
121
|
```toml
|
|
95
122
|
[mcp_servers.browser_debug]
|
|
@@ -107,7 +134,7 @@ Use JSON MCP config:
|
|
|
107
134
|
"browser-debug": {
|
|
108
135
|
"command": "node",
|
|
109
136
|
"args": [
|
|
110
|
-
"C:\\
|
|
137
|
+
"C:\\Users\\<you>\\AppData\\Roaming\\npm\\node_modules\\browser-debug-mcp-bridge\\scripts\\mcp-start.cjs"
|
|
111
138
|
]
|
|
112
139
|
}
|
|
113
140
|
}
|
|
@@ -120,7 +147,7 @@ Use the same values:
|
|
|
120
147
|
|
|
121
148
|
- `command`: `node`
|
|
122
149
|
- `args`: `[
|
|
123
|
-
"<
|
|
150
|
+
"<NPM_GLOBAL_ROOT>/browser-debug-mcp-bridge/scripts/mcp-start.cjs"
|
|
124
151
|
]`
|
|
125
152
|
|
|
126
153
|
If your VS Code MCP host uses JSON, reuse the OpenCode JSON block above.
|
|
@@ -137,17 +164,89 @@ If your VS Code MCP host uses JSON, reuse the OpenCode JSON block above.
|
|
|
137
164
|
|
|
138
165
|
- Pick a session where `liveConnection.connected` is `true`.
|
|
139
166
|
- Run query tools first (`get_session_summary`, `get_recent_events`, `get_network_failures`).
|
|
140
|
-
- Use live tools (`get_dom_document`, `capture_ui_snapshot`) only on connected sessions.
|
|
167
|
+
- Use live tools (`get_dom_document`, `capture_ui_snapshot`, `get_live_console_logs`) only on connected sessions.
|
|
168
|
+
|
|
169
|
+
## Session Scope and URL Filtering
|
|
170
|
+
|
|
171
|
+
- Sessions start bound to the active tab only.
|
|
172
|
+
- Telemetry from unbound tabs is rejected to avoid cross-tab contamination.
|
|
173
|
+
- Use the popup `Session Tabs` panel to explicitly add/remove tabs from the active session.
|
|
174
|
+
- If all bound tabs are removed/closed, the session auto-stops.
|
|
175
|
+
|
|
176
|
+
MCP query tools support `sessionId`, `url`, or both:
|
|
177
|
+
|
|
178
|
+
- `sessionId` only: filter by session
|
|
179
|
+
- `url` only: filter by URL origin across sessions (for example `http://localhost:3000`)
|
|
180
|
+
- `sessionId + url`: intersection (only rows matching both)
|
|
181
|
+
|
|
182
|
+
Supported tools:
|
|
183
|
+
|
|
184
|
+
- `get_recent_events`
|
|
185
|
+
- `get_navigation_history`
|
|
186
|
+
- `get_console_events`
|
|
187
|
+
- `get_network_failures`
|
|
188
|
+
- `get_network_calls`
|
|
189
|
+
|
|
190
|
+
Example: URL-only query
|
|
191
|
+
|
|
192
|
+
```json
|
|
193
|
+
{
|
|
194
|
+
"name": "get_recent_events",
|
|
195
|
+
"arguments": { "url": "http://localhost:3000", "limit": 50 }
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Example: session + URL intersection
|
|
200
|
+
|
|
201
|
+
```json
|
|
202
|
+
{
|
|
203
|
+
"name": "get_network_failures",
|
|
204
|
+
"arguments": { "sessionId": "sess_123", "url": "http://localhost:3000", "limit": 20 }
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Live Console Logs (Non-Persistent)
|
|
209
|
+
|
|
210
|
+
`get_live_console_logs` reads from extension in-memory ring buffers (session-scoped), so this live stream can be filtered without DB scanning.
|
|
211
|
+
|
|
212
|
+
- `sessionId` is required
|
|
213
|
+
- optional filters: `url` (origin), `tabId`, `levels`, `contains`, `sinceTs`
|
|
214
|
+
- supports substring filters like `"[auth]"` directly server-side
|
|
215
|
+
- results are bounded by `limit` and buffer capacity
|
|
216
|
+
|
|
217
|
+
Capture scope:
|
|
218
|
+
|
|
219
|
+
- Captured from page context: `console.log`, `console.info`, `console.warn`, `console.error`, `console.debug`, `console.trace`
|
|
220
|
+
- Runtime JS exceptions are included as `error`-level live entries
|
|
221
|
+
- Browser-internal/DevTools UI-only rows are not guaranteed
|
|
222
|
+
|
|
223
|
+
Example:
|
|
224
|
+
|
|
225
|
+
```json
|
|
226
|
+
{
|
|
227
|
+
"name": "get_live_console_logs",
|
|
228
|
+
"arguments": {
|
|
229
|
+
"sessionId": "sess_123",
|
|
230
|
+
"url": "http://localhost:3000",
|
|
231
|
+
"levels": ["info", "error"],
|
|
232
|
+
"contains": "[auth]",
|
|
233
|
+
"limit": 100
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
```
|
|
141
237
|
|
|
142
238
|
## Port and Startup Behavior
|
|
143
239
|
|
|
144
240
|
Default port is `8065`.
|
|
145
241
|
|
|
242
|
+
- Launcher enforces a single-instance startup lock to avoid concurrent launch races.
|
|
146
243
|
- On Windows, launcher tries automatic stale bridge recovery first.
|
|
147
244
|
- If port is still occupied, startup fails with `MCP_STARTUP_PORT_IN_USE`.
|
|
148
245
|
- In that case, free/reserve port `8065` for this bridge and restart.
|
|
246
|
+
- Launcher reports `Started` only after `/health` becomes reachable on `127.0.0.1:8065`.
|
|
149
247
|
- In `mcp-stdio` mode, bridge lifecycle is tied to the host and should stop when host transport closes.
|
|
150
248
|
- If a stale process still remains, stop it explicitly with `node scripts/mcp-start.cjs --stop`.
|
|
249
|
+
- Optional: set `MCP_STARTUP_TIMEOUT_MS` (default `15000`) for slower machines.
|
|
151
250
|
|
|
152
251
|
Useful Windows command:
|
|
153
252
|
|
|
@@ -172,12 +271,23 @@ node scripts/mcp-start.cjs --stop
|
|
|
172
271
|
pnpm typecheck
|
|
173
272
|
pnpm lint
|
|
174
273
|
pnpm test
|
|
274
|
+
pnpm test:e2e
|
|
275
|
+
pnpm test:e2e:head
|
|
276
|
+
pnpm test:e2e:smoke
|
|
277
|
+
pnpm test:e2e:full
|
|
175
278
|
pnpm build
|
|
176
279
|
pnpm docs:ci
|
|
177
280
|
pnpm verify
|
|
178
281
|
node scripts/mcp-start.cjs --stop
|
|
179
282
|
```
|
|
180
283
|
|
|
284
|
+
E2E commands run headless by default. Use `pnpm test:e2e:head` only for local headed debugging.
|
|
285
|
+
|
|
286
|
+
CI lanes:
|
|
287
|
+
|
|
288
|
+
- Pull requests and pushes to `main`: `verify` + Playwright smoke + Playwright full.
|
|
289
|
+
- Nightly: `verify` + Playwright full + runtime `/health` smoke check.
|
|
290
|
+
|
|
181
291
|
Optional one-shot local setup:
|
|
182
292
|
|
|
183
293
|
```powershell
|
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
import { resolveErrorFingerprint } from './error-fingerprints.js';
|
|
2
2
|
import { getDatabasePath } from './connection.js';
|
|
3
3
|
import { writeSnapshot } from '../retention.js';
|
|
4
|
+
const INLINE_BODY_BYTES_THRESHOLD = 16 * 1024;
|
|
5
|
+
const BODY_KIND_REQUEST = 'request';
|
|
6
|
+
const BODY_KIND_RESPONSE = 'response';
|
|
7
|
+
const SENSITIVE_FIELD_NAMES = new Set([
|
|
8
|
+
'authorization',
|
|
9
|
+
'proxy-authorization',
|
|
10
|
+
'cookie',
|
|
11
|
+
'set-cookie',
|
|
12
|
+
'x-api-key',
|
|
13
|
+
'api-key',
|
|
14
|
+
'apikey',
|
|
15
|
+
'x-auth-token',
|
|
16
|
+
'access-token',
|
|
17
|
+
'refresh-token',
|
|
18
|
+
'token',
|
|
19
|
+
'password',
|
|
20
|
+
'secret',
|
|
21
|
+
'client_secret',
|
|
22
|
+
]);
|
|
23
|
+
const REDACTION_PATTERNS = [
|
|
24
|
+
{ pattern: /(Authorization:\s*Bearer\s+)[\w\-\.=]+/gi, replacement: '$1[REDACTED]' },
|
|
25
|
+
{ pattern: /eyJ[\w-]*\.eyJ[\w-]*\.[\w-]*/g, replacement: '[JWT_TOKEN]' },
|
|
26
|
+
{ pattern: /((?:api[_-]?key|apikey)\s*[:=]\s*)[\w-]+/gi, replacement: '$1[API_KEY]' },
|
|
27
|
+
{ pattern: /((?:access[_-]?token|refresh[_-]?token|token)\s*[:=]\s*)[^\s,;]+/gi, replacement: '$1[TOKEN]' },
|
|
28
|
+
{ pattern: /((?:password|pwd)\s*[:=]\s*)\S+/gi, replacement: '$1[PASSWORD]' },
|
|
29
|
+
];
|
|
4
30
|
export class EventsRepository {
|
|
5
31
|
db;
|
|
6
32
|
constructor(db) {
|
|
@@ -11,12 +37,19 @@ export class EventsRepository {
|
|
|
11
37
|
return;
|
|
12
38
|
}
|
|
13
39
|
const insert = this.db.prepare(`
|
|
14
|
-
INSERT INTO events (event_id, session_id, ts, type, payload_json)
|
|
15
|
-
VALUES (?, ?, ?, ?, ?)
|
|
40
|
+
INSERT INTO events (event_id, session_id, ts, type, payload_json, tab_id, origin)
|
|
41
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
16
42
|
`);
|
|
17
43
|
const insertNetwork = this.db.prepare(`
|
|
18
44
|
INSERT INTO network (
|
|
19
|
-
request_id, session_id, ts_start, duration_ms, method, url, status, initiator, error_class, response_size_est
|
|
45
|
+
request_id, session_id, trace_id, tab_id, ts_start, duration_ms, method, url, origin, status, initiator, error_class, response_size_est,
|
|
46
|
+
request_content_type, request_body_text, request_body_json, request_body_bytes, request_body_truncated, request_body_chunk_ref,
|
|
47
|
+
response_content_type, response_body_text, response_body_json, response_body_bytes, response_body_truncated, response_body_chunk_ref
|
|
48
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
49
|
+
`);
|
|
50
|
+
const insertBodyChunk = this.db.prepare(`
|
|
51
|
+
INSERT INTO body_chunks (
|
|
52
|
+
chunk_ref, session_id, request_id, trace_id, body_kind, content_type, body_text, body_bytes, truncated, created_at
|
|
20
53
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
21
54
|
`);
|
|
22
55
|
const upsertFingerprint = this.db.prepare(`
|
|
@@ -33,15 +66,22 @@ export class EventsRepository {
|
|
|
33
66
|
for (const message of batch) {
|
|
34
67
|
const eventId = `${message.sessionId}-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
35
68
|
const dbEventType = this.mapEventType(message.eventType);
|
|
36
|
-
|
|
69
|
+
const sanitizedData = message.eventType === 'network'
|
|
70
|
+
? sanitizeRecord(message.data)
|
|
71
|
+
: message.data;
|
|
72
|
+
const eventTabId = typeof message.tabId === 'number' && Number.isFinite(message.tabId)
|
|
73
|
+
? Math.floor(message.tabId)
|
|
74
|
+
: this.resolveTabIdFromPayload(sanitizedData);
|
|
75
|
+
const eventOrigin = this.resolveEventOrigin(sanitizedData, message.origin);
|
|
76
|
+
insert.run(eventId, message.sessionId, message.timestamp ?? Date.now(), dbEventType, JSON.stringify(sanitizedData), eventTabId, eventOrigin);
|
|
37
77
|
if (message.eventType === 'error') {
|
|
38
|
-
this.upsertErrorFingerprintPrepared(upsertFingerprint, message.sessionId,
|
|
78
|
+
this.upsertErrorFingerprintPrepared(upsertFingerprint, message.sessionId, sanitizedData);
|
|
39
79
|
}
|
|
40
80
|
if (message.eventType === 'network') {
|
|
41
|
-
this.insertNetworkEventPrepared(insertNetwork, message.sessionId,
|
|
81
|
+
this.insertNetworkEventPrepared(insertNetwork, insertBodyChunk, message.sessionId, sanitizedData, eventOrigin, eventTabId);
|
|
42
82
|
}
|
|
43
83
|
if (message.eventType === 'ui_snapshot') {
|
|
44
|
-
this.insertSnapshotPrepared(message.sessionId, eventId,
|
|
84
|
+
this.insertSnapshotPrepared(message.sessionId, eventId, sanitizedData);
|
|
45
85
|
}
|
|
46
86
|
}
|
|
47
87
|
});
|
|
@@ -59,31 +99,63 @@ export class EventsRepository {
|
|
|
59
99
|
}
|
|
60
100
|
endSession(message) {
|
|
61
101
|
const update = this.db.prepare(`
|
|
62
|
-
UPDATE sessions
|
|
63
|
-
SET ended_at =
|
|
102
|
+
UPDATE sessions
|
|
103
|
+
SET ended_at = ?, paused_at = NULL
|
|
64
104
|
WHERE session_id = ?
|
|
65
105
|
`);
|
|
66
106
|
update.run(Date.now(), message.sessionId);
|
|
67
107
|
}
|
|
108
|
+
pauseSession(message) {
|
|
109
|
+
const update = this.db.prepare(`
|
|
110
|
+
UPDATE sessions
|
|
111
|
+
SET paused_at = COALESCE(paused_at, ?), ended_at = NULL
|
|
112
|
+
WHERE session_id = ? AND ended_at IS NULL
|
|
113
|
+
`);
|
|
114
|
+
const result = update.run(Date.now(), message.sessionId);
|
|
115
|
+
if (result.changes === 0) {
|
|
116
|
+
throw new Error(`Session not found or already ended: ${message.sessionId}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
resumeSession(message) {
|
|
120
|
+
const update = this.db.prepare(`
|
|
121
|
+
UPDATE sessions
|
|
122
|
+
SET
|
|
123
|
+
paused_at = NULL,
|
|
124
|
+
ended_at = NULL,
|
|
125
|
+
url_last = COALESCE(?, url_last),
|
|
126
|
+
tab_id = COALESCE(?, tab_id),
|
|
127
|
+
window_id = COALESCE(?, window_id),
|
|
128
|
+
user_agent = COALESCE(?, user_agent),
|
|
129
|
+
viewport_w = COALESCE(?, viewport_w),
|
|
130
|
+
viewport_h = COALESCE(?, viewport_h),
|
|
131
|
+
dpr = COALESCE(?, dpr),
|
|
132
|
+
safe_mode = COALESCE(?, safe_mode)
|
|
133
|
+
WHERE session_id = ? AND ended_at IS NULL
|
|
134
|
+
`);
|
|
135
|
+
const result = update.run(message.url ?? null, message.tabId ?? null, message.windowId ?? null, message.userAgent ?? null, message.viewport?.width ?? null, message.viewport?.height ?? null, message.dpr ?? null, message.safeMode === undefined ? null : (message.safeMode ? 1 : 0), message.sessionId);
|
|
136
|
+
if (result.changes === 0) {
|
|
137
|
+
throw new Error(`Session not found or already ended: ${message.sessionId}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
68
140
|
insertEvent(message) {
|
|
69
141
|
this.insertEventsBatch([message]);
|
|
70
142
|
}
|
|
71
143
|
mapEventType(eventType) {
|
|
72
144
|
const mapping = {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
145
|
+
navigation: 'nav',
|
|
146
|
+
console: 'console',
|
|
147
|
+
error: 'error',
|
|
148
|
+
network: 'network',
|
|
149
|
+
click: 'ui',
|
|
150
|
+
scroll: 'ui',
|
|
151
|
+
input: 'ui',
|
|
152
|
+
change: 'ui',
|
|
153
|
+
submit: 'ui',
|
|
154
|
+
focus: 'ui',
|
|
155
|
+
blur: 'ui',
|
|
156
|
+
keydown: 'ui',
|
|
157
|
+
ui_snapshot: 'ui',
|
|
158
|
+
custom: 'ui',
|
|
87
159
|
};
|
|
88
160
|
return mapping[eventType] || 'ui';
|
|
89
161
|
}
|
|
@@ -94,16 +166,214 @@ export class EventsRepository {
|
|
|
94
166
|
const now = Date.now();
|
|
95
167
|
statement.run(fingerprint, sessionId, data.message ?? 'Unknown error', data.stack ?? null, now, now);
|
|
96
168
|
}
|
|
97
|
-
insertNetworkEventPrepared(
|
|
98
|
-
const
|
|
99
|
-
|
|
169
|
+
insertNetworkEventPrepared(networkStatement, bodyChunkStatement, sessionId, data, eventOrigin, eventTabId) {
|
|
170
|
+
const normalized = this.normalizeNetworkInsertInput(sessionId, data, eventOrigin, eventTabId, bodyChunkStatement);
|
|
171
|
+
networkStatement.run(normalized.requestId, sessionId, normalized.traceId, normalized.tabId, normalized.tsStart, normalized.durationMs, normalized.method, normalized.url, normalized.origin, normalized.status, normalized.initiator, normalized.errorClass, normalized.responseSizeEst, normalized.request.contentType, normalized.request.bodyText, normalized.request.bodyJson, normalized.request.bodyBytes, normalized.request.truncated ? 1 : 0, normalized.request.chunkRef, normalized.response.contentType, normalized.response.bodyText, normalized.response.bodyJson, normalized.response.bodyBytes, normalized.response.truncated ? 1 : 0, normalized.response.chunkRef);
|
|
172
|
+
}
|
|
173
|
+
normalizeNetworkInsertInput(sessionId, data, eventOrigin, eventTabId, bodyChunkStatement) {
|
|
174
|
+
const requestId = toNonEmptyString(data.requestId)
|
|
175
|
+
?? `${sessionId}-net-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
176
|
+
const traceId = toNonEmptyString(data.traceId) ?? null;
|
|
177
|
+
const url = toNonEmptyString(data.url) ?? '';
|
|
178
|
+
const origin = eventOrigin ?? normalizeOriginCandidate(url);
|
|
179
|
+
const request = this.processNetworkBody({
|
|
180
|
+
sessionId,
|
|
181
|
+
requestId,
|
|
182
|
+
traceId,
|
|
183
|
+
bodyKind: BODY_KIND_REQUEST,
|
|
184
|
+
contentType: toNullableContentType(data.requestContentType),
|
|
185
|
+
bodyText: toNonEmptyString(data.requestBodyText),
|
|
186
|
+
bodyJson: toRecordLike(data.requestBodyJson),
|
|
187
|
+
bodyBytes: toNullableInteger(data.requestBodyBytes),
|
|
188
|
+
truncated: data.requestBodyTruncated === true,
|
|
189
|
+
bodyChunkStatement,
|
|
190
|
+
});
|
|
191
|
+
const response = this.processNetworkBody({
|
|
192
|
+
sessionId,
|
|
193
|
+
requestId,
|
|
194
|
+
traceId,
|
|
195
|
+
bodyKind: BODY_KIND_RESPONSE,
|
|
196
|
+
contentType: toNullableContentType(data.responseContentType),
|
|
197
|
+
bodyText: toNonEmptyString(data.responseBodyText),
|
|
198
|
+
bodyJson: toRecordLike(data.responseBodyJson),
|
|
199
|
+
bodyBytes: toNullableInteger(data.responseBodyBytes),
|
|
200
|
+
truncated: data.responseBodyTruncated === true,
|
|
201
|
+
bodyChunkStatement,
|
|
202
|
+
});
|
|
203
|
+
return {
|
|
204
|
+
requestId,
|
|
205
|
+
traceId,
|
|
206
|
+
tabId: eventTabId,
|
|
207
|
+
tsStart: toNullableInteger(data.timestamp) ?? Date.now(),
|
|
208
|
+
durationMs: toNullableInteger(data.duration),
|
|
209
|
+
method: normalizeMethod(toNonEmptyString(data.method)),
|
|
210
|
+
url,
|
|
211
|
+
origin,
|
|
212
|
+
status: toNullableInteger(data.status),
|
|
213
|
+
initiator: normalizeInitiator(toNonEmptyString(data.initiator)),
|
|
214
|
+
errorClass: normalizeErrorClass(toNonEmptyString(data.errorType)),
|
|
215
|
+
responseSizeEst: toNullableInteger(data.responseSize),
|
|
216
|
+
request,
|
|
217
|
+
response,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
processNetworkBody(params) {
|
|
221
|
+
const redactedJson = params.bodyJson ? sanitizeRecord(params.bodyJson) : null;
|
|
222
|
+
const redactedText = params.bodyText ? redactString(params.bodyText) : null;
|
|
223
|
+
const resolvedText = redactedText
|
|
224
|
+
?? (redactedJson ? JSON.stringify(redactedJson) : null);
|
|
225
|
+
const resolvedBytes = resolvedText ? utf8Bytes(resolvedText) : params.bodyBytes;
|
|
226
|
+
const resolvedJsonText = redactedJson ? JSON.stringify(redactedJson) : null;
|
|
227
|
+
if (!resolvedText && !resolvedJsonText && resolvedBytes === null) {
|
|
228
|
+
return {
|
|
229
|
+
contentType: params.contentType,
|
|
230
|
+
bodyText: null,
|
|
231
|
+
bodyJson: null,
|
|
232
|
+
bodyBytes: null,
|
|
233
|
+
truncated: params.truncated,
|
|
234
|
+
chunkRef: null,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
if (resolvedText && resolvedBytes !== null && resolvedBytes > INLINE_BODY_BYTES_THRESHOLD) {
|
|
238
|
+
const chunkRef = `${params.requestId}:${params.bodyKind}:${Date.now()}:${Math.random().toString(36).slice(2, 8)}`;
|
|
239
|
+
params.bodyChunkStatement.run(chunkRef, params.sessionId, params.requestId, params.traceId, params.bodyKind, params.contentType, resolvedText, resolvedBytes, params.truncated ? 1 : 0, Date.now());
|
|
240
|
+
return {
|
|
241
|
+
contentType: params.contentType,
|
|
242
|
+
bodyText: null,
|
|
243
|
+
bodyJson: null,
|
|
244
|
+
bodyBytes: resolvedBytes,
|
|
245
|
+
truncated: params.truncated,
|
|
246
|
+
chunkRef,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
contentType: params.contentType,
|
|
251
|
+
bodyText: resolvedText,
|
|
252
|
+
bodyJson: resolvedJsonText,
|
|
253
|
+
bodyBytes: resolvedBytes,
|
|
254
|
+
truncated: params.truncated,
|
|
255
|
+
chunkRef: null,
|
|
256
|
+
};
|
|
100
257
|
}
|
|
101
258
|
insertSnapshotPrepared(sessionId, triggerEventId, data) {
|
|
102
259
|
writeSnapshot(this.db, getDatabasePath(), sessionId, data, triggerEventId);
|
|
103
260
|
}
|
|
261
|
+
resolveTabIdFromPayload(payload) {
|
|
262
|
+
const candidate = payload.tabId;
|
|
263
|
+
if (typeof candidate === 'number' && Number.isFinite(candidate)) {
|
|
264
|
+
return Math.floor(candidate);
|
|
265
|
+
}
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
resolveEventOrigin(payload, fallback) {
|
|
269
|
+
const candidates = [fallback, payload.origin, payload.url, payload.to, payload.href, payload.location];
|
|
270
|
+
for (const candidate of candidates) {
|
|
271
|
+
const origin = normalizeOriginCandidate(candidate);
|
|
272
|
+
if (origin) {
|
|
273
|
+
return origin;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
104
278
|
sessionExists(sessionId) {
|
|
105
279
|
const result = this.db.prepare('SELECT 1 FROM sessions WHERE session_id = ?').get(sessionId);
|
|
106
280
|
return !!result;
|
|
107
281
|
}
|
|
108
282
|
}
|
|
283
|
+
function normalizeOriginCandidate(value) {
|
|
284
|
+
if (typeof value !== 'string' || value.trim().length === 0) {
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
try {
|
|
288
|
+
const parsed = new URL(value);
|
|
289
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
return parsed.origin;
|
|
293
|
+
}
|
|
294
|
+
catch {
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function toNonEmptyString(value) {
|
|
299
|
+
if (typeof value !== 'string') {
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
const trimmed = value.trim();
|
|
303
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
304
|
+
}
|
|
305
|
+
function toNullableInteger(value) {
|
|
306
|
+
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
return Math.floor(value);
|
|
310
|
+
}
|
|
311
|
+
function toNullableContentType(value) {
|
|
312
|
+
const normalized = toNonEmptyString(value);
|
|
313
|
+
if (!normalized) {
|
|
314
|
+
return null;
|
|
315
|
+
}
|
|
316
|
+
return normalized.toLowerCase();
|
|
317
|
+
}
|
|
318
|
+
function toRecordLike(value) {
|
|
319
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
320
|
+
return value;
|
|
321
|
+
}
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
function utf8Bytes(value) {
|
|
325
|
+
return Buffer.byteLength(value, 'utf-8');
|
|
326
|
+
}
|
|
327
|
+
function normalizeMethod(value) {
|
|
328
|
+
return value ? value.toUpperCase() : 'GET';
|
|
329
|
+
}
|
|
330
|
+
function normalizeInitiator(value) {
|
|
331
|
+
if (!value) {
|
|
332
|
+
return 'other';
|
|
333
|
+
}
|
|
334
|
+
const normalized = value.toLowerCase();
|
|
335
|
+
if (normalized === 'fetch' || normalized === 'xhr' || normalized === 'img' || normalized === 'script' || normalized === 'other') {
|
|
336
|
+
return normalized;
|
|
337
|
+
}
|
|
338
|
+
return 'other';
|
|
339
|
+
}
|
|
340
|
+
function normalizeErrorClass(value) {
|
|
341
|
+
if (!value) {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
const normalized = value.toLowerCase();
|
|
345
|
+
if (normalized === 'timeout' || normalized === 'cors' || normalized === 'dns' || normalized === 'blocked' || normalized === 'http_error' || normalized === 'unknown') {
|
|
346
|
+
return normalized;
|
|
347
|
+
}
|
|
348
|
+
return 'unknown';
|
|
349
|
+
}
|
|
350
|
+
function sanitizeRecord(value) {
|
|
351
|
+
return sanitizeValue(value, 'root');
|
|
352
|
+
}
|
|
353
|
+
function sanitizeValue(value, key) {
|
|
354
|
+
if (typeof value === 'string') {
|
|
355
|
+
if (SENSITIVE_FIELD_NAMES.has(key.toLowerCase())) {
|
|
356
|
+
return '[REDACTED]';
|
|
357
|
+
}
|
|
358
|
+
return redactString(value);
|
|
359
|
+
}
|
|
360
|
+
if (Array.isArray(value)) {
|
|
361
|
+
return value.map((entry) => sanitizeValue(entry, key));
|
|
362
|
+
}
|
|
363
|
+
if (value && typeof value === 'object') {
|
|
364
|
+
const result = {};
|
|
365
|
+
for (const [entryKey, entryValue] of Object.entries(value)) {
|
|
366
|
+
result[entryKey] = sanitizeValue(entryValue, entryKey);
|
|
367
|
+
}
|
|
368
|
+
return result;
|
|
369
|
+
}
|
|
370
|
+
return value;
|
|
371
|
+
}
|
|
372
|
+
function redactString(value) {
|
|
373
|
+
let result = value;
|
|
374
|
+
for (const rule of REDACTION_PATTERNS) {
|
|
375
|
+
result = result.replace(rule.pattern, rule.replacement);
|
|
376
|
+
}
|
|
377
|
+
return result;
|
|
378
|
+
}
|
|
109
379
|
//# sourceMappingURL=events-repository.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events-repository.js","sourceRoot":"","sources":["../../src/db/events-repository.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"events-repository.js","sourceRoot":"","sources":["../../src/db/events-repository.ts"],"names":[],"mappings":"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"}
|