@legendapp/state
Version:
365 lines (364 loc) • 15.7 kB
TypeScript
import type { MMKVConfiguration } from 'react-native-mmkv';
import type { AsyncStorageStatic } from '@react-native-async-storage/async-storage';
import type { DatabaseReference, Query } from 'firebase/database';
import type { symbolGetNode, symbolOpaque } from './globals';
type Nullable<T> = T | null | undefined;
export type TrackingType = undefined | true | symbol;
export interface MapGet<T extends Map<any, any> | WeakMap<any, any>> {
get(key: Parameters<T['get']>[0]): ObservableChild<Parameters<T['set']>[1]>;
get(): T;
size: ObservableChild<number>;
}
export interface GetOptions {
shallow: boolean;
}
export interface ObservableBaseFns<T> {
peek(): T;
get(options?: TrackingType | GetOptions): T;
onChange(cb: ListenerFn<T>, options?: {
trackingType?: TrackingType;
initial?: boolean;
immediate?: boolean;
noArgs?: boolean;
}): ObservableListenerDispose;
}
export interface ObservablePrimitiveBaseFns<T> extends ObservableBaseFns<T> {
delete(): ObservablePrimitiveBaseFns<T>;
set(value: Nullable<T> | CallbackSetter<T> | Promise<T>): ObservablePrimitiveChild<T>;
}
export interface ObservablePrimitiveBooleanFns<T> {
toggle(): T;
}
export interface ObservableObjectFns<T> extends ObservableBaseFns<T> {
set(value: Nullable<T> | CallbackSetter<T> | Promise<T>): ObservableChild<T>;
assign(value: T | Partial<T>): ObservableChild<T>;
delete(): ObservableChild<T>;
}
export type ObservablePrimitive<T> = [T] extends [boolean] ? ObservablePrimitiveBaseFns<T> & ObservablePrimitiveBooleanFns<T> : ObservablePrimitiveBaseFns<T>;
export interface ObservablePrimitiveChildFns<T> extends ObservablePrimitiveBaseFns<T> {
delete(): ObservablePrimitiveChild<T>;
}
type CallbackSetter<T> = {
bivarianceHack(prev: T): T;
}['bivarianceHack'];
export type OpaqueObject<T> = T & {
[symbolOpaque]: true;
};
type ArrayOverrideFnNames = 'find' | 'every' | 'some' | 'filter' | 'reduce' | 'reduceRight' | 'forEach' | 'map';
type RemoveIndex<T> = {
[K in keyof T as string extends K ? never : number extends K ? never : K]: T[K];
};
export type ObservableArrayOverride<T> = Omit<RemoveIndex<Array<T>>, ArrayOverrideFnNames> & Pick<Array<Observable<T>>, ArrayOverrideFnNames> & {
[n: number]: Observable<T>;
};
export interface ListenerParams<T = any> {
value: T;
getPrevious: () => T;
changes: Change[];
}
export type ListenerFn<T = any> = (params: ListenerParams<T>) => void;
type PrimitiveKeys<T> = Pick<T, {
[K in keyof T]-?: T[K] extends Primitive ? K : never;
}[keyof T]>;
type NonPrimitiveKeys<T> = Pick<T, {
[K in keyof T]-?: T[K] extends Primitive ? never : K;
}[keyof T]>;
type Recurse<T, K extends keyof T, TRecurse> = T[K] extends ObservableReadable ? T[K] : T[K] extends Promise<infer t> ? Observable<t & WithState> : T[K] extends Function ? T[K] : T[K] extends ObservableProxyTwoWay<infer t, infer t2> ? ObservableProxyTwoWay<t, t2> : T[K] extends ObservableProxy<infer t> ? ObservableProxy<t> : T[K] extends ObservableProxyLink<infer t> ? ObservableProxyLink<t> : T[K] extends Map<any, any> | WeakMap<any, any> ? ObservableMap<T[K]> : T[K] extends Set<any> | WeakSet<any> ? ObservableSet<T[K]> : T[K] extends Set<any> | WeakSet<any> ? T[K] & ObservablePrimitiveBaseFns<T[K]> : T[K] extends OpaqueObject<T[K]> ? T[K] & ObservablePrimitiveChildFns<T[K]> : T[K] extends Primitive ? ObservablePrimitiveChild<T[K]> : T[K] extends Array<any> ? ObservableObjectFns<T[K]> & ObservableArrayOverride<T[K][number]> : T extends object ? TRecurse : T[K];
type ObservableFnsRecursiveUnsafe<T> = {
[K in keyof T]-?: Recurse<T, K, ObservableObject<NonNullable<T[K]>>>;
};
type ObservableFnsRecursiveSafe<T> = {
readonly [K in keyof T]-?: Recurse<T, K, ObservableObject<NonNullable<T[K]>>>;
};
type ObservableFnsRecursive<T> = ObservableFnsRecursiveSafe<NonPrimitiveKeys<T>> & ObservableFnsRecursiveUnsafe<PrimitiveKeys<T>>;
type ObservableComputedFnsRecursive<T> = {
readonly [K in keyof T]-?: Recurse<T, K, ObservableBaseFns<NonNullable<T[K]>>>;
};
export interface ObservableEvent {
fire(): void;
on(cb?: () => void): ObservableListenerDispose;
get(): void;
}
export type QueryByModified<T> = boolean | {
[K in keyof T]?: QueryByModified<T[K]>;
} | {
'*'?: boolean;
};
export type TypeAtPath = 'object' | 'array' | 'map' | 'set';
export interface Change {
path: string[];
pathTypes: TypeAtPath[];
valueAtPath: any;
prevAtPath: any;
}
export interface PersistTransform<T = any> {
in?: (value: T) => T | Promise<T>;
out?: (value: T) => T | Promise<T>;
}
export interface PersistOptionsLocal<T = any> {
name: string;
transform?: PersistTransform<T>;
fieldTransforms?: FieldTransforms<T>;
readonly?: boolean;
mmkv?: MMKVConfiguration;
indexedDB?: {
prefixID?: string;
itemID?: string;
};
options?: any;
}
export type PersistOptionsRemote<T = any> = ObservablePersistenceConfigRemoteGlobalOptions & {
readonly?: boolean;
waitForGet?: Promise<any> | ObservableReadable<any>;
waitForSet?: Promise<any> | ObservableReadable<any>;
manual?: boolean;
fieldTransforms?: FieldTransforms<T>;
allowSetIfError?: boolean;
transform?: PersistTransform<T>;
firebase?: {
refPath: (uid: string | undefined) => string;
query?: (ref: DatabaseReference) => DatabaseReference | Query;
queryByModified?: QueryByModified<T>;
ignoreKeys?: string[];
requireAuth?: boolean;
mode?: 'once' | 'realtime';
};
offlineBehavior?: false | 'retry';
changeTimeout?: number;
onGetError?: (error: Error) => void;
onSetError?: (error: Error) => void;
log?: (message?: any, ...optionalParams: any[]) => void;
onBeforeSet?: () => void;
onSet?: () => void;
};
export interface ObservablePersistenceConfigLocalGlobalOptions {
onGetError?: (error: Error) => void;
onSetError?: (error: Error) => void;
indexedDB?: {
databaseName: string;
version: number;
tableNames: string[];
};
asyncStorage?: {
AsyncStorage: AsyncStorageStatic;
preload?: boolean | string[];
};
}
export interface ObservablePersistenceConfigRemoteGlobalOptions {
saveTimeout?: number;
dateModifiedKey?: string;
offlineBehavior?: false | 'retry';
onGetError?: (error: Error) => void;
onSetError?: (error: Error) => void;
log?: (logLevel: 'verbose' | 'warning' | 'error', message: any, ...optionalParams: any[]) => void;
onBeforeSet?: () => void;
onSet?: () => void;
}
export interface ObservablePersistenceConfig {
pluginLocal?: ClassConstructor<ObservablePersistLocal>;
pluginRemote?: ClassConstructor<ObservablePersistRemoteClass> | ObservablePersistRemoteFunctions;
localOptions?: ObservablePersistenceConfigLocalGlobalOptions;
remoteOptions?: ObservablePersistenceConfigRemoteGlobalOptions;
}
export interface PersistOptions<T = any> {
local?: string | PersistOptionsLocal<T>;
remote?: PersistOptionsRemote<T>;
pluginLocal?: ClassConstructor<ObservablePersistLocal>;
pluginRemote?: ClassConstructor<ObservablePersistRemoteClass> | ObservablePersistRemoteFunctions<T>;
}
export interface PersistMetadata {
id?: '__legend_metadata';
modified?: number;
pending?: any;
}
export interface ObservablePersistLocal {
initialize?(config: ObservablePersistenceConfigLocalGlobalOptions): void | Promise<void>;
loadTable?(table: string, config: PersistOptionsLocal): Promise<any> | void;
getTable<T = any>(table: string, config: PersistOptionsLocal, init: object): T;
set(table: string, changes: Change[], config: PersistOptionsLocal): Promise<any> | void;
deleteTable(table: string, config: PersistOptionsLocal): Promise<any> | void;
getMetadata(table: string, config: PersistOptionsLocal): PersistMetadata;
setMetadata(table: string, metadata: PersistMetadata, config: PersistOptionsLocal): Promise<any> | void;
deleteMetadata(table: string, config: PersistOptionsLocal): Promise<any> | void;
}
export interface ObservablePersistRemoteSetParams<T> {
syncState: Observable<ObservablePersistState>;
obs: Observable<T>;
options: PersistOptions<T>;
changes: Change[];
value: T;
}
export interface ObservablePersistRemoteGetParams<T> {
state: Observable<ObservablePersistState>;
obs: ObservableReadable<T>;
options: PersistOptions<T>;
dateModified?: number;
onGet: () => void;
onChange: (params: {
value: unknown;
path?: string[];
pathTypes?: TypeAtPath[];
mode?: 'assign' | 'set' | 'dateModified';
dateModified?: number | undefined;
}) => void | Promise<void>;
}
export type ObservablePersistRemoteGetFnParams<T> = Omit<ObservablePersistRemoteGetParams<T>, 'onGet'>;
export interface ObservablePersistRemoteClass {
get?<T>(params: ObservablePersistRemoteGetParams<T>): void;
set?<T>(params: ObservablePersistRemoteSetParams<T>): void | Promise<void | {
changes?: object;
dateModified?: number;
pathStrs?: string[];
}>;
}
export interface ObservablePersistRemoteFunctions<T = any> {
get?(params: ObservablePersistRemoteGetFnParams<T>): T | Promise<T>;
set?(params: ObservablePersistRemoteSetParams<T>): void | Promise<void | {
changes?: object | undefined;
dateModified?: number;
}>;
}
export interface ObservableState {
isLoaded: boolean;
error?: Error;
}
export interface WithState {
state?: ObservableState;
_state?: ObservableState;
}
export interface ObservablePersistState extends ObservableState {
isLoadedLocal: boolean;
isEnabledLocal: boolean;
isEnabledRemote: boolean;
dateModified?: number;
clearLocal: () => Promise<void>;
sync: () => Promise<void>;
getPendingChanges: () => Record<string, {
p: any;
v?: any;
}> | undefined;
}
export interface WithPersistState {
state?: ObservablePersistState;
_state?: ObservablePersistState;
}
export type RecordValue<T> = T extends Record<string, infer t> ? t : never;
export type ArrayValue<T> = T extends Array<infer t> ? t : never;
export type ObservableValue<T> = T extends Observable<infer t> ? t : never;
declare type ObjectKeys<T> = Pick<T, {
[K in keyof T]-?: K extends string ? T[K] extends Record<string, any> ? T[K] extends any[] ? never : K : never : never;
}[keyof T]>;
declare type DictKeys<T> = Pick<T, {
[K in keyof T]-?: K extends string ? (T[K] extends Record<string, Record<string, any>> ? K : never) : never;
}[keyof T]>;
declare type ArrayKeys<T> = Pick<T, {
[K in keyof T]-?: K extends string | number ? (T[K] extends any[] ? K : never) : never;
}[keyof T]>;
export declare type FieldTransforms<T> = (T extends Record<string, Record<string, any>> ? {
_dict: FieldTransformsInner<RecordValue<T>>;
} : never) | FieldTransformsInner<T>;
export declare type FieldTransformsInner<T> = {
[K in keyof T]: string;
} & ({
[K in keyof ObjectKeys<T> as `${K}_obj`]?: FieldTransforms<T[K]>;
} | {
[K in keyof DictKeys<T> as `${K}_dict`]?: FieldTransforms<RecordValue<T[K]>>;
}) & {
[K in keyof ArrayKeys<T> as `${K}_arr`]?: FieldTransforms<ArrayValue<T[K]>>;
} & {
[K in keyof ArrayKeys<T> as `${K}_val`]?: FieldTransforms<ArrayValue<T[K]>>;
};
export type Selector<T> = ObservableReadable<T> | ObservableEvent | (() => T) | T;
export type ClassConstructor<I, Args extends any[] = any[]> = new (...args: Args) => I;
export type ObservableListenerDispose = () => void;
export interface ObservableRoot {
_: any;
locked?: boolean;
toActivate?: NodeValue[];
set?: (value: any) => void;
activate?: () => void;
}
export type Primitive = boolean | string | number | Date;
export type NotPrimitive<T> = T extends Primitive ? never : T;
export type ObservableMap<T extends Map<any, any> | WeakMap<any, any>> = Omit<T, 'get' | 'size'> & Omit<ObservablePrimitiveBaseFns<T>, 'get' | 'size'> & MapGet<T>;
export type ObservableSet<T extends Set<any> | WeakSet<any>> = Omit<T, 'size'> & Omit<ObservablePrimitiveBaseFns<T>, 'size'> & {
size: ObservablePrimitiveChild<number>;
};
export type ObservableMapIfMap<T> = T extends Map<any, any> | WeakMap<any, any> ? ObservableMap<T> : never;
export type ObservableArray<T extends any[]> = ObservableObjectFns<T> & ObservableArrayOverride<T[number]>;
export type ObservableObject<T = any> = ObservableFnsRecursive<T> & ObservableObjectFns<T>;
export type ObservableChild<T = any> = [T] extends [Primitive] ? ObservablePrimitiveChild<T> : ObservableObject<T>;
export type ObservablePrimitiveChild<T = any> = [T] extends [boolean] ? ObservablePrimitiveChildFns<T> & ObservablePrimitiveBooleanFns<T> : ObservablePrimitiveChildFns<T>;
export type ObservableObjectOrArray<T> = T extends Map<any, any> | WeakMap<any, any> ? ObservableMap<T> : T extends Set<any> | WeakSet<any> ? ObservableSet<T> : T extends any[] ? ObservableArray<T> : ObservableObject<T>;
export type ObservableComputed<T = any> = ObservableBaseFns<T> & ObservableComputedFnsRecursive<T>;
export type ObservableComputedTwoWay<T = any, T2 = T> = ObservableComputed<T> & ObservablePrimitiveBaseFns<T2>;
type Equals<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;
export type Observable<T = any> = Equals<T, any> extends true ? ObservableObject<any> : [T] extends [object] ? ObservableObjectOrArray<T> : ObservablePrimitive<T>;
export type ObservableReadable<T = any> = ObservableBaseFns<T> | ObservablePrimitiveBaseFns<T> | ObservablePrimitiveChildFns<T> | ObservableObjectFns<T> | ObservableMapIfMap<T>;
export type ObservableWriteable<T = any> = ObservableReadable<T> & {
set(value: Nullable<T> | CallbackSetter<T> | Promise<T>): any;
delete?: () => any;
};
export interface NodeValueListener {
track: TrackingType;
noArgs?: boolean;
listener: ListenerFn;
}
interface BaseNodeValue {
children?: Map<string, ChildNodeValue>;
proxy?: object;
isActivatedPrimitive?: boolean;
root: ObservableRoot;
listeners?: Set<NodeValueListener>;
listenersImmediate?: Set<NodeValueListener>;
isComputed?: boolean;
proxyFn?: (key: string) => ObservableReadable;
isEvent?: boolean;
linkedToNode?: NodeValue;
linkedFromNodes?: Set<NodeValue>;
isSetting?: number;
isAssigning?: number;
parentOther?: NodeValue;
functions?: Map<string, Function | ObservableComputed<any>>;
lazy?: boolean;
state?: Observable<ObservableState>;
}
export interface RootNodeValue extends BaseNodeValue {
parent?: undefined;
key?: undefined;
}
export interface ChildNodeValue extends BaseNodeValue {
parent: NodeValue;
key: string;
}
export type NodeValue = RootNodeValue | ChildNodeValue;
export interface ObserveEvent<T> {
num: number;
previous?: T | undefined;
cancel?: boolean;
onCleanup?: () => void;
}
export interface ObserveEventCallback<T> {
num: number;
previous?: T | undefined;
value?: T;
cancel?: boolean;
onCleanup?: () => void;
onCleanupReaction?: () => void;
}
export type ObservableProxy<T extends Record<string, any>> = {
[K in keyof T]: ObservableComputed<T[K]>;
} & ObservableBaseFns<T> & {
[symbolGetNode]: NodeValue;
};
export type ObservableProxyLink<T extends Record<string, any>> = {
[K in keyof T]: Observable<T[K]>;
} & ObservableBaseFns<T> & {
[symbolGetNode]: NodeValue;
};
export type ObservableProxyTwoWay<T extends Record<string, any>, T2> = {
[K in keyof T]: ObservableComputedTwoWay<T[K], T2>;
} & ObservableBaseFns<T> & {
[symbolGetNode]: NodeValue;
};
export {};