@forgebase/sdk
v0.0.8
Published
A powerful, type-safe TypeScript SDK for interacting with ForgeBase services, providing comprehensive database operations, advanced query capabilities, and type safety.
Readme
ForgeBase TypeScript SDK
A powerful, type-safe TypeScript SDK for interacting with ForgeBase services, providing comprehensive database operations, advanced query capabilities, and type safety.
Core Features
Type-Safe Query Builder:
- Fluent API design
- Advanced filtering (
where,whereIn,whereExists, etc.) - Complex joins and relations
- Aggregations (
count,sum,avg,min,max) - Window functions (
rowNumber,rank,lag,lead) - Recursive CTEs
- Result transformations (
pivot,compute)
Database Operations:
- CRUD operations (
create,update,delete) - Batch operations
- Pagination (
limit,offset) - Sorting (
orderBy)
- CRUD operations (
Security & Validation:
- Input validation
- Type inference from your interfaces
Installation
npm install @forgebase/sdk
# or
yarn add @forgebase/sdk
# or
pnpm add @forgebase/sdkBasic Usage
Initialization
First, define your database schema and initialize the SDK. This provides automatic type safety across your entire application.
import { DatabaseSDK } from '@forgebase/sdk/client';
// 1. Define your entity types
interface User {
id: number;
name: string;
email: string;
role: 'admin' | 'user';
status: 'active' | 'inactive';
}
interface Order {
id: number;
user_id: number;
amount: number;
status: 'pending' | 'completed';
}
// 2. Define your Database Schema
interface Schema {
users: User;
orders: Order;
}
// 3. Initialize the SDK with your Schema
const db = new DatabaseSDK<Schema>({
baseUrl: 'http://localhost:3000',
axiosConfig: {
withCredentials: true,
headers: { 'Content-Type': 'application/json' },
},
});Advanced Configuration
Custom Fetch Implementation
You can provide a custom fetch implementation to handle specific environments (like edge functions) or complex authentication requirements.
import { DatabaseSDK } from '@forgebase/sdk/client';
import { authClient } from '@/lib/auth-client'; // Assuming authClient is an instance of Better-auth
const db = new DatabaseSDK<Schema>({
baseUrl: 'http://localhost:3000',
// Provide a custom fetch wrapper
fetch: async (input, init) => {
const cookies = authClient.getCookie();
return fetch(input, {
...init,
headers: {
...init?.headers,
Cookie: cookies,
},
// Avoid interference with manual cookie headers
credentials: 'omit',
});
},
});Database Operations
The SDK automatically infers types based on your Schema.
// Query users (Type is inferred as User[])
const users = await db.table('users').select('id', 'name', 'email').where('status', 'active').query();
// Create a new record (Type checking ensures payload matches User)
const newUser = await db.table('users').create({
name: 'John Doe',
email: '[email protected]',
role: 'user',
status: 'active',
});
// Update a record
await db.table('users').update(1, {
status: 'inactive',
});
// Delete a record
await db.table('users').delete(1);Advanced Queries
// Complex filtering
const results = await db
.table('users') // Type inferred automatically
.where('status', 'active')
.andWhere((query) => {
query.where('role', 'admin').orWhere('email', 'like', '%@company.com');
})
.orderBy('name', 'asc')
.limit(10)
.query();
// Aggregations
const stats = await db.table('orders').groupBy('status').sum('amount', 'total_amount').count('id', 'order_count').having('total_amount', '>', 5000).query();
// Result type is narrowed:
// stats.data -> { status: string, total_amount: number, order_count: number }[]
// Window Functions
const rankedUsers = await db
.table('users')
.select('name', 'department', 'salary')
.rank('salary_rank', ['department'], [{ field: 'salary', direction: 'desc' }])
.query();
// Recursive CTEs (e.g., for hierarchical data)
const categories = await db
.table('categories')
.withRecursive(
'category_tree',
// Initial query
db.table('categories').where('parent_id', null),
// Recursive query
db.table('categories').join('category_tree', 'parent_id', 'id'),
{ unionAll: true },
)
.query();Transformations
You can transform the result set on the client side using pivot or compute.
// Pivot data
const pivoted = await db.table('sales').pivot('month', ['Jan', 'Feb', 'Mar'], { type: 'sum', field: 'amount' }).query();
// Compute new fields
const computed = await db
.table('employees')
.compute({
fullName: (row) => `${row.firstName} ${row.lastName}`,
tax: (row) => row.salary * 0.2,
})
.query();Error Handling
The SDK throws standard errors that you can catch and handle.
try {
await db.table('users').create(data);
} catch (error) {
console.error('Failed to create user:', error.message);
}Real-time Updates
⚠️ Note: Real-time features (WebSockets/SSE) are currently experimental and under active development. They are not yet fully documented or recommended for production use.
License
MIT
