Skip to content

Commit ad8e3be

Browse files
author
Oscar
committed
Add background fetch support for run code
1 parent 9e12265 commit ad8e3be

6 files changed

Lines changed: 660 additions & 2 deletions

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
## Context
2+
Nenya already separates automatic Custom JS/CSS page-load injection from manual Run Code execution. Automatic rules intentionally stay on the legacy MAIN-world path so existing page-load behavior does not change, while manual Run Code executes through `chrome.userScripts.execute()` to avoid host-page CSP issues. The new request is to let manual snippets perform cross-origin requests through the extension background so they are not limited by the page origin's CORS rules.
3+
4+
## Goals / Non-Goals
5+
- Goals:
6+
- Provide a simple helper callable directly from manual Run Code snippets.
7+
- Perform network requests from the extension background using existing host permissions.
8+
- Preserve the current separation between manual Run Code and automatic Custom JS/CSS.
9+
- Non-Goals:
10+
- Do not change automatic page-load Custom JS/CSS execution.
11+
- Do not emulate the full browser `Response` prototype.
12+
- Do not add a generic fetch bridge for arbitrary content scripts outside the manual Run Code flow.
13+
14+
## Decisions
15+
- Decision: Inject a helper into the manual Run Code wrapper rather than requiring each user snippet to hand-roll message passing.
16+
- Rationale: The feature is specifically for manual snippets, so the wrapper is the narrowest place to expose it.
17+
- Decision: Route messages through the dedicated user-script messaging channel.
18+
- Rationale: Chrome's userScripts API treats user-script messaging as a separate, less-trusted context, so background handlers should distinguish it from ordinary extension messages.
19+
- Decision: Return a serializable response wrapper with `ok`, `status`, `statusText`, `url`, `redirected`, `headers`, `text()`, and `json()`.
20+
- Rationale: Most snippets only need these fields and readers. Returning the full native `Response` object is not possible across extension messaging boundaries.
21+
- Decision: Validate the requested URL and restrict supported init fields to an explicit allowlist.
22+
- Rationale: Even though manual Run Code is user-authored, the background should avoid becoming an unconstrained proxy surface.
23+
24+
## Risks / Trade-offs
25+
- Cookie-backed auth may still fail if the target origin does not have the expected browser session or if the browser blocks the relevant cookies.
26+
- The helper will look fetch-like, but it cannot be behavior-identical to the native `fetch()` and `Response` APIs because the result crosses a messaging boundary.
27+
- Streaming bodies are out of scope, so large responses are buffered before being returned.
28+
29+
## Migration Plan
30+
1. Add the OpenSpec delta and validate it.
31+
2. Update the manual Run Code wrapper to expose the helper.
32+
3. Add background handlers for user-script messages and request execution.
33+
4. Verify that automatic Custom JS/CSS still uses the legacy path unchanged.
34+
35+
## Open Questions
36+
- The helper name should be short and obvious in snippets. `nenyaFetch` is the current default unless product copy prefers another name.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Change: add background-backed fetch for manual Run Code
2+
3+
## Why
4+
Manual "Run Code in page" snippets currently execute in the page's browser context, so direct `fetch()` calls from sites like `https://x.com` still hit normal web CORS restrictions. Users need a supported way to make authenticated cross-origin requests from manual snippets without rewriting each script around extension internals.
5+
6+
## What Changes
7+
- Add a background-backed fetch helper that is available to manual Run Code snippets.
8+
- Keep the helper scoped to user-triggered manual Run Code, not automatic Custom JS/CSS page-load rules.
9+
- Define the request and response contract, including support for URL, method, headers, body, and credential mode passthrough.
10+
- Return response status, headers, final URL, and body readers in a snippet-friendly shape so user code can work with the result similarly to `fetch()`.
11+
12+
## Impact
13+
- Affected specs: `custom-js-css`
14+
- Affected code: `src/background/index.js`, manual Run Code wrapper generation, and any related options or popup surfaces that document or trigger Run Code
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
## MODIFIED Requirements
2+
### Requirement: The background service SHALL execute custom JavaScript payloads securely
3+
The background service SHALL keep automatic Custom JS/CSS page-load injection on the legacy MAIN-world execution path, and it SHALL provide a background-backed fetch helper only to manual, user-triggered Run Code snippets executed through the user-scripts path.
4+
5+
#### Scenario: Execute JS on behalf of the content script
6+
- **GIVEN** the content script requests `{ type: 'INJECT_CUSTOM_JS', ruleId, code }`,
7+
- **THEN** the background service worker MUST verify `sender.tab.id` exists and `code` is non-empty, call `chrome.scripting.executeScript()` with the MAIN-world eval path, and reply `{ success: true }`,
8+
- **AND** host-page CSP MAY block this automatic custom-code path on pages that disallow eval, so stored rules do not gain new page-load execution privileges unexpectedly,
9+
- **AND** errors (invalid tab, injection failure, runtime exceptions) MUST be caught and responded to with `{ success: false, error }` so the caller can log and avoid retry storms.
10+
11+
#### Scenario: Manual Run Code receives a background-backed fetch helper
12+
- **GIVEN** the user manually runs a "Run Code in page" snippet,
13+
- **WHEN** the background builds the user-script wrapper,
14+
- **THEN** it MUST expose a fetch-like helper to the snippet that sends the request through the extension background instead of the page origin,
15+
- **AND** the helper MUST only be available to manual Run Code snippets, not automatic page-load Custom JS/CSS rules.
16+
17+
#### Scenario: Background-backed fetch executes with explicit validation
18+
- **GIVEN** a manual Run Code snippet calls the helper with a URL and optional init object,
19+
- **WHEN** the request reaches the background through the user-script messaging channel,
20+
- **THEN** the background MUST validate that the URL is absolute and that only supported request fields are honored,
21+
- **AND** it MUST perform the network request from the extension origin so matching host permissions can bypass page-origin CORS limits,
22+
- **AND** it MUST return a serializable response object that includes `ok`, `status`, `statusText`, `url`, `redirected`, `headers`, plus body readers that allow the snippet to call `text()` or `json()` on the returned value,
23+
- **AND** request failures or response-body parse failures MUST reject the snippet call with a descriptive error instead of silently returning an unusable result.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
## 1. Specification
2+
- [x] 1.1 Add an OpenSpec delta for background-backed fetch in manual Run Code.
3+
- [x] 1.2 Validate the OpenSpec change.
4+
5+
## 2. Implementation
6+
- [x] 2.1 Add a manual Run Code helper that exposes background-backed fetch to user snippets.
7+
- [x] 2.2 Add background request handling that validates and performs the fetch with the extension origin.
8+
- [x] 2.3 Serialize the response into a snippet-friendly shape without changing automatic Custom JS/CSS injection behavior.
9+
10+
## 3. Verification
11+
- [x] 3.1 Run OpenSpec validation and syntax checks for touched scripts.
12+
- [x] 3.2 Manually review the final diff for helper scope, request validation, and response serialization.

0 commit comments

Comments
 (0)