export type Listener = (state: T, context: ListenerContext) => void | Promise; export type AsyncListener = (state: T, context: ListenerContext) => Promise; export interface ListenerContext { setState: SetStateFunction; previous?: T; } export type SetStateFunction = { (stateOrUpdater: Partial | ((state: T) => Partial)): void; (stateOrUpdater: Partial | ((state: T) => Partial), afterApply?: (state: T) => void): void; (stateOrUpdater: Partial | ((state: T) => Partial), replace?: boolean): void; (stateOrUpdater: Partial | ((state: T) => Partial), afterApply?: (state: T) => void, replace?: boolean): void; }; export type PropertyPath = string; export interface Subscription { unsubscribe: () => void; } export interface Store { getState(includeChanges?: boolean): T; setState: SetStateFunction; on(event: 'init' | 'change', listener: Listener): () => void; on(event: 'change', properties: PropertyPath, listener: Listener): () => void; reset(): void; compute(propName: string, computeFn: (state: T) => R | Promise, dependencies: string[]): void; clearComputed(propName: string): void; clearAllComputed(): void; } export interface ChangeOptions { previous?: T; changes: string[]; setState: SetStateFunction; setError: (errors: (Partial> & Record) | undefined | false) => void; } export interface PageOptions { page?: number; count?: number; sortBy?: string[] | ((a: any, b: any) => -1 | 0 | 1); setTotalCount: (count: number) => void; } export type ItemLoadBehavior = 'stale' | 'swr' | 'new' | number | [number, boolean]; export interface ModelConfig { createWithDefaults?: (id: any) => T; selectId?: (state: T) => any; nextId?: () => any; loadTimeout?: number; loadItem?: (id: any) => Promise; itemLoadBehavior?: ItemLoadBehavior; loadItems?: (options: PageOptions) => Promise; sortHandledBy?: 'store' | 'server'; paginationHandledBy?: 'store' | 'server'; onCreate?: (data: T, options: ChangeOptions) => Promise; onUpdate?: (data: T, options: ChangeOptions) => Promise; onDelete?: (data: T) => Promise; transform?: (state: T) => Partial; transformBehavior?: 'before_validate' | 'after_validate' | 'change' | 'save'; persist?: boolean | 'local' | 'session' | ((store: T) => void); loadFromPersist?: () => T | undefined; validate?: (state: T) => (Partial> & Record) | undefined | false; validateBehavior?: 'change' | 'save'; saveOnChange?: boolean; computedProperties?: Record>; } export interface ModelStore extends Store { id: any; isStale: boolean; isLoading: boolean; isSaving: boolean; isDeleting: boolean; save(): Promise; delete(): Promise; destroy(): void; refresh(): Promise; } export interface ListState { isLoading: boolean; items: T[]; page: number; itemsPerPage: number; totalCount: number; sortBy: string[]; } export interface ModelFactory { create(initialState: Partial): ModelStore; get(id: any): ModelStore | undefined; list(options?: { itemsPerPage?: number; page?: number; sortBy?: string | string[] | ((a: T, b: T) => -1 | 0 | 1); }): ListState; } export type Middleware = (store: Store) => Store; export interface ComputedPropertyConfig { compute: (state: T) => any; dependencies: string[]; } export interface BatchedSetStateCall { stateOrUpdater: Partial | ((state: T) => Partial); afterApply?: (state: T) => void; replace?: boolean; }