@epicdm/flowstate-rxdb-client
v1.0.0
Published
Generic, type-safe RxDB client with replication and REST support
Downloads
71
Maintainers
Readme
@epic-flow/flowstate-rxdb-client
A generic, type-safe RxDB client library with dual-mode support for replication and REST API access. Built for Epic Flow applications requiring flexible data synchronization strategies.
Features
- Dual Mode Architecture: Choose between full replication mode or lightweight REST API mode
- Type-Safe API: Full TypeScript support with generic type parameters for compile-time safety
- Cross-Platform: Works in browsers (IndexedDB), Node.js (filesystem), and in-memory environments
- Reactive Queries: Built-in RxJS observables for real-time data updates (replication mode)
- Epic Flow Preset: Pre-configured client for Epic Flow collections
- Flexible Configuration: Customize storage, replication, and REST behavior
- Comprehensive Error Handling: Custom error classes for different failure scenarios
When to Use Replication vs REST Mode
Replication Mode (mode: 'replication')
Use when you need:
- Offline-first applications
- Real-time reactive data updates
- Local-first architecture with eventual consistency
- Complex queries on local data
- Reduced server load through local caching
Best for:
- Desktop applications (Electron)
- Mobile applications (React Native)
- Progressive Web Apps (PWAs)
- Applications requiring offline capabilities
REST Mode (mode: 'rest')
Use when you need:
- Lightweight client with minimal storage
- Server-authoritative data
- Simple CRUD operations
- Reduced bundle size
- Stateless client architecture
Best for:
- Server-side applications (Node.js services)
- Serverless functions
- Microservices
- Simple data fetching without local caching
Installation
# Using yarn
yarn add @epic-flow/flowstate-rxdb-client
# Using npm
npm install @epic-flow/flowstate-rxdb-clientPeer Dependencies
The package requires the following peer dependencies:
yarn add @epic-flow/collections rxdb rxjsQuick Start
Basic Example with Replication Mode
import { createRxDBClient } from '@epic-flow/flowstate-rxdb-client';
import type { ReplicationConfig } from '@epic-flow/flowstate-rxdb-client';
import { TaskCollection } from '@epic-flow/collections';
// Define your collections
const collections = {
tasks: TaskCollection,
};
// Create replication client
const config: ReplicationConfig<typeof collections> = {
mode: 'replication',
serverUrl: 'https://api.example.com',
authToken: 'your-auth-token',
domainId: 'your-domain-id',
collections,
storage: {
type: 'indexeddb', // or 'memory', 'filesystem'
},
};
const client = createRxDBClient(config);
// Connect to server and setup replication
await client.connect();
// Type-safe collection access
const tasks = await client.tasks.find({ selector: {} });
console.log(tasks);
// Reactive queries
client.tasks.find$({ selector: {} }).subscribe(tasks => {
console.log('Tasks updated:', tasks);
});Basic Example with REST Mode
import { createRxDBClient } from '@epic-flow/flowstate-rxdb-client';
import type { RestConfig } from '@epic-flow/flowstate-rxdb-client';
import { TaskCollection } from '@epic-flow/collections';
// Define your collections
const collections = {
tasks: TaskCollection,
};
// Create REST client
const config: RestConfig<typeof collections> = {
mode: 'rest',
serverUrl: 'https://api.example.com',
authToken: 'your-auth-token',
domainId: 'your-domain-id',
collections,
rest: {
timeout: 5000,
retryAttempts: 3,
},
};
const client = createRxDBClient(config);
// Connect to server
await client.connect();
// Type-safe collection access
const tasks = await client.tasks.find({ selector: {} });
console.log(tasks);Using Epic Flow Preset
import { createEpicFlowClient } from '@epic-flow/flowstate-rxdb-client/epic-flow';
// Create client with all Epic Flow collections pre-configured
const client = createEpicFlowClient({
mode: 'replication',
serverUrl: 'https://api.epicflow.com',
authToken: 'your-auth-token',
domainId: 'your-domain-id',
userId: 'user-123',
orgId: 'org-456',
});
await client.connect();
// Access all Epic Flow collections with full type safety
const projects = await client.projects.find({ selector: {} });
const tasks = await client.tasks.find({ selector: {} });
const milestones = await client.milestones.find({ selector: {} });API Reference
Factory Function
createRxDBClient<TCollections>(config: ClientConfig<TCollections>): IRxDBClient<TCollections>
Creates an RxDB client instance based on the provided configuration. Automatically selects the appropriate implementation (ReplicationClient or RestClient) based on the mode field.
Type Parameters:
TCollections: Object type defining collection names as keys and their collection definitions as values
Parameters:
config: Client configuration (ReplicationConfig or RestConfig)
Returns:
IRxDBClient<TCollections>: Client instance with type-safe collection accessors
Throws:
ConfigurationError: If the mode is invalid or configuration is incomplete
Configuration Types
ReplicationConfig<TCollections>
Configuration for replication mode client.
interface ReplicationConfig<TCollections> {
mode: 'replication';
serverUrl: string; // RxDB server URL
authToken: string; // Authentication token
domainId: string; // Domain identifier
collections: CollectionDefinitions<TCollections>;
// Optional fields
userId?: string; // User identifier for filtering
orgId?: string; // Organization identifier
databaseName?: string; // Local database name (default: 'flowstate-client')
storage?: {
type?: 'indexeddb' | 'memory' | 'filesystem';
options?: Record<string, any>; // Storage-specific options
};
replication?: {
live?: boolean; // Enable live replication (default: true)
batchSize?: number; // Documents per batch (default: 50)
waitForLeadership?: boolean; // Wait for leadership election
};
}RestConfig<TCollections>
Configuration for REST mode client.
interface RestConfig<TCollections> {
mode: 'rest';
serverUrl: string; // RxDB server URL
authToken: string; // Authentication token
domainId: string; // Domain identifier
collections: CollectionDefinitions<TCollections>;
// Optional fields
userId?: string; // User identifier for filtering
orgId?: string; // Organization identifier
databaseName?: string; // Logical database name
rest?: {
timeout?: number; // Request timeout in ms (default: 5000)
retryAttempts?: number; // Number of retry attempts (default: 3)
};
}CollectionDefinitions<TCollections>
Type defining collection schemas and methods.
type CollectionDefinitions<TCollections> = {
[K in keyof TCollections]: {
schema: any; // RxDB schema
methods?: any; // Collection methods
statics?: any; // Static methods
};
};Query<TDocument>
Query selector for finding documents.
interface Query<TDocument = any> {
selector?: Record<string, any>; // MongoDB-style selector
sort?: Array<Record<string, 'asc' | 'desc'>>; // Sort order
limit?: number; // Maximum results
skip?: number; // Skip first N results
}Client Interface
IRxDBClient<TCollections>
Main client interface implemented by both ReplicationClient and RestClient.
interface IRxDBClient<TCollections> {
// Connection management
isConnected(): boolean;
connect(): Promise<void>;
disconnect(removeData?: boolean): Promise<void>;
// Dynamic collection accessors (type-safe)
[K: string]: any;
// Replication manager (only in ReplicationClient)
replication?: ReplicationManager;
}Methods:
isConnected(): boolean- Returns whether the client is currently connected
- Returns
trueif connected,falseotherwise
connect(): Promise<void>- Establishes connection to the RxDB server
- In replication mode: Creates local database and starts replication
- In REST mode: Initializes REST clients for all collections
- Throws
ConnectionErroron failure
disconnect(removeData?: boolean): Promise<void>- Disconnects from the server and cleans up resources
removeData: Iftrue, removes local database (replication mode only)- Cancels all active replications and clears state
Dynamic Collection Properties:
Each collection defined in the configuration is accessible as a property on the client instance:
const client = createRxDBClient({ /* config */ });
await client.connect();
// Access collections directly
const tasks = await client.tasks.find({ selector: {} });
const projects = await client.projects.findOne({ selector: { id: '123' } });CollectionAccessor Interface
Collection accessor providing CRUD operations and reactive queries.
interface CollectionAccessor<TDocument> {
// CRUD operations
insert(doc: TDocument): Promise<TDocument>;
bulkInsert(docs: TDocument[]): Promise<TDocument[]>;
findOne(query: Query<TDocument>): Promise<TDocument | null>;
find(query: Query<TDocument>): Promise<TDocument[]>;
update(id: string, updates: Partial<TDocument>): Promise<TDocument>;
delete(id: string): Promise<boolean>;
// Reactive queries (replication mode only)
findOne$(query: Query<TDocument>): Observable<TDocument | null>;
find$(query: Query<TDocument>): Observable<TDocument[]>;
// Direct RxDB access (replication mode only)
getRxCollection?(): RxCollection<TDocument>;
}Methods:
insert(doc: TDocument): Promise<TDocument>- Inserts a single document
- Returns the inserted document with generated fields
- Throws error if document with same ID exists
bulkInsert(docs: TDocument[]): Promise<TDocument[]>- Inserts multiple documents in a single operation
- Returns array of successfully inserted documents
- Skips documents that already exist (doesn't throw)
findOne(query: Query<TDocument>): Promise<TDocument | null>- Finds a single document matching the query
- Returns
nullif no document matches - Returns first match if multiple documents match
find(query: Query<TDocument>): Promise<TDocument[]>- Finds all documents matching the query
- Supports sorting, limiting, and pagination
- Returns empty array if no matches
update(id: string, updates: Partial<TDocument>): Promise<TDocument>- Updates a document by ID with partial updates
- Returns the updated document
- Throws error if document not found
delete(id: string): Promise<boolean>- Deletes a document by ID
- Returns
trueif deleted,falseif not found
findOne$(query: Query<TDocument>): Observable<TDocument | null>(Replication mode only)- Returns an observable that emits when the query result changes
- Emits
nullif no document matches - Automatically updates when local data changes
find$(query: Query<TDocument>): Observable<TDocument[]>(Replication mode only)- Returns an observable that emits when the query results change
- Emits empty array if no matches
- Automatically updates when local data changes
getRxCollection?(): RxCollection<TDocument>(Replication mode only)- Returns the underlying RxDB collection
- Use for advanced RxDB features not exposed by the wrapper
- Returns
undefinedin REST mode
ReplicationManager Interface
Interface for managing replication state (replication mode only).
interface ReplicationManager {
getState(collectionName: string): RxReplicationState<any, any> | undefined;
awaitInitialSync(timeout?: number): Promise<void>;
awaitPendingWrites(timeout?: number): Promise<void>;
}Methods:
getState(collectionName: string): RxReplicationState<any, any> | undefined- Returns the replication state for a specific collection
- Returns
undefinedif collection has no replication - Use for monitoring replication progress and errors
awaitInitialSync(timeout?: number): Promise<void>- Waits for initial replication to complete for all collections
timeout: Maximum wait time in milliseconds (default: 10000)- Resolves when all collections have completed initial sync
- Doesn't throw on timeout, just resolves
awaitPendingWrites(timeout?: number): Promise<void>- Waits for all pending writes to be pushed to server
timeout: Wait time in milliseconds (default: 5000)- Useful before disconnecting to ensure data is saved
Error Classes
RxDBClientError
Base error class for all client errors.
class RxDBClientError extends Error {
constructor(
message: string,
public code: string,
public details?: any
)
}Properties:
message: Error descriptioncode: Error code for programmatic handlingdetails: Additional error context (optional)
ConnectionError extends RxDBClientError
Thrown when connection to the server fails.
class ConnectionError extends RxDBClientError {
constructor(message: string, details?: any)
}Code: CONNECTION_ERROR
Common scenarios:
- Server unreachable
- Authentication failure
- Network timeout
- Invalid server URL
ReplicationError extends RxDBClientError
Thrown when replication setup or sync fails.
class ReplicationError extends RxDBClientError {
constructor(message: string, details?: any)
}Code: REPLICATION_ERROR
Common scenarios:
- Replication state initialization failure
- Sync conflicts
- Schema version mismatch
ConfigurationError extends RxDBClientError
Thrown when client configuration is invalid.
class ConfigurationError extends RxDBClientError {
constructor(message: string, details?: any)
}Code: CONFIGURATION_ERROR
Common scenarios:
- Invalid mode value
- Missing required fields
- Invalid collection definitions
NotSupportedError extends RxDBClientError
Thrown when attempting unsupported operations.
class NotSupportedError extends RxDBClientError {
constructor(message: string, details?: any)
}Code: NOT_SUPPORTED_ERROR
Common scenarios:
- Calling reactive queries in REST mode
- Using replication manager in REST mode
- Platform-specific features not available
Usage Examples
Creating a Replication Client
import { createRxDBClient } from '@epic-flow/flowstate-rxdb-client';
import { TaskCollection, ProjectCollection } from '@epic-flow/collections';
const collections = {
tasks: TaskCollection,
projects: ProjectCollection,
};
const client = createRxDBClient({
mode: 'replication',
serverUrl: 'https://api.example.com',
authToken: 'your-jwt-token',
domainId: 'domain-123',
userId: 'user-456',
collections,
storage: {
type: 'indexeddb',
},
replication: {
live: true,
batchSize: 100,
},
});
await client.connect();
// Wait for initial sync
await client.replication?.awaitInitialSync();
// Use the client
const tasks = await client.tasks.find({ selector: {} });Creating a REST Client
import { createRxDBClient } from '@epic-flow/flowstate-rxdb-client';
import { TaskCollection } from '@epic-flow/collections';
const client = createRxDBClient({
mode: 'rest',
serverUrl: 'https://api.example.com',
authToken: 'your-jwt-token',
domainId: 'domain-123',
collections: {
tasks: TaskCollection,
},
rest: {
timeout: 10000,
retryAttempts: 3,
},
});
await client.connect();
// Fetch data directly from server
const tasks = await client.tasks.find({ selector: {} });Using Epic Flow Preset
import { createEpicFlowClient } from '@epic-flow/flowstate-rxdb-client/epic-flow';
const client = createEpicFlowClient({
mode: 'replication',
serverUrl: 'https://api.epicflow.com',
authToken: 'your-auth-token',
domainId: 'domain-123',
userId: 'user-123',
orgId: 'org-456',
});
await client.connect();
// Access pre-configured collections
const projects = await client.projects.find({ selector: {} });
const tasks = await client.tasks.find({ selector: {} });
const milestones = await client.milestones.find({ selector: {} });
const discussions = await client.discussions.find({ selector: {} });
const timeentries = await client.timeentries.find({ selector: {} });
const steeringdocuments = await client.steeringdocuments.find({ selector: {} });Type-Safe Collection Operations
import { createRxDBClient } from '@epic-flow/flowstate-rxdb-client';
import type { Task } from '@epic-flow/collections';
// Client is fully typed based on collections
const client = createRxDBClient({
mode: 'replication',
// ... config
});
await client.connect();
// TypeScript knows about your collections
const newTask: Task = {
id: 'task-1',
title: 'Complete documentation',
status: 'in-progress',
// ... other fields
};
// Insert with type checking
const inserted = await client.tasks.insert(newTask);
// Find with typed results
const tasks: Task[] = await client.tasks.find({
selector: { status: 'in-progress' }
});
// Update with partial type checking
const updated = await client.tasks.update('task-1', {
status: 'completed'
});Reactive Queries (Replication Mode)
import { createRxDBClient } from '@epic-flow/flowstate-rxdb-client';
const client = createRxDBClient({
mode: 'replication',
// ... config
});
await client.connect();
// Subscribe to query results
const subscription = client.tasks.find$({
selector: { assignedTo: 'user-123' }
}).subscribe(tasks => {
console.log('My tasks:', tasks);
// This will fire whenever the query results change
});
// Subscribe to single document
const taskSubscription = client.tasks.findOne$({
selector: { id: 'task-1' }
}).subscribe(task => {
console.log('Task updated:', task);
});
// Clean up subscriptions
subscription.unsubscribe();
taskSubscription.unsubscribe();Handling Replication Sync
import { createRxDBClient } from '@epic-flow/flowstate-rxdb-client';
const client = createRxDBClient({
mode: 'replication',
// ... config
});
await client.connect();
// Wait for initial sync before showing UI
await client.replication?.awaitInitialSync(10000);
// Monitor replication state
const tasksReplication = client.replication?.getState('tasks');
if (tasksReplication) {
tasksReplication.error$.subscribe(error => {
console.error('Replication error:', error);
});
tasksReplication.active$.subscribe(active => {
console.log('Replication active:', active);
});
}
// Before closing app, ensure all writes are synced
window.addEventListener('beforeunload', async () => {
await client.replication?.awaitPendingWrites(5000);
await client.disconnect();
});Advanced Query Examples
// Find with sorting
const sortedTasks = await client.tasks.find({
selector: { status: 'active' },
sort: [{ createdAt: 'desc' }],
});
// Pagination
const page1 = await client.tasks.find({
selector: {},
limit: 10,
skip: 0,
});
const page2 = await client.tasks.find({
selector: {},
limit: 10,
skip: 10,
});
// Complex queries
const urgentTasks = await client.tasks.find({
selector: {
priority: 'high',
dueDate: { $lt: Date.now() },
status: { $in: ['pending', 'in-progress'] },
},
sort: [{ dueDate: 'asc' }],
limit: 50,
});Bulk Operations
// Bulk insert
const newTasks = [
{ id: 'task-1', title: 'Task 1', status: 'pending' },
{ id: 'task-2', title: 'Task 2', status: 'pending' },
{ id: 'task-3', title: 'Task 3', status: 'pending' },
];
const inserted = await client.tasks.bulkInsert(newTasks);
console.log(`Inserted ${inserted.length} tasks`);
// Batch updates (with Promise.all)
const taskIds = ['task-1', 'task-2', 'task-3'];
await Promise.all(
taskIds.map(id =>
client.tasks.update(id, { status: 'completed' })
)
);Direct RxDB Access (Advanced)
import { createRxDBClient } from '@epic-flow/flowstate-rxdb-client';
const client = createRxDBClient({
mode: 'replication',
// ... config
});
await client.connect();
// Access underlying RxDB collection for advanced features
const rxCollection = client.tasks.getRxCollection();
if (rxCollection) {
// Use RxDB's query builder
const query = rxCollection
.find()
.where('status').eq('active')
.where('priority').gt(5);
const results = await query.exec();
// Access RxDB's change stream
const changeEvent$ = rxCollection.$.subscribe(event => {
console.log('Collection changed:', event);
});
}Configuration Options
Storage Options (Replication Mode)
IndexedDB (Browser)
{
storage: {
type: 'indexeddb',
options: {
// IndexedDB-specific options
}
}
}Best for: Web applications, Progressive Web Apps
Memory (Testing/Temporary)
{
storage: {
type: 'memory',
options: {}
}
}Best for: Unit tests, temporary data, development
Filesystem (Node.js/Electron)
{
storage: {
type: 'filesystem',
options: {
basePath: './data' // Directory for database files
}
}
}Best for: Desktop applications, Node.js services
Replication Options
{
replication: {
// Enable live replication (continuous sync)
live: true,
// Number of documents per batch
batchSize: 50,
// Wait for leadership before starting replication
// Useful in multi-tab scenarios
waitForLeadership: true,
}
}REST Options
{
rest: {
// Request timeout in milliseconds
timeout: 5000,
// Number of retry attempts on failure
retryAttempts: 3,
}
}Error Handling
Basic Error Handling
import {
createRxDBClient,
ConnectionError,
ReplicationError,
ConfigurationError,
} from '@epic-flow/flowstate-rxdb-client';
try {
const client = createRxDBClient(config);
await client.connect();
} catch (error) {
if (error instanceof ConnectionError) {
console.error('Failed to connect:', error.message);
console.error('Details:', error.details);
// Retry connection or show offline UI
} else if (error instanceof ConfigurationError) {
console.error('Invalid configuration:', error.message);
// Fix configuration
} else if (error instanceof ReplicationError) {
console.error('Replication setup failed:', error.message);
// Fall back to REST mode or show error
} else {
console.error('Unexpected error:', error);
}
}Common Error Scenarios
Connection Timeout
try {
await client.connect();
} catch (error) {
if (error instanceof ConnectionError) {
// Server unreachable or slow
// Try again with exponential backoff
await retryWithBackoff(() => client.connect());
}
}Authentication Failure
try {
await client.connect();
} catch (error) {
if (error instanceof ConnectionError) {
// Check if auth token is valid
// Refresh token and retry
const newToken = await refreshAuthToken();
client = createRxDBClient({
...config,
authToken: newToken,
});
await client.connect();
}
}Document Not Found
try {
await client.tasks.update('non-existent-id', { status: 'completed' });
} catch (error) {
if (error.message.includes('not found')) {
console.error('Task does not exist');
// Handle missing document
}
}Replication Errors
const client = createRxDBClient({
mode: 'replication',
// ... config
});
await client.connect();
// Monitor replication errors
const replicationState = client.replication?.getState('tasks');
if (replicationState) {
replicationState.error$.subscribe(error => {
console.error('Replication error:', error);
// Handle sync errors
// Show sync status in UI
});
}Migration Guide
Migrating from RxDBClientManager
If you're using the old RxDBClientManager class, here's how to migrate:
Before:
import { RxDBClientManager } from '@epic-flow/old-package';
const manager = new RxDBClientManager({
serverUrl: 'https://api.example.com',
authToken: 'token',
domainId: 'domain',
collections: myCollections,
});
await manager.initialize();
const tasks = await manager.getCollection('tasks').find().exec();After:
import { createRxDBClient } from '@epic-flow/flowstate-rxdb-client';
const client = createRxDBClient({
mode: 'replication',
serverUrl: 'https://api.example.com',
authToken: 'token',
domainId: 'domain',
collections: myCollections,
});
await client.connect();
const tasks = await client.tasks.find({ selector: {} });Key differences:
- Use
createRxDBClient()factory instead ofnew RxDBClientManager() - Add
mode: 'replication'to config - Call
connect()instead ofinitialize() - Access collections as properties:
client.tasksinstead ofmanager.getCollection('tasks') - Use simplified query interface:
find({ selector: {} })instead of RxDB's query builder
Migrating from RxDBRestClient
If you're using the old RxDBRestClient class:
Before:
import { RxDBRestClient } from '@epic-flow/old-package';
const restClient = new RxDBRestClient({
serverUrl: 'https://api.example.com',
authToken: 'token',
domainId: 'domain',
});
await restClient.connect('tasks');
const tasks = await restClient.find('tasks', { status: 'active' });After:
import { createRxDBClient } from '@epic-flow/flowstate-rxdb-client';
const client = createRxDBClient({
mode: 'rest',
serverUrl: 'https://api.example.com',
authToken: 'token',
domainId: 'domain',
collections: myCollections,
});
await client.connect();
const tasks = await client.tasks.find({ selector: { status: 'active' } });Key differences:
- Use
createRxDBClient()withmode: 'rest' - Define all collections upfront in config
- Call
connect()once for all collections - Access collections as properties with type safety
- Use MongoDB-style selectors:
{ selector: { status: 'active' } }
Cross-Platform Notes
Browser (IndexedDB)
const client = createRxDBClient({
mode: 'replication',
storage: {
type: 'indexeddb',
},
// ... other config
});Considerations:
- IndexedDB has storage quotas (varies by browser)
- Data persists across sessions
- Storage is per-origin
- Use
removeData: truewhen disconnecting to clear storage
Node.js (Filesystem)
import { createRxDBClient } from '@epic-flow/flowstate-rxdb-client';
const client = createRxDBClient({
mode: 'replication',
storage: {
type: 'filesystem',
options: {
basePath: './data',
},
},
// ... other config
});Considerations:
- Requires write permissions to basePath
- Data persists in filesystem
- Suitable for desktop apps and servers
- Consider data backup strategies
Electron (Desktop Apps)
import { app } from 'electron';
import path from 'path';
const client = createRxDBClient({
mode: 'replication',
storage: {
type: 'filesystem',
options: {
basePath: path.join(app.getPath('userData'), 'database'),
},
},
// ... other config
});Considerations:
- Use app.getPath('userData') for platform-appropriate storage
- Handle app quit events to disconnect gracefully
- Consider multi-window scenarios with leadership election
React Native (Mobile Apps)
const client = createRxDBClient({
mode: 'replication',
storage: {
type: 'filesystem', // or use react-native-sqlite storage
},
// ... other config
});Considerations:
- May need platform-specific storage adapters
- Consider mobile data usage for replication
- Handle app backgrounding and foregrounding
- Test offline scenarios thoroughly
Memory (Testing)
const client = createRxDBClient({
mode: 'replication',
storage: {
type: 'memory',
},
// ... other config
});Considerations:
- Data is lost when client disconnects or process exits
- Perfect for unit tests and integration tests
- Fastest storage option
- No persistence guarantees
TypeScript Support
This package is written in TypeScript and provides comprehensive type definitions.
Generic Type Parameters
import { createRxDBClient } from '@epic-flow/flowstate-rxdb-client';
import type { Task, Project } from '@epic-flow/collections';
// Define your collection types
interface MyCollections {
tasks: Task;
projects: Project;
}
// Client is fully typed
const client = createRxDBClient<typeof collections>({
mode: 'replication',
collections: {
tasks: TaskCollection,
projects: ProjectCollection,
},
// ... other config
});
await client.connect();
// TypeScript knows about these collections
const task: Task = await client.tasks.findOne({ selector: { id: '123' } });
const projects: Project[] = await client.projects.find({ selector: {} });Type Inference
// Collections are automatically typed from config
const collections = {
tasks: TaskCollection,
projects: ProjectCollection,
};
const client = createRxDBClient({
mode: 'replication',
collections,
// ... other config
});
// TypeScript infers the types
await client.connect();
// client.tasks is typed as CollectionAccessor<Task>
// client.projects is typed as CollectionAccessor<Project>Contributing
Contributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch
- Write tests for new functionality
- Ensure all tests pass:
yarn test - Ensure type checking passes:
yarn typecheck - Lint your code:
yarn lint - Submit a pull request
License
MIT
Support
For issues and questions:
- GitHub Issues: epic-digital-im/epic-flow/issues
- Documentation: GitHub Repository
Part of the Epic Flow ecosystem - Built by Epic Digital Interactive Media LLC
