statekit-lite
Version:
Minimal proxy-based global state manager for React with nested access, persist, watch, devtools, and realtime sync via plugins.
167 lines (162 loc) • 5.3 kB
TypeScript
type ValueOrUpdater<T> = T | ((prev: T) => T);
type StorePlugin = (store: ProxyState<any>) => void;
type PersistConfig = boolean | {
key: string;
};
type Unsubscribe = () => void;
type ProxyState<T> = {
/**
* 🔗 `.get()` — object references
* 🗐 `.get(true)` — structured clone
*/
get: (clone?: boolean) => T;
/**
* 📌 `.set(value)` — direct replace
* 🔁 `.set(prev => next)` — functional update
* 🧠 `.set(draft => { draft.x = 1 })` — safe mutation via Immer
*/
set: (value: ValueOrUpdater<T>) => void;
/**
* ✏️ Direct updater, same as `.set(prev => fn(prev))`
*/
update: (fn: (prev: T) => T) => void;
/**
* ⚛️ React hook that subscribes to this value. Automatically triggers re-render when value changes
*
* 📌 Must be called inside a React component or hook
* Equivalent to `.get()` but reactive
*
* @returns Current value of the state at this path
*/
use: () => T;
/**
* 👁 Subscribes to external (non-React) changes
* Useful for triggering side effects when value changes
*
* @returns Unsubscribe function
* @example
* const unsub = state.user.name.watch((val) => console.log(val));
* unsub();
*/
watch: (fn: (val: T, unsub: () => void) => void) => Unsubscribe;
/**
* 🗐 Returns a deep cloned plain value
* Functions and components are preserved by reference
*/
export: () => T;
} & (T extends object ? {
[K in keyof T]: ProxyState<T[K]>;
} : {});
interface StoreOptions {
/** 🛢️ localStorage `{key: 'myState'}` */
persist?: PersistConfig;
/** ⚛️ enable redux dev tool log */
devtools?: boolean | {
name: string;
};
/** 🔧 default: false */
immer?: boolean;
/**
* 🧩 array plugins function
*/
plugins?: StorePlugin[];
}
declare function createStore<T extends object>(initialValue: T, options?: StoreOptions): ProxyState<T>;
type SSEPluginOptions<T> = {
/** 🌐 URL path endpoint SSE */
url: string;
/** Path inside the store, e.g., ['messages'] or ['chat', 'list'] */
path?: (string | number)[];
/** Transforms incoming data before applying to the store */
mapper?: (data: any) => T;
/**
* Mode:
* - 'set' (default): replaces the store value
* - 'push': appends to an array
*/
mode?: 'set' | 'push';
/** Enables debug logging */
debug?: boolean;
};
declare function ssePlugin<T = any>(options: SSEPluginOptions<T>): StorePlugin;
interface SyncPluginOptions<T = any> {
/**
* Subscribes to remote data source (e.g. SSE, WebSocket, polling).
* You must call `emit(data)` whenever new data arrives.
* Returns an unsubscribe function.
*/
subscribe: (emit: (data: T | ((prev: T) => T)) => void) => () => void;
/**
* Optional: pushes local store changes to a remote destination.
* Called every time the specified store path is updated.
*/
pushUpdate?: (data: T) => void;
/**
* Optional: transforms incoming data before setting it to the store.
*/
mapper?: (incoming: any) => T;
/**
* Optional: path to the specific store key you want to sync.
* Example: ['chat', 'messages'] to target store.chat.messages.
* If omitted, the root store will be used.
*/
path?: (string | number)[];
/**
* Optional: enables debug logging for all incoming/outgoing events.
*/
debug?: boolean;
}
/**
* Creates a synchronization plugin for statekit-lite.
*
* This plugin allows you to connect a piece of store state to a remote source,
* such as Server-Sent Events, WebSocket, or polling, and optionally push updates
* back to the server whenever the state changes.
*
* You can specify a nested path within the store to target a specific key,
* and customize the synchronization behavior via optional mapper and debug options.
*
* @param options - Configuration for data subscription and update behavior
* @returns A store plugin function compatible with statekit-lite
*/
declare function syncPlugin<T>(options: SyncPluginOptions<T>): StorePlugin;
type SupabaseGlobalPluginOptions = {
/**
* Supabase project URL (e.g., https://your-project.supabase.co)
*/
url: string;
/**
* Supabase public anon key for client-side access
*/
anon_key: string;
/**
* The table name where the data will be synced
* (e.g., 'kv_store')
*/
table: string;
/**
* The name of the primary key column used to identify rows
* Default is 'key'
*/
primary_key?: string;
/**
* The value of the primary key to target
* This uniquely identifies the row for this store instance
*/
key: string;
/**
* in milliseconds (0 = disabled by default)
*/
polling?: number;
/**
* The column name where the store state will be stored
* Default is 'value'
*/
field?: string;
/**
* Enables debug logging to console
*/
debug?: boolean;
};
declare function supabaseGlobalPlugin(options: SupabaseGlobalPluginOptions): StorePlugin;
export { createStore, ssePlugin, supabaseGlobalPlugin as supabasePlugin, syncPlugin };