Supabase client wrapper with Row Level Security, authentication integration, and type-safe queries
npm install @bernierllc/supabase-clientSupabase client wrapper with Row Level Security, authentication integration, retry logic, and type-safe queries.
``bash`
npm install @bernierllc/supabase-client
- Supabase Client Wrapper - Clean API around Supabase JavaScript SDK
- Retry Logic - Automatic retry for transient failures using @bernierllc/retry-policySupabaseResult
- Structured Error Handling - Consistent interface for all operations@bernierllc/logger
- Logger Integration - Built-in logging with
- Type Safety - Full TypeScript support with strict typing
- CRUD Operations - Query, insert, update, delete with filters
- RPC Support - Call Supabase RPC functions
- Storage Operations - Upload, download, and manage files
- Auth Operations - Sign in, sign up, sign out, session management
- Query Builder - Flexible query building with filters, ordering, pagination
`typescript
import { SupabaseClient } from '@bernierllc/supabase-client';
const client = new SupabaseClient({
url: process.env.SUPABASE_URL!,
anonKey: process.env.SUPABASE_ANON_KEY!,
enableRetry: true,
maxRetries: 3,
debug: false,
});
`
`typescript
// Simple query
const result = await client.query('users', {
select: '*',
limit: 10,
});
if (result.success) {
console.log('Users:', result.data);
console.log('Count:', result.count);
} else {
console.error('Error:', result.error);
}
// Query with filters
const activeUsers = await client.query('users', {
select: 'id, name, email',
filters: [
{ column: 'status', operator: 'eq', value: 'active' },
{ column: 'created_at', operator: 'gt', value: '2024-01-01' },
],
orderBy: { column: 'created_at', ascending: false },
limit: 20,
offset: 0,
});
// Get single record
const user = await client.query('users', {
filters: [{ column: 'id', operator: 'eq', value: 123 }],
single: true,
});
`
`typescript
// Insert single record
const result = await client.insert('users', {
name: 'John Doe',
email: 'john@example.com',
status: 'active',
});
if (result.success) {
console.log('Inserted:', result.data);
}
// Insert multiple records
const bulkResult = await client.insert('users', [
{ name: 'User 1', email: 'user1@example.com' },
{ name: 'User 2', email: 'user2@example.com' },
]);
// Upsert (insert or update)
const upsertResult = await client.insert(
'users',
{ id: 123, name: 'Updated Name' },
{ upsert: true }
);
`
`typescript
const result = await client.update(
'users',
{ status: 'inactive', updated_at: new Date().toISOString() },
[{ column: 'id', operator: 'eq', value: 123 }]
);
if (result.success) {
console.log('Updated:', result.data);
}
`
`typescript
const result = await client.delete('users', [
{ column: 'status', operator: 'eq', value: 'deleted' },
]);
if (result.success) {
console.log('Deleted:', result.data);
}
`
`typescript
const result = await client.rpc('calculate_user_stats', {
params: {
user_id: 123,
start_date: '2024-01-01',
},
});
if (result.success) {
console.log('Stats:', result.data);
}
`
`typescript
// Upload file
const file = new File(['content'], 'document.pdf', { type: 'application/pdf' });
const uploadResult = await client.storageUpload('documents', 'user123/document.pdf', file, {
contentType: 'application/pdf',
cacheControl: '3600',
upsert: false,
});
if (uploadResult.success) {
console.log('Uploaded to:', uploadResult.data?.path);
}
// Download file
const downloadResult = await client.storageDownload('documents', 'user123/document.pdf');
if (downloadResult.success) {
const blob = downloadResult.data;
// Use blob...
}
// Get public URL
const urlResult = client.getStoragePublicUrl('avatars', 'user123/avatar.jpg');
if (urlResult.success) {
console.log('Public URL:', urlResult.data);
}
`
`typescript
// Sign in
const signInResult = await client.authSignIn({
email: 'user@example.com',
password: 'password123',
});
if (signInResult.success) {
console.log('User:', signInResult.data?.user);
console.log('Session:', signInResult.data?.session);
}
// Sign up
const signUpResult = await client.authSignUp({
email: 'newuser@example.com',
password: 'password123',
options: {
data: { name: 'New User' },
emailRedirectTo: 'https://app.example.com/welcome',
},
});
// Sign out
await client.authSignOut();
// Get current session
const sessionResult = await client.authGetSession();
if (sessionResult.success && sessionResult.data?.session) {
console.log('Active session:', sessionResult.data.session);
}
`
`typescript
// Access underlying Supabase client for advanced features
const supabaseClient = client.getClient();
// Use Supabase realtime subscriptions
const channel = supabaseClient
.channel('users-changes')
.on('postgres_changes', { event: '*', schema: 'public', table: 'users' }, (payload) => {
console.log('Change received!', payload);
})
.subscribe();
`
`typescript`
interface SupabaseClientConfig {
/* Supabase project URL /
url: string;
/* Supabase anonymous key /
anonKey: string;
/* Service role key (optional, for admin operations) /
serviceRoleKey?: string;
/* Enable retry logic for transient failures (default: true) /
enableRetry?: boolean;
/* Maximum number of retry attempts (default: 3) /
maxRetries?: number;
/* Enable debug logging (default: false) /
debug?: boolean;
}
`typescript`
type FilterOperator =
| 'eq' // equals
| 'neq' // not equals
| 'gt' // greater than
| 'gte' // greater than or equal
| 'lt' // less than
| 'lte' // less than or equal
| 'like' // pattern match (case-sensitive)
| 'ilike' // pattern match (case-insensitive)
| 'in' // in array
| 'is'; // is null/not null
- query
- insert
- update
- delete
- rpc
- storageUpload(bucket: string, path: string, file: File | Blob | Buffer, options?: StorageUploadOptions): PromisestorageDownload(bucket: string, path: string, options?: StorageDownloadOptions): Promise
- getStoragePublicUrl(bucket: string, path: string): SupabaseResult
-
- authSignIn(options: AuthSignInOptions): PromiseauthSignUp(options: AuthSignUpOptions): Promise
- authSignOut(): Promise
- authGetSession(): Promise
-
- getClient(): SupabaseClient - Get underlying Supabase client for advanced usage
All methods return a SupabaseResult with consistent structure:
`typescript`
interface SupabaseResult
success: boolean;
data?: T;
error?: string;
count?: number;
}
Always check success before accessing data:
`typescript
const result = await client.query('users');
if (result.success) {
// Safe to access result.data
console.log(result.data);
} else {
// Handle error
console.error(result.error);
}
`
The client automatically retries transient failures using exponential backoff:
- Initial delay: 1000ms
- Max delay: 10000ms
- Jitter: enabled
- Default max retries: 3
Disable retry for specific operations:
`typescript`
const client = new SupabaseClient({
url: process.env.SUPABASE_URL!,
anonKey: process.env.SUPABASE_ANON_KEY!,
enableRetry: false, // Disable retry
});
Justification: This package uses @bernierllc/logger for structured logging of all database operations. Logs include query execution, authentication events, retry attempts, and error details to help with debugging and monitoring.
Pattern: Direct integration - logger is a required dependency for this package.
Justification: This is a core database client package that provides Supabase connectivity. It does not participate in service discovery, event publishing, or service mesh operations. Database clients are infrastructure utilities that don't require service registration or discovery.
Pattern: Core utility - no service mesh integration needed. Service-level packages that use this client can integrate with NeverHub if needed.
Format: TypeDoc-compatible JSDoc comments are included throughout the source code. All public APIs are documented with examples and type information.
- @supabase/supabase-js - Official Supabase JavaScript client@bernierllc/logger
- - Structured logging@bernierllc/retry-policy
- - Retry logic and backoff calculation
`bashRun tests
npm test
Building
`bash
Build TypeScript
npm run buildClean build artifacts
npm run clean
``Copyright (c) 2025 Bernier LLC. All rights reserved.
- @bernierllc/logger - Structured logging
- @bernierllc/retry-policy - Retry logic
- Supabase Documentation - Official Supabase docs