UNPKG

@tanstack/db

Version:

A reactive client store for building super fast apps on sync

95 lines (94 loc) 4.14 kB
import { InitialQueryBuilder, QueryBuilder } from './builder/index.js'; import { Context } from './builder/types.js'; /** Event types for query result deltas */ export type DeltaType = 'enter' | 'exit' | 'update'; /** Delta event emitted when a row enters, exits, or updates within a query result */ export type DeltaEvent<TRow extends object = Record<string, unknown>, TKey extends string | number = string | number> = { type: 'enter'; key: TKey; /** Current value for the entering row */ value: TRow; metadata?: Record<string, unknown>; } | { type: 'exit'; key: TKey; /** Current value for the exiting row */ value: TRow; metadata?: Record<string, unknown>; } | { type: 'update'; key: TKey; /** Current value after the update */ value: TRow; /** Previous value before the batch */ previousValue: TRow; metadata?: Record<string, unknown>; }; /** Context passed to effect handlers */ export interface EffectContext { /** ID of this effect (auto-generated if not provided) */ effectId: string; /** Aborted when effect.dispose() is called */ signal: AbortSignal; } /** Query input - can be a builder function or a prebuilt query */ export type EffectQueryInput<TContext extends Context> = ((q: InitialQueryBuilder) => QueryBuilder<TContext>) | QueryBuilder<TContext>; type EffectEventHandler<TRow extends object = Record<string, unknown>, TKey extends string | number = string | number> = (event: DeltaEvent<TRow, TKey>, ctx: EffectContext) => void | Promise<void>; type EffectBatchHandler<TRow extends object = Record<string, unknown>, TKey extends string | number = string | number> = (events: Array<DeltaEvent<TRow, TKey>>, ctx: EffectContext) => void | Promise<void>; /** Effect configuration */ export interface EffectConfig<TRow extends object = Record<string, unknown>, TKey extends string | number = string | number> { /** Optional ID for debugging/tracing */ id?: string; /** Query to watch for deltas */ query: EffectQueryInput<any>; /** Called once for each row entering the query result */ onEnter?: EffectEventHandler<TRow, TKey>; /** Called once for each row updating within the query result */ onUpdate?: EffectEventHandler<TRow, TKey>; /** Called once for each row exiting the query result */ onExit?: EffectEventHandler<TRow, TKey>; /** Called once per graph run with all delta events from that batch */ onBatch?: EffectBatchHandler<TRow, TKey>; /** Error handler for exceptions thrown by effect callbacks */ onError?: (error: Error, event: DeltaEvent<TRow, TKey>) => void; /** * Called when a source collection enters an error or cleaned-up state. * The effect is automatically disposed after this callback fires. * If not provided, the error is logged to console.error. */ onSourceError?: (error: Error) => void; /** * Skip deltas during initial collection load. * Defaults to false (process all deltas including initial sync). * Set to true for effects that should only process new changes. */ skipInitial?: boolean; } /** Handle returned by createEffect */ export interface Effect { /** Dispose the effect. Returns a promise that resolves when in-flight handlers complete. */ dispose: () => Promise<void>; /** Whether this effect has been disposed */ readonly disposed: boolean; } /** * Creates a reactive effect that fires handlers when rows enter, exit, or * update within a query result. Effects process deltas only — they do not * maintain or require the full materialised query result. * * @example * ```typescript * const effect = createEffect({ * query: (q) => q.from({ msg: messagesCollection }) * .where(({ msg }) => eq(msg.role, 'user')), * onEnter: async (event) => { * await generateResponse(event.value) * }, * }) * * // Later: stop the effect * await effect.dispose() * ``` */ export declare function createEffect<TRow extends object = Record<string, unknown>, TKey extends string | number = string | number>(config: EffectConfig<TRow, TKey>): Effect; export {};