/** * Core Types for @dotdo/tanstack * * TanStack DB integration types for local-first sync with PostgreSQL/PGLite. */ /** * Base record type for collection items */ export interface BaseRecord { id: string | number } /** * Collection configuration options */ export interface CollectionOptions { /** Unique identifier for this collection */ id: string /** Optional schema name */ schema?: string /** Table name in PostgreSQL */ table: string /** Primary key field name */ primaryKey?: keyof T /** Timestamps configuration */ timestamps?: { createdAt?: string updatedAt?: string } } /** * Query collection options - fetches data via TanStack Query */ export interface QueryCollectionOptions extends CollectionOptions { /** Query function for fetching data */ queryFn: () => Promise /** Stale time in milliseconds */ staleTime?: number /** Cache time in milliseconds */ cacheTime?: number /** Refetch interval in milliseconds */ refetchInterval?: number } /** * Sync collection options - maintains real-time sync */ export interface SyncCollectionOptions extends CollectionOptions { /** Sync endpoint URL */ syncUrl: string /** Shape parameters for Electric-style sync */ shapeParams?: Record /** Polling interval for sync in milliseconds */ pollInterval?: number /** Enable debug logging for mutation lifecycle (default: false) */ debug?: boolean } /** * Live query options for reactive queries */ export interface LiveQueryOptions { /** Collection ID to query */ collectionId: string /** WHERE clause conditions */ where?: Partial | ((item: T) => boolean) /** ORDER BY configuration */ orderBy?: { field: keyof T direction: 'asc' | 'desc' } /** LIMIT clause */ limit?: number /** OFFSET clause */ offset?: number /** Transform function for results */ select?: (items: T[]) => R } /** * Mutation options for transactional writes */ export interface MutationOptions { /** Collection ID to mutate */ collectionId: string /** Whether to apply optimistically */ optimistic?: boolean /** Rollback on error */ rollbackOnError?: boolean /** Custom conflict resolution */ onConflict?: ConflictResolver } /** * Optimistic update state */ export interface OptimisticState { /** Pending mutations not yet confirmed */ pending: PendingMutation[] /** Applied changes awaiting server confirmation */ applied: AppliedMutation[] } /** * Pending mutation waiting to be sent */ export interface PendingMutation { id: string type: 'insert' | 'update' | 'delete' collectionId: string data: Partial timestamp: number } /** * Applied mutation awaiting confirmation */ export interface AppliedMutation { id: string type: 'insert' | 'update' | 'delete' collectionId: string recordId: string | number data: Partial previousData?: T timestamp: number txId?: string } /** * Conflict types that can occur during sync */ export type ConflictType = | 'update-update' // Both local and remote updated same record | 'update-delete' // Local updated, remote deleted | 'delete-update' // Local deleted, remote updated | 'insert-insert' // Both inserted record with same key /** * Conflict information for resolution */ export interface Conflict { type: ConflictType collectionId: string recordId: string | number localValue?: Partial remoteValue?: Partial baseValue?: T localTimestamp: number remoteTimestamp: number } /** * Conflict resolution strategy */ export type ConflictStrategy = | 'local-wins' | 'remote-wins' | 'latest-wins' | 'merge' | 'manual' /** * Conflict resolver function */ export type ConflictResolver = ( conflict: Conflict ) => Promise | T | null /** * Sync state for a collection */ export interface SyncState { /** Whether sync is currently active */ connected: boolean /** Last successful sync timestamp */ lastSyncAt?: number /** Last sync error if any */ lastError?: Error /** Number of pending changes */ pendingCount: number /** Whether initial sync is complete */ initialized: boolean } /** * PGLite collection options for local database */ export interface PGLiteCollectionOptions extends CollectionOptions { /** PGLite instance or factory */ pglite: PGLiteInterface | (() => Promise) /** Whether to create table if not exists */ autoCreateTable?: boolean /** Table schema definition for auto-create */ tableSchema?: string } /** * Minimal PGLite interface for type safety */ export interface PGLiteInterface { query(sql: string, params?: unknown[]): Promise<{ rows: R[] }> exec(sql: string): Promise close(): Promise } /** * Collection instance with methods */ export interface Collection { /** Collection ID */ readonly id: string /** Get all items */ getAll(): T[] /** Get item by ID */ get(id: string | number): T | undefined /** Insert a new item */ insert(data: Omit & { id?: T['id'] }): Promise /** Update an existing item */ update(id: string | number, data: Partial): Promise /** Delete an item */ delete(id: string | number): Promise /** Subscribe to changes */ subscribe(callback: (items: T[]) => void): () => void /** Get current sync state */ getSyncState(): SyncState } /** * TanStack DB Store interface */ export interface TanStackStore { /** Get a collection by ID */ getCollection(id: string): Collection | undefined /** Register a new collection */ registerCollection( options: QueryCollectionOptions | SyncCollectionOptions | PGLiteCollectionOptions ): Collection /** Get all registered collection IDs */ getCollectionIds(): string[] /** Dispose of all resources */ dispose(): Promise }