Package Exports
- @bernierllc/supabase-client
- @bernierllc/supabase-client/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@bernierllc/supabase-client) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
@bernierllc/supabase-client
Supabase client wrapper with Row Level Security, authentication integration, retry logic, and type-safe queries.
Installation
npm install @bernierllc/supabase-clientFeatures
- Supabase Client Wrapper - Clean API around Supabase JavaScript SDK
- Retry Logic - Automatic retry for transient failures using
@bernierllc/retry-policy - Structured Error Handling - Consistent
SupabaseResultinterface for all operations - Logger Integration - Built-in logging with
@bernierllc/logger - 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
Usage
Basic Setup
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,
});Query Data
// 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,
});Insert Data
// 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 }
);Update Data
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);
}Delete Data
const result = await client.delete('users', [
{ column: 'status', operator: 'eq', value: 'deleted' },
]);
if (result.success) {
console.log('Deleted:', result.data);
}RPC Functions
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);
}Storage Operations
// 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);
}Auth Operations
// 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);
}Advanced Usage
// 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();Configuration
SupabaseClientConfig
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;
}Filter Operators
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 nullAPI Reference
Query Operations
query<T>(table: string, options?: QueryOptions): Promise<SupabaseResult<T[]>>
Insert Operations
insert<T>(table: string, data: Partial<T> | Partial<T>[], options?: InsertOptions): Promise<SupabaseResult<T[]>>
Update Operations
update<T>(table: string, data: Partial<T>, filters: QueryFilter[], options?: UpdateOptions): Promise<SupabaseResult<T[]>>
Delete Operations
delete<T>(table: string, filters: QueryFilter[], options?: DeleteOptions): Promise<SupabaseResult<T[]>>
RPC Operations
rpc<T>(functionName: string, options?: RPCOptions): Promise<SupabaseResult<T>>
Storage Operations
storageUpload(bucket: string, path: string, file: File | Blob | Buffer, options?: StorageUploadOptions): Promise<SupabaseResult<{ path: string }>>storageDownload(bucket: string, path: string, options?: StorageDownloadOptions): Promise<SupabaseResult<Blob>>getStoragePublicUrl(bucket: string, path: string): SupabaseResult<string>
Auth Operations
authSignIn(options: AuthSignInOptions): Promise<SupabaseResult<{ user: unknown; session: unknown }>>authSignUp(options: AuthSignUpOptions): Promise<SupabaseResult<{ user: unknown; session: unknown }>>authSignOut(): Promise<SupabaseResult<void>>authGetSession(): Promise<SupabaseResult<{ session: unknown }>>
Utility
getClient(): SupabaseClient- Get underlying Supabase client for advanced usage
Error Handling
All methods return a SupabaseResult<T> with consistent structure:
interface SupabaseResult<T = unknown> {
success: boolean;
data?: T;
error?: string;
count?: number;
}Always check success before accessing data:
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);
}Retry Logic
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:
const client = new SupabaseClient({
url: process.env.SUPABASE_URL!,
anonKey: process.env.SUPABASE_ANON_KEY!,
enableRetry: false, // Disable retry
});Integration Status
Logger Integration
Status: Integrated
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.
NeverHub Integration
Status: Not applicable
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.
Docs-Suite Integration
Status: Ready
Format: TypeDoc-compatible JSDoc comments are included throughout the source code. All public APIs are documented with examples and type information.
Dependencies
@supabase/supabase-js- Official Supabase JavaScript client@bernierllc/logger- Structured logging@bernierllc/retry-policy- Retry logic and backoff calculation
Testing
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Run tests once (no watch)
npm run test:runBuilding
# Build TypeScript
npm run build
# Clean build artifacts
npm run cleanLicense
Copyright (c) 2025 Bernier LLC. All rights reserved.
See Also
- @bernierllc/logger - Structured logging
- @bernierllc/retry-policy - Retry logic
- Supabase Documentation - Official Supabase docs