cbrowser 7.4.4 → 7.4.7

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.
@@ -0,0 +1,201 @@
1
+ # Auth0 OAuth Setup for CBrowser MCP Server
2
+
3
+ This guide walks you through setting up Auth0 authentication for the CBrowser Remote MCP Server, enabling integration with claude.ai's custom connector feature.
4
+
5
+ ## Quick Start
6
+
7
+ ### 1. Create Auth0 Account
8
+
9
+ 1. Go to [auth0.com](https://auth0.com) and sign up (free tier works)
10
+ 2. Create a new tenant (e.g., `cbrowser` or use your existing tenant)
11
+
12
+ ### 2. Create an API
13
+
14
+ 1. Go to **Applications → APIs**
15
+ 2. Click **+ Create API**
16
+ 3. Configure:
17
+ - **Name:** `CBrowser MCP API`
18
+ - **Identifier:** `https://cbrowser-mcp.wyldfyre.ai` (your server URL)
19
+ - **Signing Algorithm:** RS256
20
+ 4. Click **Create**
21
+
22
+ ### 3. Create an Application (Static Registration)
23
+
24
+ For secure integration, we use static client registration:
25
+
26
+ 1. Go to **Applications → Applications**
27
+ 2. Click **+ Create Application**
28
+ 3. Configure:
29
+ - **Name:** `Claude.ai MCP Client`
30
+ - **Type:** Regular Web Application
31
+ 4. Click **Create**
32
+ 5. In Settings tab, configure:
33
+ - **Allowed Callback URLs:**
34
+ ```
35
+ https://claude.ai/api/mcp/auth_callback,
36
+ https://claude.com/api/mcp/auth_callback
37
+ ```
38
+ - **Allowed Web Origins:** `https://claude.ai, https://claude.com`
39
+ 6. Save Changes
40
+ 7. Note down:
41
+ - **Domain** (e.g., `your-tenant.auth0.com`)
42
+ - **Client ID**
43
+ - **Client Secret**
44
+
45
+ ### 4. Configure MCP Server
46
+
47
+ Add these environment variables to your systemd service:
48
+
49
+ ```bash
50
+ sudo nano /etc/systemd/system/cbrowser-mcp.service
51
+ ```
52
+
53
+ Add under `[Service]`:
54
+
55
+ ```ini
56
+ Environment=AUTH0_DOMAIN=your-tenant.auth0.com
57
+ Environment=AUTH0_AUDIENCE=https://cbrowser-mcp.wyldfyre.ai
58
+ Environment=AUTH0_CLIENT_ID=your-client-id
59
+ ```
60
+
61
+ Reload and restart:
62
+
63
+ ```bash
64
+ sudo systemctl daemon-reload
65
+ sudo systemctl restart cbrowser-mcp
66
+ ```
67
+
68
+ ### 5. Verify Setup
69
+
70
+ ```bash
71
+ # Check protected resource metadata
72
+ curl https://cbrowser-mcp.wyldfyre.ai/.well-known/oauth-protected-resource
73
+
74
+ # Should return:
75
+ {
76
+ "resource": "https://cbrowser-mcp.wyldfyre.ai",
77
+ "authorization_servers": ["https://your-tenant.auth0.com"],
78
+ "bearer_methods_supported": ["header"],
79
+ "scopes_supported": ["openid", "profile", "cbrowser:read", "cbrowser:write"]
80
+ }
81
+ ```
82
+
83
+ ### 6. Connect from Claude.ai
84
+
85
+ 1. Go to [claude.ai](https://claude.ai)
86
+ 2. Open **Settings → Connectors**
87
+ 3. Click **Add custom connector**
88
+ 4. Enter: `https://cbrowser-mcp.wyldfyre.ai/mcp`
89
+ 5. Claude will:
90
+ - Fetch the OAuth metadata from `/.well-known/oauth-protected-resource`
91
+ - Redirect you to Auth0 for authentication
92
+ - Exchange tokens and connect
93
+
94
+ ---
95
+
96
+ ## Architecture
97
+
98
+ ```
99
+ ┌─────────────────┐ ┌────────────────┐ ┌─────────────────┐
100
+ │ Claude.ai │────▶│ Auth0 │────▶│ CBrowser MCP │
101
+ │ │ │ │ │ Server │
102
+ │ 1. Discover │ │ 2. Authorize │ │ │
103
+ │ OAuth metadata │ │ 3. Get token │ │ 4. Validate │
104
+ │ │ │ │ │ JWT │
105
+ └─────────────────┘ └────────────────┘ └─────────────────┘
106
+ ```
107
+
108
+ ## Flow Details
109
+
110
+ 1. **Discovery**: Claude fetches `/.well-known/oauth-protected-resource` to find Auth0
111
+ 2. **Authorization**: User is redirected to Auth0 login
112
+ 3. **Token Exchange**: Auth0 issues JWT access token
113
+ 4. **API Access**: Claude sends requests with `Authorization: Bearer <jwt>`
114
+ 5. **Validation**: CBrowser validates JWT against Auth0 JWKS
115
+
116
+ ---
117
+
118
+ ## Environment Variables
119
+
120
+ | Variable | Required | Description |
121
+ |----------|----------|-------------|
122
+ | `AUTH0_DOMAIN` | Yes | Your Auth0 tenant domain (e.g., `your-tenant.auth0.com`) |
123
+ | `AUTH0_AUDIENCE` | Yes | API identifier (your server URL) |
124
+ | `AUTH0_CLIENT_ID` | No | Client ID for static registration info |
125
+
126
+ ---
127
+
128
+ ## Scopes
129
+
130
+ The server supports these OAuth scopes:
131
+
132
+ | Scope | Description |
133
+ |-------|-------------|
134
+ | `openid` | OpenID Connect authentication |
135
+ | `profile` | User profile information |
136
+ | `cbrowser:read` | Read-only access to CBrowser tools |
137
+ | `cbrowser:write` | Full access to CBrowser tools |
138
+
139
+ ---
140
+
141
+ ## Troubleshooting
142
+
143
+ ### "Invalid token" errors
144
+
145
+ 1. Check Auth0 domain is correct
146
+ 2. Verify audience matches exactly (including trailing slash if needed)
147
+ 3. Check token hasn't expired
148
+
149
+ ### "OAuth not configured" response
150
+
151
+ 1. Ensure `AUTH0_DOMAIN` and `AUTH0_AUDIENCE` are set
152
+ 2. Restart the service after config changes
153
+
154
+ ### Claude.ai can't connect
155
+
156
+ 1. Verify callback URLs include both `claude.ai` and `claude.com`
157
+ 2. Check CORS is working (test with browser dev tools)
158
+ 3. Ensure `/.well-known/oauth-protected-resource` is accessible
159
+
160
+ ### Rate limit errors (429)
161
+
162
+ Auth0 free tier has strict rate limits. CBrowser caches validated tokens for 30 minutes to avoid hitting these limits. If you're still seeing rate limits:
163
+
164
+ 1. Upgrade to Auth0 paid tier
165
+ 2. Reduce concurrent users
166
+
167
+ ### Opaque token instead of JWT
168
+
169
+ If Auth0 returns an opaque (encrypted) token instead of a JWT, CBrowser validates it via Auth0's `/userinfo` endpoint. This works but:
170
+
171
+ 1. Ensure API Identifier in Auth0 exactly matches your audience (including trailing slash)
172
+ 2. Check the Application is authorized for the API in Auth0
173
+
174
+ ---
175
+
176
+ ## Security Best Practices
177
+
178
+ 1. **Use static registration** - Don't enable open DCR without IP restrictions
179
+ 2. **Restrict callback URLs** - Only allow Claude's official callbacks
180
+ 3. **Monitor logs** - Check Auth0 logs for unauthorized access attempts
181
+ 4. **Rotate secrets** - Periodically rotate client secrets
182
+ 5. **Use scopes** - Implement scope-based access control for sensitive tools
183
+
184
+ ---
185
+
186
+ ## Dual Authentication
187
+
188
+ The server supports both API keys and OAuth simultaneously:
189
+
190
+ - **API Key**: For Claude Code CLI and programmatic access
191
+ - **OAuth**: For claude.ai web interface
192
+
193
+ Both can be enabled at the same time. The server checks OAuth JWT first, then falls back to API key.
194
+
195
+ ---
196
+
197
+ ## Related Documentation
198
+
199
+ - [Auth0 MCP Documentation](https://auth0.com/ai/docs/mcp/)
200
+ - [MCP Authorization Spec](https://spec.modelcontextprotocol.io/specification/architecture/transports/)
201
+ - [RFC 9728 - OAuth Protected Resource Metadata](https://datatracker.ietf.org/doc/html/rfc9728)
@@ -295,7 +295,7 @@ Create a page rule to bypass caching:
295
295
 
296
296
  ```bash
297
297
  curl https://cbrowser-mcp.yourdomain.com/health
298
- # {"status":"ok","version":"7.4.2"}
298
+ # {"status":"ok","version":"7.4.6","auth":true,"auth_methods":{"api_key":true,"oauth":true}}
299
299
  ```
300
300
 
301
301
  ### Info Endpoint
@@ -317,14 +317,34 @@ curl -X POST https://cbrowser-mcp.yourdomain.com/mcp \
317
317
 
318
318
  ## Step 6: Connect to Claude.ai
319
319
 
320
- 1. Go to [claude.ai](https://claude.ai)
321
- 2. Open **Settings → Integrations → Custom MCP Servers**
322
- 3. Add new connector:
323
- - **Name:** CBrowser
324
- - **URL:** `https://cbrowser-mcp.yourdomain.com/mcp`
325
- 4. Click **Connect**
320
+ ### Option A: With Auth0 OAuth (Recommended)
326
321
 
327
- You should see 31 CBrowser tools become available in Claude.
322
+ For secure authentication with claude.ai, set up Auth0 OAuth:
323
+
324
+ 1. See the [Auth0 Setup Guide](AUTH0-SETUP.md) to configure Auth0
325
+ 2. Add Auth0 environment variables to your systemd service:
326
+ ```ini
327
+ Environment=AUTH0_DOMAIN=your-tenant.auth0.com
328
+ Environment=AUTH0_AUDIENCE=https://cbrowser-mcp.yourdomain.com/
329
+ ```
330
+ 3. Restart the service: `sudo systemctl restart cbrowser-mcp`
331
+ 4. Go to [claude.ai](https://claude.ai) → **Settings → Connectors**
332
+ 5. Click **Add Custom Connector**
333
+ 6. Enter URL: `https://cbrowser-mcp.yourdomain.com/mcp`
334
+ 7. Enter your Auth0 **Client ID** and **Client Secret** when prompted
335
+ 8. Complete the OAuth login flow
336
+
337
+ ### Option B: Open Access (Public Demo)
338
+
339
+ For a public demo server without authentication:
340
+
341
+ 1. Remove `MCP_API_KEY` from your systemd service
342
+ 2. Remove `AUTH0_*` variables
343
+ 3. Add rate limiting in nginx (see Security section)
344
+ 4. Go to [claude.ai](https://claude.ai) → **Settings → Connectors**
345
+ 5. Add URL: `https://cbrowser-mcp.yourdomain.com/mcp`
346
+
347
+ You should see 31+ CBrowser tools become available in Claude.
328
348
 
329
349
  ---
330
350
 
@@ -340,11 +360,29 @@ sudo ufw allow 443/tcp # HTTPS
340
360
  sudo ufw enable
341
361
  ```
342
362
 
343
- ### Authentication (v7.4.3+)
363
+ ### Authentication (v7.4.6+)
364
+
365
+ CBrowser Remote MCP Server supports two authentication methods:
366
+
367
+ #### Method 1: Auth0 OAuth (for claude.ai)
368
+
369
+ Claude.ai requires OAuth 2.1 authentication. Set up Auth0:
370
+
371
+ ```bash
372
+ # Auth0 OAuth (enables claude.ai login)
373
+ Environment=AUTH0_DOMAIN=your-tenant.auth0.com
374
+ Environment=AUTH0_AUDIENCE=https://cbrowser-mcp.yourdomain.com/
375
+ ```
376
+
377
+ See [Auth0 Setup Guide](AUTH0-SETUP.md) for full configuration.
344
378
 
345
- CBrowser Remote MCP Server supports API key authentication:
379
+ **OAuth Endpoints:**
380
+ - `/.well-known/oauth-protected-resource` - OAuth metadata discovery
381
+ - `/mcp` - MCP endpoint (requires valid JWT)
346
382
 
347
- **Enable authentication:**
383
+ #### Method 2: API Key (for Claude Code CLI)
384
+
385
+ For programmatic access and Claude Code CLI:
348
386
 
349
387
  ```bash
350
388
  # Single API key
@@ -370,14 +408,24 @@ curl -H "Authorization: Bearer your-api-key" https://your-server/mcp
370
408
  curl -H "X-API-Key: your-api-key" https://your-server/mcp
371
409
  ```
372
410
 
373
- **Endpoints:**
374
- - `/health` and `/info` are always open (no auth required)
375
- - `/mcp` requires authentication when `MCP_API_KEY` or `MCP_API_KEYS` is set
411
+ #### Dual Authentication
412
+
413
+ Both methods can be enabled simultaneously:
414
+ - **OAuth** - For claude.ai web interface
415
+ - **API Key** - For Claude Code CLI and scripts
416
+
417
+ **Public Endpoints (no auth required):**
418
+ - `/health` - Server health status
419
+ - `/info` - Server information
420
+ - `/.well-known/oauth-protected-resource` - OAuth metadata
421
+
422
+ **Protected Endpoints:**
423
+ - `/mcp` - MCP endpoint (requires valid auth)
376
424
 
377
425
  **Additional security layers:**
378
- 1. Use Cloudflare Access for additional authentication
379
- 2. Restrict to IP whitelist in nginx
380
- 3. Enable rate limiting (see below)
426
+ 1. Rate limiting in nginx
427
+ 2. Cloudflare WAF rules
428
+ 3. IP whitelisting
381
429
 
382
430
  ### Rate Limiting
383
431
 
@@ -0,0 +1,137 @@
1
+ /**
2
+ * CBrowser v7.4.6 Remote MCP Server Examples
3
+ *
4
+ * Demonstrates:
5
+ * - Starting a remote MCP server
6
+ * - Authentication options (API key, OAuth)
7
+ * - Connecting from claude.ai
8
+ *
9
+ * Run the server: npx cbrowser mcp-remote
10
+ * Or with authentication: MCP_API_KEY=your-key npx cbrowser mcp-remote
11
+ */
12
+
13
+ import { createServer } from "http";
14
+
15
+ /**
16
+ * Example: Start Remote MCP Server Programmatically
17
+ *
18
+ * Note: In most cases, use the CLI:
19
+ * npx cbrowser mcp-remote
20
+ *
21
+ * This example shows programmatic configuration.
22
+ */
23
+ async function startRemoteMCPServer() {
24
+ console.log("=== Remote MCP Server Configuration ===\n");
25
+
26
+ console.log("Environment Variables:\n");
27
+
28
+ console.log("Basic Configuration:");
29
+ console.log(" PORT=3100 # Server port (default: 3000)");
30
+ console.log(" HOST=127.0.0.1 # Bind address");
31
+ console.log(" MCP_SESSION_MODE=stateless # Session handling\n");
32
+
33
+ console.log("API Key Authentication:");
34
+ console.log(" MCP_API_KEY=your-secret-key # Single API key");
35
+ console.log(" MCP_API_KEYS=key1,key2,key3 # Multiple API keys\n");
36
+
37
+ console.log("Auth0 OAuth (for claude.ai):");
38
+ console.log(" AUTH0_DOMAIN=your-tenant.auth0.com");
39
+ console.log(" AUTH0_AUDIENCE=https://your-server.com/\n");
40
+
41
+ console.log("Start command:");
42
+ console.log(" npx cbrowser mcp-remote\n");
43
+ }
44
+
45
+ /**
46
+ * Example: Client Configuration for claude.ai
47
+ */
48
+ function claudeAISetup() {
49
+ console.log("=== claude.ai Custom Connector Setup ===\n");
50
+
51
+ console.log("Demo Server (rate-limited, no auth):");
52
+ console.log(" URL: https://cbrowser-mcp-demo.wyldfyre.ai/mcp");
53
+ console.log(" Rate limit: 5 requests/minute, burst of 10");
54
+ console.log(" Purpose: Evaluation only\n");
55
+
56
+ console.log("Authenticated Server (full access):");
57
+ console.log(" URL: https://cbrowser-mcp.wyldfyre.ai/mcp");
58
+ console.log(" Auth: Auth0 OAuth 2.1");
59
+ console.log(" Rate limit: None\n");
60
+
61
+ console.log("Setup Steps:");
62
+ console.log(" 1. Go to claude.ai");
63
+ console.log(" 2. Open Settings -> Integrations -> Custom MCP Servers");
64
+ console.log(" 3. Add the server URL");
65
+ console.log(" 4. Complete OAuth login when prompted (for authenticated server)");
66
+ console.log(" 5. You now have 31 browser automation tools!\n");
67
+ }
68
+
69
+ /**
70
+ * Example: API Key Authentication
71
+ */
72
+ function apiKeyAuth() {
73
+ console.log("=== API Key Authentication ===\n");
74
+
75
+ console.log("Set API key when starting server:");
76
+ console.log(" MCP_API_KEY=your-secret-key npx cbrowser mcp-remote\n");
77
+
78
+ console.log("Client usage (Bearer token - recommended):");
79
+ console.log(' curl -H "Authorization: Bearer your-api-key" https://server/mcp\n');
80
+
81
+ console.log("Client usage (X-API-Key header):");
82
+ console.log(' curl -H "X-API-Key: your-api-key" https://server/mcp\n');
83
+
84
+ console.log("Generate a secure key:");
85
+ console.log(" openssl rand -hex 32\n");
86
+ }
87
+
88
+ /**
89
+ * Example: OAuth Protected Resource Metadata
90
+ */
91
+ function oauthMetadata() {
92
+ console.log("=== OAuth Protected Resource Metadata ===\n");
93
+
94
+ console.log("Endpoint: /.well-known/oauth-protected-resource\n");
95
+
96
+ console.log("Response example:");
97
+ const metadata = {
98
+ resource: "https://cbrowser-mcp.wyldfyre.ai",
99
+ authorization_servers: ["https://your-tenant.auth0.com"],
100
+ bearer_methods_supported: ["header"],
101
+ scopes_supported: ["openid", "profile", "cbrowser:read", "cbrowser:write"],
102
+ };
103
+ console.log(JSON.stringify(metadata, null, 2));
104
+ console.log();
105
+ }
106
+
107
+ /**
108
+ * Example: Health Check
109
+ */
110
+ function healthCheck() {
111
+ console.log("=== Health Check Endpoint ===\n");
112
+
113
+ console.log("Endpoint: /health\n");
114
+
115
+ console.log("Response example:");
116
+ const health = {
117
+ status: "ok",
118
+ version: "7.4.6",
119
+ auth: true,
120
+ auth_methods: {
121
+ api_key: true,
122
+ oauth: true,
123
+ },
124
+ };
125
+ console.log(JSON.stringify(health, null, 2));
126
+ console.log();
127
+ }
128
+
129
+ async function main() {
130
+ await startRemoteMCPServer();
131
+ claudeAISetup();
132
+ apiKeyAuth();
133
+ oauthMetadata();
134
+ healthCheck();
135
+ }
136
+
137
+ main().catch(console.error);
@@ -1,16 +1,19 @@
1
1
  /**
2
- * CBrowser v5.0.0 Smart Automation Examples
2
+ * CBrowser v7.x Smart Automation Examples
3
3
  *
4
4
  * Demonstrates:
5
5
  * - Smart click with auto-retry
6
6
  * - Natural language assertions
7
7
  * - Self-healing selector cache
8
8
  * - AI test generation
9
+ * - Modular imports
9
10
  *
10
11
  * Run with: npx ts-node examples/smart-automation.ts
12
+ * Or: bun run examples/smart-automation.ts
11
13
  */
12
14
 
13
- import { CBrowser } from "../src/index.js";
15
+ import { CBrowser } from "cbrowser";
16
+ // For local development: import { CBrowser } from "../src/index.js";
14
17
 
15
18
  async function smartClickExample() {
16
19
  console.log("=== Smart Click with Auto-Retry ===\n");
@@ -0,0 +1,177 @@
1
+ /**
2
+ * CBrowser v7.x Visual Testing Examples
3
+ *
4
+ * Demonstrates:
5
+ * - AI Visual Regression (v7.0)
6
+ * - Cross-Browser Testing (v7.1)
7
+ * - Responsive Testing (v7.2)
8
+ * - A/B Comparison (v7.3)
9
+ *
10
+ * Run with: npx ts-node examples/visual-testing.ts
11
+ * Or: bun run examples/visual-testing.ts
12
+ */
13
+
14
+ import { CBrowser } from "cbrowser";
15
+ // Modular imports for tree-shaking:
16
+ // import { runVisualRegression, runCrossBrowserTest, runResponsiveTest, runABComparison } from "cbrowser/visual";
17
+
18
+ async function visualRegressionExample() {
19
+ console.log("=== AI Visual Regression (v7.0) ===\n");
20
+
21
+ const browser = new CBrowser({ headless: true });
22
+
23
+ try {
24
+ // Capture a baseline
25
+ const baseline = await browser.captureVisualBaseline(
26
+ "https://example.com",
27
+ "homepage"
28
+ );
29
+ console.log(`Baseline captured: ${baseline.name}`);
30
+ console.log(`Screenshot: ${baseline.screenshotPath}`);
31
+ console.log(`Timestamp: ${baseline.timestamp}`);
32
+
33
+ // Later, compare against baseline
34
+ const result = await browser.runVisualRegression(
35
+ "https://example.com",
36
+ "homepage"
37
+ );
38
+
39
+ console.log(`\nComparison result:`);
40
+ console.log(` Match: ${result.match}`);
41
+ console.log(` Similarity: ${(result.similarity * 100).toFixed(1)}%`);
42
+ console.log(` AI Analysis: ${result.aiAnalysis}`);
43
+
44
+ if (result.differences.length > 0) {
45
+ console.log(`\nDifferences found:`);
46
+ for (const diff of result.differences) {
47
+ console.log(` - ${diff.type}: ${diff.description}`);
48
+ console.log(` Severity: ${diff.severity}`);
49
+ }
50
+ }
51
+ } finally {
52
+ await browser.close();
53
+ }
54
+ }
55
+
56
+ async function crossBrowserExample() {
57
+ console.log("\n=== Cross-Browser Testing (v7.1) ===\n");
58
+
59
+ const browser = new CBrowser({ headless: true });
60
+
61
+ try {
62
+ // Compare rendering across browsers
63
+ const result = await browser.runCrossBrowserTest("https://example.com", {
64
+ browsers: ["chromium", "firefox", "webkit"],
65
+ });
66
+
67
+ console.log(`URL tested: ${result.url}`);
68
+ console.log(`Browsers: ${result.browsers.join(", ")}`);
69
+ console.log(`Overall match: ${result.overallMatch}`);
70
+
71
+ console.log(`\nBrowser comparisons:`);
72
+ for (const comparison of result.comparisons) {
73
+ console.log(` ${comparison.browserA} vs ${comparison.browserB}:`);
74
+ console.log(` Similarity: ${(comparison.similarity * 100).toFixed(1)}%`);
75
+ console.log(` Differences: ${comparison.differences.length}`);
76
+ }
77
+
78
+ if (result.criticalDifferences.length > 0) {
79
+ console.log(`\nCritical differences:`);
80
+ for (const diff of result.criticalDifferences) {
81
+ console.log(` - ${diff.browser}: ${diff.description}`);
82
+ }
83
+ }
84
+ } finally {
85
+ await browser.close();
86
+ }
87
+ }
88
+
89
+ async function responsiveExample() {
90
+ console.log("\n=== Responsive Testing (v7.2) ===\n");
91
+
92
+ const browser = new CBrowser({ headless: true });
93
+
94
+ try {
95
+ // Test across viewport sizes
96
+ const result = await browser.runResponsiveTest("https://example.com", {
97
+ viewports: ["mobile", "tablet", "desktop"],
98
+ });
99
+
100
+ console.log(`URL tested: ${result.url}`);
101
+ console.log(`Viewports tested: ${result.viewports.length}`);
102
+
103
+ console.log(`\nViewport results:`);
104
+ for (const viewport of result.viewports) {
105
+ console.log(` ${viewport.name} (${viewport.width}x${viewport.height}):`);
106
+ console.log(` Layout: ${viewport.layoutType}`);
107
+ console.log(` Issues: ${viewport.issues.length}`);
108
+
109
+ if (viewport.issues.length > 0) {
110
+ for (const issue of viewport.issues) {
111
+ console.log(` - ${issue.type}: ${issue.description}`);
112
+ }
113
+ }
114
+ }
115
+
116
+ // Breakpoint analysis
117
+ if (result.breakpointIssues.length > 0) {
118
+ console.log(`\nBreakpoint issues:`);
119
+ for (const issue of result.breakpointIssues) {
120
+ console.log(` At ${issue.breakpoint}px: ${issue.description}`);
121
+ }
122
+ }
123
+ } finally {
124
+ await browser.close();
125
+ }
126
+ }
127
+
128
+ async function abComparisonExample() {
129
+ console.log("\n=== A/B Comparison (v7.3) ===\n");
130
+
131
+ const browser = new CBrowser({ headless: true });
132
+
133
+ try {
134
+ // Compare two URLs (staging vs production, old vs new design)
135
+ const result = await browser.runABComparison(
136
+ "https://staging.example.com",
137
+ "https://example.com",
138
+ {
139
+ labelA: "Staging",
140
+ labelB: "Production",
141
+ }
142
+ );
143
+
144
+ console.log(`Comparison: ${result.labelA} vs ${result.labelB}`);
145
+ console.log(`Overall similarity: ${(result.similarity * 100).toFixed(1)}%`);
146
+ console.log(`Match: ${result.match}`);
147
+
148
+ console.log(`\nDifferences:`);
149
+ for (const diff of result.differences) {
150
+ console.log(` - ${diff.category}: ${diff.description}`);
151
+ console.log(` Severity: ${diff.severity}`);
152
+ console.log(` Location: ${diff.location}`);
153
+ }
154
+
155
+ // AI summary
156
+ console.log(`\nAI Summary:`);
157
+ console.log(` ${result.aiSummary}`);
158
+
159
+ if (result.recommendations.length > 0) {
160
+ console.log(`\nRecommendations:`);
161
+ for (const rec of result.recommendations) {
162
+ console.log(` - ${rec}`);
163
+ }
164
+ }
165
+ } finally {
166
+ await browser.close();
167
+ }
168
+ }
169
+
170
+ async function main() {
171
+ await visualRegressionExample();
172
+ await crossBrowserExample();
173
+ await responsiveExample();
174
+ await abComparisonExample();
175
+ }
176
+
177
+ main().catch(console.error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cbrowser",
3
- "version": "7.4.4",
3
+ "version": "7.4.7",
4
4
  "description": "AI-powered browser automation with constitutional safety, AI visual regression, persona testing, and natural language test suites. Modular architecture for visual, testing, analysis, and performance modules.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -89,6 +89,7 @@
89
89
  },
90
90
  "dependencies": {
91
91
  "@modelcontextprotocol/sdk": "^1.25.3",
92
+ "jose": "^5.2.0",
92
93
  "playwright": "^1.40.0",
93
94
  "zod": "^3.25.76"
94
95
  },