Skip to main content
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.
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";
ExportKindDescription
BlueBubblesClientclassThe main client that exposes all service namespaces.
ApiErrorclassError thrown when a request receives a non-2xx response.
BaseHttpRequestabstract classBase class you extend to provide a custom HTTP transport.
CancelablePromise<T>classA Promise<T> with an added cancel() method.
CancelErrorclassThrown by CancelablePromise when cancel() is called.
OpenAPIconstThe mutable default config object used when no config is passed.
OpenAPIConfigtypeThe 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.
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

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.
const client = new BlueBubblesClient({ BASE: "http://192.168.1.50:1234" });
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.
const client = new BlueBubblesClient({ BASE: "http://your-server:1234", VERSION: "1.0.0" });
Type: boolean | Default: falseWhen 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.
const client = new BlueBubblesClient({ WITH_CREDENTIALS: true });
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.
Type: string | ((options: ApiRequestOptions) => Promise<string>) | undefinedA 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.
// 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;
  },
});
Type: string | ((options: ApiRequestOptions) => Promise<string>) | undefinedCredentials for HTTP Basic authentication. BlueBubbles Server uses PASSWORD to validate requests. Like TOKEN, both fields accept a static string or an async resolver.
const client = new BlueBubblesClient({
  BASE: "http://your-server:1234",
  PASSWORD: "your-server-password",
});
Type: Record<string, string> | ((options: ApiRequestOptions) => Promise<Record<string, string>>) | undefinedAdditional headers merged into every request. Useful for custom tracing headers, API gateways, or proxies that require specific headers.
const client = new BlueBubblesClient({
  HEADERS: { "X-Request-Source": "my-app/1.0.0" },
});
Type: ((path: string) => string) | undefinedA 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.
const client = new BlueBubblesClient({
  ENCODE_PATH: (path) => encodeURIComponent(path).replace(/%20/g, "+"),
});

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.
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.
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.
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.
1

Extend BaseHttpRequest

Your class must implement a single abstract method: request<T>(options: ApiRequestOptions): CancelablePromise<T>.
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);
    });
  }
}
2

Pass it to BlueBubblesClient

The second argument to BlueBubblesClient is the constructor of your BaseHttpRequest subclass.
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();
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.

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:
// 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.
// These imports compile to nothing at runtime
import type { OpenAPIConfig } from "bluebubbles-sdk";
import type { CancelablePromise } from "bluebubbles-sdk";
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.