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 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: Full Local Setup (MCP + Extension)
34
+ ### Recommended for Most Users: No-Repo Quick Setup
31
35
 
32
- Use this when you want the full product (including extension).
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
- Generate ready-to-paste snippets:
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:\\ABSOLUTE\\PATH\\TO\\browser-debug-mcp-bridge\\scripts\\mcp-start.cjs"
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
- "<ABSOLUTE_PATH>/scripts/mcp-start.cjs"
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
- insert.run(eventId, message.sessionId, message.timestamp ?? Date.now(), dbEventType, JSON.stringify(message.data));
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, message.data);
78
+ this.upsertErrorFingerprintPrepared(upsertFingerprint, message.sessionId, sanitizedData);
39
79
  }
40
80
  if (message.eventType === 'network') {
41
- this.insertNetworkEventPrepared(insertNetwork, message.sessionId, message.data);
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, message.data);
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
- 'navigation': 'nav',
74
- 'console': 'console',
75
- 'error': 'error',
76
- 'network': 'network',
77
- 'click': 'ui',
78
- 'scroll': 'ui',
79
- 'input': 'ui',
80
- 'change': 'ui',
81
- 'submit': 'ui',
82
- 'focus': 'ui',
83
- 'blur': 'ui',
84
- 'keydown': 'ui',
85
- 'ui_snapshot': 'ui',
86
- 'custom': 'ui',
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(statement, sessionId, data) {
98
- const requestId = `${sessionId}-net-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
99
- statement.run(requestId, sessionId, data.timestamp ?? Date.now(), data.duration ?? null, data.method ?? 'GET', data.url ?? '', data.status ?? null, data.initiator ?? 'other', data.errorType ?? null, data.responseSize ?? null);
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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"}