🚧 FastCMS is under active development — not ready for production use. APIs and features may change without notice.
FastCMS
SDKs

TypeScript SDK

Official TypeScript/JavaScript SDK for FastCMS with full type safety, auto token refresh, batch operations, real-time subscriptions, and OTP authentication.

TypeScript SDK

The official TypeScript SDK for FastCMS provides a fully-typed client for all API operations with automatic token refresh and real-time support.

Installation

npm install @fastcms/sdk
# or
yarn add @fastcms/sdk

Quick Start

import { FastCMS } from '@fastcms/sdk';

const client = new FastCMS({
  baseUrl: 'http://localhost:8000',
});

// Sign in
const { user, tokens } = await client.auth.signInWithEmail(
  'admin@example.com',
  'password123'
);

// Query records
const posts = await client.collection('posts').list({
  sort: '-created',
  filter: 'published=true',
  perPage: 20,
});

Authentication

Email & Password

// Register
const { user } = await client.auth.signUpWithEmail(
  'user@example.com',
  'SecurePass123',
  'John Doe'         // optional name
);

// Login
const { user, tokens } = await client.auth.signInWithEmail(
  'user@example.com',
  'SecurePass123'
);

// Refresh token
const newTokens = await client.auth.refreshToken(tokens.refreshToken);

// Get current user
const me = await client.auth.getCurrentUser();

// Change password
await client.auth.changePassword('oldPass', 'newPass');

OTP (Passwordless)

// Step 1: Request OTP
await client.auth.requestOTP('user@example.com');

// Step 2: Authenticate with the code from email
const { user, tokens } = await client.auth.authWithOTP(
  'user@example.com',
  '483921'
);

Email Management

// Request email change (sends verification to new address)
await client.auth.requestEmailChange('new@example.com', 'currentPassword');

// Confirm email change (token from the verification email)
await client.auth.confirmEmailChange('verification-token');

// Verify email address
await client.auth.verifyEmail('verification-token');

Session Management

// List all active sessions
const sessions = await client.auth.getSessions();

// Revoke a specific session
await client.auth.revokeSession(sessionId);

// Logout all devices
await client.auth.logoutAll();

Collections

CRUD Operations

const col = client.collection('products');

// List with filtering, sorting, pagination
const result = await col.list({
  page: 1,
  perPage: 30,
  sort: '-created',
  filter: 'price>=100&&active=true',
  search: 'laptop',
});
// result.items, result.total, result.page, result.perPage

// Get one record
const product = await col.getOne('record-id');

// Create
const created = await col.create({ name: 'Laptop', price: 999 });

// Update
const updated = await col.update('record-id', { price: 899 });

// Delete
await col.delete('record-id');

Batch Operations

Process multiple records in a single request:

// Bulk create
const created = await client.batch.createMany('products', [
  { name: 'Product A', price: 10 },
  { name: 'Product B', price: 20 },
]);

// Bulk upsert
const { created, updated } = await client.batch.upsertMany(
  'products',
  records,
  ['sku']            // upsert key field(s)
);

// Bulk delete
const { deleted } = await client.batch.deleteMany('products', ['id1', 'id2', 'id3']);

// Raw batch (custom requests)
const results = await client.batch.execute([
  { method: 'POST', url: '/api/v1/collections/posts/records', body: { title: 'A' } },
  { method: 'PATCH', url: '/api/v1/collections/posts/records/xyz', body: { title: 'B' } },
]);

Files

// Upload
const file = await client.files.upload(fileBlob, {
  collectionName: 'products',
  recordId: 'record-id',
  fieldName: 'image',
});

// Get download URL
const url = client.files.getDownloadUrl(file.id);

// Thumbnail — WxH with optional modifier
// Modifiers: (none)=center-crop, f=fit/letterbox, t=top-crop, b=bottom-crop
// Use 0xH or Wx0 for proportional resize
const thumb     = client.files.getDownloadUrl(file.id, '300x200');   // center crop
const fit       = client.files.getDownloadUrl(file.id, '300x200f');  // fit + pad
const topCrop   = client.files.getDownloadUrl(file.id, '300x200t');  // crop from top
const propHeight = client.files.getDownloadUrl(file.id, '0x150');    // prop. to 150px tall

// Protected file — get a short-lived token (2 min)
const { token } = await client.files.getToken(file.id);
const protectedUrl = client.files.getDownloadUrl(file.id, undefined, token);

// Set file as protected
await client.files.setProtected(file.id, true);

// Delete
await client.files.delete(file.id);

Real-time Subscriptions

const rt = client.realtime.connect(tokens.accessToken);

// Subscribe to a collection
rt.subscribe('posts', { published: true });

// Listen to events
rt.on('posts:record.created', (data) => {
  console.log('New post:', data);
});

rt.on('posts:record.updated', (data) => {
  console.log('Post updated:', data);
});

// Unsubscribe
rt.unsubscribe('posts');

// Disconnect
rt.disconnect();

API Keys

// Use an API key instead of a user token
const client = new FastCMS({
  baseUrl: 'http://localhost:8000',
  apiKey: 'fk_live_your_key_here',
});

Auto Token Refresh

The SDK automatically refreshes the access token on 401 responses using the stored refresh token. No manual handling required.

// Set tokens after login
client.setTokens(tokens.accessToken, tokens.refreshToken);

// Tokens are refreshed silently in the background
const data = await client.collection('posts').list();

TypeScript Types

import type { FastCMS, CollectionRecord, AuthTokens, FileRecord } from '@fastcms/sdk';

interface Post extends CollectionRecord {
  title: string;
  content: string;
  published: boolean;
}

const posts = await client.collection<Post>('posts').list();
// posts.items is Post[]

On this page