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

@baasix/sdk

v0.1.4

Published

Official JavaScript/TypeScript SDK for Baasix Backend-as-a-Service

Readme

@baasix/sdk

Official JavaScript/TypeScript SDK for Baasix Backend-as-a-Service.

npm version npm downloads license

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
  • 👥 User & Role Management - Admin operations for users and roles
  • 📊 Reports - Generate reports with aggregations
  • 🔔 Notifications - User notification system with realtime delivery
  • 🗃️ Migrations - Database schema migration management
  • 🔃 Sort/Reorder - Drag-and-drop style item reordering

Installation

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

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: '[email protected]',
  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 (default: 30000)
  autoRefresh: true,                      // Auto-refresh tokens (default: true)
  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', // Required for cookies
});

Server-Side / Service Account

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

Authentication

Register

const { user, token } = await baasix.auth.register({
  email: '[email protected]',
  password: 'securepassword',
  firstName: 'John',
  lastName: 'Doe',
});

Login

const { user, token } = await baasix.auth.login({
  email: '[email protected]',
  password: 'password123',
});

// With tenant (multi-tenant mode)
const result = await baasix.auth.login({
  email: '[email protected]',
  password: 'password123',
  tenantId: 'tenant-uuid',
});

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();

Logout

await baasix.auth.logout();

Check Authentication

if (await baasix.auth.isAuthenticated()) {
  // User is logged in
}

Magic Link Login

// Send magic link
await baasix.auth.sendMagicLink({
  email: '[email protected]',
  redirectUrl: 'https://myapp.com/auth/callback',
});

// Verify (after user clicks link)
const { user, token } = await baasix.auth.verifyMagicLink('verification-token');

Password Reset

// Request reset
await baasix.auth.forgotPassword({
  email: '[email protected]',
  redirectUrl: 'https://myapp.com/reset-password',
});

// Reset password
await baasix.auth.resetPassword('reset-token', 'newpassword123');

Change Password

// Change current user's 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
await baasix.auth.requestEmailVerification('https://myapp.com/verify-email');

// Verify email with token
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: '[email protected]',
  roleId: 'editor-role-uuid',
  tenantId: 'tenant-uuid',
  redirectUrl: 'https://myapp.com/accept-invite',
});

// Verify invitation
const inviteInfo = await baasix.auth.verifyInvite('invite-token');

// 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: '[email protected]',
  password: 'password123',
  firstName: 'John',
  lastName: 'Doe',
  inviteToken: 'invite-token',
});

Items (CRUD Operations)

Query Items

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

// Basic find
const { data, totalCount } = await items.find();

// With parameters
const { data: activeProducts } = await items.find({
  filter: { status: { eq: 'active' } },
  sort: { createdAt: 'desc' },
  limit: 20,
  page: 1,
  fields: ['id', 'name', 'price', 'category.*'],
});

// Find one by ID
const product = await items.findOne('product-uuid');

// With related data
const product = await items.findOne('product-uuid', {
  fields: ['*', 'category.*', 'reviews.*'],
});

Query Builder

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

// First result only
const post = await baasix.items('posts')
  .query()
  .filter({ slug: { eq: 'my-post' } })
  .first();

// Count
const count = await baasix.items('products')
  .query()
  .filter({ inStock: { eq: true } })
  .count();

Create Items

// Single item
const id = await baasix.items('products').create({
  name: 'New Product',
  price: 29.99,
  status: 'draft',
});

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

Update Items

// Single item
await baasix.items('products').update('product-uuid', {
  price: 24.99,
  status: 'published',
});

// Multiple items
await baasix.items('products').updateMany(
  ['id1', 'id2', 'id3'],
  { status: 'archived' }
);

// Upsert (create or update)
const id = await baasix.items('products').upsert(
  { sku: { eq: 'SKU-001' } },
  { name: 'Widget', price: 29.99, sku: 'SKU-001' }
);

Delete Items

// Single item
await baasix.items('products').delete('product-uuid');

// Multiple items
await baasix.items('products').deleteMany(['id1', 'id2', 'id3']);

// Soft delete (if paranoid mode enabled)
await baasix.items('products').softDelete('product-uuid');

// Restore soft-deleted
await baasix.items('products').restore('product-uuid');

Aggregation

const results = await baasix.items('orders').aggregate({
  aggregate: {
    totalRevenue: { function: 'sum', field: 'total' },
    orderCount: { function: 'count', field: 'id' },
    avgOrderValue: { function: 'avg', field: 'total' },
  },
  groupBy: ['status', 'category'],
  filter: { createdAt: { gte: '$NOW-DAYS_30' } },
});

Filter Operators

Baasix supports 50+ filter operators:

// Comparison
{ field: { eq: value } }        // Equal
{ field: { ne: value } }        // Not equal
{ field: { gt: value } }        // Greater than
{ field: { gte: value } }       // Greater than or equal
{ field: { lt: value } }        // Less than
{ field: { lte: value } }       // Less than or equal

// Collection
{ field: { in: [1, 2, 3] } }    // In list
{ field: { notIn: [1, 2, 3] } } // Not in list

// String
{ field: { like: 'pattern' } }        // LIKE (case-sensitive)
{ field: { iLike: 'pattern' } }       // ILIKE (case-insensitive)
{ field: { startsWith: 'prefix' } }   // Starts with
{ field: { endsWith: 'suffix' } }     // Ends with
{ field: { contains: 'substring' } }  // Contains

// Range
{ field: { between: [10, 100] } }     // Between

// Null
{ field: { isNull: true } }           // Is null
{ field: { isNotNull: true } }        // Is not null

// Array (PostgreSQL)
{ tags: { arraycontains: ['js', 'api'] } }

// JSONB
{ metadata: { jsonbHasKey: 'discount' } }
{ metadata: { jsonbKeyEquals: { key: 'status', value: 'active' } } }

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

// Relation filtering
{ 'author.name': { like: 'John' } }

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

Files

Upload Files

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

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

Get Asset URLs

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

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

File Operations

// List files
const { data: files } = await baasix.files.find({
  filter: { mimeType: { startsWith: 'image/' } },
});

// Get file info
const file = await baasix.files.findOne('file-uuid');

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

// Delete file
await baasix.files.delete('file-uuid');

Schemas

Create Collection

await baasix.schemas.create({
  collectionName: 'products',
  schema: {
    name: 'Product',
    timestamps: true,
    paranoid: true, // Soft deletes
    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 },
        defaultValue: 0,
        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,
        },
      },
      slug: {
        type: 'String',
        validate: {
          matches: '^[a-z0-9-]+$',
        },
      },
      tags: {
        type: 'Array',
        values: { type: 'String' },
        defaultValue: [],
      },
      metadata: {
        type: 'JSONB',
        defaultValue: {},
      },
      status: {
        type: 'String',
        defaultValue: 'draft',
      },
      isActive: {
        type: 'Boolean',
        defaultValue: true,
      },
      sortOrder: {
        type: 'Integer',
        defaultValue: { type: 'AUTOINCREMENT' },
      },
      publishedAt: {
        type: 'DateTime',
        defaultValue: { type: 'NOW' },
      },
    },
  },
});

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 | string | Pattern matching with regex |

Default Value Types

| Type | Description | |------|-------------| | UUIDV4 | Random UUID v4 | | SUID | Short unique ID (compact, URL-safe) | | NOW | Current timestamp | | AUTOINCREMENT | Auto-incrementing integer | | SQL | Custom SQL expression | | Static | Any constant value ("active", false, 0) |

Relationships

// Many-to-One (BelongsTo)
// Auto-creates index on foreign key column
await baasix.schemas.createRelationship('products', {
  type: 'M2O',
  target: 'categories',
  name: 'category',
  alias: 'products',
});

// Many-to-Many
// Auto-generates junction table: products_tags_tags_junction
await baasix.schemas.createRelationship('products', {
  type: 'M2M',
  target: 'tags',
  name: 'tags',
  alias: 'products',
});

// Many-to-Many with custom junction table name
// Useful when auto-generated name exceeds PostgreSQL's 63 char limit
await baasix.schemas.createRelationship('products', {
  type: 'M2M',
  target: 'tags',
  name: 'tags',
  alias: 'products',
  through: 'product_tags', // Custom junction table name (max 63 chars)
});

// Many-to-Any (Polymorphic)
await baasix.schemas.createRelationship('comments', {
  type: 'M2A',
  name: 'commentable',
  tables: ['posts', 'products'],
  alias: 'comments',
  through: 'comment_refs', // Optional custom junction table name
});

Junction Tables (M2M/M2A)

  • Auto-generated name: {source}_{target}_{name}_junction
  • Custom name: Use through property (max 63 characters for PostgreSQL)
  • Schema property: Junction tables have isJunction: true in their schema
  • Auto-indexed: Foreign key columns are automatically indexed

Indexes

await baasix.schemas.createIndex('products', {
  name: 'idx_products_sku',
  fields: ['sku'],
  unique: true,
});

Reports & Analytics

Generate Report (POST)

Use generate() to create a report with a POST request, sending the query in the request body:

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 a GET request, sending parameters as query strings:

const report = await baasix.reports.query('orders', {
  aggregate: {
    total: { function: 'sum', field: 'amount' },
  },
  groupBy: ['status'],
  filter: { createdAt: { gte: '$NOW-DAYS_30' } },
});

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' },
      },
    },
  },
  {
    name: 'products_by_category',
    collection: 'products',
    query: {
      groupBy: ['categoryId'],
      aggregate: {
        count: { function: 'count', field: 'id' },
        avg_price: { function: 'avg', field: 'price' },
      },
      fields: ['categoryId', 'category.name'],
    },
  },
]);
// Returns: [{ name: 'total_products', collection: 'products', data: [...] }, ...]

Aggregation Query

Run aggregation queries directly on a collection (uses items endpoint):

const results = await baasix.reports.aggregate('orders', {
  aggregate: {
    total: { function: 'sum', field: 'amount' },
    count: { function: 'count', field: 'id' },
    min: { function: 'min', field: 'amount' },
    max: { function: 'max', field: 'amount' },
    avg: { function: 'avg', field: 'amount' },
  },
  groupBy: ['status', 'paymentMethod'],
  filter: { createdAt: { gte: '$NOW-DAYS_30' } },
});

Quick Count

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

Distinct Values

const categories = await baasix.reports.distinct('products', 'category');
// Returns: ['Electronics', 'Clothing', 'Books', ...]

Workflows

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

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

// Subscribe to execution updates (requires realtime)
const unsubscribe = baasix.realtime.subscribeToExecution(executionId, (update) => {
  console.log('Execution progress:', update.progress, '%');
  if (update.status === 'complete') {
    console.log('Workflow finished!', update.result);
  }
});

Realtime Subscriptions

The SDK supports real-time data updates via WebSocket connections.

Setup

// Install socket.io-client separately
npm install socket.io-client

// Initialize realtime
import { io } from 'socket.io-client';

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

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

Subscribe to Collections

// Subscribe to all changes on a collection
const unsubscribe = baasix.realtime.subscribe('products', (payload) => {
  console.log(`Product ${payload.action}:`, payload.data);
  // payload.action: 'create' | 'update' | 'delete'
  // payload.data: the created/updated/deleted item
  // payload.timestamp: ISO timestamp
});

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

// Unsubscribe when done
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();

Connection Management

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

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

// Disconnect
baasix.realtime.disconnect();

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);
}

Invitation System (Multi-tenant)

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

// Verify invitation token (in callback page)
const result = await baasix.auth.verifyInvite(token);
if (result.valid) {
  // Show registration form with pre-filled email
  console.log('Invite for:', result.email);
}

// Register with invitation
const { user } = await baasix.auth.registerWithInvite({
  email: '[email protected]',
  password: 'password123',
  firstName: 'John',
  lastName: 'Doe',
  inviteToken: token,
});

Users Management (Admin)

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

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

// Update user
await baasix.users.update(userId, { firstName: 'Jane' });

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

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

Roles Management

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

// Find by name
const adminRole = await baasix.roles.findByName('Administrator');

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

// Update role
await baasix.roles.update(roleId, { description: 'Updated description' });

Bulk Operations

// Bulk create
const ids = await baasix.items('products').createMany([
  { name: 'Product 1', price: 29.99 },
  { name: 'Product 2', price: 39.99 },
]);

// Bulk update - apply same data to multiple items
await baasix.items('products').updateMany(
  ['uuid-1', 'uuid-2', 'uuid-3'],
  { status: 'archived' }
);

// Bulk delete
await baasix.items('products').deleteMany(['uuid-1', 'uuid-2']);

CSV/JSON Import

// Import from CSV file
const result = await baasix.items('products').importCSV(csvFile);
console.log(`Imported: ${result.imported}, Failed: ${result.failed}`);

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

Sort / Reorder Items

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

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

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

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();

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

Custom Storage Adapter

Create a custom storage adapter for any environment:

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

class MyCustomStorage implements StorageAdapter {
  async get(key: string): Promise<string | null> {
    // Your implementation
  }

  async set(key: string, value: string): Promise<void> {
    // Your implementation
  }

  async remove(key: string): Promise<void> {
    // Your implementation
  }

  async clear(): Promise<void> {
    // Your implementation
  }
}

const baasix = createBaasix({
  url: 'https://api.example.com',
  storage: new MyCustomStorage(),
});

Error Handling

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

try {
  await baasix.items('products').create({ name: 'Product' });
} catch (error) {
  if (error instanceof BaasixError) {
    console.error('Status:', error.status);
    console.error('Code:', error.code);
    console.error('Message:', error.message);
    console.error('Details:', error.details);

    if (error.status === 401) {
      // Handle unauthorized
    }
    if (error.status === 403) {
      // Handle forbidden
    }
    if (error.isRetryable) {
      // Can retry request
    }
  }
}

TypeScript Support

Shared Types from @baasix/types

The SDK uses shared types from @baasix/types. Import common types directly:

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

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

  // Response types
  PaginatedResponse,

  // File types
  FileMetadata,
  UploadOptions,

  // Schema types
  SchemaDefinition,
  FieldDefinition,

  // Spatial types
  GeoJSONPoint,
  GeoJSONGeometry,
} from '@baasix/types';

Using Generics

Use generics for type-safe operations:

interface Product {
  id: string;
  name: string;
  price: number;
  category_Id: string;
  createdAt: string;
}

// Typed items module
const products = baasix.items<Product>('products');

// Type inference
const { data } = await products.find();
// data is Product[]

const product = await products.findOne('uuid');
// product is Product

await products.create({
  name: 'Widget',
  price: 29.99,
  category_Id: 'cat-uuid',
}); // Type-checked

React Example

import { createBaasix } from '@baasix/sdk';
import { useEffect, useState } from 'react';

const baasix = createBaasix({
  url: process.env.REACT_APP_BAASIX_URL!,
  onAuthStateChange: (event, user) => {
    console.log('Auth:', event, user);
  },
});

function App() {
  const [user, setUser] = useState(null);
  const [products, setProducts] = useState([]);

  useEffect(() => {
    // Initialize auth on mount
    baasix.auth.initialize().then((state) => {
      setUser(state.user);
    });
  }, []);

  useEffect(() => {
    // Fetch products
    baasix.items('products')
      .find({ filter: { status: { eq: 'active' } } })
      .then(({ data }) => setProducts(data));
  }, []);

  const handleLogin = async (email, password) => {
    const { user } = await baasix.auth.login({ email, password });
    setUser(user);
  };

  const handleLogout = async () => {
    await baasix.auth.logout();
    setUser(null);
  };

  return (
    <div>
      {user ? (
        <>
          <p>Welcome, {user.email}</p>
          <button onClick={handleLogout}>Logout</button>
        </>
      ) : (
        <LoginForm onSubmit={handleLogin} />
      )}
      <ProductList products={products} />
    </div>
  );
}

API Reference

createBaasix(config)

Creates a new Baasix SDK instance.

| Option | Type | Default | Description | |--------|------|---------|-------------| | url | string | Required | Your Baasix server URL | | authMode | 'jwt' \| 'cookie' | 'jwt' | Authentication mode | | storage | StorageAdapter | Auto-detected | Token storage adapter | | token | string | - | Static auth token | | timeout | number | 30000 | Request timeout (ms) | | autoRefresh | boolean | true | Auto-refresh tokens | | headers | object | {} | Custom headers | | tenantId | string | - | Multi-tenant ID | | credentials | RequestCredentials | Based on authMode | Fetch credentials | | onAuthStateChange | function | - | Auth state callback | | onError | function | - | Global error handler |

Storage Adapters

  • LocalStorageAdapter - Browser localStorage (default for web)
  • MemoryStorageAdapter - In-memory (default for SSR/Node.js)
  • AsyncStorageAdapter - React Native AsyncStorage

License

MIT © Vivek Palanisamy