> ## Documentation Index
> Fetch the complete documentation index at: https://bluebubbles.anmho.com/llms.txt
> Use this file to discover all available pages before exploring further.

# TypeScript support in the BlueBubbles SDK

> Explore the types, generics, and configuration interfaces exported by the BlueBubbles SDK to build fully type-safe integrations in TypeScript.

The BlueBubbles SDK is written entirely in TypeScript and ships with complete type definitions. Every service method is typed end-to-end — from request parameters to response shapes — so your editor can autocomplete fields, flag mismatches at compile time, and help you navigate the API without leaving your IDE. This page covers the key types and interfaces you will interact with when building on top of the SDK.

## Exported symbols

The package root (`bluebubbles-sdk`) re-exports everything you need. Import only what your code uses to keep bundles small.

```typescript theme={null}
import {
  BlueBubblesClient,   // The main client class
  ApiError,            // Thrown on non-2xx responses
  BaseHttpRequest,     // Abstract base for custom HTTP transports
  CancelablePromise,   // Promise subclass returned by every service method
  CancelError,         // Thrown when a request is cancelled
  OpenAPI,             // The mutable default config object
} from "bluebubbles-sdk";

// OpenAPIConfig is a type-only export — no runtime value
import type { OpenAPIConfig } from "bluebubbles-sdk";
```

| Export                 | Kind             | Description                                                            |
| ---------------------- | ---------------- | ---------------------------------------------------------------------- |
| `BlueBubblesClient`    | `class`          | The main client that exposes all service namespaces.                   |
| `ApiError`             | `class`          | Error thrown when a request receives a non-2xx response.               |
| `BaseHttpRequest`      | `abstract class` | Base class you extend to provide a custom HTTP transport.              |
| `CancelablePromise<T>` | `class`          | A `Promise<T>` with an added `cancel()` method.                        |
| `CancelError`          | `class`          | Thrown by `CancelablePromise` when `cancel()` is called.               |
| `OpenAPI`              | `const`          | The mutable default config object used when no config is passed.       |
| `OpenAPIConfig`        | `type`           | The shape of the configuration object accepted by `BlueBubblesClient`. |

## The `OpenAPIConfig` type

`OpenAPIConfig` controls how the SDK authenticates and constructs requests. You pass a `Partial<OpenAPIConfig>` to the `BlueBubblesClient` constructor — any fields you omit fall back to their defaults.

```typescript theme={null}
export type OpenAPIConfig = {
  BASE: string;
  VERSION: string;
  WITH_CREDENTIALS: boolean;
  CREDENTIALS: 'include' | 'omit' | 'same-origin';
  TOKEN?: string | Resolver<string> | undefined;
  USERNAME?: string | Resolver<string> | undefined;
  PASSWORD?: string | Resolver<string> | undefined;
  HEADERS?: Headers | Resolver<Headers> | undefined;
  ENCODE_PATH?: ((path: string) => string) | undefined;
};
```

### Field reference

<AccordionGroup>
  <Accordion title="BASE — server base URL">
    **Type:** `string` | **Default:** `"http://localhost"`

    The root URL of your BlueBubbles Server, without a trailing slash. Include the port if your server is not on the default HTTP/HTTPS port.

    ```typescript theme={null}
    const client = new BlueBubblesClient({ BASE: "http://192.168.1.50:1234" });
    ```
  </Accordion>

  <Accordion title="VERSION — API version string">
    **Type:** `string` | **Default:** `"1.0.0"`

    The API version to target. You do not normally need to change this unless you are explicitly pinning to a specific server version.

    ```typescript theme={null}
    const client = new BlueBubblesClient({ BASE: "http://your-server:1234", VERSION: "1.0.0" });
    ```
  </Accordion>

  <Accordion title="WITH_CREDENTIALS — send cookies cross-origin">
    **Type:** `boolean` | **Default:** `false`

    When `true`, the underlying `fetch` call includes credentials (cookies) for cross-origin requests. Set this to `true` only if your server and client are on different origins and you are using cookie-based session management.

    ```typescript theme={null}
    const client = new BlueBubblesClient({ WITH_CREDENTIALS: true });
    ```
  </Accordion>

  <Accordion title="CREDENTIALS — fetch credentials mode">
    **Type:** `'include' | 'omit' | 'same-origin'` | **Default:** `'include'`

    Maps directly to the `credentials` option of the Fetch API. Controls whether cookies and HTTP authentication headers are sent with requests. `'include'` sends credentials for both same-origin and cross-origin requests.
  </Accordion>

  <Accordion title="TOKEN — bearer token auth">
    **Type:** `string | ((options: ApiRequestOptions) => Promise<string>) | undefined`

    A static bearer token string, or an async resolver function that returns a token. Use the function form when your token may expire and needs to be refreshed per-request.

    ```typescript theme={null}
    // Static token
    const client = new BlueBubblesClient({ TOKEN: "my-static-token" });

    // Dynamic token — resolved before each request
    const client = new BlueBubblesClient({
      TOKEN: async (options) => {
        const token = await getAccessToken(); // your refresh logic
        return token;
      },
    });
    ```
  </Accordion>

  <Accordion title="USERNAME and PASSWORD — basic auth">
    **Type:** `string | ((options: ApiRequestOptions) => Promise<string>) | undefined`

    Credentials for HTTP Basic authentication. BlueBubbles Server uses `PASSWORD` to validate requests. Like `TOKEN`, both fields accept a static string or an async resolver.

    ```typescript theme={null}
    const client = new BlueBubblesClient({
      BASE: "http://your-server:1234",
      PASSWORD: "your-server-password",
    });
    ```
  </Accordion>

  <Accordion title="HEADERS — global request headers">
    **Type:** `Record<string, string> | ((options: ApiRequestOptions) => Promise<Record<string, string>>) | undefined`

    Additional headers merged into every request. Useful for custom tracing headers, API gateways, or proxies that require specific headers.

    ```typescript theme={null}
    const client = new BlueBubblesClient({
      HEADERS: { "X-Request-Source": "my-app/1.0.0" },
    });
    ```
  </Accordion>

  <Accordion title="ENCODE_PATH — custom path segment encoding">
    **Type:** `((path: string) => string) | undefined`

    A function that encodes dynamic path segments before they are inserted into the URL. By default the SDK uses `encodeURIComponent`. Override this if your server expects a different encoding scheme.

    ```typescript theme={null}
    const client = new BlueBubblesClient({
      ENCODE_PATH: (path) => encodeURIComponent(path).replace(/%20/g, "+"),
    });
    ```
  </Accordion>
</AccordionGroup>

## Typed usage patterns

### Strongly typed service calls

Every service method accepts a typed parameter object and returns a typed `CancelablePromise`. TypeScript will catch incorrect field names and type mismatches before you run your code.

```typescript theme={null}
import { BlueBubblesClient } from "bluebubbles-sdk";

const client = new BlueBubblesClient({ BASE: "http://your-server:1234", PASSWORD: "pass" });

// TypeScript infers the return type from the service definition
const response = await client.messages.list({
  requestBody: {
    limit: 25,
    offset: 0,
    sort: "DESC",
  },
});

// `response.data` is typed — your editor knows its shape
const messages = response.data ?? [];
```

### Using `CancelablePromise<T>` as a type annotation

When you store a pending request in a variable (for example, so you can cancel it later), annotate it with `CancelablePromise<T>` to preserve type safety.

```typescript theme={null}
import { CancelablePromise } from "bluebubbles-sdk";

let pending: CancelablePromise<Awaited<ReturnType<typeof client.chats.get>>> | null = null;

function loadChat(guid: string) {
  pending?.cancel();
  pending = client.chats.get({ chatGuid: guid });
  return pending;
}
```

### Narrowing `ApiError` in catch blocks

TypeScript's `catch` clause types the caught value as `unknown`. Import and check `ApiError` before accessing its properties.

```typescript theme={null}
import { ApiError } from "bluebubbles-sdk";

try {
  await client.server.getServerMetadata();
} catch (err: unknown) {
  if (err instanceof ApiError) {
    // `err` is narrowed to ApiError — all properties are available
    console.error(err.status, err.statusText, err.url);
  }
}
```

## Extending the HTTP layer with `BaseHttpRequest`

`BaseHttpRequest` is the abstract class that sits between the service layer and the network. The SDK ships with `FetchHttpRequest`, which uses the native Fetch API. You can replace it with any implementation — for example, to use `axios`, to add retry logic, or to mock requests in tests.

<Steps>
  <Step title="Extend BaseHttpRequest">
    Your class must implement a single abstract method: `request<T>(options: ApiRequestOptions): CancelablePromise<T>`.

    ```typescript theme={null}
    import {
      BaseHttpRequest,
      CancelablePromise,
    } from "bluebubbles-sdk";
    import type { OpenAPIConfig } from "bluebubbles-sdk";

    export class LoggingHttpRequest extends BaseHttpRequest {
      constructor(config: OpenAPIConfig) {
        super(config);
      }

      public request<T>(options: any): CancelablePromise<T> {
        console.log(`[${options.method}] ${this.config.BASE}${options.url}`);

        return new CancelablePromise<T>((resolve, reject) => {
          fetch(`${this.config.BASE}${options.url}`, {
            method: options.method,
            headers: options.headers as HeadersInit,
            body: options.body ? JSON.stringify(options.body) : undefined,
            credentials: this.config.CREDENTIALS,
          })
            .then((res) => res.json() as T)
            .then(resolve)
            .catch(reject);
        });
      }
    }
    ```
  </Step>

  <Step title="Pass it to BlueBubblesClient">
    The second argument to `BlueBubblesClient` is the constructor of your `BaseHttpRequest` subclass.

    ```typescript theme={null}
    import { BlueBubblesClient } from "bluebubbles-sdk";
    import { LoggingHttpRequest } from "./LoggingHttpRequest";

    const client = new BlueBubblesClient(
      { BASE: "http://your-server:1234", PASSWORD: "pass" },
      LoggingHttpRequest, // replaces FetchHttpRequest
    );

    // All service calls now go through LoggingHttpRequest
    await client.server.getServerMetadata();
    ```
  </Step>
</Steps>

<Tip>
  This pattern is especially useful for testing. Create a `MockHttpRequest` that returns fixture data from a map of `(method, url) → response`, then pass it to `BlueBubblesClient` in your test setup. Your service logic is exercised without any real network traffic.
</Tip>

## Tree-shaking and selective imports

The SDK uses named exports throughout — there is no default export and no barrel file that forces you to load everything. Modern bundlers (Vite, esbuild, Rollup, webpack 5) will tree-shake unused service classes and utilities automatically.

Import only what your module actually uses:

```typescript theme={null}
// Good — bundler can eliminate everything else
import { BlueBubblesClient, ApiError } from "bluebubbles-sdk";
import type { OpenAPIConfig } from "bluebubbles-sdk";

// Avoid — pulls in the entire module graph unnecessarily
import * as BlueBubbles from "bluebubbles-sdk";
```

Type-only imports (`import type`) are always safe: they are erased entirely at compile time and add zero bytes to your bundle.

```typescript theme={null}
// These imports compile to nothing at runtime
import type { OpenAPIConfig } from "bluebubbles-sdk";
import type { CancelablePromise } from "bluebubbles-sdk";
```

<Note>
  If you are using `"moduleResolution": "bundler"` or `"moduleResolution": "node16"` in your `tsconfig.json`, the SDK's package exports map ensures that TypeScript resolves the correct type declaration files automatically — no `typeRoots` or manual `paths` configuration is needed.
</Note>
