async-states
Version:
Core of async-states
277 lines (274 loc) • 14.2 kB
TypeScript
import { Status, RunEffect } from './enums.js';
interface BaseSource<TData, TArgs extends unknown[], TError> {
key: string;
uniqueId: number;
readonly inst: StateInterface<TData, TArgs, TError>;
getVersion(): number;
getPayload(): Record<string, unknown>;
mergePayload(partialPayload?: Record<string, unknown>): void;
getState(): State<TData, TArgs, TError>;
setState(value: StateFunctionUpdater<TData, TArgs, TError> | TData, status: "initial", callbacks?: ProducerCallbacks<TData, TArgs, TError>): void;
setState(value: null, status: "pending", callbacks?: ProducerCallbacks<TData, TArgs, TError>): void;
setState(value: TError, status: "error", callbacks?: ProducerCallbacks<TData, TArgs, TError>): void;
setState(value: StateFunctionUpdater<TData, TArgs, TError> | TData, status?: "success", callbacks?: ProducerCallbacks<TData, TArgs, TError>): void;
setData(newData: TData | ((prevData: TData | null) => TData)): void;
replaceState(newState: State<TData, TArgs, TError>, notify?: boolean, callbacks?: ProducerCallbacks<TData, TArgs, TError>): void;
subscribe(cb: (s: State<TData, TArgs, TError>) => void): AbortFn;
subscribe(subProps: AsyncStateSubscribeProps<TData, TArgs, TError>): AbortFn;
subscribe(argv: ((s: State<TData, TArgs, TError>) => void) | AsyncStateSubscribeProps<TData, TArgs, TError>): AbortFn;
replay(): AbortFn;
abort(reason?: any): void;
replaceProducer(newProducer: Producer<TData, TArgs, TError> | null): void;
invalidateCache(cacheKey?: string): void;
replaceCache(cacheKey: string, cache: CachedState<TData, TArgs, TError>): void;
patchConfig(partialConfig?: Partial<ProducerConfig<TData, TArgs, TError>>): void;
patchConfig(updater?: (config: Partial<ProducerConfig<TData, TArgs, TError>>) => Partial<ProducerConfig<TData, TArgs, TError>>): void;
patchConfig(updater?: Partial<ProducerConfig<TData, TArgs, TError>> | ((config: Partial<ProducerConfig<TData, TArgs, TError>>) => Partial<ProducerConfig<TData, TArgs, TError>>)): void;
getConfig(): ProducerConfig<TData, TArgs, TError>;
on(eventType: InstanceChangeEvent, eventHandler: InstanceChangeEventHandlerType<TData, TArgs, TError>): () => void;
on(eventType: InstanceDisposeEvent, eventHandler: InstanceDisposeEventHandlerType<TData, TArgs, TError>): () => void;
on(eventType: InstanceCacheChangeEvent, eventHandler: InstanceCacheChangeEventHandlerType<TData, TArgs, TError>): () => void;
dispose(): boolean;
}
type StateChangeEventHandler<TData, TArgs extends unknown[], TError> = ((newState: State<TData, TArgs, TError>) => void) | InstanceChangeEventObject<TData, TArgs, TError>;
type InstanceChangeEventObject<TData, TArgs extends unknown[], TError> = {
status: Status;
handler: (newState: State<TData, TArgs, TError>) => void;
};
type InstanceChangeEventHandlerType<TData, TArgs extends unknown[], TError> = StateChangeEventHandler<TData, TArgs, TError> | StateChangeEventHandler<TData, TArgs, TError>[];
type InstanceDisposeEventHandlerType<TData, TArgs extends unknown[], TError> = (() => void) | (() => void)[];
type InstanceCacheChangeEventHandlerType<TData, TArgs extends unknown[], TError> = ((cache: Record<string, CachedState<TData, TArgs, TError>> | null | undefined) => void) | ((cache: Record<string, CachedState<TData, TArgs, TError>> | null | undefined) => void)[];
type InstanceChangeEvent = "change";
type InstanceDisposeEvent = "dispose";
type InstanceCacheChangeEvent = "cache-change";
type AsyncStateSubscribeProps<TData, TArgs extends unknown[], TError> = {
key?: string;
flags?: number;
cb(s: State<TData, TArgs, TError>): void;
};
type InstanceEvents<TData, TArgs extends unknown[], TError> = {
change?: Record<number, InstanceChangeEventHandlerType<TData, TArgs, TError>>;
dispose?: Record<number, InstanceDisposeEventHandlerType<TData, TArgs, TError>>;
["cache-change"]?: Record<number, InstanceCacheChangeEventHandlerType<TData, TArgs, TError>>;
};
type HydrationData<TData, TArgs extends unknown[], TError> = {
state: State<TData, TArgs, TError>;
payload: Record<string, unknown>;
latestRun: RunTask<TData, TArgs, TError> | null;
};
interface PromiseLike<TData, TError> extends Promise<TData> {
status: "pending" | "fulfilled" | "rejected";
value?: TData;
reason?: TError;
}
type HydratedState<TData, TArgs extends unknown[], TError> = InitialState<TData, TArgs> | PendingState<TData, TArgs, TError> | SuccessState<TData, TArgs> | ErrorState<TData, TArgs, TError>;
type SourceHydration<TData, TArgs extends unknown[], TError> = [
HydratedState<TData, TArgs, TError>,
RunTask<TData, TArgs, TError> | null,
Record<string, any> | null
];
interface StateInterface<TData, TArgs extends unknown[], TError> {
key: string;
version: number;
id: number;
actions: Source<TData, TArgs, TError>;
config: ProducerConfig<TData, TArgs, TError>;
payload: Record<string, any> | null;
state: State<TData, TArgs, TError>;
lastSuccess: LastSuccessSavedState<TData, TArgs>;
pendingUpdate: PendingUpdate | null;
pendingTimeout: PendingTimeout | null;
queue: UpdateQueue<TData, TArgs, TError> | null;
subsIndex: number | null;
subscriptions: Record<number, StateSubscription<TData, TArgs, TError>> | null;
promise: PromiseLike<TData, TError> | null;
res: {
res: (data: TData) => void;
rej: (error: TError) => void;
} | null;
fn: Producer<TData, TArgs, TError> | null;
readonly ctx: LibraryContext | null;
latestRun: RunTask<TData, TArgs, TError> | null;
currentAbort: AbortFn | null;
parent: StateInterface<TData, TArgs, TError> | null;
lanes: Record<string, StateInterface<TData, TArgs, TError>> | null;
cache: Record<string, CachedState<TData, TArgs, TError>> | null;
events: InstanceEvents<TData, TArgs, TError> | null;
eventsIndex: number | null;
journal?: any[] | null;
global: boolean | null;
}
interface RUNCProps<TData, TArgs extends unknown[], TError> extends ProducerCallbacks<TData, TArgs, TError> {
args?: TArgs;
}
type LastSuccessSavedState<TData, TArgs extends unknown[]> = InitialState<TData, TArgs> | SuccessState<TData, TArgs>;
interface BaseState<TData, TArgs extends unknown[]> {
data: TData;
status: Status;
timestamp: number;
props: ProducerSavedProps<TData, TArgs>;
}
type SuccessState<TData, TArgs extends unknown[]> = {
data: TData;
timestamp: number;
status: "success";
props: ProducerSavedProps<TData, TArgs>;
};
type ErrorState<TData, TArgs extends unknown[], TError> = {
data: TError;
timestamp: number;
status: "error";
props: ProducerSavedProps<TData, TArgs>;
};
type PendingState<TData, TArgs extends unknown[], TError> = {
data: null;
timestamp: number;
status: "pending";
props: ProducerSavedProps<TData, TArgs>;
prev: PendingPreviousState<TData, TArgs, TError>;
};
type PendingPreviousState<TData, TArgs extends unknown[], TError> = InitialState<TData, TArgs> | SuccessState<TData, TArgs> | ErrorState<TData, TArgs, TError>;
type InitialState<TData, TArgs extends unknown[]> = {
timestamp: number;
data: TData | undefined;
status: "initial";
props: ProducerSavedProps<TData, TArgs>;
};
type State<TData, TArgs extends unknown[], TError> = InitialState<TData, TArgs> | PendingState<TData, TArgs, TError> | SuccessState<TData, TArgs> | ErrorState<TData, TArgs, TError>;
type AbortFn = ((reason?: any) => void) | undefined;
type OnAbortFn<R = unknown> = (cb?: (reason?: R) => void) => void;
interface ProducerProps<TData, TArgs extends unknown[] = [], TError = Error> {
onAbort: OnAbortFn;
isAborted: () => boolean;
abort: (reason?: any) => void;
args: TArgs;
signal: AbortSignal;
payload: Record<string, unknown>;
lastSuccess: LastSuccessSavedState<TData, TArgs>;
emit(value: StateFunctionUpdater<TData, TArgs, TError> | TData, status: "initial"): void;
emit(value: null, status: "pending"): void;
emit(value: TError, status: "error"): void;
emit(value: StateFunctionUpdater<TData, TArgs, TError> | TData, status?: "success"): void;
getState: () => State<TData, TArgs, TError>;
}
type RunIndicators = {
index: number;
done: boolean;
cleared: boolean;
aborted: boolean;
};
type ProducerCallbacks<TData, TArgs extends unknown[], TError> = {
onError?(errorState: ErrorState<TData, TArgs, TError>): void;
onSuccess?(successState: SuccessState<TData, TArgs>): void;
};
type ProducerSavedProps<TData, TArgs extends unknown[]> = {
args: TArgs;
payload: Record<string, unknown> | null;
};
type Producer<TData, TArgs extends unknown[] = [], TError = Error> = (props: ProducerProps<TData, TArgs, TError>) => TData | Promise<TData>;
type ProducerFunction<TData, TArgs extends unknown[], TError> = (props: ProducerProps<TData, TArgs, TError>, runIndicators: RunIndicators, callbacks?: ProducerCallbacks<TData, TArgs, TError>) => AbortFn;
type ProducerConfig<TData, TArgs extends unknown[], TError> = {
skipPendingStatus?: boolean;
initialValue?: TData | ((cache: Record<string, CachedState<TData, TArgs, TError>> | null) => TData);
cacheConfig?: CacheConfig<TData, TArgs, TError>;
runEffectDurationMs?: number;
runEffect?: RunEffect;
keepPendingForMs?: number;
skipPendingDelayMs?: number;
resetStateOnDispose?: boolean;
context?: unknown;
hideFromDevtools?: boolean;
retryConfig?: RetryConfig<TData, TArgs, TError>;
storeInContext?: boolean;
};
type RetryConfig<TData, TArgs extends unknown[], TError> = {
enabled: boolean;
maxAttempts?: number;
backoff?: number | ((attemptIndex: number, error: TError) => number);
retry?: boolean | ((attemptIndex: number, error: TError) => boolean);
};
type StateFunctionUpdater<TData, TArgs extends unknown[], TError> = (updater: State<TData, TArgs, TError>) => TData;
type CreateSourceObject<TData, TArgs extends unknown[], TError> = {
key: string;
config?: ProducerConfig<TData, TArgs, TError>;
producer?: Producer<TData, TArgs, TError> | null;
};
interface Source<TData, TArgs extends unknown[], TError> extends BaseSource<TData, TArgs, TError> {
run(...args: TArgs): AbortFn;
runp(...args: TArgs): Promise<State<TData, TArgs, TError>>;
runc(props: RUNCProps<TData, TArgs, TError>): AbortFn;
hasLane(laneKey: string): boolean;
removeLane(laneKey?: string): boolean;
getLane(laneKey?: string): Source<TData, TArgs, TError>;
getAllLanes(): Source<TData, TArgs, TError>[];
}
type RunTask<TData, TArgs extends unknown[], TError> = {
args: TArgs;
payload: Record<string, unknown>;
};
type StateSubscription<TData, TArgs extends unknown[], TError> = {
cleanup: () => void;
props: AsyncStateSubscribeProps<TData, TArgs, TError>;
};
type OnCacheLoadProps<TData, TArgs extends unknown[], TError> = {
cache: Record<string, CachedState<TData, TArgs, TError>>;
source: Source<TData, TArgs, TError>;
};
type CacheConfig<TData, TArgs extends unknown[], TError> = {
enabled: boolean;
timeout?: ((currentState: State<TData, TArgs, TError>) => number) | number;
hash?(args: TArgs | undefined, payload: Record<string, unknown> | null | undefined): string;
auto?: boolean;
persist?(cache: Record<string, CachedState<TData, TArgs, TError>>): void;
load?(): Record<string, CachedState<TData, TArgs, TError>> | Promise<Record<string, CachedState<TData, TArgs, TError>>>;
onCacheLoad?({ cache, source }: OnCacheLoadProps<TData, TArgs, TError>): void;
};
type CachedState<TData, TArgs extends unknown[], TError> = {
state: State<TData, TArgs, TError>;
addedAt: number;
deadline: number;
id?: ReturnType<typeof setTimeout>;
};
type PendingTimeout = {
id: ReturnType<typeof setTimeout>;
at: number;
};
type PendingUpdate = {
id: ReturnType<typeof setTimeout>;
callback(): void;
};
type SetStateUpdateQueue<TData, TArgs extends unknown[], TError> = {
id?: ReturnType<typeof setTimeout>;
kind: 0;
data: State<TData, TArgs, TError>;
next: UpdateQueue<TData, TArgs, TError> | null;
callbacks?: ProducerCallbacks<TData, TArgs, TError>;
};
type SetDataUpdateQueue<TData, TArgs extends unknown[], TError> = {
id?: ReturnType<typeof setTimeout>;
kind: 2;
data: TData | ((prev: TData | null) => TData);
next: UpdateQueue<TData, TArgs, TError> | null;
};
type ReplaceStateUpdateQueue<TData, TArgs extends unknown[], TError> = {
id?: ReturnType<typeof setTimeout>;
kind: 1;
data: {
status?: Status;
data: TData | StateFunctionUpdater<TData, TArgs, TError>;
};
next: UpdateQueue<TData, TArgs, TError> | null;
callbacks?: ProducerCallbacks<TData, TArgs, TError>;
};
type UpdateQueue<TData, TArgs extends unknown[], TError> = ReplaceStateUpdateQueue<TData, TArgs, TError> | SetStateUpdateQueue<TData, TArgs, TError> | SetDataUpdateQueue<TData, TArgs, TError>;
type LibraryContext = {
ctx: any;
name?: string;
terminate(): void;
payload: Record<string, any>;
remove(key: string): boolean;
getAll(): StateInterface<any, any, any>[];
get(key: string): StateInterface<any, any, any> | undefined;
set(key: string, inst: StateInterface<any, any, any>): void;
};
export { AbortFn, AsyncStateSubscribeProps, BaseSource, BaseState, CacheConfig, CachedState, CreateSourceObject, ErrorState, HydrationData, InitialState, InstanceCacheChangeEvent, InstanceCacheChangeEventHandlerType, InstanceChangeEvent, InstanceChangeEventHandlerType, InstanceChangeEventObject, InstanceDisposeEvent, InstanceDisposeEventHandlerType, InstanceEvents, LastSuccessSavedState, LibraryContext, OnAbortFn, OnCacheLoadProps, PendingPreviousState, PendingState, PendingTimeout, PendingUpdate, Producer, ProducerCallbacks, ProducerConfig, ProducerFunction, ProducerProps, ProducerSavedProps, PromiseLike, RUNCProps, ReplaceStateUpdateQueue, RetryConfig, RunIndicators, RunTask, SetDataUpdateQueue, SetStateUpdateQueue, Source, SourceHydration, State, StateChangeEventHandler, StateFunctionUpdater, StateInterface, StateSubscription, SuccessState, UpdateQueue };