@btraut/browser-bridge 0.5.0 → 0.6.1
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/CHANGELOG.md +18 -3
- package/README.md +135 -70
- package/extension/assets/ui.css +105 -10
- package/extension/dist/background.js +29 -15
- package/extension/dist/background.js.map +2 -2
- package/extension/dist/content.js +10 -0
- package/extension/dist/content.js.map +2 -2
- package/extension/dist/options-ui.js +109 -3
- package/extension/dist/options-ui.js.map +2 -2
- package/extension/dist/popup-ui.js +34 -18
- package/extension/dist/popup-ui.js.map +2 -2
- package/extension/manifest.json +1 -1
- package/package.json +1 -1
- package/skills/browser-bridge/SKILL.md +28 -0
- package/skills/browser-bridge/skill.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,17 +6,32 @@ The format is based on "Keep a Changelog", and this project adheres to Semantic
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
_TBD_
|
|
10
|
+
|
|
11
|
+
## [0.6.1] - 2026-02-10
|
|
12
|
+
|
|
9
13
|
### Added
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
- README: competitor feature comparison table.
|
|
12
16
|
|
|
13
17
|
### Fixed
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
- Extension popup menu: Settings/About always open in a new tab/window (no more crushing the UI inside the popup).
|
|
20
|
+
- Extension options: default permissions mode to Granular when unset, and show a real empty state for the approved sites allowlist.
|
|
21
|
+
- Extension options: remove the nested-card empty state styling, simplify the copy, and always show the Approved sites disclosure + list in both Granular and Bypass modes.
|
|
22
|
+
- Extension options: add a drop shadow to the permission mode controls to match the rest of the settings containers.
|
|
23
|
+
- Extension options: remove the "Bypass mode is intentionally unsafe" warning box.
|
|
24
|
+
- Extension options: tighten and vertically align the Approved sites disclosure triangle.
|
|
16
25
|
|
|
17
26
|
### Changed
|
|
18
27
|
|
|
19
|
-
|
|
28
|
+
- Expand `scripts/cli-full-tool-smoke.sh` coverage (health-check, locator variants, ref reuse, more dom-snapshot modes, more screenshot options).
|
|
29
|
+
|
|
30
|
+
## [0.6.0] - 2026-02-09
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- Extension options: permissions mode toggle (Granular per-site vs dangerous bypass), with bypass collapsing and ignoring the approved sites allowlist.
|
|
20
35
|
|
|
21
36
|
## [0.5.0] - 2026-02-09
|
|
22
37
|
|
package/README.md
CHANGED
|
@@ -8,85 +8,53 @@
|
|
|
8
8
|
|
|
9
9
|
Browser Bridge drives your real, local Chrome (not headless) and inspects page state through a Chrome extension plus a local daemon. You stay in the loop with your existing tabs and login state.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
- **Real browser state**: operate on your actual Chrome profile (tabs, cookies, logins, extensions).
|
|
14
|
-
- **Two-plane architecture**: a **drive** plane that does what a user does (click, type, navigate), plus an **inspect** plane that reads state (DOM, console, screenshots). This separation makes runs less flaky and lets inspection happen in parallel.
|
|
15
|
-
- **Token-efficient inspection**: stable element refs like `@e1` (find once, reuse everywhere) plus knobs to bound output (`--max-nodes`, `--compact`, `--interactive`, `--selector`).
|
|
16
|
-
- **Structured errors for agents**: stable error codes with a `retryable` flag (no more guessing whether to retry).
|
|
17
|
-
- **Recovery-first**: sessions have an explicit state machine with `session.recover()` and `diagnostics doctor`.
|
|
18
|
-
- **Inspect beyond screenshots**: DOM snapshots (AX + HTML) and `inspect dom-diff` to detect page changes.
|
|
19
|
-
|
|
20
|
-
## Why Browser Bridge
|
|
21
|
-
|
|
22
|
-
Browser Bridge is built for agent reliability and "stay logged in" workflows in your real Chrome, not for headless test automation.
|
|
23
|
-
|
|
24
|
-
If you're coming from Playwright/Puppeteer-style tooling:
|
|
25
|
-
|
|
26
|
-
- Browser Bridge targets the user's existing, interactive Chrome session by default (typical Playwright/Puppeteer flows spin up a separate browser/context).
|
|
27
|
-
- Browser Bridge surfaces retry guidance in the API (`retryable`) instead of forcing the agent to infer it from exceptions and timing.
|
|
28
|
-
- Browser Bridge ships a first-class inspect plane (DOM snapshots, diffs, diagnostics) designed for LLM consumption, with output-bounding options to keep agent context small.
|
|
29
|
-
|
|
30
|
-
If you're coming from an extension-only MCP tool:
|
|
31
|
-
|
|
32
|
-
- Browser Bridge puts a stateful local Core daemon behind the tools (sessions, recovery, diagnostics, artifacts).
|
|
33
|
-
- Drive actions are serialized for determinism; inspect is a separate plane that can keep producing structured state.
|
|
34
|
-
- CLI works everywhere; MCP is optional.
|
|
35
|
-
|
|
36
|
-
## How It Works
|
|
37
|
-
|
|
38
|
-
Core keeps a session state machine and exposes a small set of stable tools:
|
|
11
|
+
## 🏁 Install + Quickstart (Do This First)
|
|
39
12
|
|
|
40
|
-
|
|
41
|
-
- `drive.*` - navigation + input (single-flight)
|
|
42
|
-
- `inspect.*` - DOM snapshots/diffs + evaluation
|
|
43
|
-
- `diagnostics.*` - health checks
|
|
44
|
-
- `artifacts.*` - screenshots
|
|
13
|
+
You need Node.js 20+ and Chrome (stable). Browser Bridge is local-only (binds to 127.0.0.1).
|
|
45
14
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
- Node.js 20+
|
|
49
|
-
- Chrome (stable)
|
|
50
|
-
- Browser Bridge extension (Chrome Web Store listing pending; see manual install below)
|
|
51
|
-
- Local-only usage (all services bind to 127.0.0.1)
|
|
52
|
-
|
|
53
|
-
## Install (CLI)
|
|
15
|
+
1. Install the CLI:
|
|
54
16
|
|
|
55
17
|
```bash
|
|
56
18
|
npm i -g @btraut/browser-bridge
|
|
57
19
|
browser-bridge --help
|
|
58
20
|
```
|
|
59
21
|
|
|
60
|
-
|
|
22
|
+
2. Run the installer:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
browser-bridge install
|
|
26
|
+
```
|
|
61
27
|
|
|
62
|
-
|
|
28
|
+
Select your client(s) (Codex, Claude, Cursor, etc).
|
|
63
29
|
|
|
64
|
-
|
|
30
|
+
3. Install the Chrome extension:
|
|
65
31
|
|
|
66
|
-
|
|
32
|
+
- Chrome Web Store listing is pending. For now, install manually.
|
|
33
|
+
- Download the latest pre-built extension zip from [GitHub Releases](https://github.com/btraut/browser-bridge/releases) (Assets), unzip it.
|
|
34
|
+
- Chrome -> `chrome://extensions` -> enable **Developer mode** -> **Load unpacked** -> select the folder with `manifest.json`.
|
|
67
35
|
|
|
68
|
-
|
|
69
|
-
|
|
36
|
+
<details>
|
|
37
|
+
<summary>Build the extension from source (instead of using a release zip)</summary>
|
|
70
38
|
|
|
71
39
|
```bash
|
|
72
40
|
npm install
|
|
73
41
|
npm run build
|
|
74
42
|
```
|
|
75
43
|
|
|
76
|
-
|
|
77
|
-
4. Enable **Developer mode**, click **Load unpacked**, and select the extension folder (the folder with `manifest.json`).
|
|
44
|
+
Then load the unpacked extension from `packages/extension/`.
|
|
78
45
|
|
|
79
|
-
|
|
46
|
+
</details>
|
|
47
|
+
|
|
48
|
+
4. Try it:
|
|
80
49
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
50
|
+
```text
|
|
51
|
+
Use Browser Bridge to navigate to https://example.com.
|
|
52
|
+
```
|
|
84
53
|
|
|
85
|
-
|
|
54
|
+
If Chrome shows a Browser Bridge permissions prompt, approve it, then tell the agent to retry.
|
|
86
55
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
3. Run a quick CLI check (Core auto-starts by default):
|
|
56
|
+
<details>
|
|
57
|
+
<summary>CLI sanity check (debugging)</summary>
|
|
90
58
|
|
|
91
59
|
```bash
|
|
92
60
|
browser-bridge session create
|
|
@@ -100,7 +68,108 @@ Notes:
|
|
|
100
68
|
|
|
101
69
|
- `inspect dom-snapshot` defaults to `--format ax`; `--max-nodes` is only supported for AX snapshots.
|
|
102
70
|
|
|
103
|
-
|
|
71
|
+
</details>
|
|
72
|
+
|
|
73
|
+
## ✨ What You Get
|
|
74
|
+
|
|
75
|
+
What makes it different:
|
|
76
|
+
|
|
77
|
+
- **Real browser state**: operate on your actual Chrome profile (tabs, cookies, logins, extensions).
|
|
78
|
+
- **Two-plane architecture**: a **drive** plane that does what a user does (click, type, navigate), plus an **inspect** plane that reads state (DOM, console, screenshots). This separation makes runs less flaky and lets inspection happen in parallel.
|
|
79
|
+
- **Safe-by-default drive permissions**: `drive.*` actions are blocked on new sites until you approve them. You can allow once, always allow (per-site allowlist you can audit/revoke), or enable a clearly-labeled bypass mode if you want zero guardrails.
|
|
80
|
+
- **Token-efficient inspection**: stable element refs like `@e1` (find once, reuse everywhere) plus knobs to bound output (`--max-nodes`, `--compact`, `--interactive`, `--selector`).
|
|
81
|
+
- **Structured errors for agents**: stable error codes with a `retryable` flag (no more guessing whether to retry).
|
|
82
|
+
- **Recovery-first**: sessions have an explicit state machine with `session.recover()` and `diagnostics doctor`.
|
|
83
|
+
- **Inspect beyond screenshots**: DOM snapshots (AX + HTML) and `inspect dom-diff` to detect page changes.
|
|
84
|
+
|
|
85
|
+
## 🔒 Site Permissions (Drive Actions)
|
|
86
|
+
|
|
87
|
+
Browser Bridge is intentionally safe: **drive actions** (`drive.navigate`, click, type, etc.) require **per-site approval**. `inspect.*` is not gated, so agents can inspect first and only ask for permission when it's time to click/type.
|
|
88
|
+
|
|
89
|
+
<details>
|
|
90
|
+
<summary>How approvals work (click to expand)</summary>
|
|
91
|
+
|
|
92
|
+
- The first time a `drive.*` action targets a new site, Chrome opens a small permissions prompt.
|
|
93
|
+
- Click **Allow this action** to allow once (no allowlist entry).
|
|
94
|
+
- Click **Always allow actions on this site** to add the site to your approved-sites allowlist.
|
|
95
|
+
- Click **Decline** to fail the command with `PERMISSION_DENIED` (non-retryable).
|
|
96
|
+
- If you ignore the prompt, the command fails with `PERMISSION_PROMPT_TIMEOUT` (retryable). Default wait is 30 seconds; approve the prompt, then retry the command.
|
|
97
|
+
|
|
98
|
+
Manage approvals (and bypass mode):
|
|
99
|
+
|
|
100
|
+
- Open the extension options page from `chrome://extensions` (Browser Bridge -> **Extension options**) or from the Extensions toolbar menu (Browser Bridge -> **Extension options**).
|
|
101
|
+
- The options page shows your **Approved sites** allowlist with revoke controls.
|
|
102
|
+
- Switch **Permission mode** to **Bypass (dangerous)** to skip the allowlist and prompts entirely.
|
|
103
|
+
- In bypass mode, the agent can take actions on any website without asking.
|
|
104
|
+
- Restricted URLs (for example `chrome://` and `file://`) are still blocked.
|
|
105
|
+
|
|
106
|
+
</details>
|
|
107
|
+
|
|
108
|
+
## 🧰 Tools (MCP + CLI)
|
|
109
|
+
|
|
110
|
+
The CLI mirrors the MCP tool surface.
|
|
111
|
+
|
|
112
|
+
<details>
|
|
113
|
+
<summary>All MCP tools (click to expand)</summary>
|
|
114
|
+
|
|
115
|
+
**session**
|
|
116
|
+
|
|
117
|
+
- `session.create`
|
|
118
|
+
- `session.status`
|
|
119
|
+
- `session.recover`
|
|
120
|
+
- `session.close`
|
|
121
|
+
|
|
122
|
+
**drive**
|
|
123
|
+
|
|
124
|
+
- `drive.navigate`
|
|
125
|
+
- `drive.go_back`
|
|
126
|
+
- `drive.go_forward`
|
|
127
|
+
- `drive.back`
|
|
128
|
+
- `drive.forward`
|
|
129
|
+
- `drive.click`
|
|
130
|
+
- `drive.hover`
|
|
131
|
+
- `drive.select`
|
|
132
|
+
- `drive.type`
|
|
133
|
+
- `drive.fill_form`
|
|
134
|
+
- `drive.drag`
|
|
135
|
+
- `drive.handle_dialog`
|
|
136
|
+
- `drive.key`
|
|
137
|
+
- `drive.key_press`
|
|
138
|
+
- `drive.scroll`
|
|
139
|
+
- `drive.wait_for`
|
|
140
|
+
- `drive.tab_list`
|
|
141
|
+
- `drive.tab_activate`
|
|
142
|
+
- `drive.tab_close`
|
|
143
|
+
|
|
144
|
+
**dialog**
|
|
145
|
+
|
|
146
|
+
- `dialog.accept`
|
|
147
|
+
- `dialog.dismiss`
|
|
148
|
+
|
|
149
|
+
**inspect**
|
|
150
|
+
|
|
151
|
+
- `inspect.dom_snapshot`
|
|
152
|
+
- `inspect.dom_diff`
|
|
153
|
+
- `inspect.find`
|
|
154
|
+
- `inspect.extract_content`
|
|
155
|
+
- `inspect.page_state`
|
|
156
|
+
- `inspect.console_list`
|
|
157
|
+
- `inspect.network_har`
|
|
158
|
+
- `inspect.evaluate`
|
|
159
|
+
- `inspect.performance_metrics`
|
|
160
|
+
|
|
161
|
+
**artifacts**
|
|
162
|
+
|
|
163
|
+
- `artifacts.screenshot`
|
|
164
|
+
|
|
165
|
+
**misc**
|
|
166
|
+
|
|
167
|
+
- `health_check`
|
|
168
|
+
- `diagnostics.doctor`
|
|
169
|
+
|
|
170
|
+
</details>
|
|
171
|
+
|
|
172
|
+
## 🧩 Skills (Agent Clients)
|
|
104
173
|
|
|
105
174
|
Browser Bridge skills work across many agent clients, including Codex and Claude Code.
|
|
106
175
|
|
|
@@ -110,13 +179,6 @@ Easiest option (recommended):
|
|
|
110
179
|
browser-bridge install
|
|
111
180
|
```
|
|
112
181
|
|
|
113
|
-
Skill only:
|
|
114
|
-
|
|
115
|
-
```bash
|
|
116
|
-
browser-bridge skill install
|
|
117
|
-
browser-bridge skill status
|
|
118
|
-
```
|
|
119
|
-
|
|
120
182
|
Or copy the Browser Bridge skill into your agent skills directory (advanced):
|
|
121
183
|
|
|
122
184
|
```bash
|
|
@@ -131,7 +193,7 @@ cp -R "$(npm root -g)/@btraut/browser-bridge/skills/browser-bridge" ~/.claude/sk
|
|
|
131
193
|
|
|
132
194
|
Restart your agent app if it does not pick up the new skill automatically.
|
|
133
195
|
|
|
134
|
-
## MCP Server (Optional)
|
|
196
|
+
## 🧪 MCP Server (Optional)
|
|
135
197
|
|
|
136
198
|
The MCP server runs over stdio and forwards tool calls to Core. It is optional, since you can use the CLI directly. MCP clients launch it automatically when needed, so you typically do not run it yourself.
|
|
137
199
|
|
|
@@ -140,7 +202,8 @@ The MCP server runs over stdio and forwards tool calls to Core. It is optional,
|
|
|
140
202
|
- Use your MCP client to call `tools/list`, then `session.create`
|
|
141
203
|
- Override Core host/port with `--host`, `--port`, or `BROWSER_BRIDGE_CORE_HOST` / `BROWSER_BRIDGE_CORE_PORT`.
|
|
142
204
|
|
|
143
|
-
|
|
205
|
+
<details>
|
|
206
|
+
<summary>Manual MCP setup (advanced)</summary>
|
|
144
207
|
|
|
145
208
|
Codex:
|
|
146
209
|
|
|
@@ -172,19 +235,21 @@ claude mcp add --transport stdio browser-bridge \
|
|
|
172
235
|
-- browser-bridge mcp
|
|
173
236
|
```
|
|
174
237
|
|
|
175
|
-
|
|
238
|
+
</details>
|
|
239
|
+
|
|
240
|
+
## 🩺 Diagnostics
|
|
176
241
|
|
|
177
242
|
- CLI: `browser-bridge diagnostics doctor --session-id <id>`
|
|
178
243
|
- Reports extension and debugger status alongside session state.
|
|
179
244
|
|
|
180
|
-
## Recovery
|
|
245
|
+
## 🔧 Recovery
|
|
181
246
|
|
|
182
247
|
If drive or inspect gets into a bad state, recovery is explicit:
|
|
183
248
|
|
|
184
249
|
- `browser-bridge session recover --session-id <id>`
|
|
185
250
|
- Then retry the failed operation once (tools report whether failures are `retryable`).
|
|
186
251
|
|
|
187
|
-
## Session TTL (Core Daemon)
|
|
252
|
+
## 🧹 Session TTL (Core Daemon)
|
|
188
253
|
|
|
189
254
|
The Core daemon keeps sessions in memory. By default, it automatically cleans up idle sessions after 1 hour.
|
|
190
255
|
|
package/extension/assets/ui.css
CHANGED
|
@@ -96,6 +96,10 @@ body.bb-page.bb-page--popup {
|
|
|
96
96
|
background: var(--bb-bg);
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
.bb-menu--shadow {
|
|
100
|
+
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.06);
|
|
101
|
+
}
|
|
102
|
+
|
|
99
103
|
body.bb-page--popup .bb-menu {
|
|
100
104
|
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.06);
|
|
101
105
|
}
|
|
@@ -271,6 +275,10 @@ body.bb-page--popup .bb-menu {
|
|
|
271
275
|
color: var(--bb-ink-2);
|
|
272
276
|
}
|
|
273
277
|
|
|
278
|
+
.bb-site-empty > * + * {
|
|
279
|
+
margin-top: 8px;
|
|
280
|
+
}
|
|
281
|
+
|
|
274
282
|
.bb-link-button {
|
|
275
283
|
appearance: none;
|
|
276
284
|
border: 0;
|
|
@@ -295,16 +303,6 @@ body.bb-page--popup .bb-menu {
|
|
|
295
303
|
color: var(--bb-accent);
|
|
296
304
|
}
|
|
297
305
|
|
|
298
|
-
.bb-empty {
|
|
299
|
-
margin-top: 12px;
|
|
300
|
-
border: 1px dashed var(--bb-border-2);
|
|
301
|
-
border-radius: var(--bb-radius-sm);
|
|
302
|
-
padding: 12px;
|
|
303
|
-
font-size: 13px;
|
|
304
|
-
color: var(--bb-ink-2);
|
|
305
|
-
background: rgba(0, 0, 0, 0.02);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
306
|
.bb-toast-wrap {
|
|
309
307
|
position: fixed;
|
|
310
308
|
left: 14px;
|
|
@@ -351,3 +349,100 @@ body.bb-page--popup .bb-menu {
|
|
|
351
349
|
monospace;
|
|
352
350
|
font-size: 0.95em;
|
|
353
351
|
}
|
|
352
|
+
|
|
353
|
+
.bb-fieldset {
|
|
354
|
+
border: 0;
|
|
355
|
+
padding: 0;
|
|
356
|
+
margin: 0;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.bb-fieldset-legend {
|
|
360
|
+
padding: 0;
|
|
361
|
+
margin: 0 0 8px;
|
|
362
|
+
font-size: 12px;
|
|
363
|
+
color: var(--bb-ink-2);
|
|
364
|
+
font-weight: 650;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
.bb-radio-row {
|
|
368
|
+
cursor: pointer;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.bb-radio {
|
|
372
|
+
flex: 0 0 auto;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.bb-radio-text {
|
|
376
|
+
display: flex;
|
|
377
|
+
flex-direction: column;
|
|
378
|
+
gap: 3px;
|
|
379
|
+
min-width: 0;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.bb-radio-title {
|
|
383
|
+
font-weight: 650;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.bb-radio-title--danger {
|
|
387
|
+
color: var(--bb-accent);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.bb-radio-sub {
|
|
391
|
+
font-size: 12px;
|
|
392
|
+
color: var(--bb-ink-2);
|
|
393
|
+
font-weight: 500;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.bb-warning {
|
|
397
|
+
margin-top: 10px;
|
|
398
|
+
border: 1px solid rgba(224, 107, 61, 0.35);
|
|
399
|
+
border-radius: var(--bb-radius-sm);
|
|
400
|
+
background: rgba(224, 107, 61, 0.1);
|
|
401
|
+
padding: 10px 12px;
|
|
402
|
+
font-size: 13px;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
.bb-sites-details {
|
|
406
|
+
margin-top: 14px;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
.bb-sites-summary {
|
|
410
|
+
list-style: none;
|
|
411
|
+
cursor: pointer;
|
|
412
|
+
user-select: none;
|
|
413
|
+
display: flex;
|
|
414
|
+
align-items: center;
|
|
415
|
+
gap: 4px;
|
|
416
|
+
font-size: 13px;
|
|
417
|
+
font-weight: 650;
|
|
418
|
+
padding: 10px 6px 0;
|
|
419
|
+
color: var(--bb-ink);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
.bb-sites-summary::-webkit-details-marker {
|
|
423
|
+
display: none;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
.bb-sites-summary::before {
|
|
427
|
+
content: '▸';
|
|
428
|
+
display: block;
|
|
429
|
+
flex: 0 0 auto;
|
|
430
|
+
font-size: 20px;
|
|
431
|
+
line-height: 1;
|
|
432
|
+
color: var(--bb-ink);
|
|
433
|
+
transform: translateY(-1px);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
details[open] > .bb-sites-summary::before {
|
|
437
|
+
content: '▾';
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
.bb-sites-details--no-summary > .bb-sites-summary {
|
|
441
|
+
display: none;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
.bb-sites-ignored {
|
|
445
|
+
margin: 10px 0 8px;
|
|
446
|
+
font-size: 13px;
|
|
447
|
+
color: var(--bb-ink-2);
|
|
448
|
+
}
|
|
@@ -96,6 +96,8 @@ var sanitizeDriveErrorInfo = (error) => {
|
|
|
96
96
|
var SITE_ALLOWLIST_KEY = "siteAllowlist";
|
|
97
97
|
var PERMISSION_PROMPT_WAIT_MS_KEY = "permissionPromptWaitMs";
|
|
98
98
|
var DEFAULT_PERMISSION_PROMPT_WAIT_MS = 3e4;
|
|
99
|
+
var SITE_PERMISSIONS_MODE_KEY = "sitePermissionsMode";
|
|
100
|
+
var DEFAULT_SITE_PERMISSIONS_MODE = "granular";
|
|
99
101
|
var siteKeyFromUrl = (rawUrl) => {
|
|
100
102
|
if (!rawUrl || typeof rawUrl !== "string") {
|
|
101
103
|
return null;
|
|
@@ -154,6 +156,27 @@ var writeAllowlistRaw = async (allowlist) => {
|
|
|
154
156
|
);
|
|
155
157
|
});
|
|
156
158
|
};
|
|
159
|
+
var readSitePermissionsMode = async () => {
|
|
160
|
+
return await new Promise((resolve) => {
|
|
161
|
+
chrome.storage.local.get(
|
|
162
|
+
[SITE_PERMISSIONS_MODE_KEY],
|
|
163
|
+
(result) => {
|
|
164
|
+
const raw = result?.[SITE_PERMISSIONS_MODE_KEY];
|
|
165
|
+
if (raw === "granular" || raw === "bypass") {
|
|
166
|
+
resolve(raw);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
chrome.storage.local.set({
|
|
171
|
+
[SITE_PERMISSIONS_MODE_KEY]: DEFAULT_SITE_PERMISSIONS_MODE
|
|
172
|
+
});
|
|
173
|
+
} catch {
|
|
174
|
+
}
|
|
175
|
+
resolve(DEFAULT_SITE_PERMISSIONS_MODE);
|
|
176
|
+
}
|
|
177
|
+
);
|
|
178
|
+
});
|
|
179
|
+
};
|
|
157
180
|
var readPermissionPromptWaitMs = async () => {
|
|
158
181
|
return await new Promise((resolve) => {
|
|
159
182
|
chrome.storage.local.get(
|
|
@@ -1170,6 +1193,9 @@ var DriveSocket = class {
|
|
|
1170
1193
|
};
|
|
1171
1194
|
}
|
|
1172
1195
|
}
|
|
1196
|
+
if (await readSitePermissionsMode() === "bypass") {
|
|
1197
|
+
return { ok: true, siteKey, touchOnSuccess: false };
|
|
1198
|
+
}
|
|
1173
1199
|
if (await isSiteAllowed(siteKey)) {
|
|
1174
1200
|
return { ok: true, siteKey, touchOnSuccess: true };
|
|
1175
1201
|
}
|
|
@@ -1287,21 +1313,9 @@ var DriveSocket = class {
|
|
|
1287
1313
|
if (tabId === void 0) {
|
|
1288
1314
|
tabId = await getDefaultTabId();
|
|
1289
1315
|
}
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
if (isBack) {
|
|
1294
|
-
chrome.tabs.goBack(tabId, () => callback());
|
|
1295
|
-
} else {
|
|
1296
|
-
chrome.tabs.goForward(tabId, () => callback());
|
|
1297
|
-
}
|
|
1298
|
-
});
|
|
1299
|
-
} catch (error) {
|
|
1300
|
-
respondError({
|
|
1301
|
-
code: "FAILED_PRECONDITION",
|
|
1302
|
-
message: error instanceof Error ? error.message : "No history entry.",
|
|
1303
|
-
retryable: false
|
|
1304
|
-
});
|
|
1316
|
+
const result = await sendToTab(tabId, message.action);
|
|
1317
|
+
if (!result.ok) {
|
|
1318
|
+
respondError(result.error);
|
|
1305
1319
|
return;
|
|
1306
1320
|
}
|
|
1307
1321
|
markTabActive(tabId);
|