import { AnyAction, Action, Reducer, Observable, StoreEnhancer, PreloadedState, Store as ReduxStore } from 'redux' import { Client, ClientMeta } from '@logux/client' import { Unsubscribe } from 'nanoevents' import { Log } from '@logux/core' export interface LoguxDispatch { (action: T): T /** * Add sync action to log and update store state. * This action will be visible only for server and all browser tabs. * * ```js * store.dispatch.sync( * { type: 'CHANGE_NAME', name }, * { reasons: ['lastName'] } * ).then(meta => { * store.log.removeReason('lastName', { maxAdded: meta.added - 1 }) * }) * ``` * * @param action The new action. * @param meta Action’s metadata. * @returns Promise when action will be processed by the server. */ sync(action: T, meta?: Partial): Promise /** * Add cross-tab action to log and update store state. * This action will be visible only for all tabs. * * ```js * store.dispatch.crossTab( * { type: 'CHANGE_FAVICON', favicon }, * { reasons: ['lastFavicon'] } * ).then(meta => { * store.log.removeReason('lastFavicon', { maxAdded: meta.added - 1 }) * }) * ``` * * @param action The new action. * @param meta Action’s metadata. * @returns Promise when action will be saved to the log. */ crossTab( action: T, meta?: Partial ): Promise /** * Add local action to log and update store state. * This action will be visible only for current tab. * * ```js * * store.dispatch.local( * { type: 'OPEN_MENU' }, * { reasons: ['lastMenu'] } * ).then(meta => { * store.log.removeReason('lastMenu', { maxAdded: meta.added - 1 }) * }) * ``` * * @param action The new action. * @param meta Action’s metadata. * @returns Promise when action will be saved to the log. */ local(action: T, meta?: Partial): Promise } export interface ReduxStateListener { (state: S, prevState: S, action: A, meta: ClientMeta): void } export class LoguxReduxStore< S = any, A extends Action = AnyAction, L extends Log = Log, C extends Client = Client<{}, L> > implements ReduxStore { /** * Logux synchronization client. */ client: C /** * The Logux log. */ log: L /** * Promise until loading the state from IndexedDB. */ initialize: Promise /** * Add action to log with Redux compatible API. */ dispatch: LoguxDispatch /** * Subscribe for store events. Supported events: * * * `change`: when store was changed by action. * * ```js * store.on('change', (state, prevState, action, meta) => { * console.log(state, prevState, action, meta) * }) * ``` * * @param event The event name. * @param listener The listener function. * @returns Unbind listener from event. */ on(event: 'change', listener: ReduxStateListener): Unsubscribe /** * Reads the state tree managed by the store. * * @returns The current state tree of your application. */ getState(): S /** * Adds a change listener. * * @param listener A callback to be invoked on every dispatch. * @returns A function to remove this change listener. */ subscribe(listener: () => void): Unsubscribe /** * Replaces the reducer currently used by the store to calculate the state. * * @param nextReducer The reducer for the store to use instead. */ replaceReducer(nextReducer: Reducer): void [Symbol.observable](): Observable } export interface LoguxStoreCreator< L extends Log = Log, C extends Client = Client<{}, L> > { ( reducer: Reducer, enhancer?: StoreEnhancer ): LoguxReduxStore & Ext ( reducer: Reducer, preloadedState?: PreloadedState, enhancer?: StoreEnhancer ): LoguxReduxStore & Ext } export type LoguxReduxOptions = { /** * How many actions without `meta.reasons` will be kept for time travel. * Default is `1000`. */ reasonlessHistory?: number /** * How often save state to history. Default is `50`. */ saveStateEvery?: number /** * Callback when there is no history to replay actions accurate. */ onMissedHistory?: (action: Action) => void /** * How often we need to clean log from old actions. Default is every `25` * actions. */ cleanEvery?: number } /** * Connects Logux Client to Redux createStore function. * * ```js * import { CrossTabClient, createStoreCreator } from '@logux/redux' * * const client = new CrossTabClient({ * subprotocol: '1.0.0', * server: process.env.NODE_ENV === 'development' * ? 'ws://localhost:31337' * : 'wss://logux.example.com', * userId: userId.content * token: token.content * }) * * const createStore = createStoreCreator(client) * * const store = createStore(reducer) * store.client.start() * ``` * * @param client Logux Client. * @param options Logux Redux options. * @returns Redux’s `createStore` compatible function. */ export function createStoreCreator< L extends Log = Log, C extends Client = Client<{}, L> >(client: C, options?: LoguxReduxOptions): LoguxStoreCreator