From b9f950707b5d071ab0752e9881f7c3a84f20967e Mon Sep 17 00:00:00 2001 From: Matic Zavadlal Date: Tue, 2 Sep 2025 17:28:29 +0200 Subject: [PATCH] Polish README --- .fernignore | 5 +- README.md | 384 +------------------------------------ assets/cloud-banner-js.png | Bin 0 -> 32184 bytes src/wrapper/lib/parse.ts | 28 ++- 4 files changed, 17 insertions(+), 400 deletions(-) create mode 100644 assets/cloud-banner-js.png diff --git a/.fernignore b/.fernignore index 18815d2..e984ed3 100644 --- a/.fernignore +++ b/.fernignore @@ -2,8 +2,11 @@ src/wrapper/ tests/wrapper/ src/index.ts +assets/ examples/ .vscode/ .gitignore -jest.config.mjs \ No newline at end of file +jest.config.mjs + +README.md \ No newline at end of file diff --git a/README.md b/README.md index 19e46c6..270d355 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +Browser Use JS + # BrowserUse TypeScript Library [![fern shield](https://img.shields.io/badge/%F0%9F%8C%BF-Built%20with%20Fern-brightgreen)](https://buildwithfern.com?utm_source=github&utm_medium=github&utm_campaign=readme&utm_source=https%3A%2F%2Fgithub.com%2Fbrowser-use%2Fbrowser-use-node) @@ -134,262 +136,6 @@ export async function POST(req: Request) { } ``` -## Advanced Usage - -## Handling errors - -When the library is unable to connect to the API, -or if the API returns a non-success status code (i.e., 4xx or 5xx response), -a subclass of `APIError` will be thrown: - - -```ts -const task = await client.tasks - .create({ task: 'Search for the top 10 Hacker News posts and return the title and url.' }) - .catch(async (err) => { - if (err instanceof BrowserUse.APIError) { - console.log(err.status); // 400 - console.log(err.name); // BadRequestError - console.log(err.headers); // {server: 'nginx', ...} - } else { - throw err; - } - }); -``` - -Error codes are as follows: - -| Status Code | Error Type | -| ----------- | -------------------------- | -| 400 | `BadRequestError` | -| 401 | `AuthenticationError` | -| 403 | `PermissionDeniedError` | -| 404 | `NotFoundError` | -| 422 | `UnprocessableEntityError` | -| 429 | `RateLimitError` | -| >=500 | `InternalServerError` | -| N/A | `APIConnectionError` | - -### Retries - -Certain errors will be automatically retried 2 times by default, with a short exponential backoff. -Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, -429 Rate Limit, and >=500 Internal errors will all be retried by default. - -You can use the `maxRetries` option to configure or disable this: - - -```js -// Configure the default for all requests: -const client = new BrowserUse({ - maxRetries: 0, // default is 2 -}); - -// Or, configure per-request: -await client.tasks.create({ task: 'Search for the top 10 Hacker News posts and return the title and url.' }, { - maxRetries: 5, -}); -``` - -### Timeouts - -Requests time out after 1 minute by default. You can configure this with a `timeout` option: - - -```ts -// Configure the default for all requests: -const client = new BrowserUse({ - timeout: 20 * 1000, // 20 seconds (default is 1 minute) -}); - -// Override per-request: -await client.tasks.create({ task: 'Search for the top 10 Hacker News posts and return the title and url.' }, { - timeout: 5 * 1000, -}); -``` - -On timeout, an `APIConnectionTimeoutError` is thrown. - -Note that requests which time out will be [retried twice by default](#retries). - -### Accessing raw Response data (e.g., headers) - -The "raw" `Response` returned by `fetch()` can be accessed through the `.asResponse()` method on the `APIPromise` type that all methods return. -This method returns as soon as the headers for a successful response are received and does not consume the response body, so you are free to write custom parsing or streaming logic. - -You can also use the `.withResponse()` method to get the raw `Response` along with the parsed data. -Unlike `.asResponse()` this method consumes the body, returning once it is parsed. - - -```ts -const client = new BrowserUse(); - -const response = await client.tasks - .create({ task: 'Search for the top 10 Hacker News posts and return the title and url.' }) - .asResponse(); -console.log(response.headers.get('X-My-Header')); -console.log(response.statusText); // access the underlying Response object - -const { data: task, response: raw } = await client.tasks - .create({ task: 'Search for the top 10 Hacker News posts and return the title and url.' }) - .withResponse(); -console.log(raw.headers.get('X-My-Header')); -console.log(task.id); -``` - -### Logging - -> [!IMPORTANT] -> All log messages are intended for debugging only. The format and content of log messages -> may change between releases. - -#### Log levels - -The log level can be configured in two ways: - -1. Via the `BROWSER_USE_LOG` environment variable -2. Using the `logLevel` client option (overrides the environment variable if set) - -```ts -import BrowserUse from "browser-use-sdk"; - -const client = new BrowserUse({ - logLevel: "debug", // Show all log messages -}); -``` - -Available log levels, from most to least verbose: - -- `'debug'` - Show debug messages, info, warnings, and errors -- `'info'` - Show info messages, warnings, and errors -- `'warn'` - Show warnings and errors (default) -- `'error'` - Show only errors -- `'off'` - Disable all logging - -At the `'debug'` level, all HTTP requests and responses are logged, including headers and bodies. -Some authentication-related headers are redacted, but sensitive data in request and response bodies -may still be visible. - -#### Custom logger - -By default, this library logs to `globalThis.console`. You can also provide a custom logger. -Most logging libraries are supported, including [pino](https://www.npmjs.com/package/pino), [winston](https://www.npmjs.com/package/winston), [bunyan](https://www.npmjs.com/package/bunyan), [consola](https://www.npmjs.com/package/consola), [signale](https://www.npmjs.com/package/signale), and [@std/log](https://jsr.io/@std/log). If your logger doesn't work, please open an issue. - -When providing a custom logger, the `logLevel` option still controls which messages are emitted, messages -below the configured level will not be sent to your logger. - -```ts -import BrowserUse from "browser-use-sdk"; -import pino from "pino"; - -const logger = pino(); - -const client = new BrowserUse({ - logger: logger.child({ name: "BrowserUse" }), - logLevel: "debug", // Send all messages to pino, allowing it to filter -}); -``` - -### Customizing the fetch client - -By default, this library expects a global `fetch` function is defined. - -If you want to use a different `fetch` function, you can either polyfill the global: - -```ts -import fetch from "my-fetch"; - -globalThis.fetch = fetch; -``` - -Or pass it to the client: - -```ts -import BrowserUse from "browser-use-sdk"; -import fetch from "my-fetch"; - -const client = new BrowserUse({ fetch }); -``` - -### Fetch options - -If you want to set custom `fetch` options without overriding the `fetch` function, you can provide a `fetchOptions` object when instantiating the client or making a request. (Request-specific options override client options.) - -```ts -import BrowserUse from "browser-use-sdk"; - -const client = new BrowserUse({ - fetchOptions: { - // `RequestInit` options - }, -}); -``` - -#### Configuring proxies - -To modify proxy behavior, you can provide custom `fetchOptions` that add runtime-specific proxy -options to requests: - - **Node** [[docs](https://github.com/nodejs/undici/blob/main/docs/docs/api/ProxyAgent.md#example---proxyagent-with-fetch)] - -```ts -import BrowserUse from "browser-use-sdk"; -import * as undici from "undici"; - -const proxyAgent = new undici.ProxyAgent("http://localhost:8888"); -const client = new BrowserUse({ - fetchOptions: { - dispatcher: proxyAgent, - }, -}); -``` - - **Bun** [[docs](https://bun.sh/guides/http/proxy)] - -```ts -import BrowserUse from "browser-use-sdk"; - -const client = new BrowserUse({ - fetchOptions: { - proxy: "http://localhost:8888", - }, -}); -``` - - **Deno** [[docs](https://docs.deno.com/api/deno/~/Deno.createHttpClient)] - -```ts -import BrowserUse from "npm:browser-use-sdk"; - -const httpClient = Deno.createHttpClient({ proxy: { url: "http://localhost:8888" } }); -const client = new BrowserUse({ - fetchOptions: { - client: httpClient, - }, -}); -``` - -## Frequently Asked Questions - -## Requirements - -TypeScript >= 4.9 is supported. - -The following runtimes are supported: - -- Web browsers (Up-to-date Chrome, Firefox, Safari, Edge, and more) -- Node.js 20 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions. -- Deno v1.28.0 or higher. -- Bun 1.0 or later. -- Cloudflare Workers. -- Vercel Edge Runtime. -- Jest 28 or greater with the `"node"` environment (`"jsdom"` is not supported at this time). -- Nitro v2.6 or greater. - -Note that React Native is not supported at this time. - -If you are interested in other runtime environments, please open or upvote an issue on GitHub. - ## Contributing While we value open-source contributions to this SDK, this library is generated programmatically. @@ -410,132 +156,6 @@ npm i -s browser-use-sdk A full reference for this library is available [here](https://github.com/browser-use/browser-use-node/blob/HEAD/./reference.md). -## Usage - -Instantiate and use the client with the following: - -```typescript -import { BrowserUseClient } from "browser-use-sdk"; - -const client = new BrowserUseClient({ apiKey: "YOUR_API_KEY" }); -await client.tasks.createTask({ - task: "task", -}); -``` - -## Request And Response Types - -The SDK exports all request and response types as TypeScript interfaces. Simply import them with the -following namespace: - -```typescript -import { BrowserUse } from "browser-use-sdk"; - -const request: BrowserUse.ListTasksTasksGetRequest = { - ... -}; -``` - -## Exception Handling - -When the API returns a non-success status code (4xx or 5xx response), a subclass of the following error -will be thrown. - -```typescript -import { BrowserUseError } from "browser-use-sdk"; - -try { - await client.tasks.createTask(...); -} catch (err) { - if (err instanceof BrowserUseError) { - console.log(err.statusCode); - console.log(err.message); - console.log(err.body); - console.log(err.rawResponse); - } -} -``` - -## Advanced - -### Additional Headers - -If you would like to send additional headers as part of the request, use the `headers` request option. - -```typescript -const response = await client.tasks.createTask(..., { - headers: { - 'X-Custom-Header': 'custom value' - } -}); -``` - -### Additional Query String Parameters - -If you would like to send additional query string parameters as part of the request, use the `queryParams` request option. - -```typescript -const response = await client.tasks.createTask(..., { - queryParams: { - 'customQueryParamKey': 'custom query param value' - } -}); -``` - -### Retries - -The SDK is instrumented with automatic retries with exponential backoff. A request will be retried as long -as the request is deemed retryable and the number of retry attempts has not grown larger than the configured -retry limit (default: 2). - -A request is deemed retryable when any of the following HTTP status codes is returned: - -- [408](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/408) (Timeout) -- [429](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429) (Too Many Requests) -- [5XX](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500) (Internal Server Errors) - -Use the `maxRetries` request option to configure this behavior. - -```typescript -const response = await client.tasks.createTask(..., { - maxRetries: 0 // override maxRetries at the request level -}); -``` - -### Timeouts - -The SDK defaults to a 60 second timeout. Use the `timeoutInSeconds` option to configure this behavior. - -```typescript -const response = await client.tasks.createTask(..., { - timeoutInSeconds: 30 // override timeout to 30s -}); -``` - -### Aborting Requests - -The SDK allows users to abort requests at any point by passing in an abort signal. - -```typescript -const controller = new AbortController(); -const response = await client.tasks.createTask(..., { - abortSignal: controller.signal -}); -controller.abort(); // aborts the request -``` - -### Access Raw Response Data - -The SDK provides access to raw response data, including headers, through the `.withRawResponse()` method. -The `.withRawResponse()` method returns a promise that results to an object with a `data` and a `rawResponse` property. - -```typescript -const { data, rawResponse } = await client.tasks.createTask(...).withRawResponse(); - -console.log(data); -console.log(rawResponse.headers['X-My-Header']); -``` - ### Runtime Compatibility The SDK works in the following runtimes: diff --git a/assets/cloud-banner-js.png b/assets/cloud-banner-js.png new file mode 100644 index 0000000000000000000000000000000000000000..fb9f50c17f5b0296f3bf1e2ad960876e9d64bb55 GIT binary patch literal 32184 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 c-%r?h*`X(HkI$7eM}@|NNB | TaskView> { - const interval = config?.interval ?? 2000; - - poll: do { - if (options?.signal?.aborted) { - break poll; - } - - const res = await client.getTask(response.id); - - switch (res.status) { + for await (const msg of _watch(response.id, config, options)) { + switch (msg.data.status) { case "finished": case "stopped": case "paused": { if (schema != null) { - const parsed: TaskViewWithSchema = parseStructuredTaskOutput(res, schema); + const parsed: TaskViewWithSchema = parseStructuredTaskOutput( + msg.data, + schema, + ); return parsed; } else { - const result: TaskView = res; + const result: TaskView = msg.data; return result; } } case "started": - await new Promise((resolve) => setTimeout(resolve, interval)); break; default: - throw new ExhaustiveSwitchCheck(res.status); + throw new ExhaustiveSwitchCheck(msg.data.status); } - } while (true); + } - throw new Error("Task did not finish"); + throw new Error("Stream ended before the task finished!"); } // NOTE: Finally, we return the wrapped task response.