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 @@
+
+
# BrowserUse TypeScript Library
[](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 0000000..fb9f50c
Binary files /dev/null and b/assets/cloud-banner-js.png differ
diff --git a/src/wrapper/lib/parse.ts b/src/wrapper/lib/parse.ts
index 66e174e..60c47b8 100644
--- a/src/wrapper/lib/parse.ts
+++ b/src/wrapper/lib/parse.ts
@@ -182,9 +182,9 @@ export function wrapCreateTaskResponse(
for await (const msg of _watch(response.id, config, options)) {
for (let i = steps.total; i < msg.data.steps.length; i++) {
+ steps.total = i + 1;
yield msg.data.steps[i] satisfies BrowserUse.TaskStepView;
}
- steps.total = msg.data.steps.length;
}
}
@@ -237,38 +237,32 @@ export function wrapCreateTaskResponse(
config?: PollConfig,
options?: RequestOptions,
): Promise | 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.