JavaScript SDK
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/sdkTypeScript 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.tsThen 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),
});Cookie Mode (Web with HTTP-only cookies)
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);
}Magic Link (Passwordless)
// 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-clientimport { 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:
| Option | Type | Default | Description |
|---|---|---|---|
width | number | — | Target width in pixels |
height | number | — | Target height in pixels |
fit | 'cover'|'contain'|'fill'|'inside'|'outside' | 'cover' | Resize fit mode |
quality | number (1–100) | 80 | Output quality |
format | 'jpeg'|'png'|'webp'|'avif' | 'jpeg' | Output format. webp and png preserve alpha transparency; jpeg flattens to white |
withoutEnlargement | boolean | false | Prevent 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
| Rule | Type | Description |
|---|---|---|
min | number | Minimum value for numeric fields |
max | number | Maximum value for numeric fields |
isInt | boolean | Validate as integer |
notEmpty | boolean | String must not be empty |
isEmail | boolean | Validate email format |
isUrl | boolean | Validate URL format |
len | [min, max] | String length range |
is / matches | regex | Pattern matching |
Default Value Types
| Type | Description |
|---|---|
UUIDV4 | Random UUID v4 |
SUID | Short unique ID |
NOW | Current timestamp |
AUTOINCREMENT | Auto-increment integer |
SQL | Custom 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 daysMigrations (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[]Related Documentation
- Integration Guide — Complete integration patterns
- Authentication Routes — API authentication details
- Item Routes — API item operations
- Socket.IO Integration — Real-time setup
- MCP Server — AI assistant integration