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 @tspvivek/baasix-sdk
# or
yarn add @tspvivek/baasix-sdk
# or
pnpm add @tspvivek/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 '@tspvivek/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 '@tspvivek/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 '@tspvivek/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 '@tspvivek/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',
});
// Logout
await baasix.auth.logout();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);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',
});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();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']);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.
// Join a room
await baasix.realtime.joinRoom('game:lobby');
// Send a message to the room
await baasix.realtime.sendToRoom('game:lobby', 'chat', {
text: 'Hello everyone!',
});
// 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
baasix.realtime.onRoomUserJoined('game:lobby', (data) => {
console.log(`User ${data.userId} joined`);
});
baasix.realtime.onRoomUserLeft('game:lobby', (data) => {
console.log(`User ${data.userId} left`);
});
// 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');
// With transformations
const thumbnailUrl = baasix.files.getAssetUrl('file-uuid', {
width: 200,
height: 200,
fit: 'cover',
format: 'webp',
quality: 80,
});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
// Execute workflow
const result = await baasix.workflows.execute('workflow-uuid', {
orderId: 'order-123',
});
// Monitor execution (with realtime)
const unsubscribe = baasix.realtime.subscribeToExecution(result.executionId, (update) => {
console.log('Progress:', update.progress, '%');
if (update.status === 'complete') {
console.log('Done!', update.result);
}
});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 '@tspvivek/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
// 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