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

@cakemail-org/cakemail-sdk

v2.1.0

Published

TypeScript SDK for Cakemail API with 100% coverage (232 operations)

Readme

Cakemail SDK

TypeScript SDK for the Cakemail API.

Installation

npm install @cakemail-org/cakemail-sdk

Quick Start

import { CakemailClient } from '@cakemail-org/cakemail-sdk';

// Initialize the client
const client = new CakemailClient({
  email: '[email protected]',
  password: 'your-password',
});

// Get current account
const account = await client.accounts.getSelf();
console.log('Account:', account);

// List contacts
const contacts = await client.contacts.list({
  page: 1,
  per_page: 20,
  status: 'active',
});
console.log('Contacts:', contacts.data);

Features

  • 🔒 Automatic Authentication - OAuth 2.0 with automatic token refresh
  • 🔄 Retry Logic - Exponential backoff for failed requests
  • 📊 Multi-Tenant Support - Manage child accounts seamlessly
  • 💪 Type-Safe - Full TypeScript support with comprehensive types
  • 🎯 User-Friendly Errors - Clear, actionable error messages
  • Well Tested - Comprehensive unit test coverage

Configuration

Email/Password Authentication

const client = new CakemailClient({
  email: '[email protected]',
  password: 'your-password',
});

Access Token Authentication

If you already have an access token from an external OAuth flow, you can use it directly:

const client = new CakemailClient({
  accessToken: 'your-access-token',
  refreshToken: 'your-refresh-token', // Optional but recommended
  expiresIn: 3600, // Optional: Token expiration in seconds (default: 3600)
  scope: 'read write', // Optional: Token scope (default: 'read write')
});

Use cases for access token authentication:

  • Web applications with browser-based OAuth flows
  • Service accounts with pre-generated tokens
  • Integration with external authentication systems
  • Token-based authentication without storing passwords

Note: If a refreshToken is provided, the SDK will automatically refresh expired access tokens. Without a refresh token, you'll need to provide a new access token when the current one expires.

Advanced Configuration

const client = new CakemailClient({
  email: '[email protected]',
  password: 'your-password',
  baseURL: 'https://api.cakemail.dev', // Optional: Custom API URL
  timeout: 30000, // Optional: Request timeout in ms (default: 30000)
  maxRetries: 3, // Optional: Max retry attempts (default: 3)
});

Resources

Accounts

// Get current account
const account = await client.accounts.getSelf();

// Get account by ID
const account = await client.accounts.get(123);

// List accounts
const accounts = await client.accounts.list({
  page: 1,
  per_page: 20,
  status: 'active',
});

// Create account
const newAccount = await client.accounts.create({
  name: 'New Account',
  primary_email: '[email protected]',
});

// Update account
const updated = await client.accounts.update(123, {
  name: 'Updated Name',
});

// Delete account
await client.accounts.delete(123);

// Get child accounts
const children = await client.accounts.getChildren(123);

Contacts

// Get contact by ID
const contact = await client.contacts.get(456);

// Get contact by email
const contact = await client.contacts.getByEmail('[email protected]');

// List contacts
const contacts = await client.contacts.list({
  page: 1,
  per_page: 20,
  status: 'active',
  list_id: 789,
});

// Create contact
const newContact = await client.contacts.create({
  email: '[email protected]',
  first_name: 'John',
  last_name: 'Doe',
  custom_attributes: {
    company: 'Acme Corp',
  },
});

// Update contact
const updated = await client.contacts.update(456, {
  first_name: 'Jane',
});

// Delete contact
await client.contacts.delete(456);

// Subscribe to list
await client.contacts.subscribe(456, 789);

// Unsubscribe from list
await client.contacts.unsubscribe(456, 789);

// Add tags
await client.contacts.addTags(456, ['vip', 'newsletter']);

// Remove tags
await client.contacts.removeTags(456, ['newsletter']);

// Bulk operations
const result = await client.contacts.bulkOperation({
  contact_ids: [1, 2, 3],
  operation: 'subscribe',
  parameters: { list_id: 789 },
});

Lists

// Get list by ID
const list = await client.lists.get(789);

// List all lists
const lists = await client.lists.list({
  page: 1,
  per_page: 20,
  status: 'active',
});

// Create list
const newList = await client.lists.create({
  name: 'Newsletter Subscribers',
  sender_name: 'Acme Corp',
  sender_email: '[email protected]',
});

// Update list
const updated = await client.lists.update(789, {
  name: 'Updated List Name',
});

// Delete list
await client.lists.delete(789);

// Get list statistics
const stats = await client.lists.getStatistics(789);

Campaigns

// Get campaign by ID
const campaign = await client.campaigns.get(101);

// List campaigns
const campaigns = await client.campaigns.list({
  page: 1,
  per_page: 20,
  status: 'sent',
});

// Create campaign
const newCampaign = await client.campaigns.create({
  name: 'Monthly Newsletter',
  subject: 'Your Monthly Update',
  sender_name: 'Acme Corp',
  sender_email: '[email protected]',
  list_ids: [789],
  content: {
    html: '<h1>Hello!</h1><p>Welcome to our newsletter.</p>',
    text: 'Hello! Welcome to our newsletter.',
  },
});

// Update campaign
const updated = await client.campaigns.update(101, {
  subject: 'Updated Subject Line',
});

// Schedule campaign
await client.campaigns.schedule(101, {
  scheduled_at: '2024-12-31T10:00:00Z',
});

// Send campaign immediately
await client.campaigns.send(101);

// Pause campaign
await client.campaigns.pause(101);

// Resume campaign
await client.campaigns.resume(101);

// Cancel campaign
await client.campaigns.cancel(101);

// Get campaign statistics
const stats = await client.campaigns.getStatistics(101);

// Send test email
await client.campaigns.sendTest(101, ['[email protected]']);

Multi-Tenant Operations

For parent accounts managing child accounts, you can specify an accountId option:

// Access child account data
const childContacts = await client.contacts.list(
  { status: 'active' },
  { accountId: 456 } // Child account ID
);

// Create resource in child account
const newContact = await client.contacts.create(
  {
    email: '[email protected]',
    first_name: 'John',
  },
  { accountId: 456 }
);

Error Handling

The SDK provides detailed error types for better error handling:

import {
  CakemailError,
  CakemailAPIError,
  CakemailAuthError,
  CakemailNetworkError,
  CakemailValidationError,
} from '@cakemail-org/cakemail-sdk';

try {
  const contact = await client.contacts.get(999);
} catch (error) {
  if (error instanceof CakemailAPIError) {
    console.error('API Error:', error.getUserFriendlyMessage());
    console.error('Status Code:', error.statusCode);
    console.error('Response:', error.responseBody);
  } else if (error instanceof CakemailAuthError) {
    console.error('Authentication failed:', error.message);
  } else if (error instanceof CakemailNetworkError) {
    console.error('Network error:', error.message);
  } else if (error instanceof CakemailValidationError) {
    console.error('Validation error:', error.message);
  }
}

User-Friendly Error Messages

API errors include user-friendly messages via getUserFriendlyMessage():

try {
  await client.contacts.create({ email: 'invalid-email' });
} catch (error) {
  if (error instanceof CakemailAPIError) {
    // Shows: "Invalid request: Invalid email format. Please check your parameters."
    console.error(error.getUserFriendlyMessage());
  }
}

Authentication

Automatic Token Management

The SDK automatically handles OAuth 2.0 token lifecycle:

  • Authenticates on first API request
  • Caches access tokens
  • Refreshes tokens before expiration (5-minute buffer)
  • Retries failed requests after token refresh

Manual Authentication

// Explicitly authenticate (optional)
await client.authenticate();

// Get token information
const tokenInfo = client.getTokenInfo();
console.log('Token valid:', tokenInfo.isValid);
console.log('Expires at:', new Date(tokenInfo.expiresAt!));

// Clear cached token (forces re-authentication)
client.clearAuthCache();

Retry Logic

The SDK automatically retries failed requests with exponential backoff:

  • Network errors: Retries automatically
  • 5xx server errors: Retries automatically
  • 401 errors: Refreshes token and retries once
  • Max retries: 3 attempts (configurable)
  • Backoff: 1s, 2s, 4s, 8s (max 10s)

TypeScript Support

The SDK is written in TypeScript and includes comprehensive type definitions:

import {
  Account,
  Contact,
  List,
  Campaign,
  CreateContactRequest,
  UpdateContactRequest,
  ContactStatus,
  CampaignStatus,
} from '@cakemail-org/cakemail-sdk';

const contact: Contact = await client.contacts.get(123);

const createRequest: CreateContactRequest = {
  email: '[email protected]',
  first_name: 'John',
  status: ContactStatus.Active,
};

Command-Line Interface

For quick testing, automation scripts, and terminal access, the Cakemail CLI is also available:

Installation:

# via Homebrew (macOS/Linux)
brew tap cakemail/cakemail
brew install cakemail-cli

# via npm
npm install -g @cakemail-org/cakemail-cli

# via npx (no installation)
npx @cakemail-org/cakemail-cli --help

Example usage:

cakemail campaigns list
cakemail contacts create --email [email protected] --first-name John
cakemail campaigns send --id 123

The CLI uses this SDK internally and is ideal for:

  • Quick testing and debugging
  • DevOps automation and CI/CD pipelines
  • Non-developer users (marketers, operations teams)
  • Scripting and batch operations

See the CLI documentation for complete details.

Development

# Install dependencies
npm install

# Build
npm run build

# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Generate coverage report
npm run test:coverage

# Lint code
npm run lint

License

MIT

Related Projects

Support

For issues and questions:

  • GitHub Issues: https://github.com/cakemail/cakemail-sdk/issues
  • Documentation: https://docs.cakemail.com