|
| 1 | +# Plan: Add WebSocket Endpoint and Headers Support |
| 2 | + |
| 3 | +## Overview |
| 4 | +Add support for connecting to Chrome via WebSocket endpoint with custom headers, in addition to the existing `--browserUrl` argument. |
| 5 | + |
| 6 | +## Puppeteer Support Verification ✅ |
| 7 | +Based on Puppeteer documentation, the `puppeteer.connect()` method supports: |
| 8 | +- **`browserWSEndpoint`** (string): WebSocket URL to connect directly to the browser (e.g., `ws://127.0.0.1:9222/devtools/browser/<id>`) |
| 9 | +- **`headers`** (Record<string, string>): Custom headers for the WebSocket connection (Node.js only) |
| 10 | + |
| 11 | +Source: `ConnectOptions` interface in Puppeteer Core |
| 12 | + |
| 13 | +## Current Implementation |
| 14 | +- `--browserUrl` / `-u`: Connects using `puppeteer.connect({ browserURL: ... })` |
| 15 | +- Uses HTTP endpoint which Puppeteer converts to WebSocket internally |
| 16 | +- No support for custom headers |
| 17 | + |
| 18 | +## Proposed Changes |
| 19 | + |
| 20 | +### 1. CLI Arguments (src/cli.ts) |
| 21 | +Add two new arguments: |
| 22 | +```typescript |
| 23 | +browserWsEndpoint: { |
| 24 | + type: 'string', |
| 25 | + description: 'WebSocket endpoint to connect to a running Chrome instance (e.g., ws://127.0.0.1:9222/devtools/browser/<id>). Alternative to --browserUrl.', |
| 26 | + alias: 'w', |
| 27 | + conflicts: 'browserUrl', |
| 28 | +} |
| 29 | + |
| 30 | +wsHeaders: { |
| 31 | + type: 'string', |
| 32 | + description: 'Custom headers for WebSocket connection in JSON format (e.g., \'{"Authorization":"Bearer token"}\'). Only works with --browserWsEndpoint.', |
| 33 | + coerce: (val: string | undefined) => { |
| 34 | + if (!val) return undefined; |
| 35 | + try { |
| 36 | + const parsed = JSON.parse(val); |
| 37 | + if (typeof parsed !== 'object' || Array.isArray(parsed)) { |
| 38 | + throw new Error('Headers must be a JSON object'); |
| 39 | + } |
| 40 | + return parsed; |
| 41 | + } catch (error) { |
| 42 | + throw new Error(`Invalid JSON for wsHeaders: ${error.message}`); |
| 43 | + } |
| 44 | + }, |
| 45 | + implies: 'browserWsEndpoint', |
| 46 | +} |
| 47 | +``` |
| 48 | + |
| 49 | +### 2. Browser Connection (src/browser.ts) |
| 50 | +Update `ensureBrowserConnected` function: |
| 51 | +```typescript |
| 52 | +export async function ensureBrowserConnected(options: { |
| 53 | + browserURL?: string; |
| 54 | + browserWSEndpoint?: string; |
| 55 | + headers?: Record<string, string>; |
| 56 | + devtools: boolean; |
| 57 | +}) { |
| 58 | + if (browser?.connected) { |
| 59 | + return browser; |
| 60 | + } |
| 61 | + |
| 62 | + const connectOptions: ConnectOptions = { |
| 63 | + targetFilter: makeTargetFilter(options.devtools), |
| 64 | + defaultViewport: null, |
| 65 | + handleDevToolsAsPage: options.devtools, |
| 66 | + }; |
| 67 | + |
| 68 | + if (options.browserWSEndpoint) { |
| 69 | + connectOptions.browserWSEndpoint = options.browserWSEndpoint; |
| 70 | + if (options.headers) { |
| 71 | + connectOptions.headers = options.headers; |
| 72 | + } |
| 73 | + } else if (options.browserURL) { |
| 74 | + connectOptions.browserURL = options.browserURL; |
| 75 | + } |
| 76 | + |
| 77 | + browser = await puppeteer.connect(connectOptions); |
| 78 | + return browser; |
| 79 | +} |
| 80 | +``` |
| 81 | + |
| 82 | +### 3. Main Entry Point (src/main.ts) |
| 83 | +Update `getContext()` to pass new options: |
| 84 | +```typescript |
| 85 | +const browser = args.browserUrl || args.browserWsEndpoint |
| 86 | + ? await ensureBrowserConnected({ |
| 87 | + browserURL: args.browserUrl, |
| 88 | + browserWSEndpoint: args.browserWsEndpoint, |
| 89 | + headers: args.wsHeaders, |
| 90 | + devtools, |
| 91 | + }) |
| 92 | + : await ensureBrowserLaunched({...}); |
| 93 | +``` |
| 94 | + |
| 95 | +### 4. Documentation (README.md) |
| 96 | +Add new options to the configuration section: |
| 97 | +- `--browserWsEndpoint`, `-w`: WebSocket endpoint |
| 98 | +- `--wsHeaders`: Custom headers in JSON format |
| 99 | + |
| 100 | +Add usage examples showing: |
| 101 | +1. Basic WebSocket connection |
| 102 | +2. WebSocket with authentication headers |
| 103 | +3. Comparison with browserUrl approach |
| 104 | + |
| 105 | +## Benefits |
| 106 | +1. **Direct WebSocket connection**: Bypass HTTP endpoint resolution |
| 107 | +2. **Authentication support**: Pass custom headers for secured browser instances |
| 108 | +3. **Flexibility**: Choose between HTTP URL or WebSocket endpoint based on use case |
| 109 | +4. **API keys/tokens**: Support authenticated remote debugging scenarios |
| 110 | + |
| 111 | +## Testing Considerations |
| 112 | +- Verify WebSocket URL validation |
| 113 | +- Test header JSON parsing (valid/invalid cases) |
| 114 | +- Ensure headers only work with WebSocket endpoint |
| 115 | +- Test mutual exclusivity of browserUrl and browserWsEndpoint |
| 116 | +- Verify wsHeaders requires browserWsEndpoint |
0 commit comments