import { Unsubscribe } from 'nanoevents' import { Client, ClientMeta } from '@logux/client' import { Action, AnyAction, Log } from '@logux/core' import { CommitOptions, Store as VuexStore, Commit as VuexCommit, Payload as VuexPayload, Dispatch as VuexDispatch, StoreOptions as VuexStoreOptions, ActionContext as VuexActionContext } from 'vuex' export type LoguxVuexAction = AnyAction & VuexPayload export interface LoguxVuexCommit extends VuexCommit { (type: string, payload?: any, options?: CommitOptions): void (payloadWithType: A, options?: CommitOptions): void /** * Adds sync action to log and updates store state. * This action will be visible only for server and all browser tabs. * * ```js * store.commit.sync( * { type: 'CHANGE_NAME', name }, * { reasons: ['lastName'] } * ).then(meta => { * store.log.removeReason('lastName', { maxAdded: meta.added - 1 }) * }) * ``` * * @param type Action type. * @param payload Action’s payload. * @param meta Action’s metadata. * @returns Promise when action will be processed by the server. */ sync( type: string, payload?: any, meta?: Partial ): Promise /** * @param action Action. * @param meta Action’s metadata. */ sync( action: A, meta?: Partial ): Promise /** * Adds cross-tab action to log and updates store state. * This action will be visible only for all tabs. * * ```js * store.commit.crossTab( * { type: 'CHANGE_FAVICON', favicon }, * { reasons: ['lastFavicon'] } * ).then(meta => { * store.log.removeReason('lastFavicon', { maxAdded: meta.added - 1 }) * }) * ``` * * @param type Action type. * @param payload Action’s payload. * @param meta Action’s metadata. * @returns Promise when action will be processed by the server. */ crossTab( type: string, payload?: any, meta?: Partial ): Promise /** * @param action Action. * @param meta Action’s metadata. */ crossTab( action: A, meta?: Partial ): Promise /** * Adds local action to log and updates store state. * This action will be visible only for current tab. * * ```js * * store.commit.local( * { type: 'OPEN_MENU' }, * { reasons: ['lastMenu'] } * ).then(meta => { * store.log.removeReason('lastMenu', { maxAdded: meta.added - 1 }) * }) * ``` * * @param type Action type. * @param payload Action’s payload. * @param meta Action’s metadata. * @returns Promise when action will be processed by the server. */ local( type: string, payload?: any, meta?: Partial ): Promise /** * @param action Action. * @param meta Action’s metadata. */ local( action: A, meta?: Partial ): Promise } interface StateListener { ( state: S, prevState: S, action: A, meta: ClientMeta ): void } export interface LoguxVuexActionContext extends VuexActionContext { commit: LoguxVuexCommit } export type LoguxVuexActionHandler = ( this: LoguxVuexStore, injectee: LoguxVuexActionContext, payload?: any ) => any export interface LoguxVuexActionObject { root?: boolean handler: LoguxVuexActionHandler } export type LoguxVuexNativeAction = | LoguxVuexActionHandler | LoguxVuexActionObject export interface LoguxVuexActionTree { [key: string]: LoguxVuexNativeAction } export interface LoguxVuexStoreOptions extends Omit, 'actions'> { actions?: LoguxVuexActionTree } export class LoguxVuexStore< S = any, L extends Log = Log, C extends Client = Client<{}, L> > extends VuexStore { constructor(options: LoguxVuexStoreOptions) dispatch: VuexDispatch /** * Add action to log with Vuex compatible API. */ commit: LoguxVuexCommit /** * Subscribes 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: StateListener): Unsubscribe /** * Logux synchronization client. */ client: C /** * The Logux log. */ log: L /** * Promise until loading the state from log store. */ initialize: Promise } export interface LoguxVuexOptions { /** * 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 } /** * Vuex’s `createStore` function, compatible with Logux Client. * * @param options Vuex store options. * @returns Vuex store, compatible with Logux Client. */ export interface createStore< L extends Log = Log, C extends Client = Client<{}, L> > { (options: LoguxVuexStoreOptions): LoguxVuexStore } /** * Connects Logux client to Vuex’s `createStore` function. * * ```js * import { CrossTabClient } from '@logux/client' * import { createStoreCreator } from '@logux/vuex' * * const client = new CrossTabClient({ * server: process.env.NODE_ENV === 'development' * ? 'ws://localhost:31337' * : 'wss://logux.example.com', * subprotocol: '1.0.0', * userId: 'anonymous', * token: '' * }) * * const createStore = createStoreCreator(client) * * const store = createStore({ * state: {}, * mutations: {}, * actions: {}, * modules: {} * }) * * store.client.start() * ``` * * @param client Logux Client. * @param options Logux Vuex options. * @returns Vuex’s `createStore` function, compatible with Logux Client. */ export function createStoreCreator< L extends Log = Log, C extends Client = Client<{}, L> >(client: C, options?: LoguxVuexOptions): createStore