@tanstack/optimistic
Version:
Core optimistic updates library
177 lines (176 loc) • 7.57 kB
text/typescript
import { Derived, Store } from '@tanstack/store';
import { SortedMap } from './SortedMap.cjs';
import { ChangeMessage, CollectionConfig, InsertConfig, OperationConfig, OptimisticChangeMessage, Transaction } from './types.cjs';
export declare const collectionsStore: Store<Map<string, Collection<any>>, (cb: Map<string, Collection<any>>) => Map<string, Collection<any>>>;
/**
* Preloads a collection with the given configuration
* Returns a promise that resolves once the sync tool has done its first commit (initial sync is finished)
* If the collection has already loaded, it resolves immediately
*
* This function is useful in route loaders or similar pre-rendering scenarios where you want
* to ensure data is available before a route transition completes. It uses the same shared collection
* instance that will be used by useCollection, ensuring data consistency.
*
* @example
* ```typescript
* // In a route loader
* async function loader({ params }) {
* await preloadCollection({
* id: `users-${params.userId}`,
* sync: { ... },
* });
*
* return null;
* }
* ```
*
* @template T - The type of items in the collection
* @param config - Configuration for the collection, including id and sync
* @returns Promise that resolves when the initial sync is finished
*/
export declare function preloadCollection<T extends object = Record<string, unknown>>(config: CollectionConfig<T>): Promise<Collection<T>>;
/**
* Custom error class for schema validation errors
*/
export declare class SchemaValidationError extends Error {
type: `insert` | `update`;
issues: ReadonlyArray<{
message: string;
path?: ReadonlyArray<string | number | symbol>;
}>;
constructor(type: `insert` | `update`, issues: ReadonlyArray<{
message: string;
path?: ReadonlyArray<string | number | symbol>;
}>, message?: string);
}
export declare class Collection<T extends object = Record<string, unknown>> {
transactions: Store<SortedMap<string, Transaction>>;
optimisticOperations: Derived<Array<OptimisticChangeMessage<T>>>;
derivedState: Derived<Map<string, T>>;
derivedArray: Derived<Array<T>>;
derivedChanges: Derived<Array<ChangeMessage<T>>>;
private syncedData;
syncedMetadata: Store<Map<string, unknown>, (cb: Map<string, unknown>) => Map<string, unknown>>;
private pendingSyncedTransactions;
private syncedKeys;
config: CollectionConfig<T>;
private hasReceivedFirstCommit;
objectKeyMap: WeakMap<object, string>;
private onFirstCommitCallbacks;
/**
* Register a callback to be executed on the next commit
* Useful for preloading collections
* @param callback Function to call after the next commit
*/
onFirstCommit(callback: () => void): void;
id: `${string}-${string}-${string}-${string}-${string}`;
/**
* Creates a new Collection instance
*
* @param config - Configuration object for the collection
* @throws Error if sync config is missing
*/
constructor(config?: CollectionConfig<T>);
/**
* Attempts to commit pending synced transactions if there are no active transactions
* This method processes operations from pending transactions and applies them to the synced data
*/
commitPendingTransactions: () => void;
private ensureStandardSchema;
private validateData;
private generateKey;
/**
* Inserts one or more items into the collection
* @param items - Single item or array of items to insert
* @param config - Optional configuration including metadata and custom keys
* @returns A Transaction object representing the insert operation(s)
* @throws {SchemaValidationError} If the data fails schema validation
* @example
* // Insert a single item
* insert({ text: "Buy groceries", completed: false })
*
* // Insert multiple items
* insert([
* { text: "Buy groceries", completed: false },
* { text: "Walk dog", completed: false }
* ])
*
* // Insert with custom key
* insert({ text: "Buy groceries" }, { key: "grocery-task" })
*/
insert: (data: T | Array<T>, config?: InsertConfig) => Transaction;
/**
* Updates one or more items in the collection using a callback function
* @param items - Single item/key or array of items/keys to update
* @param configOrCallback - Either update configuration or update callback
* @param maybeCallback - Update callback if config was provided
* @returns A Transaction object representing the update operation(s)
* @throws {SchemaValidationError} If the updated data fails schema validation
* @example
* // Update a single item
* update(todo, (draft) => { draft.completed = true })
*
* // Update multiple items
* update([todo1, todo2], (drafts) => {
* drafts.forEach(draft => { draft.completed = true })
* })
*
* // Update with metadata
* update(todo, { metadata: { reason: "user update" } }, (draft) => { draft.text = "Updated text" })
*/
update<TItem extends object = T>(item: TItem, configOrCallback: ((draft: TItem) => void) | OperationConfig, maybeCallback?: (draft: TItem) => void): Transaction;
update<TItem extends object = T>(items: Array<TItem>, configOrCallback: ((draft: Array<TItem>) => void) | OperationConfig, maybeCallback?: (draft: Array<TItem>) => void): Transaction;
/**
* Deletes one or more items from the collection
* @param items - Single item/key or array of items/keys to delete
* @param config - Optional configuration including metadata
* @returns A Transaction object representing the delete operation(s)
* @example
* // Delete a single item
* delete(todo)
*
* // Delete multiple items
* delete([todo1, todo2])
*
* // Delete with metadata
* delete(todo, { metadata: { reason: "completed" } })
*/
delete: (items: Array<T | string> | T | string, config?: OperationConfig) => Transaction;
/**
* Gets the current state of the collection as a Map
*
* @returns A Map containing all items in the collection, with keys as identifiers
*/
get state(): Map<string, T>;
/**
* Gets the current state of the collection as a Map, but only resolves when data is available
* Waits for the first sync commit to complete before resolving
*
* @returns Promise that resolves to a Map containing all items in the collection
*/
stateWhenReady(): Promise<Map<string, T>>;
/**
* Gets the current state of the collection as an Array
*
* @returns An Array containing all items in the collection
*/
get toArray(): T[];
/**
* Gets the current state of the collection as an Array, but only resolves when data is available
* Waits for the first sync commit to complete before resolving
*
* @returns Promise that resolves to an Array containing all items in the collection
*/
toArrayWhenReady(): Promise<Array<T>>;
/**
* Returns the current state of the collection as an array of changes
* @returns An array of changes
*/
currentStateAsChanges(): Array<ChangeMessage<T>>;
/**
* Subscribe to changes in the collection
* @param callback - A function that will be called with the changes in the collection
* @returns A function that can be called to unsubscribe from the changes
*/
subscribeChanges(callback: (changes: Array<ChangeMessage<T>>) => void): () => void;
}