npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@callowayisweird/supersaas

v1.0.0

Published

Modern, fully-typed TypeScript SDK for the SuperSaaS booking platform.

Readme

@callowayisweird/supersaas

npm version ci license

Modern, fully-typed TypeScript SDK for the SuperSaaS booking platform.

This library is a ground-up TypeScript rewrite of the official SuperSaaS Node.js client with strict typing, structured errors, real concurrency-safe rate limiting, retries with exponential backoff, request timeouts, async-iterator pagination, and a pluggable HTTP layer. Drop-in for any modern Node project.


Install

npm install @callowayisweird/supersaas

Requires Node ≥ 22.

Quickstart

import { SuperSaas } from '@callowayisweird/supersaas';

const client = new SuperSaas({
  accountName: 'your-account-name',
  apiKey: process.env.SSS_API_KEY!,
  timezone: 'America/New_York', // your schedules' configured timezone
});

const schedules = await client.schedules.list();
console.log(schedules);

Or build from environment variables (SSS_API_ACCOUNT_NAME and SSS_API_KEY):

const client = SuperSaas.fromEnv({ timezone: 'America/New_York' });

Why this library

The upstream supersaas-api-client package works but has several real issues:

| Upstream | This library | |---|---| | No TypeScript types — everything is any | Strict TS end-to-end, full inference at call sites | | Methods take both Promise and Node-style callback (footgun) | Promise-only | | Errors are bare Error with status-only message | Typed error hierarchy with status, path, method, body, requestId | | Throttle is broken under concurrency (parallel calls all pass) | Real async-mutex queue, honors Retry-After | | No request timeout | Configurable per-request timeout via AbortSignal | | No retries on 5xx or transient errors | Exponential-backoff retry for idempotent + 5xx | | new Buffer.from(...) (deprecated) | Modern Buffer.from(...) | | Module-level singleton reads env at import time | Class-based, explicit instantiation | | Datetime formatter uses local-machine TZ silently | Explicit IANA timezone, Intl-based | | Magic numeric roles [3, 4, -1] | Named Role.Customer, Role.Admin, Role.Restricted | | 10-arg positional method signatures | Options-object signatures | | Manual limit/offset pagination | for await async iterators | | console.log baked into library | Pluggable Logger interface (default: silent) | | Appointments.agenda returns malformed result | Returns array of typed results | | dryRun half-implemented | Test by injecting your own HttpClient | | CommonJS only | Dual ESM + CJS, tree-shakeable |

API surface

Client

const client = new SuperSaas({
  accountName: string,           // required
  apiKey: string,                // required
  host?: string,                 // default: https://www.supersaas.com
  timezone?: string,             // default: 'UTC'
  timeout?: number,              // default: 30_000 (ms)
  maxRetries?: number,           // default: 3
  retryBaseDelayMs?: number,     // default: 200
  retryMaxDelayMs?: number,      // default: 30_000
  rateLimitIntervalMs?: number,  // default: 1000 (set to 0 to disable)
  logger?: Logger,               // default: noopLogger
  httpClient?: HttpClient,       // default: built-in FetchHttpClient
});

Resources

| Namespace | Methods | |---|---| | client.appointments | list, get, create, update, delete, agenda, available, range, changes | | client.users | list, iterate, get, create, update, delete, fieldList | | client.schedules | list, resources, fieldList | | client.forms | list, get, templates | | client.promotions | list, get, duplicate | | client.groups | list |

Every method returns a fully typed Promise<T>. Every method accepts an optional RequestOptions parameter for per-request signal, timeout, maxRetries, and idempotencyKey.

Pagination

List endpoints return one page. To walk all results, use iterate():

for await (const user of client.users.iterate({ pageSize: 100 })) {
  console.log(user.email);
}

// Or materialize with a cap:
import { collect } from '@callowayisweird/supersaas';
const all = await collect(client.users.iterate({ maxResults: 500 }));

Errors

All errors extend SuperSaasError and carry context:

import {
  AuthError,
  ForbiddenError,
  NotFoundError,
  ValidationError,
  RateLimitError,
  ServerError,
  NetworkError,
  TimeoutError,
} from '@callowayisweird/supersaas';

try {
  await client.appointments.create({ ... });
} catch (err) {
  if (err instanceof RateLimitError) {
    await new Promise((r) => setTimeout(r, err.retryAfterMs));
  } else if (err instanceof ValidationError) {
    console.error(err.fieldErrors); // { field: [messages...] }
  } else if (err instanceof NotFoundError) {
    // ...
  }
}

Errors expose status, method, path, requestId, and body for production debugging.

Idempotency

Pass an idempotencyKey to make POST requests safe to retry:

await client.appointments.create(
  { scheduleId, userId, attributes },
  { idempotencyKey: crypto.randomUUID() },
);

When set, the request is automatically retried on transient failures. SuperSaaS will not double-create resources for the same key.

Custom HTTP transport

Inject a custom transport for testing, observability, or custom auth:

import type { HttpClient, HttpRequest, HttpResponse } from '@callowayisweird/supersaas';

class LoggingHttpClient implements HttpClient {
  constructor(private inner: HttpClient) {}
  async request<T>(req: HttpRequest): Promise<HttpResponse<T>> {
    console.time(`${req.method} ${req.path}`);
    try {
      return await this.inner.request<T>(req);
    } finally {
      console.timeEnd(`${req.method} ${req.path}`);
    }
  }
}

Migrating from supersaas-api-client

- const Client = require('supersaas-api-client');
- Client.configure({ accountName: 'a', api_key: 'k' });
- const slots = await Client.Instance.appointments.range(
-   42, false, '2026-04-28 09:00:00', '2026-04-28 23:00:00',
-   false, null, null, null, 50, 0,
- );
+ import { SuperSaas } from '@callowayisweird/supersaas';
+ const client = new SuperSaas({ accountName: 'a', apiKey: 'k' });
+ const slots = await client.appointments.range({
+   scheduleId: 42,
+   from: '2026-04-28 09:00:00',
+   to: '2026-04-28 23:00:00',
+   limit: 50,
+ });

Key differences:

  • api_keyapiKey
  • All resource methods take an options object instead of positional args
  • Client.Instance singleton pattern is gone; instantiate explicitly
  • Appointments.agenda now returns an array (not a wrapped object)
  • Typed errors instead of Error('Request failed with status 422')

Configuration recipes

Client with an explicit timezone

const client = new SuperSaas({
  accountName: 'your-account-name',
  apiKey: process.env.SSS_API_KEY!,
  timezone: 'America/New_York',
});

Tight rate limiting / fast retries

const client = new SuperSaas({
  accountName: 'a',
  apiKey: 'k',
  rateLimitIntervalMs: 250,
  retryBaseDelayMs: 100,
  maxRetries: 5,
});

Disable rate limiting (e.g. when SuperSaaS doesn't enforce one for your tier)

const client = new SuperSaas({
  accountName: 'a',
  apiKey: 'k',
  rateLimitIntervalMs: 0,
});

Development

npm install
npm run typecheck
npm run lint
npm test
npm run build

License

MIT — see LICENSE.

This library is a derivative work of the official SuperSaaS Node.js API Client (© 2018 SuperSaaS), also MIT.