@saiden/browse 0.2.10 → 0.2.12

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/README.md CHANGED
@@ -6,9 +6,6 @@
6
6
  [![Node.js](https://img.shields.io/node/v/@saiden/browse.svg)](https://nodejs.org)
7
7
 
8
8
  #### Headless browser automation for Claude Code using Playwright WebKit.
9
-
10
- <img width="1040" height="588" alt="image" src="https://github.com/user-attachments/assets/e5436f5c-b46d-4d1b-8f5a-54044969d095" />
11
-
12
9
  ## Installation
13
10
 
14
11
  ```bash
@@ -148,9 +145,79 @@ Add to Claude Code's MCP config (`~/.claude/settings.json`):
148
145
  }
149
146
  ```
150
147
 
151
- **Available Tools:** `goto`, `click`, `type`, `query`, `screenshot`, `url`, `html`, `back`, `forward`, `reload`, `wait`, `eval`
148
+ ### MCP Tools Reference
149
+
150
+ **Navigation & Interaction:**
151
+ | Tool | Description |
152
+ |------|-------------|
153
+ | `goto` | Navigate to a URL |
154
+ | `click` | Click on an element |
155
+ | `type` | Type text into an input field |
156
+ | `hover` | Hover over an element |
157
+ | `select` | Select option(s) in a dropdown |
158
+ | `keys` | Send keyboard shortcuts (e.g., "Enter", "Control+a") |
159
+ | `scroll` | Scroll page or element into view |
160
+ | `upload` | Upload files to a file input |
161
+ | `back`, `forward`, `reload` | Browser navigation |
162
+ | `wait` | Wait for a specified time |
163
+
164
+ **Debugging & Inspection:**
165
+ | Tool | Description |
166
+ |------|-------------|
167
+ | `console` | Get captured console messages (log, warn, error, etc.) |
168
+ | `errors` | Get page errors (uncaught exceptions) |
169
+ | `network` | Get captured network requests/responses |
170
+ | `intercept` | Block or mock network requests |
171
+ | `metrics` | Get performance metrics and DOM statistics |
172
+ | `a11y` | Get accessibility tree snapshot |
173
+
174
+ **Page Content:**
175
+ | Tool | Description |
176
+ |------|-------------|
177
+ | `query` | Query elements by CSS selector |
178
+ | `screenshot` | Take a screenshot |
179
+ | `url` | Get current URL and title |
180
+ | `html` | Get page HTML content |
181
+ | `eval` | Execute JavaScript in browser context |
182
+
183
+ **Storage & Session:**
184
+ | Tool | Description |
185
+ |------|-------------|
186
+ | `cookies` | Get, set, delete, or clear cookies |
187
+ | `storage` | Access localStorage or sessionStorage |
188
+ | `dialog` | Configure how browser dialogs are handled |
189
+ | `session_save` | Save session state to file |
190
+ | `session_restore` | Restore session from file |
191
+
192
+ **Viewport & Emulation:**
193
+ | Tool | Description |
194
+ |------|-------------|
195
+ | `viewport` | Resize browser viewport |
196
+ | `emulate` | Emulate a mobile device |
197
+
198
+ **Image Processing:**
199
+ | Tool | Description |
200
+ |------|-------------|
201
+ | `favicon` | Generate favicon set from image |
202
+ | `convert` | Convert image format |
203
+ | `resize` | Resize image |
204
+ | `crop` | Crop image |
205
+ | `compress` | Compress image |
206
+ | `thumbnail` | Create thumbnail |
207
+
208
+ ### MCP Resources
152
209
 
153
- **Image Processing Tools:** `favicon`, `convert`, `resize`, `crop`, `compress`, `thumbnail`
210
+ | Resource | Description |
211
+ |----------|-------------|
212
+ | `browser://state` | Browser state (URL, title, launched) |
213
+ | `browser://html` | Page HTML (truncated to 10KB) |
214
+ | `browser://html/full` | Complete page HTML |
215
+ | `browser://console` | Captured console messages |
216
+ | `browser://network` | All network requests |
217
+ | `browser://network/failed` | Failed requests only |
218
+ | `browser://errors` | Page errors |
219
+ | `browser://a11y` | Accessibility tree |
220
+ | `browser://screenshot` | Page screenshot as base64 PNG |
154
221
 
155
222
  ## Programmatic Usage
156
223
 
@@ -185,18 +252,56 @@ const server = await startServer({ port: 3000, headless: false });
185
252
 
186
253
  ### ClaudeBrowser
187
254
 
255
+ **Lifecycle:**
188
256
  - `launch()` - Launch the browser
189
257
  - `close()` - Close the browser
258
+ - `newPage()` - Open new page
259
+
260
+ **Navigation:**
190
261
  - `goto(url)` - Navigate to URL
262
+ - `back()` / `forward()` / `reload()` - Browser navigation
263
+ - `wait(ms)` - Wait for timeout
264
+
265
+ **Interaction:**
191
266
  - `click(selector)` - Click element
192
267
  - `type(selector, text)` - Type into input
268
+ - `hover(selector)` - Hover over element
269
+ - `select(selector, value)` - Select dropdown option(s)
270
+ - `keys(keys)` - Press keyboard keys
271
+ - `scroll(selector?, x?, y?)` - Scroll page or element
272
+ - `upload(selector, files)` - Upload files
273
+
274
+ **Content:**
193
275
  - `query(selector)` - Query elements, returns attributes
194
276
  - `screenshot(path?, fullPage?)` - Take screenshot
195
277
  - `getUrl()` - Get current URL and title
196
278
  - `getHtml(full?)` - Get page HTML
197
- - `back()` / `forward()` / `reload()` - Navigation
198
- - `wait(ms)` - Wait for timeout
199
- - `newPage()` - Open new page
279
+ - `eval(script)` - Execute JavaScript
280
+
281
+ **Debugging:**
282
+ - `getConsole(level?, clear?)` - Get console messages
283
+ - `getErrors(clear?)` - Get page errors
284
+ - `getNetwork(filter?, clear?)` - Get network requests
285
+ - `getMetrics(includeResources?)` - Get performance metrics
286
+ - `getA11y(selector?)` - Get accessibility tree
287
+
288
+ **Storage:**
289
+ - `getCookies(name?)` - Get cookies
290
+ - `setCookie(name, value, url?)` - Set cookie
291
+ - `deleteCookie(name)` / `clearCookies()` - Remove cookies
292
+ - `getStorage(type, key?)` - Get localStorage/sessionStorage
293
+ - `setStorage(type, key, value)` - Set storage item
294
+ - `deleteStorage(type, key)` / `clearStorage(type)` - Remove storage
295
+
296
+ **Interception:**
297
+ - `addIntercept(pattern, action, response?)` - Block or mock requests
298
+ - `clearIntercepts()` - Remove all intercepts
299
+
300
+ **Viewport:**
301
+ - `setViewport(width, height)` - Resize viewport
302
+ - `emulate(device)` - Emulate device (e.g., 'iPhone 13')
303
+
304
+ **Commands:**
200
305
  - `executeCommand(cmd)` - Execute a command object
201
306
 
202
307
  ### BrowserServer
package/dist/browser.d.ts CHANGED
@@ -1,12 +1,22 @@
1
1
  import { type BrowserContext, type Page } from 'playwright';
2
- import type { BrowserCommand, BrowserOptions, CommandResponse, ElementInfo } from './types.js';
2
+ import type { A11yNode, BrowserCommand, BrowserOptions, CommandResponse, ConsoleMessage, DialogEntry, ElementInfo, MetricsData, NetworkEntry, PageError } from './types.js';
3
3
  export declare class ClaudeBrowser {
4
4
  private browser;
5
5
  private context;
6
6
  private page;
7
7
  private options;
8
+ private consoleMessages;
9
+ private networkEntries;
10
+ private pageErrors;
11
+ private dialogHistory;
12
+ private dialogConfig;
13
+ private interceptPatterns;
8
14
  constructor(options?: BrowserOptions);
9
15
  launch(): Promise<void>;
16
+ private setupErrorListener;
17
+ private setupDialogListener;
18
+ private setupConsoleListener;
19
+ private setupNetworkListener;
10
20
  close(): Promise<void>;
11
21
  private ensurePage;
12
22
  /** Get the current page instance (for advanced usage) */
@@ -43,6 +53,62 @@ export declare class ClaudeBrowser {
43
53
  wait(ms?: number): Promise<void>;
44
54
  newPage(): Promise<void>;
45
55
  eval(script: string): Promise<unknown>;
56
+ getConsole(level?: string, clear?: boolean): ConsoleMessage[];
57
+ clearConsole(): void;
58
+ getNetwork(filter?: string, clear?: boolean): NetworkEntry[];
59
+ clearNetwork(): void;
60
+ getErrors(clear?: boolean): PageError[];
61
+ clearErrors(): void;
62
+ getMetrics(includeResources?: boolean): Promise<MetricsData>;
63
+ getA11y(selector?: string): Promise<A11yNode | null>;
64
+ getDialogs(): DialogEntry[];
65
+ clearDialogs(): void;
66
+ setDialogConfig(config: {
67
+ autoAccept?: boolean;
68
+ autoDismiss?: boolean;
69
+ text?: string;
70
+ }): void;
71
+ getDialogConfig(): {
72
+ autoAccept: boolean;
73
+ autoDismiss: boolean;
74
+ };
75
+ addIntercept(pattern: string, action: 'block' | 'mock', response?: {
76
+ status?: number;
77
+ body?: string;
78
+ contentType?: string;
79
+ }): Promise<void>;
80
+ private handleIntercept;
81
+ clearIntercepts(): Promise<void>;
82
+ getInterceptPatterns(): string[];
83
+ getCookies(name?: string): Promise<Array<{
84
+ name: string;
85
+ value: string;
86
+ domain: string;
87
+ path: string;
88
+ }>>;
89
+ setCookie(name: string, value: string, url?: string): Promise<void>;
90
+ deleteCookie(name: string): Promise<void>;
91
+ clearCookies(): Promise<void>;
92
+ getStorage(type: 'local' | 'session', key?: string): Promise<Record<string, string>>;
93
+ setStorage(type: 'local' | 'session', key: string, value: string): Promise<void>;
94
+ deleteStorage(type: 'local' | 'session', key: string): Promise<void>;
95
+ clearStorage(type: 'local' | 'session'): Promise<void>;
96
+ hover(selector: string): Promise<void>;
97
+ select(selector: string, value: string | string[]): Promise<string[]>;
98
+ keys(keys: string): Promise<void>;
99
+ upload(selector: string, files: string[]): Promise<void>;
100
+ scroll(selector?: string, x?: number, y?: number): Promise<void>;
101
+ setViewport(width: number, height: number): Promise<{
102
+ width: number;
103
+ height: number;
104
+ }>;
105
+ emulate(device: string): Promise<{
106
+ width: number;
107
+ height: number;
108
+ }>;
109
+ private handleDialogCommand;
110
+ private handleCookiesCommand;
111
+ private handleStorageCommand;
46
112
  executeCommand(cmd: BrowserCommand): Promise<CommandResponse>;
47
113
  }
48
114
  //# sourceMappingURL=browser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,cAAc,EAAE,KAAK,IAAI,EAAU,MAAM,YAAY,CAAC;AAElF,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE/F,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,OAAO,CAA2B;gBAE9B,OAAO,GAAE,cAAmB;IAQlC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAWvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B,OAAO,CAAC,UAAU;IAOlB,yDAAyD;IACzD,OAAO,IAAI,IAAI,GAAG,IAAI;IAItB,gEAAgE;IAChE,UAAU,IAAI,cAAc,GAAG,IAAI;IAI7B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAM1D,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAOjD,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnD,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAiB/C,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,UAAQ,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAOvF,MAAM,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAKjD,OAAO,CAAC,IAAI,UAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAMtC,IAAI,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAMhC,OAAO,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAMnC,MAAM,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAMlC,IAAI,CAAC,EAAE,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAK9B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAOxB,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKtC,cAAc,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;CAsIpE"}
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"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"}