feat(extension): add resident browser proxy CDP resolver - #2801
feat(extension): add resident browser proxy CDP resolver#2801miguelg719 wants to merge 1 commit into
Conversation
Port the loopback-only /json/version resolver from #2463 (feat/resident-transport) into packages/extension, re-derived on main. The module is standalone and not yet imported; worker wiring lands later in the stack. Changes versus #2463: - accept a wss: upstream when the proxy is https (matches the Go proxy in browserbase/go#3194, which emits wss for an https loopback URL) - emit path/query from the validated URL (pathname + search) instead of slicing the raw string - abort with a contextual Error reason and raise the default timeout to 5s to match the Go proxy's upstream timeout - fail on HTTP redirects so the request can never leave loopback - tests: wss upstream, identity rewrite (ws://127.0.0.1:9224), [::1] upstream, trailing slash and fragment rejection, timeout message
|
There was a problem hiding this comment.
1 issue found across 2 files
Confidence score: 5/5
packages/extension/service-worker-lifecycle/resident-browser-proxy.tsomits the proxy URL from timeout abort reasons, making it harder to identify which resident endpoint failed from logs; include the proxy origin alongsidetimeoutMsin the error.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/extension/service-worker-lifecycle/resident-browser-proxy.ts">
<violation number="1" location="packages/extension/service-worker-lifecycle/resident-browser-proxy.ts:24">
P2: When a timeout occurs, the abort reason omits the proxy URL, so logs cannot identify which resident endpoint timed out. Include the proxy origin alongside `timeoutMs` in this error.</violation>
</file>
Architecture diagram
sequenceDiagram
participant Ext as Extension (Service Worker)
participant Resolver as ResidentBrowserProxyResolver
participant Proxy as Loopback Proxy (127.0.0.1:9224)
participant Chromium as Chromium (Internal)
Note over Ext,Chromium: NEW: Resident Browser Discovery Flow
Ext->>Resolver: resolveResidentBrowserWebSocketUrl(proxyUrl)
Resolver->>Resolver: NEW: parseBrowserProxyUrl()<br/>(Validate loopback + origin-only)
rect rgb(240, 240, 240)
Note right of Resolver: Start 5s Timeout Budget
Resolver->>Proxy: NEW: GET /json/version
Proxy->>Chromium: Forward version request
Chromium-->>Proxy: 200 OK (JSON with webSocketDebuggerUrl)
Proxy-->>Resolver: Return browser metadata
alt Request timed out or HTTP error
Resolver-->>Ext: Throw AbortError / HTTP Error
end
end
Resolver->>Resolver: NEW: Zod parse BrowserVersionSchema
Resolver->>Resolver: NEW: rewriteDebuggerUrl()<br/>(Validate loopback ws/wss target)
Note over Resolver: NEW: Protocol Mapping<br/>http -> ws | https -> wss
Resolver->>Resolver: NEW: Map internal Chromium path/query<br/>to Proxy authority
alt Validation Failure (e.g. non-loopback or invalid path)
Resolver-->>Ext: Throw Validation Error
else Success
Resolver-->>Ext: Return proxied WebSocket URL
end
Note over Ext,Proxy: Future: Connect to Browser via Proxy WS URL
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| const timeout = setTimeout( | ||
| () => | ||
| abortController.abort( | ||
| new Error(`Resident browser proxy version request timed out after ${timeoutMs}ms`), |
There was a problem hiding this comment.
P2: When a timeout occurs, the abort reason omits the proxy URL, so logs cannot identify which resident endpoint timed out. Include the proxy origin alongside timeoutMs in this error.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/extension/service-worker-lifecycle/resident-browser-proxy.ts, line 24:
<comment>When a timeout occurs, the abort reason omits the proxy URL, so logs cannot identify which resident endpoint timed out. Include the proxy origin alongside `timeoutMs` in this error.</comment>
<file context>
@@ -0,0 +1,90 @@
+ const timeout = setTimeout(
+ () =>
+ abortController.abort(
+ new Error(`Resident browser proxy version request timed out after ${timeoutMs}ms`),
+ ),
+ timeoutMs,
</file context>
Summary
Stack A/5 (resident Stagehand on
main):feat/resident-main-a-transport(this PR) →-b-target-safety→-c-gateway-runtime→-d-artifacts→-e-browserbase-opt-in. Supersedes #2463 (archived v4-spike base).Adds the resident browser proxy CDP resolver (
packages/extension/service-worker-lifecycle/resident-browser-proxy.ts) used by the image-resident extension to find Chromium through pid2's loopback filtered proxy (127.0.0.1:9224, Go #3193–#3196): fetch/json/versionfrom a loopback-only http(s) origin, validate that Chromium returned a loopbackws(s)://…/devtools/browser/<id>URL, and rewrite only scheme+authority to the proxy while preserving the exact target path/query.Inert in this PR: nothing imports the module yet (wired in stack C). No ordinary-session behavior changes.
Changes vs the v4-spike version, from the 2026-08-20 review: accepts
wss:when the proxy ishttps:(matches the Go side), emits path/query from the validated URL (not a raw slice), abort reason carries the proxy URL and budget, timeout raised 1 s → 5 s to match the Go upstream dial timeout, tests for identity rewrite /[::1]/ trailing slash / fragment.Validation
pnpm check, extension unit tests (incl. extension-source-compatibility), protocol tests — green. Verified end to end on a devbox k3d stack with the real image bytes (see stack E).