BaasixBaasix
SDKs

JavaScript SDK

← Back to Documentation Home

The official JavaScript/TypeScript SDK for Baasix provides a type-safe, easy-to-use client for integrating with your Baasix backend.

Features

  • 🌐 Universal — Works in browsers, Node.js, and React Native
  • 🔐 Flexible Auth — JWT tokens, HTTP-only cookies, OAuth (Google, Facebook, Apple, GitHub)
  • 💾 Customizable Storage — LocalStorage, AsyncStorage, or custom adapters
  • 📝 Type-Safe — Full TypeScript support with generics
  • 🔄 Auto Token Refresh — Seamless token management
  • 🏢 Multi-Tenant — Built-in tenant switching and invitation support
  • Query Builder — Fluent API for complex queries with 50+ filter operators
  • 📡 Realtime — WebSocket subscriptions for live data updates
  • 📁 File Management — Upload, download, and transform assets
  • 🔀 Workflows — Execute and monitor workflow executions
  • 🔔 Notifications — User notification system with realtime delivery
  • 🗃️ Migrations — Database schema migration management
  • 📊 Reports — Analytics and aggregation queries
  • 🔃 Sort/Reorder — Drag-and-drop style item reordering

Installation

npm install @baasix/sdk
# or
yarn add @baasix/sdk
# or
pnpm add @baasix/sdk

TypeScript Types Generation

For full type safety, use the Baasix CLI to generate TypeScript types from your schemas:

# Generate types from running Baasix instance
npx baasix generate --url http://localhost:8056 --output ./src/types/baasix.d.ts

Then use the generated types with the SDK:

import { createBaasix } from '@baasix/sdk';
import type { BaasixCollections, Product } from './types/baasix';

// Create typed client
const baasix = createBaasix<BaasixCollections>({
  url: 'https://api.example.com',
});

// All queries are now fully typed
const { data } = await baasix.items('products').find({
  filter: { price: { gte: 10 } },
});
// data is typed as Product[]

See the CLI Guide for more details on type generation.

Quick Start

import { createBaasix } from '@baasix/sdk';

// Create client
const baasix = createBaasix({
  url: 'https://your-baasix-instance.com',
});

// Login
const { user, token } = await baasix.auth.login({
  email: 'user@example.com',
  password: 'password123',
});

// Query items
const { data: products } = await baasix.items('products').find({
  filter: { status: { eq: 'active' } },
  sort: { createdAt: 'desc' },
  limit: 10,
});

// Create item
const productId = await baasix.items('products').create({
  name: 'New Product',
  price: 29.99,
});

Configuration

Basic Configuration

import { createBaasix } from '@baasix/sdk';

const baasix = createBaasix({
  url: 'https://api.example.com', // Required: Your Baasix URL
  authMode: 'jwt', // 'jwt' (default) or 'cookie'
  timeout: 30000, // Request timeout in ms
  autoRefresh: true, // Auto-refresh tokens
  onAuthStateChange: (event, user) => {
    // Auth state callback
    console.log('Auth changed:', event, user);
  },
});

React Native Setup

import { createBaasix, AsyncStorageAdapter } from '@baasix/sdk';
import AsyncStorage from '@react-native-async-storage/async-storage';

const baasix = createBaasix({
  url: 'https://api.example.com',
  storage: new AsyncStorageAdapter(AsyncStorage),
});
const baasix = createBaasix({
  url: 'https://api.example.com',
  authMode: 'cookie',
  credentials: 'include',
});

Server-Side / Service Account

const baasix = createBaasix({
  url: 'https://api.example.com',
  token: 'your-static-api-token',
});

Authentication

Login & Register

// Register
const { user, token } = await baasix.auth.register({
  email: 'newuser@example.com',
  password: 'securepassword',
  firstName: 'John',
  lastName: 'Doe',
});

// Login
const { user, token } = await baasix.auth.login({
  email: 'user@example.com',
  password: 'password123',
});

// Login with tenant (multi-tenant mode)
const result = await baasix.auth.login({
  email: 'user@example.com',
  password: 'password123',
  tenantId: 'tenant-uuid',
});

// Login with authMode and authType
const result = await baasix.auth.login({
  email: 'user@example.com',
  password: 'password123',
  authMode: 'cookie', // 'jwt' (default) or 'cookie'
  authType: 'mobile', // for session management
});

// Logout
await baasix.auth.logout();

Get Current User

// From server (makes API call to /auth/me)
const user = await baasix.auth.getUser();

// Alias for getUser()
const user = await baasix.auth.me();

// From cache (no API call)
const cachedUser = await baasix.auth.getCachedUser();

// Check if authenticated
if (await baasix.auth.isAuthenticated()) {
  console.log('User is logged in');
}

OAuth / Social Login

// Redirect to OAuth provider
const url = baasix.auth.getOAuthUrl({
  provider: 'google', // 'google' | 'facebook' | 'apple' | 'github'
  redirectUrl: 'https://myapp.com/auth/callback',
});
window.location.href = url;

// In your callback page
const params = new URLSearchParams(window.location.search);
const token = params.get('token');

if (token) {
  const { user } = await baasix.auth.handleOAuthCallback(token);
  console.log('Logged in as:', user.email);
}
// Send magic link
await baasix.auth.sendMagicLink({
  email: 'user@example.com',
  redirectUrl: 'https://myapp.com/auth/verify',
});

// Verify (in callback page)
const { user, token } = await baasix.auth.verifyMagicLink(tokenFromUrl);

Password Management

// Request password reset (sends email)
await baasix.auth.forgotPassword({
  email: 'user@example.com',
  redirectUrl: 'https://myapp.com/reset-password',
});

// Reset password with token (from email link)
await baasix.auth.resetPassword('reset-token', 'newSecurePassword');

// Change password (requires current password)
await baasix.auth.changePassword('currentPassword', 'newPassword');

Token Management

// Get current access token
const token = await baasix.auth.getToken();

// Set a static token (for server-side/service accounts)
await baasix.auth.setToken('your-api-token');

// Refresh the current token
const { token, expiresIn } = await baasix.auth.refreshToken();

Session & State Management

// Initialize auth state from storage (call on app startup)
const state = await baasix.auth.initialize();

// Get current auth state
const { user, isAuthenticated } = await baasix.auth.getState();

// Check if session is valid with server
const isValid = await baasix.auth.checkSession();

Email Verification

// Request email verification (sends verification email)
await baasix.auth.requestEmailVerification('https://myapp.com/verify-email');

// Verify email with token (from email link)
await baasix.auth.verifyEmail('verification-token');

Multi-tenant

// Get available tenants
const tenants = await baasix.auth.getTenants();

// Switch tenant
const { user, token } = await baasix.auth.switchTenant('tenant-uuid');

// Send invitation
await baasix.auth.sendInvite({
  email: 'newuser@example.com',
  roleId: 'editor-role-uuid',
  tenantId: 'tenant-uuid',
  redirectUrl: 'https://myapp.com/accept-invite',
});

// Verify invitation token
const inviteInfo = await baasix.auth.verifyInvite('invite-token');
if (inviteInfo.valid) {
  console.log('Invited to:', inviteInfo.tenant.name);
}

// Accept invitation (for existing users)
const { user, token } = await baasix.auth.acceptInvite('invite-token');

// Register with invitation (for new users)
const { user, token } = await baasix.auth.registerWithInvite({
  email: 'newuser@example.com',
  password: 'password123',
  firstName: 'John',
  lastName: 'Doe',
  inviteToken: 'invite-token',
});

Items (CRUD Operations)

Basic Operations

const products = baasix.items('products');

// Find all
const { data, totalCount } = await products.find({
  filter: { status: { eq: 'active' } },
  sort: { createdAt: 'desc' },
  limit: 20,
  page: 1,
});

// Find one
const product = await products.findOne('product-uuid');

// Create
const id = await products.create({
  name: 'New Product',
  price: 29.99,
});

// Update
await products.update('product-uuid', { price: 24.99 });

// Delete
await products.delete('product-uuid');

Query Builder

const results = await baasix
  .items('posts')
  .query()
  .select('*', 'author.*', 'comments.*')
  .filter({ status: { eq: 'published' } })
  .sort({ createdAt: 'desc' })
  .limit(10)
  .page(1)
  .get();

// Get first matching item
const post = await baasix
  .items('posts')
  .query()
  .filter({ slug: { eq: 'my-post' } })
  .first();

// Count matching items
const count = await baasix
  .items('posts')
  .query()
  .filter({ status: { eq: 'published' } })
  .count();

// Skip results with offset
const page2 = await baasix.items('posts').query().offset(20).limit(10).get();

// Full-text search
const results = await baasix.items('posts').query().search('javascript', ['title', 'content']).get();

// Include soft-deleted items
const allItems = await baasix.items('posts').query().withDeleted().get();

// Filter related items
const posts = await baasix
  .items('posts')
  .query()
  .select('*', 'comments.*')
  .relFilter({
    comments: { approved: { eq: true } },
  })
  .get();

Filter Operators

// Comparison
{ price: { eq: 100 } }        // equals
{ price: { neq: 100 } }       // not equals
{ price: { gt: 100 } }        // greater than
{ price: { gte: 100 } }       // greater than or equal
{ price: { lt: 100 } }        // less than
{ price: { lte: 100 } }       // less than or equal

// String
{ name: { like: '%Product%' } }
{ name: { ilike: '%product%' } }  // case-insensitive
{ name: { startsWith: 'Pro' } }
{ name: { contains: 'duct' } }

// List
{ status: { in: ['active', 'pending'] } }
{ price: { between: [10, 100] } }

// Null
{ deletedAt: { isNull: true } }

// Array (PostgreSQL)
{ tags: { arraycontains: ['featured'] } }

// Logical
{ AND: [{ status: { eq: 'active' } }, { price: { gt: 0 } }] }
{ OR: [{ featured: { eq: true } }, { views: { gt: 1000 } }] }

// Dynamic variables
{ author_Id: { eq: '$CURRENT_USER' } }
{ createdAt: { gte: '$NOW-DAYS_30' } }

Bulk Operations

// Create many
const ids = await products.createMany([
  { name: 'Product 1', price: 10 },
  { name: 'Product 2', price: 20 },
]);

// Update many - apply same data to multiple IDs
await products.updateMany(['uuid-1', 'uuid-2'], { status: 'archived' });

// Delete many
await products.deleteMany(['uuid-1', 'uuid-2']);

Import Data

// Import from CSV file
const fileInput = document.querySelector('input[type="file"]');
const result = await products.importCSV(fileInput.files[0]);
console.log(`Imported ${result.imported} items`);

// Import from JSON file
const result = await products.importJSON(jsonFile);

// Import from array (bulk create)
const ids = await products.createMany([
  { name: 'Product 1', price: 29.99 },
  { name: 'Product 2', price: 39.99 },
]);

Sort / Reorder Items

// Move item1 before item2
await products.sortItem('item1-uuid', 'item2-uuid');

// Move item1 after item2
await products.sortItem('item1-uuid', 'item2-uuid', 'after');

// Reorder multiple items (set explicit order)
await products.reorder(['item3-uuid', 'item1-uuid', 'item2-uuid']);

Upsert (Update or Insert)

// Update if exists, create if not (based on filter)
const id = await products.upsert(
  { sku: { eq: 'WIDGET-001' } }, // filter to find existing
  { name: 'Widget', price: 29.99, sku: 'WIDGET-001' }, // data to upsert
);

Soft Delete & Restore

// Soft delete an item (sets deletedAt timestamp)
await products.softDelete('product-uuid');

// Restore a soft-deleted item
await products.restore('product-uuid');

Aggregations

// Run aggregation queries with grouping
const results = await products.aggregate({
  aggregate: {
    total: { function: 'sum', field: 'price' },
    count: { function: 'count', field: 'id' },
    avgPrice: { function: 'avg', field: 'price' },
  },
  groupBy: ['category', 'status'],
  filter: { createdAt: { gte: '$NOW-DAYS_30' } },
});

Realtime Subscriptions

The SDK supports real-time data updates via WebSocket connections, powered by PostgreSQL WAL (Write-Ahead Log) for reliable change capture.

Setup

npm install socket.io-client
import { io } from 'socket.io-client';

// Set the socket client
baasix.realtime.setSocketClient(io);

// Connect
await baasix.realtime.connect();

Subscribe to Collections

// Subscribe to all changes
const unsubscribe = baasix.realtime.subscribe('products', (payload) => {
  console.log(`${payload.action}:`, payload.data);
  // payload.action: 'create' | 'update' | 'delete'
});

// Subscribe to specific events
baasix.realtime.on('orders', 'create', (data) => {
  console.log('New order:', data);
});

// Unsubscribe
unsubscribe();

Supabase-style Channel API

const channel = baasix.realtime
  .channel('products')
  .on('INSERT', (payload) => console.log('New:', payload))
  .on('UPDATE', (payload) => console.log('Updated:', payload))
  .on('DELETE', (payload) => console.log('Deleted:', payload))
  .subscribe();

// Later
channel.unsubscribe();

Custom Rooms

Custom rooms allow real-time communication between users for use cases like chat, games, or collaborative features. The first user to join a room becomes its creator. If the creator leaves, ownership temporarily transfers — but the original creator automatically reclaims it when they rejoin.

// Join a room — optionally attach metadata visible to all members.
// The return value includes a history array with the room's last 200 messages
// so late joiners can catch up without extra requests.
const { history } = await baasix.realtime.joinRoom('game:lobby', {
  username: 'Alice',
  avatar: 'https://example.com/alice.png',
  team: 'blue',
});

// Replay buffered messages for late joiners
// Each entry: { event, payload, sender: { userId, socketId }, timestamp }
history.forEach((msg) => {
  addMessageToUI(msg.sender.userId, msg.payload.text);
});

// Get current members (must be a member yourself)
// Each entry includes userId, socketId, isCreator, and metadata
const members = await baasix.realtime.getRoomMembers('game:lobby');
// [{ socketId, userId, isCreator, metadata: { username, avatar, team } }, ...]

// List all active rooms (no membership required)
const rooms = await baasix.realtime.listRooms();
// [{ name: 'game:lobby', memberCount: 4 }, { name: 'chat:general', memberCount: 12 }]

// Filter by prefix
const gameRooms = await baasix.realtime.listRooms('game:');
// [{ name: 'game:lobby', memberCount: 4 }, { name: 'game:arena', memberCount: 8 }]

// Send a persisted message (stored in history buffer — default)
await baasix.realtime.sendToRoom('game:lobby', 'chat', { text: 'Hello everyone!' });

// Send an ephemeral message (broadcast only, NOT stored in history)
// Use this for high-frequency events like cursors or typing indicators
await baasix.realtime.sendToRoom('game:lobby', 'typing', { userId }, { history: false });
await baasix.realtime.sendToRoom('game:lobby', 'cursor', { x: 120, y: 340 }, { history: false });

// Listen for room messages
const unsubscribe = baasix.realtime.onRoomMessage('game:lobby', 'chat', (data) => {
  console.log(`${data.sender.userId}: ${data.payload.text}`);
});

// Listen for users joining/leaving (joined event includes their metadata)
baasix.realtime.onRoomUserJoined('game:lobby', (data) => {
  console.log(`User ${data.userId} joined`, data.metadata);
});

baasix.realtime.onRoomUserLeft('game:lobby', (data) => {
  console.log(`User ${data.userId} left`);
});

// Kick a user (creator only)
await baasix.realtime.kickFromRoom('game:lobby', 'target-user-id');

// Listen for being kicked out
baasix.realtime.onKicked('game:lobby', ({ kickedBy }) => {
  console.log(`You were kicked by user ${kickedBy}`);
});

// Listen for room ownership changes
baasix.realtime.onRoomCreatorChanged('game:lobby', ({ newCreatorUserId }) => {
  console.log(`New room owner: ${newCreatorUserId}`);
});

// Leave the room
await baasix.realtime.leaveRoom('game:lobby');

Custom Event Handlers

Invoke custom server-side handlers registered by extensions:

// Call a custom server handler
const result = await baasix.realtime.invoke('game:roll-dice', { sides: 6 });
console.log('Dice result:', result);

Connection Management

// Check status
if (baasix.realtime.isConnected) {
  console.log('Connected');
}

// Listen for changes
baasix.realtime.onConnectionChange((connected) => {
  console.log('Realtime:', connected ? 'online' : 'offline');
});

// Disconnect
baasix.realtime.disconnect();

Files

Upload

// Browser
const metadata = await baasix.files.upload(fileInput.files[0], {
  title: 'Product Image',
  folder: 'products',
  isPublic: true,
  onProgress: (progress) => console.log(`${progress}%`),
});

// React Native
const metadata = await baasix.files.upload({
  uri: result.uri,
  name: 'photo.jpg',
  type: 'image/jpeg',
});

Get Asset URLs

// Original
const url = baasix.files.getAssetUrl('file-uuid');

// Resize with WebP output
const thumbnailUrl = baasix.files.getAssetUrl('file-uuid', {
  width: 200,
  height: 200,
  fit: 'cover',
  format: 'webp',
  quality: 80,
});

// Convert to WebP without resizing (preserves transparency)
const webpUrl = baasix.files.getAssetUrl('file-uuid', {
  format: 'webp',
  quality: 85,
});

// Safe resize — won't upscale small images
const safeUrl = baasix.files.getAssetUrl('file-uuid', {
  width: 1200,
  format: 'webp',
  withoutEnlargement: true,
});

Transform options:

OptionTypeDefaultDescription
widthnumberTarget width in pixels
heightnumberTarget height in pixels
fit'cover'|'contain'|'fill'|'inside'|'outside''cover'Resize fit mode
qualitynumber (1–100)80Output quality
format'jpeg'|'png'|'webp'|'avif''jpeg'Output format. webp and png preserve alpha transparency; jpeg flattens to white
withoutEnlargementbooleanfalsePrevent upscaling images smaller than the target dimensions

Download

const blob = await baasix.files.download('file-uuid');

Schemas

// List schemas
const schemas = await baasix.schemas.find();

// Create schema with validation and default values
await baasix.schemas.create('products', {
  name: 'Product',
  timestamps: true,
  fields: {
    id: {
      type: 'UUID',
      primaryKey: true,
      defaultValue: { type: 'UUIDV4' },
    },
    sku: {
      type: 'SUID',
      unique: true,
      defaultValue: { type: 'SUID' },
    },
    name: {
      type: 'String',
      allowNull: false,
      values: { length: 255 },
      validate: {
        notEmpty: true,
        len: [3, 255],
      },
    },
    price: {
      type: 'Decimal',
      values: { precision: 10, scale: 2 },
      validate: {
        min: 0,
        max: 999999.99,
      },
    },
    quantity: {
      type: 'Integer',
      defaultValue: 0,
      validate: {
        isInt: true,
        min: 0,
      },
    },
    email: {
      type: 'String',
      validate: {
        isEmail: true,
      },
    },
    website: {
      type: 'String',
      validate: {
        isUrl: true,
      },
    },
    status: {
      type: 'String',
      defaultValue: 'draft',
    },
    isActive: {
      type: 'Boolean',
      defaultValue: true,
    },
    sortOrder: {
      type: 'Integer',
      defaultValue: { type: 'AUTOINCREMENT' },
    },
    publishedAt: {
      type: 'DateTime',
      defaultValue: { type: 'NOW' },
    },
  },
});

// Create relationship
await baasix.schemas.createRelationship('products', {
  type: 'M2O',
  target: 'categories',
  name: 'category',
  alias: 'products',
});

Validation Rules

RuleTypeDescription
minnumberMinimum value for numeric fields
maxnumberMaximum value for numeric fields
isIntbooleanValidate as integer
notEmptybooleanString must not be empty
isEmailbooleanValidate email format
isUrlbooleanValidate URL format
len[min, max]String length range
is / matchesregexPattern matching

Default Value Types

TypeDescription
UUIDV4Random UUID v4
SUIDShort unique ID
NOWCurrent timestamp
AUTOINCREMENTAuto-increment integer
SQLCustom SQL expression

Users & Roles (Admin)

Users

// List users
const { data: users } = await baasix.users.find({
  filter: { status: { eq: 'active' } },
});

// Create user
const userId = await baasix.users.create({
  email: 'user@example.com',
  password: 'password123',
  firstName: 'John',
  role_Id: 'role-uuid',
});

// Admin password change
await baasix.users.changePassword(userId, 'newPassword');

// Suspend/Activate
await baasix.users.suspend(userId);
await baasix.users.activate(userId);

Roles

// List roles
const { data: roles } = await baasix.roles.find();

// Create role
const roleId = await baasix.roles.create({
  name: 'Editor',
  description: 'Content editors',
  appAccess: true,
});

Workflows

// List workflows
const { data: workflows } = await baasix.workflows.find();

// Get workflow by ID
const workflow = await baasix.workflows.findOne('workflow-uuid');

// Execute workflow
const result = await baasix.workflows.execute('workflow-uuid', {
  orderId: 'order-123',
});

// Execute a specific node
const nodeResult = await baasix.workflows.executeNode(
  'workflow-uuid',
  'node-id',
  { inputData: 'value' }
);

// Test workflow (without persisting execution)
const testResult = await baasix.workflows.test('workflow-uuid', {
  testData: { value: 123 }
});

// Get execution history
const { data: executions } = await baasix.workflows.getExecutions('workflow-uuid', {
  limit: 50,
  status: 'completed'
});

// Get execution logs
const logs = await baasix.workflows.getExecutionLogs('workflow-uuid', 'execution-uuid');

// Cancel a running execution
await baasix.workflows.cancelExecution('workflow-uuid', 'execution-uuid');

// Get workflow statistics
const stats = await baasix.workflows.getStats('workflow-uuid');
console.log(stats.totalExecutions, stats.successRate);

// Validate workflow definition
const validation = await baasix.workflows.validate({
  name: 'My Workflow',
  nodes: [...],
  edges: [...]
});
if (!validation.valid) {
  console.log('Errors:', validation.errors);
}

// Enable/Disable workflow
await baasix.workflows.enable('workflow-uuid');
await baasix.workflows.disable('workflow-uuid');

// Duplicate workflow
const newWorkflow = await baasix.workflows.duplicate('workflow-uuid', {
  name: 'Copy of My Workflow'
});

Workflow Export/Import

// Export single workflow
const exported = await baasix.workflows.export('workflow-uuid');

// Export all workflows
const allWorkflows = await baasix.workflows.exportAll({
  ids: ['workflow-1', 'workflow-2'], // Optional: specific workflows
  includeInactive: true,
});

// Preview import
const preview = await baasix.workflows.importPreview(file);
console.log('Will import:', preview.workflows.length);
console.log('Conflicts:', preview.conflicts);

// Import workflows
const importResult = await baasix.workflows.import(file, {
  overwrite: true,
});
console.log(`Imported: ${importResult.imported}`);

Monitor Execution (Realtime)

const unsubscribe = baasix.realtime.subscribeToExecution(result.executionId, (update) => {
  console.log('Progress:', update.progress, '%');
  if (update.status === 'complete') {
    console.log('Done!', update.result);
  }
});

Settings

// Get all settings
const settings = await baasix.settings.get();

// Get a specific setting
const appName = await baasix.settings.getKey('appName');

// Update settings
await baasix.settings.update({
  appName: 'My Application',
  theme: 'dark',
});

// Set a specific setting
await baasix.settings.set('appName', 'New App Name');

// Get settings by app URL (multi-tenant)
const tenantSettings = await baasix.settings.getByAppUrl('https://myapp.example.com');

// Get email branding
const branding = await baasix.settings.getBranding();

// Test email configuration (admin only)
await baasix.settings.testEmail('admin@example.com');

// Reload settings cache (admin only)
await baasix.settings.reload();

// Delete tenant settings (admin only)
await baasix.settings.deleteTenant();

Permissions

// List all permissions
const { data: permissions } = await baasix.permissions.find();

// Get permissions for a role
const { data: rolePerms } = await baasix.permissions.findByRole('role-uuid');

// Get permissions for a collection
const { data: collectionPerms } = await baasix.permissions.findByCollection('products');

// Create permission
const permission = await baasix.permissions.create({
  role_Id: 'editor-role-uuid',
  collection: 'posts',
  action: 'update',
  fields: ['title', 'content', 'status'],
  conditions: {
    author_Id: { eq: '$CURRENT_USER' },
  },
});

// Create CRUD permissions for a collection
await baasix.permissions.createCrudPermissions('role-uuid', 'products', {
  create: { fields: ['name', 'price'] },
  read: { fields: ['*'] },
  update: { fields: ['name', 'price'] },
  delete: false, // No delete permission
});

// Update permission
await baasix.permissions.update('permission-uuid', {
  fields: ['*'],
  conditions: null,
});

// Delete permission
await baasix.permissions.delete('permission-uuid');

// Reload permissions cache (admin only)
await baasix.permissions.reloadCache();

// Export all permissions
const exported = await baasix.permissions.export();

// Import permissions
const importResult = await baasix.permissions.import(exportedData, {
  overwrite: true,
});
console.log(`Imported: ${importResult.imported}`);

Reports & Analytics

Generate Report (POST)

Use generate() to create a report with a POST request:

const report = await baasix.reports.generate('orders', {
  aggregate: {
    revenue: { function: 'sum', field: 'total' },
    orders: { function: 'count', field: 'id' },
  },
  groupBy: ['category'],
  filter: { status: { eq: 'completed' } },
  dateRange: {
    start: '2025-01-01',
    end: '2025-12-31',
  },
});

Query Report (GET)

Use query() to fetch a report with query parameters:

const report = await baasix.reports.query('orders', {
  aggregate: { total: { function: 'sum', field: 'amount' } },
  groupBy: ['status'],
});

Multi-Collection Stats

Get statistics for multiple collections in a single request:

const stats = await baasix.reports.getStats([
  {
    name: 'total_products',
    collection: 'products',
    query: {
      aggregate: { count: { function: 'count', field: '*' } },
    },
  },
  {
    name: 'total_orders',
    collection: 'orders',
    query: {
      aggregate: {
        count: { function: 'count', field: '*' },
        total_amount: { function: 'sum', field: 'amount' },
      },
    },
  },
]);

Aggregation, Count & Distinct

// Aggregation query on items
const results = await baasix.reports.aggregate('orders', {
  aggregate: {
    total: { function: 'sum', field: 'amount' },
    avg: { function: 'avg', field: 'amount' },
  },
  groupBy: ['status'],
});

// Quick count
const activeUsers = await baasix.reports.count('users', {
  status: { eq: 'active' },
});

// Get distinct values
const categories = await baasix.reports.distinct('products', 'category');

Notifications

// Get user notifications
const { data } = await baasix.notifications.find({
  limit: 20,
  filter: { seen: { eq: false } },
});

// Get unread count
const count = await baasix.notifications.getUnreadCount();

// Mark notifications as seen
await baasix.notifications.markAsSeen(['id1', 'id2']);
// Or mark all as seen
await baasix.notifications.markAsSeen();

// Delete notifications
await baasix.notifications.delete(['id1', 'id2']);

// Send notification (admin only)
await baasix.notifications.send({
  type: 'alert',
  title: 'System Update',
  message: 'Maintenance scheduled for tonight',
  userIds: ['user1-uuid', 'user2-uuid'],
});

// Cleanup old notifications (admin only)
await baasix.notifications.cleanup(30); // older than 30 days

Migrations (Admin)

// Check migration status
const status = await baasix.migrations.status();
console.log(`Pending: ${status.pendingCount}`);

// Get pending migrations
const pending = await baasix.migrations.pending();

// Run pending migrations
const result = await baasix.migrations.run();
console.log(`Completed: ${result.summary.completed}`);

// Run with options
const result = await baasix.migrations.run({
  step: 1, // Run only 1 migration
  dryRun: true, // Preview without executing
});

// Rollback a specific migration
await baasix.migrations.rollback('20231201000000');

// Rollback last batch
await baasix.migrations.rollbackBatch();

// Create new migration file
const { filepath } = await baasix.migrations.create('add_status_column', {
  type: 'schema',
  description: 'Add status column to orders',
});

// Mark migrations as completed (without running)
await baasix.migrations.markCompleted('20231201000000');
await baasix.migrations.markAllCompleted();

Error Handling

import { BaasixError } from '@baasix/sdk';

try {
  await baasix.items('products').create({ name: 'Test' });
} catch (error) {
  if (error instanceof BaasixError) {
    console.error('API Error:', error.message);
    console.error('Status:', error.status);
    console.error('Code:', error.code);
  }
}

TypeScript Support

Shared Types from @baasix/types

The SDK uses shared types from @baasix/types. You can import these types directly for use in your application:

import type {
  // Auth types
  User,
  Role,
  Permission,
  Accountability,
  AuthMode,

  // Query types
  Filter,
  FilterOperator,
  Sort,
  QueryParams,
  PaginationMetadata,

  // Aggregation types
  AggregateFunction,
  AggregateConfig,
  ReportQuery,
  StatsQuery,

  // Response types
  PaginatedResponse,
  ReadResult,

  // File types
  FileMetadata,
  UploadOptions,
  ImportOptions,
  ExportOptions,

  // Schema types
  SchemaDefinition,
  FieldDefinition,
  FieldType,
  RelationshipType,

  // Spatial types (PostGIS)
  GeoJSONPoint,
  GeoJSONPolygon,
  GeoJSONGeometry,

  // Cache types
  CacheConfig,
  ICacheAdapter,

  // Workflow types
  Workflow,
  WorkflowExecution,

  // Common types
  BaseItem,
  DeepPartial,
  Settings,
} from '@baasix/types';

Using Generics

// Define your types
interface Product {
  id: string;
  name: string;
  price: number;
  status: 'active' | 'inactive';
  createdAt: string;
}

// Use with generics
const products = baasix.items<Product>('products');

const { data } = await products.find({
  filter: { status: { eq: 'active' } }, // Type-safe!
});

// data is Product[]

On this page