@e-techsolutions/e-baas-sdk
v1.3.0
Published
Official E-BaaS TypeScript SDK - Backend as a Service client library
Maintainers
Readme
E-BaaS SDK
The official TypeScript SDK for E-BaaS (Enterprise Backend as a Service) - A comprehensive backend-as-a-service platform.
Installation
npm install @e-techsolutions/e-baas-sdk@latest
# or
yarn add @e-techsolutions/e-baas-sdk@latestQuick Start
import { createClient } from "@e-techsolutions/e-baas-sdk";
// Basic configuration (required)
const EBAAS_URL = process.env.EBAAS_API_URL; // required - https://your-api-e-baas-service
const EBAAS_KEY = process.env.EBAAS_API_KEY; // required - your API key
const WORKSPACE_ID = process.env.EBAAS_WORKSPACE_ID; // required - your workspace ID
export const ebaas = createClient(EBAAS_URL, EBAAS_KEY, {
// Database configuration (required)
database: {
workspaceId: WORKSPACE_ID, // required
autoDetectCustomDatabase: true, // optional (default: false)
},
// Other configurations are optional
});Complete Authentication Flow
// 1. User login
const { user, session, error } = await ebaas.auth.signIn({
email: "[email protected]",
password: "secure-password",
});
if (error) {
console.error("Login failed:", error);
return;
}
// 2. Configure session in SDK (REQUIRED!)
ebaas.auth.setSession(session);
// 3. Persist session (optional)
localStorage.setItem("ebaas_session", JSON.stringify(session));
localStorage.setItem("ebaas_user", JSON.stringify(user));
// 4. Now you can use database operations normally
const query = ebaas.from("users").select("*");
const { data, error } = await query.execute();
if (error) {
console.error("Error fetching users:", error);
} else {
console.log("Users found:", data.length);
}Session Restoration
// Restore session on app initialization
const restoreSession = () => {
const savedSession = localStorage.getItem("ebaas_session");
const savedUser = localStorage.getItem("ebaas_user");
if (savedSession && savedUser) {
const sessionData = JSON.parse(savedSession);
// Check if not expired
if (sessionData.expires_at > Date.now()) {
// Restore session in SDK
ebaas.auth.setSession(sessionData);
console.log("✅ Session restored automatically");
} else {
// Clear expired session
localStorage.removeItem("ebaas_session");
localStorage.removeItem("ebaas_user");
}
}
};Environment Variables
Create a .env file in your project root:
EBAAS_API_URL=https://your-api-e-baas-service
EBAAS_API_KEY=your-api-key-here
EBAAS_WORKSPACE_ID=your-workspace-id-hereNote: This works with any bundler (Webpack, Vite, Next.js, etc.) that supports process.env.
Features
- Authentication - Email/password and OAuth providers (Google, GitHub, Facebook)
- Database - PostgreSQL with real-time subscriptions and RPC support
- Custom Database - Use your own PostgreSQL database with automatic detection
- Storage - File uploads with CDN integration and image transformations
- Realtime - WebSocket subscriptions for live data updates
- Edge Functions - Serverless functions with dual runtime (Node.js VM + Deno) and native SDK integration
- TypeScript - Full type safety and IntelliSense support
Usage Examples
Authentication
// Sign up with email/password
const { user, session, error } = await ebaas.auth.signUp({
email: "[email protected]",
password: "secure-password",
name: "John Doe",
});
// Sign in
const { user, session, error } = await ebaas.auth.signIn({
email: "[email protected]",
password: "secure-password",
});
// Get current user
const user = await ebaas.auth.getUser();
// Sign out
await ebaas.auth.signOut();⚠️ IMPORTANT - Session Configuration:
After login, you MUST configure the session in the SDK for all subsequent operations to work correctly:
// Complete authentication flow
const loginUser = async () => {
// 1. Perform login
const { user, session, error } = await ebaas.auth.signIn({
email: "[email protected]",
password: "secure-password",
});
if (error) {
console.error("Login failed:", error);
return;
}
// 2. Configure session in SDK (MANDATORY STEP!)
ebaas.auth.setSession(session);
// 3. Persist session in localStorage (optional)
localStorage.setItem("ebaas_session", JSON.stringify(session));
localStorage.setItem("ebaas_user", JSON.stringify(user));
console.log("✅ Login and session configuration completed");
};
// Restore session on application initialization
const restoreSession = () => {
const savedSession = localStorage.getItem("ebaas_session");
const savedUser = localStorage.getItem("ebaas_user");
if (savedSession && savedUser) {
const sessionData = JSON.parse(savedSession);
// Check if not expired
if (sessionData.expires_at > Date.now()) {
// Restore session in SDK
ebaas.auth.setSession(sessionData);
console.log("✅ Session restored automatically");
} else {
// Clear expired session
localStorage.removeItem("ebaas_session");
localStorage.removeItem("ebaas_user");
}
}
};Database Operations
// Select data
const query = ebaas.from("users").select("*");
const { data, error } = await query.execute();
if (error) {
console.error("Error fetching users:", error);
} else {
console.log("Users found:", data.length);
}
// Select specific fields for better performance
const query = ebaas
.from("users")
.select("id, name, email")
.eq("status", "active")
.order("created_at", { ascending: false })
.limit(10);
const { data, error } = await query.execute();
// Insert data
const query = ebaas.from("users").insert({
name: "John Doe",
email: "[email protected]",
});
const { data, error } = await query.execute();
if (error) {
console.error("Error creating user:", error);
} else {
console.log("User created successfully:", data);
}
// Update data
const query = ebaas.from("users").update({ name: "John Smith" }).eq("id", 123);
const { data, error } = await query.execute();
if (error) {
console.error("Error updating user:", error);
} else {
console.log("User updated successfully:", data);
}
// Delete data
const query = ebaas.from("users").delete().eq("id", 123);
const { data, error } = await query.execute();
if (error) {
console.error("Error deleting user:", error);
} else {
console.log("User deleted successfully");
}
// RPC (stored procedures)
const query = ebaas.rpc("get_user_stats", {
user_id: 123,
});
const { data, error } = await query.execute();Advanced Filtering & Query Operators
The E-BaaS SDK supports PostgREST-style operators for powerful filtering capabilities:
Comparison Operators
// Equality
const users = await ebaas.from("users")
.select("*")
.eq("status", "active") // status = 'active'
.execute();
// Not equal
const users = await ebaas.from("users")
.select("*")
.neq("status", "deleted") // status != 'deleted'
.execute();
// Greater than
const users = await ebaas.from("users")
.select("*")
.gt("age", 18) // age > 18
.execute();
// Greater than or equal
const users = await ebaas.from("users")
.select("*")
.gte("created_at", "2024-01-01") // created_at >= '2024-01-01'
.execute();
// Less than
const users = await ebaas.from("users")
.select("*")
.lt("age", 65) // age < 65
.execute();
// Less than or equal
const users = await ebaas.from("users")
.select("*")
.lte("updated_at", "2024-12-31") // updated_at <= '2024-12-31'
.execute();Text Search Operators
// Case-sensitive pattern matching
const users = await ebaas.from("users")
.select("*")
.like("name", "%John%") // name LIKE '%John%'
.execute();
// Case-insensitive pattern matching
const users = await ebaas.from("users")
.select("*")
.ilike("email", "%@gmail.com") // email ILIKE '%@gmail.com'
.execute();Null Checks
// Check for null values
const users = await ebaas.from("users")
.select("*")
.is("deleted_at", null) // deleted_at IS NULL
.execute();Multiple Filters on Same Field
NEW: You can now apply multiple filters to the same field for range queries:
// Date range filtering (multiple filters on same field)
const expenses = await ebaas.from("expenses")
.select("id, user_id, description, amount, due_date")
.eq("user_id", "7a79cc66-140e-41e0-9bde-ba51e338adac")
.gte("due_date", "2025-11-01") // due_date >= '2025-11-01'
.lt("due_date", "2025-12-01") // due_date < '2025-12-01'
.order("due_date", { ascending: true })
.execute();
// Numeric range filtering
const products = await ebaas.from("products")
.select("*")
.gte("price", 100) // price >= 100
.lte("price", 500) // price <= 500
.execute();
// Age range
const users = await ebaas.from("users")
.select("*")
.gt("age", 18) // age > 18
.lt("age", 65) // age < 65
.execute();Combining Multiple Filters
// Multiple conditions (AND logic)
const activeUsers = await ebaas.from("users")
.select("id, name, email, status, created_at")
.eq("status", "active")
.gte("created_at", "2024-01-01")
.ilike("email", "%@company.com")
.order("created_at", { ascending: false })
.limit(50)
.execute();
// Complex date and status filtering
const recentExpenses = await ebaas.from("expenses")
.select("*")
.eq("status", "pending")
.gte("due_date", "2025-11-01")
.lt("due_date", "2025-12-01")
.gt("amount", 0)
.order("due_date", { ascending: true })
.execute();Ordering and Pagination
// Single column ordering
const users = await ebaas.from("users")
.select("*")
.order("created_at", { ascending: false }) // ORDER BY created_at DESC
.execute();
// Multiple column ordering
const expenses = await ebaas.from("expenses")
.select("*")
.order("due_date", { ascending: true })
.order("created_at", { ascending: false }) // Secondary sort
.execute();
// Pagination
const users = await ebaas.from("users")
.select("*")
.order("id", { ascending: true })
.range(0, 9) // LIMIT 10 OFFSET 0 (first 10 records)
.execute();
const nextPage = await ebaas.from("users")
.select("*")
.order("id", { ascending: true })
.range(10, 19) // LIMIT 10 OFFSET 10 (next 10 records)
.execute();Performance Tips
// Select only needed columns for better performance
const users = await ebaas.from("users")
.select("id, name, email") // Instead of select("*")
.eq("status", "active")
.limit(100)
.execute();
// Use indexes for filtering - ensure your database has indexes on:
// - Frequently filtered columns (status, user_id, etc.)
// - Date columns used in range queries (created_at, due_date, etc.)
// - Foreign keys (user_id, category_id, etc.)Query Builder Pattern
// Build queries conditionally
let query = ebaas.from("expenses")
.select("id, description, amount, due_date, status");
// Add filters conditionally
if (userId) {
query = query.eq("user_id", userId);
}
if (startDate) {
query = query.gte("due_date", startDate);
}
if (endDate) {
query = query.lt("due_date", endDate);
}
if (status) {
query = query.eq("status", status);
}
// Execute the final query
const { data, error } = await query
.order("due_date", { ascending: true })
.limit(100)
.execute();Raw SQL Queries
For complex queries beyond the query builder, use RPC functions:
// Create a stored procedure for complex filtering
const query = ebaas.rpc("get_expenses_by_date_range", {
p_user_id: "7a79cc66-140e-41e0-9bde-ba51e338adac",
p_start_date: "2025-11-01",
p_end_date: "2025-12-01",
p_status: "pending"
});
const { data, error } = await query.execute();Custom Database
// Configure with automatic custom database detection
const ebaas = createClient(EBAAS_URL, EBAAS_KEY, {
database: {
workspaceId: WORKSPACE_ID,
autoDetectCustomDatabase: true, // Enable custom database auto-detection
},
});Storage
// Upload file
const { data, error } = await ebaas.storage.from("avatars").upload("user-123.jpg", file, {
cacheControl: "3600",
upsert: true,
});
// Download file
const { data, error } = await ebaas.storage.from("avatars").download("user-123.jpg");
// Get public URL
const { data } = ebaas.storage.from("avatars").getPublicUrl("user-123.jpg");
// Get signed URL (for private files)
const { data, error } = await ebaas.storage.from("private-docs").createSignedUrl("document.pdf", 60); // 60 seconds
// List files
const { data, error } = await ebaas.storage.from("avatars").list("", {
limit: 100,
offset: 0,
sortBy: { column: "name", order: "asc" },
});Realtime Subscriptions
// Subscribe to database changes
const channel = ebaas.channel("realtime:users");
channel.onPostgresChanges(
{
event: "*", // INSERT, UPDATE, DELETE, or *
schema: "public",
table: "users",
},
(payload) => {
console.log("Change received!", payload);
}
);
channel.subscribe();
// Broadcast messages
channel.send({
type: "broadcast",
event: "message",
payload: { text: "Hello World!" },
});
// Presence tracking
channel.track({ user_id: 123, status: "online" });
// Unsubscribe
channel.unsubscribe();Edge Functions
Client-side Function Invocation
// Invoke authenticated function (requires session)
const { data, error } = await ebaas.functions.invoke("hello-world", {
body: { name: "John" },
headers: { "Content-Type": "application/json" },
});
// Invoke public function (no authentication required)
const response = await fetch("https://your-api-domain.com/functions/v1/public/hello-world", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "John" }),
});
const data = await response.json();
// List functions
const { data, error } = await ebaas.functions.list();
// Get function details
const { data, error } = await ebaas.functions.get("hello-world");Native SDK Integration in Edge Functions
The SDK is natively available within Edge Functions with global methods:
// Edge Function with native SDK access
const users = await from("users").select("*").limit(10);
const bucket = bucket("uploads");
await channel("notifications").send("user_created", { user: userData });
return createResponse({ success: true, users });Available globals: from(), rpc(), bucket(), channel(), invoke(), ebaas.*
Advanced Configuration
const ebaas = createClient(
"https://your-api-domain.com", // required - API URL
"your-api-key", // required - API Key
{
// Database configuration (required)
database: {
workspaceId: "your-workspace-id", // required - Workspace ID
autoDetectCustomDatabase: true, // optional (default: false)
},
// Authentication configuration (optional)
auth: {
autoRefreshToken: true, // optional (default: true)
persistSession: true, // optional (default: true)
detectSessionInUrl: true, // optional (default: true)
},
// Realtime configuration (optional)
realtime: {
params: {
eventsPerSecond: 10, // optional (default: 10)
},
},
// Global configuration (optional)
global: {
headers: {
"x-custom-header": "custom-value", // optional - custom headers
},
},
}
);Error Handling
import { EBaaSError } from "@e-techsolutions/e-baas-sdk";
try {
const query = ebaas.from("users").select("*");
const { data, error } = await query.execute();
} catch (error) {
if (error instanceof EBaaSError) {
console.error("E-BaaS Error:", error.message);
console.error("Status:", error.status);
console.error("Details:", error.details);
}
}Secure DELETE Operations
Security Validation
E-BaaS implements strict validation for DELETE and UPDATE operations, requiring at least one filter to prevent accidental mass deletions:
// ✅ CORRECT: DELETE with specific filter
const query = ebaas.from("users").delete().eq("id", 123);
const { data, error } = await query.execute();
// ❌ ERROR: DELETE without filters (returns "Security violation")
const query = ebaas.from("users").delete();
const { data, error } = await query.execute(); // Fails with security errorSecure DELETE Operations with Required Filters
Always use the SDK with proper filters for safe DELETE operations:
// DELETE using SDK with required filter
const query = ebaas.from("users").delete().eq("id", userId);
const { data, error } = await query.execute();
if (error) {
console.error("Error deleting user:", error);
} else {
console.log("User deleted successfully");
}Refresh Token Management
Automatic Token Refresh (Default)
The E-BaaS SDK automatically manages refresh tokens for workspace users, ensuring seamless authentication without manual intervention:
const ebaas = createClient(EBAAS_URL, EBAAS_KEY, {
database: {
workspaceId: WORKSPACE_ID,
},
auth: {
autoRefreshToken: true, // Default: true - automatic refresh enabled
persistSession: true, // Default: true - session persistence
},
});How Automatic Refresh Works
- Login Phase: When a user logs in, they receive both an access token and a refresh token
- Background Monitoring: The SDK monitors token expiration automatically
- Seamless Refresh: Before expiration, the SDK calls
/auth/v1/sdk/refreshto get new tokens - Token Rotation: Old refresh tokens are invalidated for security (refresh token rotation)
- Continued Operation: All database operations continue without interruption
Manual Refresh Token Management
For advanced use cases, you can disable automatic refresh and manage tokens manually:
const ebaas = createClient(EBAAS_URL, EBAAS_KEY, {
database: {
workspaceId: WORKSPACE_ID,
},
auth: {
autoRefreshToken: false, // Disable automatic refresh
},
});
// Manual refresh when needed
const refreshTokens = async () => {
try {
const query = ebaas.auth.refreshSession();
const { data, error } = await query.execute();
if (error) {
console.error('Failed to refresh token:', error);
// Redirect to login page
return;
}
// Update session in SDK
ebaas.auth.setSession(data.session);
// Update localStorage
localStorage.setItem('ebaas_session', JSON.stringify(data.session));
console.log('✅ Tokens refreshed successfully');
} catch (error) {
console.error('Token refresh error:', error);
// Handle refresh failure - redirect to login
}
};React Hook for Token Management
Here's a custom React hook for handling token refresh and expiration:
import { useEffect, useCallback } from 'react';
import { ebaas } from './ebaas-client';
export const useTokenRefresh = () => {
const checkTokenExpiration = useCallback(async () => {
const session = ebaas.auth.getSession();
if (!session?.expires_at) return;
const expiresAt = new Date(session.expires_at);
const now = new Date();
const timeToExpiry = expiresAt.getTime() - now.getTime();
// Refresh if token expires in less than 5 minutes
if (timeToExpiry < 5 * 60 * 1000) {
try {
const query = ebaas.auth.refreshSession();
const { data, error } = await query.execute();
if (error) {
console.error('Token refresh failed:', error);
// Redirect to login
window.location.href = '/login';
return;
}
// Update session
ebaas.auth.setSession(data.session);
localStorage.setItem('ebaas_session', JSON.stringify(data.session));
console.log('✅ Token refreshed proactively');
} catch (error) {
console.error('Token refresh error:', error);
// Handle error - redirect to login
window.location.href = '/login';
}
}
}, []);
useEffect(() => {
// Check immediately
checkTokenExpiration();
// Check every 2 minutes
const interval = setInterval(checkTokenExpiration, 2 * 60 * 1000);
return () => clearInterval(interval);
}, [checkTokenExpiration]);
};
// Usage in your main App component
const App = () => {
useTokenRefresh(); // Add this hook to your main App
return (
<div>
{/* Your app content */}
</div>
);
};Token Refresh Error Handling
const handleDatabaseOperation = async () => {
try {
const query = ebaas.from('users').select('*');
const { data, error } = await query.execute();
if (error) {
// Check if error is due to token expiration
if (error.status === 401 || error.message?.includes('token')) {
console.log('Token expired, attempting refresh...');
const { session, error } = await ebaas.auth.refreshSession();
if (error) {
// Refresh failed - redirect to login
console.error('Token refresh failed:', error);
window.location.href = '/login';
return;
}
// Update session and retry operation
ebaas.auth.setSession(session);
const { data, error } = await query.execute();
if (!error) {
console.log('✅ Operation successful after token refresh');
return data;
}
}
console.error('Database operation failed:', error);
}
return data;
} catch (error) {
console.error('Unexpected error:', error);
}
};Security Benefits
- Token Rotation: Each refresh generates new tokens and invalidates old ones
- Short-lived Access Tokens: Access tokens have shorter lifespans for security
- Automatic Cleanup: Expired and revoked tokens are automatically cleaned up
- Session Tracking: Each session is tracked with IP address and user agent
- Workspace Isolation: Refresh tokens are isolated per workspace for multi-tenancy
Configuration Options
const ebaas = createClient(EBAAS_URL, EBAAS_KEY, {
auth: {
autoRefreshToken: true, // Enable/disable automatic refresh
persistSession: true, // Persist session in localStorage
detectSessionInUrl: true, // Detect session from URL params
},
});TypeScript Support
The SDK is built with TypeScript and provides full type safety:
interface User {
id: number;
name: string;
email: string;
created_at: string;
}
const query = ebaas.from<User>("users").select("*");
const { data, error } = await query.execute();
// data is now typed as User[] | nullEdge Functions Runtime Support
Enhanced Edge Functions with dual runtime support (Node.js VM + Deno) and native SDK integration.
License
MIT
