@corbit-cloud/sdk
v0.1.6
Published
Official Corbit JavaScript/TypeScript SDK
Maintainers
Readme
@corbit/js
Official Corbit JavaScript/TypeScript SDK for browser and Node.js.
Installation
npm install @corbit/js
# or
pnpm add @corbit/js
# or
yarn add @corbit/jsQuick Start
Basic Setup
import { createClient } from '@corbit/js';
const corbit = createClient({
url: 'https://api.corbit.cloud/api/v1',
projectRef: {
orgSlug: 'my-org',
projectSlug: 'my-project',
},
auth: {
apiKey: 'sk_live_xxx', // or accessToken for JWT mode
},
});JWT Authentication (Console/Management)
const corbit = createClient({
url: 'https://api.corbit.cloud/api/v1',
projectRef: {
orgSlug: 'my-org',
projectSlug: 'my-project',
},
auth: {
accessToken: 'jwt-token',
refreshToken: 'refresh-token', // optional
persistSession: true,
storage: 'localStorage',
autoRefreshToken: true,
},
});API Key Authentication (App/Data)
const corbit = createClient({
url: 'https://api.corbit.cloud/api/v1',
projectRef: {
orgSlug: 'my-org',
projectSlug: 'my-project',
},
auth: {
apiKey: 'sk_live_xxx',
},
});Database
Query Data
// Select all (queries are awaitable directly, no .execute() needed)
const { data, error } = await corbit
.from('users')
.select('*')
.limit(10);
// Filter and sort
const { data, error } = await corbit
.from('users')
.select('id, name, email')
.eq('status', 'active')
.gt('created_at', '2024-01-01')
.order('created_at', { ascending: false })
.limit(20);
// Single row
const { data, error } = await corbit
.from('users')
.select('*')
.eq('id', 'user-id')
.single();
// Maybe single (returns null if not found)
const { data, error } = await corbit
.from('users')
.select('*')
.eq('email', '[email protected]')
.maybeSingle();Insert Data
// Single row
const { data, error } = await corbit
.from('users')
.insert({
name: 'John Doe',
email: '[email protected]',
});
// Multiple rows
const { data, error } = await corbit
.from('users')
.insert([
{ name: 'John', email: '[email protected]' },
{ name: 'Jane', email: '[email protected]' },
]);Update Data
// Update by primary key (pass as second argument or use .eq())
const { data, error } = await corbit
.from('users')
.eq('id', 'user-id')
.update({
name: 'Updated Name',
status: 'active',
});
// Or pass primary key directly
const { data, error } = await corbit
.from('users')
.update({
name: 'Updated Name',
}, 'user-id');Delete Data
// Delete by primary key (pass as argument or use .eq())
const { data, error } = await corbit
.from('users')
.eq('id', 'user-id')
.delete();
// Or pass primary key directly
const { data, error } = await corbit
.from('users')
.delete('user-id');Filter Operators
.eq(column, value)- equals.neq(column, value)- not equals.gt(column, value)- greater than.gte(column, value)- greater than or equal.lt(column, value)- less than.lte(column, value)- less than or equal.like(column, pattern)- LIKE (case-sensitive).ilike(column, pattern)- ILIKE (case-insensitive).in(column, values[])- IN array
Count
// Get count with results
const { data, count, error } = await corbit
.from('users')
.select('*')
.count('exact')
.eq('status', 'active');
console.log('Total:', count);
// Request count mode (if API supports it)
const result = await corbit
.from('users')
.select('*')
.count('estimated'); // 'exact' | 'estimated' | 'planned'Head (Count Only)
// NOTE: Requires backend support (see GAPS.md)
const { count, error } = await corbit
.from('users')
.select('*')
.head(); // Returns only count, no dataFunctions (Edge Functions)
Invoke Function
const { data, error } = await corbit.functions.invoke('sendEmail', {
body: {
to: '[email protected]',
subject: 'Hello',
message: 'Welcome!',
},
headers: {
'Custom-Header': 'value',
},
});
if (data) {
console.log('Status:', data.status);
console.log('Response:', data.body);
console.log('Headers:', data.headers);
}Storage
Upload File
const file = new File(['content'], 'document.pdf', { type: 'application/pdf' });
const { data, error } = await corbit.storage
.from('my-bucket')
.upload('docs/document.pdf', file, {
upsert: false,
contentType: 'application/pdf',
metadata: { author: 'John Doe' },
tags: { category: 'document' },
});Download File
// Get presigned URL
const { data: url, error } = await corbit.storage
.from('my-bucket')
.download('docs/document.pdf', {
expiresIn: 3600, // 1 hour
});
// url is a presigned URL
if (url) {
window.open(url);
}
// Or download as Blob (browser only)
const { data: blob, error } = await corbit.storage
.from('my-bucket')
.download('docs/document.pdf', {
expiresIn: 3600,
as: 'blob',
});
if (blob) {
const objectUrl = URL.createObjectURL(blob);
// Use objectUrl
}Create Signed URLs
// Single signed URL
const { data: url, error } = await corbit.storage
.from('my-bucket')
.createSignedUrl('docs/document.pdf', 3600);
// Multiple signed URLs
const { data: urls, error } = await corbit.storage
.from('my-bucket')
.createSignedUrls(['docs/file1.pdf', 'docs/file2.pdf'], 3600);
// urls is { 'docs/file1.pdf': 'url1', 'docs/file2.pdf': 'url2' }Check if Object Exists
const { data: exists, error } = await corbit.storage
.from('my-bucket')
.exists('docs/document.pdf');
if (exists) {
console.log('File exists');
}Get Public URL
// NOTE: Requires backend support for public objects (see GAPS.md)
const publicUrl = corbit.storage
.from('my-bucket')
.getPublicUrl('docs/document.pdf');
// Returns null if not supportedList Objects
const { data, error } = await corbit.storage
.from('my-bucket')
.list('docs/', {
delimiter: '/',
limit: 100,
});
// data.objects - array of files
// data.folders - array of folders
// data.cursor - pagination cursor
// data.hasMore - booleanDelete Object
const { data, error } = await corbit.storage
.from('my-bucket')
.remove('docs/document.pdf');Move/Copy Objects
// Move
await corbit.storage
.from('my-bucket')
.move('docs/old.pdf', 'docs/new.pdf', { overwrite: false });
// Copy
await corbit.storage
.from('my-bucket')
.copy('docs/original.pdf', 'docs/copy.pdf', { overwrite: false });Folder Operations
// Create folder
await corbit.storage
.from('my-bucket')
.createFolder('new-folder', { prefix: 'docs/' });
// Move folder
await corbit.storage
.from('my-bucket')
.moveFolder('docs/old/', 'docs/new/', { overwrite: false });
// Delete folder (recursive)
await corbit.storage
.from('my-bucket')
.deleteFolder('docs/folder/');Metadata
// Get metadata
const { data, error } = await corbit.storage
.from('my-bucket')
.getMetadata('docs/document.pdf');
// Update metadata
await corbit.storage
.from('my-bucket')
.updateMetadata('docs/document.pdf', {
customMetadata: { author: 'Jane Doe' },
contentType: 'application/pdf',
});
// Update tags
await corbit.storage
.from('my-bucket')
.updateTags('docs/document.pdf', {
category: 'document',
version: '2.0',
});Realtime
Subscribe to Table Changes
const channel = corbit.realtime.channel('table:users', {
filter: 'id=eq.user-id', // optional
});
channel.on('INSERT', (payload) => {
console.log('New user inserted:', payload.new);
});
channel.on('UPDATE', (payload) => {
console.log('User updated:', payload.new);
});
channel.on('DELETE', (payload) => {
console.log('User deleted:', payload.old);
});
await channel.subscribe();
// Later, unsubscribe
await channel.unsubscribe();Disconnect
corbit.realtime.disconnect();Authentication
Sign Up
const { data, error } = await corbit.auth.signUp({
email: '[email protected]',
password: 'securepassword',
data: { displayName: 'John Doe' }, // optional metadata
});
if (data) {
console.log('User:', data.user);
console.log('Access token:', data.accessToken);
}Sign In
const { data, error } = await corbit.auth.signInWithPassword({
email: '[email protected]',
password: 'securepassword',
});
if (data) {
console.log('User:', data.user);
// Session is automatically stored if persistSession=true
}Sign Out
const { data, error } = await corbit.auth.signOut();
// Session is cleared and refresh token is invalidatedGet Current User
// NOTE: Requires backend endpoint (see GAPS.md)
const { data: user, error } = await corbit.auth.getUser();Get Session
const session = corbit.auth.getSession();
if (session) {
console.log('Access token:', session.accessToken);
console.log('Expires at:', new Date(session.expiresAt));
}Refresh Session
const { data: session, error } = await corbit.auth.refreshSession();
// Forces a token refresh if refresh token is availableUpdate User
// NOTE: Requires backend endpoint (see GAPS.md)
const { data: user, error } = await corbit.auth.updateUser({
email: '[email protected]',
password: 'newpassword',
data: { displayName: 'Jane Doe' },
});Reset Password
// NOTE: Requires backend endpoint (see GAPS.md)
const { data, error } = await corbit.auth.resetPasswordForEmail('[email protected]', {
redirectTo: 'https://app.example.com/reset-password',
});Auth State Changes
const { unsubscribe } = corbit.auth.onAuthStateChange((event, session) => {
switch (event) {
case 'SIGNED_IN':
console.log('User signed in:', session);
break;
case 'SIGNED_OUT':
console.log('User signed out');
break;
case 'TOKEN_REFRESHED':
console.log('Token refreshed:', session);
break;
case 'USER_UPDATED':
console.log('User updated:', session);
break;
}
});
// Later, unsubscribe
unsubscribe();Set Auth Dynamically
// Set JWT tokens
corbit.setAuth('new-access-token', 'new-refresh-token');
// Set API key
corbit.setApiKey('sk_live_xxx');
// Get current session
const session = corbit.getSession();Error Handling
All methods return { data, error } pattern:
const { data, error } = await corbit.from('users').select('*');
if (error) {
console.error('Error:', error.message);
console.error('Status:', error.status);
console.error('Code:', error.code);
console.error('Details:', error.details);
return;
}
// Use data
console.log(data);TypeScript Support
Generate Types
Use the CLI to generate TypeScript types from your database schema:
corbit gen types --org my-org --project my-project --out ./corbit.types.ts --token YOUR_JWT_TOKENUse Generated Types
import { createClient } from '@corbit/js';
import type { Database } from './corbit.types';
const corbit = createClient<Database>({
url: 'https://api.corbit.cloud/api/v1',
projectRef: {
orgSlug: 'my-org',
projectSlug: 'my-project',
},
auth: {
apiKey: 'sk_live_xxx',
},
});
// Now queries are fully typed!
const { data } = await corbit.from('users').select('*');
// data is typed as Database['public']['Tables']['users']['Row'][]API Reference
Client Options
type CorbitClientOptions = {
url: string; // Base API URL (no trailing slash)
projectRef: {
orgSlug: string;
projectSlug: string;
};
auth: {
accessToken?: string; // JWT access token
refreshToken?: string; // JWT refresh token
apiKey?: string; // API key (sk_live_xxx or sk_test_xxx)
persistSession?: boolean; // Default: true
storage?: 'localStorage' | 'memory'; // Default: 'localStorage'
autoRefreshToken?: boolean; // Default: true
};
};Compatibility Matrix
| Feature | Status | Notes |
|---------|--------|-------|
| Authentication: signUp/signIn/signOut | ✅ Supported | Uses /auth/register, /auth/login, /auth/logout |
| Authentication: getUser | ❌ Not Supported | Requires backend endpoint (see GAPS.md) |
| Authentication: updateUser | ❌ Not Supported | Requires backend endpoint (see GAPS.md) |
| Authentication: resetPassword | ❌ Not Supported | Requires backend endpoint (see GAPS.md) |
| Authentication: onAuthStateChange | ✅ Supported | Client-side event system |
| Database: CRUD operations | ✅ Supported | Full CRUD with filters |
| Database: count | ✅ Supported | Count returned in response |
| Database: count modes | ⚠️ Limited | API returns count but no mode selection |
| Database: head mode | ❌ Not Supported | Requires backend support (see GAPS.md) |
| Database: RPC | ❌ Not Supported | Requires backend endpoint (see GAPS.md) |
| Database: upsert | ❌ Not Supported | Requires backend support (see GAPS.md) |
| Database: OR filters | ❌ Not Supported | Only AND logic supported |
| Database: textSearch | ❌ Not Supported | Use .like() or .ilike() instead |
| Functions: invoke | ✅ Supported | Uses /functions/:slug/invoke |
| Storage: upload/download | ✅ Supported | Full upload/download flow |
| Storage: presigned URLs | ✅ Supported | Never rewritten, used as-is |
| Storage: exists | ✅ Supported | Uses metadata endpoint |
| Storage: public URLs | ❌ Not Supported | Requires backend support (see GAPS.md) |
| Storage: multipart upload | ❌ Not Supported | Requires backend support (see GAPS.md) |
| Realtime: subscribe/unsubscribe | ✅ Supported | WebSocket with auto-reconnect |
| Realtime: presence | ❌ Not Supported | Requires backend support (see GAPS.md) |
| Realtime: broadcast | ❌ Not Supported | Requires backend support (see GAPS.md) |
| Type generation | ✅ Supported | corbit gen types CLI command |
Missing Features (GAPS)
Some features require backend API endpoints that are not currently available. See GAPS.md for a complete list of missing endpoints and suggested implementations.
Key missing features:
- User management endpoints (getUser, updateUser, resetPassword)
- Database RPC calls
- Database upsert operations
- Advanced filtering (OR conditions, text search)
- Realtime presence and broadcast
- Storage public URLs and multipart uploads
License
MIT
