browser-debug-mcp-bridge 1.4.0 → 1.6.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
@@ -1,94 +1,300 @@
1
1
  # Browser Debug MCP Bridge
2
2
 
3
- Chrome Extension + local Node.js MCP server that captures browser debugging telemetry from a real user session and exposes it through MCP tools.
3
+ Chrome Extension + local Node.js MCP runtime for real-browser debugging.
4
4
 
5
- ## Why this project exists
5
+ It captures telemetry from an actual browser session (console, network, navigation, UI events), stores it locally, and exposes debugging tools through MCP to your AI client.
6
6
 
7
- - Debug with real browser context (logged-in sessions, feature flags, extensions)
8
- - Store lightweight telemetry continuously, request heavy DOM data on demand
9
- - Keep privacy-first defaults with safe mode, allowlists, and redaction
7
+ ## What You Can Do
10
8
 
11
- ## Prerequisites
9
+ - Inspect real sessions instead of synthetic test runs
10
+ - Query recent errors, failed requests, and event timelines
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
+ - Correlate user actions with network/runtime failures
14
+ - Keep privacy controls enabled (safe mode, allowlist, redaction)
12
15
 
13
- - Node.js 20+
14
- - pnpm 9+
15
- - Chrome (for the extension)
16
+ ## How It Works
16
17
 
17
- ## Quick start
18
+ 1. Chrome extension captures session telemetry.
19
+ 2. Local server ingests via HTTP/WebSocket on `127.0.0.1:8065`.
20
+ 3. Data is persisted in local SQLite.
21
+ 4. MCP stdio server exposes tools to your AI client.
22
+
23
+ ## Requirements
24
+
25
+ - Node.js `>=20`
26
+ - npm (for no-repo quick mode)
27
+ - pnpm `>=9` (for local repo mode)
28
+ - Chrome (Developer Mode to load unpacked extension)
29
+
30
+ ## Setup Modes
31
+
32
+ ### Recommended for Most Users: No-Repo Quick Setup
33
+
34
+ Use this when you want to install and run quickly without cloning this repository.
35
+
36
+ 1. Install runtime globally:
18
37
 
19
38
  ```bash
20
- pnpm install
21
- pnpm nx serve mcp-server
22
- pnpm nx build chrome-extension --watch
39
+ npm i -g browser-debug-mcp-bridge
23
40
  ```
24
41
 
25
- Run unified ingest + MCP stdio runtime (for external MCP clients):
42
+ 1. Download the latest extension asset `chrome-extension-dist.tgz` from:
43
+
44
+ - `https://github.com/RobertoM80/browser-debug-mcp-bridge/releases/latest`
45
+
46
+ 1. Extract the archive and load extension in Chrome:
47
+
48
+ 1. Open `chrome://extensions`
49
+ 1. Enable Developer mode
50
+ 1. Click **Load unpacked**
51
+ 1. Select the extracted extension folder
52
+
53
+ 1. Configure MCP host with direct Node launch (recommended):
54
+
55
+ 1. Find npm global root: `npm root -g`
56
+ 1. Use script path: `<NPM_GLOBAL_ROOT>/browser-debug-mcp-bridge/scripts/mcp-start.cjs`
57
+
58
+ 1. Alternative quick runtime (secondary):
26
59
 
27
60
  ```bash
28
- pnpm install
29
- node scripts/mcp-start.cjs
61
+ npx -y browser-debug-mcp-bridge
30
62
  ```
31
63
 
32
- Quick npm MCP launch (marketplace-style, after publish):
64
+ ### Local Repo Setup (Contributors/Customization)
65
+
66
+ Use this when you need local development, customization, or source-level debugging.
33
67
 
34
68
  ```bash
35
- npx -y browser-debug-mcp-bridge
69
+ git clone https://github.com/RobertoM80/browser-debug-mcp-bridge.git
70
+ cd browser-debug-mcp-bridge
71
+ pnpm install
72
+ pnpm nx build mcp-server
73
+ pnpm nx build chrome-extension
36
74
  ```
37
75
 
38
- Note: npm mode starts the MCP server runtime. The Chrome extension still needs to be built/loaded separately (see "Load the extension").
76
+ Load extension:
77
+
78
+ 1. Open `chrome://extensions`
79
+ 2. Enable Developer mode
80
+ 3. Click **Load unpacked**
81
+ 4. Select `dist/apps/chrome-extension`
39
82
 
40
- GitHub fallback launch (if npm package is not available yet):
83
+ Start MCP runtime:
41
84
 
42
85
  ```bash
43
- npx -y --package=github:RobertoM80/browser-debug-mcp-bridge browser-debug-mcp-bridge
86
+ node scripts/mcp-start.cjs
44
87
  ```
45
88
 
46
- Optional one-step setup scripts:
89
+ ## MCP Client Configuration
90
+
91
+ If you are using local repo mode, generate ready-to-paste snippets:
47
92
 
48
93
  ```bash
49
- # Windows (PowerShell)
50
- ./install.ps1
94
+ pnpm mcp:print-config
95
+ ```
51
96
 
52
- # macOS/Linux
53
- bash ./install.sh
97
+ ### OpenAI (Codex CLI / Codex in VS Code)
98
+
99
+ Best-practice launch path: use direct `node` launch to the installed script path.
100
+
101
+ Edit `~/.codex/config.toml` (Windows: `C:\Users\<you>\.codex\config.toml`) and add:
102
+
103
+ ```toml
104
+ [mcp_servers.browser_debug]
105
+ command = "node"
106
+ args = ["C:\\Users\\<you>\\AppData\\Roaming\\npm\\node_modules\\browser-debug-mcp-bridge\\scripts\\mcp-start.cjs"]
107
+ ```
108
+
109
+ local repo mode alternative:
110
+
111
+ ```toml
112
+ [mcp_servers.browser_debug]
113
+ command = "node"
114
+ args = ["C:\\ABSOLUTE\\PATH\\TO\\browser-debug-mcp-bridge\\scripts\\mcp-start.cjs"]
115
+ ```
116
+
117
+ npm quick mode (secondary):
118
+
119
+ ```toml
120
+ [mcp_servers.browser_debug]
121
+ command = "npx"
122
+ args = ["-y", "browser-debug-mcp-bridge"]
123
+ ```
124
+
125
+ ### OpenCode
126
+
127
+ Use JSON MCP config:
128
+
129
+ ```json
130
+ {
131
+ "mcpServers": {
132
+ "browser-debug": {
133
+ "command": "node",
134
+ "args": [
135
+ "C:\\Users\\<you>\\AppData\\Roaming\\npm\\node_modules\\browser-debug-mcp-bridge\\scripts\\mcp-start.cjs"
136
+ ]
137
+ }
138
+ }
139
+ }
54
140
  ```
55
141
 
56
- Useful workspace commands:
142
+ ### VS Code (any MCP host expecting command/args)
143
+
144
+ Use the same values:
145
+
146
+ - `command`: `node`
147
+ - `args`: `[
148
+ "<NPM_GLOBAL_ROOT>/browser-debug-mcp-bridge/scripts/mcp-start.cjs"
149
+ ]`
150
+
151
+ If your VS Code MCP host uses JSON, reuse the OpenCode JSON block above.
152
+
153
+ ## First End-to-End Check
154
+
155
+ - Start MCP host/client (so it launches this server).
156
+ - Open extension popup, allowlist domain, start a session.
157
+ - Ask your AI client to run:
158
+
159
+ ```json
160
+ { "name": "list_sessions", "arguments": { "sinceMinutes": 60 } }
161
+ ```
162
+
163
+ - Pick a session where `liveConnection.connected` is `true`.
164
+ - Run query tools first (`get_session_summary`, `get_recent_events`, `get_network_failures`).
165
+ - Use live tools (`get_dom_document`, `capture_ui_snapshot`, `get_live_console_logs`) only on connected sessions.
166
+
167
+ ## Session Scope and URL Filtering
168
+
169
+ - Sessions start bound to the active tab only.
170
+ - Telemetry from unbound tabs is rejected to avoid cross-tab contamination.
171
+ - Use the popup `Session Tabs` panel to explicitly add/remove tabs from the active session.
172
+ - If all bound tabs are removed/closed, the session auto-stops.
173
+
174
+ MCP query tools support `sessionId`, `url`, or both:
175
+
176
+ - `sessionId` only: filter by session
177
+ - `url` only: filter by URL origin across sessions (for example `http://localhost:3000`)
178
+ - `sessionId + url`: intersection (only rows matching both)
179
+
180
+ Supported tools:
181
+
182
+ - `get_recent_events`
183
+ - `get_navigation_history`
184
+ - `get_console_events`
185
+ - `get_network_failures`
186
+
187
+ Example: URL-only query
188
+
189
+ ```json
190
+ {
191
+ "name": "get_recent_events",
192
+ "arguments": { "url": "http://localhost:3000", "limit": 50 }
193
+ }
194
+ ```
195
+
196
+ Example: session + URL intersection
197
+
198
+ ```json
199
+ {
200
+ "name": "get_network_failures",
201
+ "arguments": { "sessionId": "sess_123", "url": "http://localhost:3000", "limit": 20 }
202
+ }
203
+ ```
204
+
205
+ ## Live Console Logs (Non-Persistent)
206
+
207
+ `get_live_console_logs` reads from extension in-memory ring buffers (session-scoped), so this live stream can be filtered without DB scanning.
208
+
209
+ - `sessionId` is required
210
+ - optional filters: `url` (origin), `tabId`, `levels`, `contains`, `sinceTs`
211
+ - supports substring filters like `"[auth]"` directly server-side
212
+ - results are bounded by `limit` and buffer capacity
213
+
214
+ Capture scope:
215
+
216
+ - Captured from page context: `console.log`, `console.info`, `console.warn`, `console.error`, `console.debug`, `console.trace`
217
+ - Runtime JS exceptions are included as `error`-level live entries
218
+ - Browser-internal/DevTools UI-only rows are not guaranteed
219
+
220
+ Example:
221
+
222
+ ```json
223
+ {
224
+ "name": "get_live_console_logs",
225
+ "arguments": {
226
+ "sessionId": "sess_123",
227
+ "url": "http://localhost:3000",
228
+ "levels": ["info", "error"],
229
+ "contains": "[auth]",
230
+ "limit": 100
231
+ }
232
+ }
233
+ ```
234
+
235
+ ## Port and Startup Behavior
236
+
237
+ Default port is `8065`.
238
+
239
+ - Launcher enforces a single-instance startup lock to avoid concurrent launch races.
240
+ - On Windows, launcher tries automatic stale bridge recovery first.
241
+ - If port is still occupied, startup fails with `MCP_STARTUP_PORT_IN_USE`.
242
+ - In that case, free/reserve port `8065` for this bridge and restart.
243
+ - Launcher reports `Started` only after `/health` becomes reachable on `127.0.0.1:8065`.
244
+ - In `mcp-stdio` mode, bridge lifecycle is tied to the host and should stop when host transport closes.
245
+ - If a stale process still remains, stop it explicitly with `node scripts/mcp-start.cjs --stop`.
246
+ - Optional: set `MCP_STARTUP_TIMEOUT_MS` (default `15000`) for slower machines.
247
+
248
+ Useful Windows command:
249
+
250
+ ```powershell
251
+ netstat -ano | findstr :8065
252
+ ```
253
+
254
+ Stop command:
57
255
 
58
256
  ```bash
59
- pnpm typecheck
60
- pnpm test
61
- pnpm nx run-many -t lint
62
- pnpm nx run-many -t build
257
+ node scripts/mcp-start.cjs --stop
63
258
  ```
64
259
 
65
- Enable local pre-commit checks (typecheck + lint + test before each commit):
260
+ ## Common Failure Signals
261
+
262
+ - `LIVE_SESSION_DISCONNECTED`: session exists in DB but no active extension transport. Fix: restart/reconnect extension session, then use a `liveConnection.connected = true` session id.
263
+ - `MCP_STARTUP_PORT_IN_USE`: required MCP port is blocked. Fix: stop the process using that port and restart bridge.
264
+
265
+ ## Useful Commands
66
266
 
67
267
  ```bash
68
- pnpm hooks:install
268
+ pnpm typecheck
269
+ pnpm lint
270
+ pnpm test
271
+ pnpm build
272
+ pnpm docs:ci
273
+ pnpm verify
274
+ node scripts/mcp-start.cjs --stop
69
275
  ```
70
276
 
71
- ## Load the extension
277
+ Optional one-shot local setup:
278
+
279
+ ```powershell
280
+ # Windows
281
+ ./install.ps1
282
+ ```
72
283
 
73
- 1. Build the extension: `pnpm nx build chrome-extension`
74
- 2. Open Chrome -> `chrome://extensions`
75
- 3. Enable Developer mode
76
- 4. Click **Load unpacked**
77
- 5. Select `dist/apps/chrome-extension`
284
+ ```bash
285
+ # macOS/Linux
286
+ bash ./install.sh
287
+ ```
78
288
 
79
- ## Main docs
289
+ ## Tooling Docs
80
290
 
81
- - Project spec: `PROJECT_INFOS.md`
82
- - Full beginner setup guide: `HOW_TO_USE_BROWSER_DEBUG_MCP_BRIDGE.md`
83
- - MCP tools reference: `docs/MCP_TOOLS.md`
84
- - MCP client setup (Codex/Claude/Cursor/Windsurf): `docs/MCP_CLIENT_SETUP.md`
85
- - GitHub Actions explained: `docs/GITHUB_ACTIONS.md`
86
- - Security and privacy controls: `SECURITY.md`
87
- - Troubleshooting guide: `docs/TROUBLESHOOTING.md`
88
- - Architecture overview: `docs/ARCHITECTURE.md`
89
- - Architecture decisions: `docs/ARCHITECTURE_DECISIONS.md`
291
+ - [MCP tools reference](https://github.com/RobertoM80/browser-debug-mcp-bridge/blob/main/docs/MCP_TOOLS.md)
292
+ - [MCP client setup](https://github.com/RobertoM80/browser-debug-mcp-bridge/blob/main/docs/MCP_CLIENT_SETUP.md)
293
+ - [Troubleshooting](https://github.com/RobertoM80/browser-debug-mcp-bridge/blob/main/docs/TROUBLESHOOTING.md)
294
+ - [Architecture](https://github.com/RobertoM80/browser-debug-mcp-bridge/blob/main/docs/ARCHITECTURE.md)
295
+ - [Security and privacy](https://github.com/RobertoM80/browser-debug-mcp-bridge/blob/main/SECURITY.md)
90
296
 
91
- ## Repository layout
297
+ ## Repository Layout
92
298
 
93
299
  ```text
94
300
  apps/
@@ -98,6 +304,6 @@ apps/
98
304
  libs/
99
305
  shared/ Shared schemas/types/utils
100
306
  redaction/ Privacy redaction engine
101
- selectors/ Robust selector generation
102
- mcp-contracts/ MCP tool contracts and schemas
307
+ selectors/ Selector generation
308
+ mcp-contracts/ MCP tool contracts and schemas
103
309
  ```
@@ -11,13 +11,13 @@ export class EventsRepository {
11
11
  return;
12
12
  }
13
13
  const insert = this.db.prepare(`
14
- INSERT INTO events (event_id, session_id, ts, type, payload_json)
15
- VALUES (?, ?, ?, ?, ?)
14
+ INSERT INTO events (event_id, session_id, ts, type, payload_json, tab_id, origin)
15
+ VALUES (?, ?, ?, ?, ?, ?, ?)
16
16
  `);
17
17
  const insertNetwork = this.db.prepare(`
18
18
  INSERT INTO network (
19
- request_id, session_id, ts_start, duration_ms, method, url, status, initiator, error_class, response_size_est
20
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
19
+ request_id, session_id, ts_start, duration_ms, method, url, origin, status, initiator, error_class, response_size_est
20
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
21
21
  `);
22
22
  const upsertFingerprint = this.db.prepare(`
23
23
  INSERT INTO error_fingerprints (
@@ -33,12 +33,16 @@ export class EventsRepository {
33
33
  for (const message of batch) {
34
34
  const eventId = `${message.sessionId}-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
35
35
  const dbEventType = this.mapEventType(message.eventType);
36
- insert.run(eventId, message.sessionId, message.timestamp ?? Date.now(), dbEventType, JSON.stringify(message.data));
36
+ const eventTabId = typeof message.tabId === 'number' && Number.isFinite(message.tabId)
37
+ ? Math.floor(message.tabId)
38
+ : this.resolveTabIdFromPayload(message.data);
39
+ const eventOrigin = this.resolveEventOrigin(message.data, message.origin);
40
+ insert.run(eventId, message.sessionId, message.timestamp ?? Date.now(), dbEventType, JSON.stringify(message.data), eventTabId, eventOrigin);
37
41
  if (message.eventType === 'error') {
38
42
  this.upsertErrorFingerprintPrepared(upsertFingerprint, message.sessionId, message.data);
39
43
  }
40
44
  if (message.eventType === 'network') {
41
- this.insertNetworkEventPrepared(insertNetwork, message.sessionId, message.data);
45
+ this.insertNetworkEventPrepared(insertNetwork, message.sessionId, message.data, eventOrigin);
42
46
  }
43
47
  if (message.eventType === 'ui_snapshot') {
44
48
  this.insertSnapshotPrepared(message.sessionId, eventId, message.data);
@@ -59,7 +63,7 @@ export class EventsRepository {
59
63
  }
60
64
  endSession(message) {
61
65
  const update = this.db.prepare(`
62
- UPDATE sessions
66
+ UPDATE sessions
63
67
  SET ended_at = ?
64
68
  WHERE session_id = ?
65
69
  `);
@@ -70,20 +74,20 @@ export class EventsRepository {
70
74
  }
71
75
  mapEventType(eventType) {
72
76
  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',
77
+ navigation: 'nav',
78
+ console: 'console',
79
+ error: 'error',
80
+ network: 'network',
81
+ click: 'ui',
82
+ scroll: 'ui',
83
+ input: 'ui',
84
+ change: 'ui',
85
+ submit: 'ui',
86
+ focus: 'ui',
87
+ blur: 'ui',
88
+ keydown: 'ui',
89
+ ui_snapshot: 'ui',
90
+ custom: 'ui',
87
91
  };
88
92
  return mapping[eventType] || 'ui';
89
93
  }
@@ -94,16 +98,50 @@ export class EventsRepository {
94
98
  const now = Date.now();
95
99
  statement.run(fingerprint, sessionId, data.message ?? 'Unknown error', data.stack ?? null, now, now);
96
100
  }
97
- insertNetworkEventPrepared(statement, sessionId, data) {
101
+ insertNetworkEventPrepared(statement, sessionId, data, eventOrigin) {
98
102
  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);
103
+ const url = data.url ?? '';
104
+ const origin = eventOrigin ?? normalizeOriginCandidate(url);
105
+ statement.run(requestId, sessionId, data.timestamp ?? Date.now(), data.duration ?? null, data.method ?? 'GET', url, origin, data.status ?? null, data.initiator ?? 'other', data.errorType ?? null, data.responseSize ?? null);
100
106
  }
101
107
  insertSnapshotPrepared(sessionId, triggerEventId, data) {
102
108
  writeSnapshot(this.db, getDatabasePath(), sessionId, data, triggerEventId);
103
109
  }
110
+ resolveTabIdFromPayload(payload) {
111
+ const candidate = payload.tabId;
112
+ if (typeof candidate === 'number' && Number.isFinite(candidate)) {
113
+ return Math.floor(candidate);
114
+ }
115
+ return null;
116
+ }
117
+ resolveEventOrigin(payload, fallback) {
118
+ const candidates = [fallback, payload.origin, payload.url, payload.to, payload.href, payload.location];
119
+ for (const candidate of candidates) {
120
+ const origin = normalizeOriginCandidate(candidate);
121
+ if (origin) {
122
+ return origin;
123
+ }
124
+ }
125
+ return null;
126
+ }
104
127
  sessionExists(sessionId) {
105
128
  const result = this.db.prepare('SELECT 1 FROM sessions WHERE session_id = ?').get(sessionId);
106
129
  return !!result;
107
130
  }
108
131
  }
132
+ function normalizeOriginCandidate(value) {
133
+ if (typeof value !== 'string' || value.trim().length === 0) {
134
+ return null;
135
+ }
136
+ try {
137
+ const parsed = new URL(value);
138
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
139
+ return null;
140
+ }
141
+ return parsed.origin;
142
+ }
143
+ catch {
144
+ return null;
145
+ }
146
+ }
109
147
  //# 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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"}
@@ -1,4 +1,40 @@
1
1
  import { initializeSchema, getSchemaVersion, clearDatabase, SCHEMA_VERSION } from './schema.js';
2
+ function getColumnNames(db, tableName) {
3
+ const rows = db.prepare(`PRAGMA table_info('${tableName}')`).all();
4
+ return new Set(rows.map((row) => row.name));
5
+ }
6
+ function normalizeOriginCandidate(value) {
7
+ if (typeof value !== 'string' || value.trim().length === 0) {
8
+ return null;
9
+ }
10
+ try {
11
+ const parsed = new URL(value);
12
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
13
+ return null;
14
+ }
15
+ return parsed.origin;
16
+ }
17
+ catch {
18
+ return null;
19
+ }
20
+ }
21
+ function extractEventOrigin(payload) {
22
+ const candidates = [
23
+ payload.origin,
24
+ payload.url,
25
+ payload.to,
26
+ payload.href,
27
+ payload.location,
28
+ payload.requestUrl,
29
+ ];
30
+ for (const candidate of candidates) {
31
+ const origin = normalizeOriginCandidate(candidate);
32
+ if (origin) {
33
+ return origin;
34
+ }
35
+ }
36
+ return null;
37
+ }
2
38
  const migrations = [
3
39
  {
4
40
  version: 1,
@@ -76,7 +112,74 @@ const migrations = [
76
112
  CREATE INDEX IF NOT EXISTS idx_snapshots_png_path ON snapshots(png_path);
77
113
  `);
78
114
  },
79
- }
115
+ },
116
+ {
117
+ version: 4,
118
+ name: 'event_origin_and_tab_scope',
119
+ up: (db) => {
120
+ const eventColumns = getColumnNames(db, 'events');
121
+ if (!eventColumns.has('tab_id')) {
122
+ db.exec('ALTER TABLE events ADD COLUMN tab_id INTEGER;');
123
+ }
124
+ if (!eventColumns.has('origin')) {
125
+ db.exec('ALTER TABLE events ADD COLUMN origin TEXT;');
126
+ }
127
+ const networkColumns = getColumnNames(db, 'network');
128
+ if (!networkColumns.has('origin')) {
129
+ db.exec('ALTER TABLE network ADD COLUMN origin TEXT;');
130
+ }
131
+ db.exec(`
132
+ CREATE INDEX IF NOT EXISTS idx_events_tab_id ON events(tab_id);
133
+ CREATE INDEX IF NOT EXISTS idx_events_origin ON events(origin);
134
+ CREATE INDEX IF NOT EXISTS idx_events_session_origin_ts ON events(session_id, origin, ts);
135
+ CREATE INDEX IF NOT EXISTS idx_network_origin ON network(origin);
136
+ CREATE INDEX IF NOT EXISTS idx_network_session_origin_ts ON network(session_id, origin, ts_start);
137
+ `);
138
+ const updateEvent = db.prepare(`
139
+ UPDATE events
140
+ SET tab_id = COALESCE(?, tab_id), origin = COALESCE(?, origin)
141
+ WHERE event_id = ?
142
+ `);
143
+ const updateNetwork = db.prepare('UPDATE network SET origin = ? WHERE request_id = ?');
144
+ const runBackfill = db.transaction(() => {
145
+ const eventRows = db.prepare(`
146
+ SELECT event_id, payload_json, tab_id, origin
147
+ FROM events
148
+ WHERE tab_id IS NULL OR origin IS NULL
149
+ `).all();
150
+ for (const row of eventRows) {
151
+ let payload = {};
152
+ try {
153
+ const parsed = JSON.parse(row.payload_json);
154
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
155
+ payload = parsed;
156
+ }
157
+ }
158
+ catch {
159
+ payload = {};
160
+ }
161
+ const tabIdCandidate = payload.tabId;
162
+ const tabId = typeof tabIdCandidate === 'number' && Number.isFinite(tabIdCandidate)
163
+ ? Math.floor(tabIdCandidate)
164
+ : null;
165
+ const origin = extractEventOrigin(payload);
166
+ updateEvent.run(tabId, origin, row.event_id);
167
+ }
168
+ const networkRows = db.prepare(`
169
+ SELECT request_id, url
170
+ FROM network
171
+ WHERE origin IS NULL
172
+ `).all();
173
+ for (const row of networkRows) {
174
+ const origin = normalizeOriginCandidate(row.url);
175
+ if (origin) {
176
+ updateNetwork.run(origin, row.request_id);
177
+ }
178
+ }
179
+ });
180
+ runBackfill();
181
+ },
182
+ },
80
183
  ];
81
184
  export function runMigrations(db) {
82
185
  const currentVersion = getSchemaVersion(db) || 0;
@@ -1 +1 @@
1
- {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../src/db/migrations.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAQhG,MAAM,UAAU,GAAgB;IAC9B;QACE,OAAO,EAAE,CAAC;QACV,IAAI,EAAE,gBAAgB;QACtB,EAAE,EAAE,gBAAgB;KACrB;IACD;QACE,OAAO,EAAE,CAAC;QACV,IAAI,EAAE,uBAAuB;QAC7B,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE;YACT,MAAM,eAAe,GAAI,EAAE,CAAC,OAAO,CAAC,+BAA+B,CAAC,CAAC,GAAG,EAA8B,CAAC,IAAI,CACzG,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,QAAQ,CACrC,CAAC;YACF,IAAI,CAAC,eAAe,EAAE,CAAC;gBACrB,EAAE,CAAC,IAAI,CAAC;;SAEP,CAAC,CAAC;YACL,CAAC;YACD,EAAE,CAAC,IAAI,CAAC;;OAEP,CAAC,CAAC;YACH,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;OAUP,CAAC,CAAC;YACH,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;OAUP,CAAC,CAAC;QACL,CAAC;KACF;IACD;QACE,OAAO,EAAE,CAAC;QACV,IAAI,EAAE,mBAAmB;QACzB,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE;YACT,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;OAuBP,CAAC,CAAC;YACH,EAAE,CAAC,IAAI,CAAC;;;;OAIP,CAAC,CAAC;QACL,CAAC;KACF;CACF,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,EAAY;IACxC,MAAM,cAAc,GAAG,gBAAgB,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IAEjD,MAAM,iBAAiB,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,cAAc,CAAC,CAAC;IAE7E,KAAK,MAAM,SAAS,IAAI,iBAAiB,EAAE,CAAC;QAC1C,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAEjB,MAAM,aAAa,GAAG,EAAE,CAAC,OAAO,CAAC;;;KAGhC,CAAC,CAAC;QACH,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,EAAY;IAC7C,aAAa,CAAC,EAAE,CAAC,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,EAAY;IACxC,aAAa,CAAC,EAAE,CAAC,CAAC;IAClB,kBAAkB,CAAC,EAAE,CAAC,CAAC;AACzB,CAAC;AAED,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../src/db/migrations.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- export const SCHEMA_VERSION = 3;
1
+ export const SCHEMA_VERSION = 4;
2
2
  export const CREATE_TABLES_SQL = `
3
3
  -- Sessions table
4
4
  CREATE TABLE IF NOT EXISTS sessions (