UNPKG

@persevie/statemanjs

Version:

Proper state manager for JavaScript

206 lines (198 loc) 8.04 kB
type Transaction<T> = { number: number; snapshot: T; timestamp: number; }; type TransactionDiff<T> = { old: T; new: T; }; /** * Interface for a transaction API that stores state history in a chain * (with a configurable length) and allows for receiving diffs and rolling back changes. * * @template T - The type of the state being managed by the transactions. */ interface TransactionAPI<T> { /** * The total number of transactions that have occurred since the state was initialized. */ totalTransactions: number; /** * Adds a new transaction to the transaction chain. * * @param {T} snapshot - The snapshot of the state to be added as a transaction. */ addTransaction(snapshot: T): void; /** * Retrieves the last transaction in the transaction chain. * * @returns {Transaction<T> | null} The last transaction, or null if there are no transactions. */ getLastTransaction(): Transaction<T> | null; /** * Retrieves all transactions that have occurred. * * @returns {Transaction<T>[]} An array of all transactions. */ getAllTransactions(): Transaction<T>[]; /** * Retrieves a specific transaction by its number in the transaction chain. * * @param {number} transactionNumber - The number of the transaction to retrieve. * @returns {Transaction<T> | null} The transaction with the specified number, or null if it doesn't exist. */ getTransactionByNumber(transactionNumber: number): Transaction<T> | null; /** * Retrieves the difference between the current state and the last transaction. * * @returns {TransactionDiff<T> | null} The difference between the current state and the last transaction, or null if there are no transactions. */ getLastDiff(): TransactionDiff<T> | null; /** * Retrieves the difference between two specific transactions. * * @param {number} transactionA - The number of the first transaction. * @param {number} transactionB - The number of the second transaction. * @returns {TransactionDiff<T> | null} The difference between the two specified transactions, or null if the transactions don't exist or there is no difference. */ getDiffBetween(transactionA: number, transactionB: number): TransactionDiff<T> | null; } interface DebugAPI<T> { transactionService: TransactionAPI<T>; } /** * A callback function that will be called every time the state changes. * Can take the updated state as an argument. */ type SubscriptionCb<T> = (newState: T) => void; /** * A callback function for unsubscribing. */ type UnsubscribeCb = () => void; /** Callback for state updates. */ type UpdateCb<T> = (state: T) => void; /** * It may contain additional information about the subscriber, * as well as a condition for notification, a mark that the subscriber is protected and properties to watch. */ type SubscriptionOptions<T> = { notifyCondition?: (state: T) => boolean; protect?: boolean; properties?: Array<string>; }; type CustomComparator<T> = (a: T, b: T) => boolean; type DefaultComparator = "none" | "ref" | "shallow" | "custom"; type BaseModifyOptions<T> = { skipComparison?: boolean; comparatorOverride?: DefaultComparator; customComparatorOverride?: CustomComparator<T>; afterUpdate: () => void; }; type SetOptions<T> = Omit<BaseModifyOptions<T>, "afterUpdate">; type UpdateOptions<T> = Omit<BaseModifyOptions<T>, "afterUpdate">; interface StatemanjsComputedAPI<T> { /** Get current state */ get(): T; /** * The method of subscribing to the status change. * Accepts a callback function (subscription callback), * which will be called at each update, and a subscription options object. * In the options, you can specify information about the subscription, * as well as specify the condition under which the subscriber will be notified * and mark the subscriber as protected. All subscribers are unprotected by default. * Protected subscribers can only be unsubscribed using the unsubscribe method returned by this method. * Returns the unsubscribe callback function. * * @param subscriptionCb A function that runs on every update. * @param subscriptionOptions Additional information and notification condition. * @returns Unsubscribe callback function. */ subscribe(subscriptionCb: SubscriptionCb<T>, subscriptionOptions?: SubscriptionOptions<T>): UnsubscribeCb; /** Remove all unprotected subscribers */ unsubscribeAll(): void; /** * Returns count of all active subscribers. * @returns number. */ getActiveSubscribersCount(): number; /** * Unwrap a proxy object to a regular JavaScript object * @returns unwrapped state */ unwrap(): T; } /** * Public API. * Interacts with the @see {StatemanjsBaseAPI}. */ interface StatemanjsAPI<T> { /** * Accepts a new state and compares it with the current one. * Nothing will happen if the passed value is equal to the current one. * @param newState New state. * @returns Status of operation. */ set(newState: T, options?: SetOptions<T>): boolean; /** Get current state */ get(): T; /** * The method of subscribing to the status change. * Accepts a callback function (subscription callback), * which will be called at each update, and a subscription options object. * In the options, you can specify information about the subscription, * as well as specify the condition under which the subscriber will be notified * and mark the subscriber as protected. All subscribers are unprotected by default. * Protected subscribers can only be unsubscribed using the unsubscribe method returned by this method. * Returns the unsubscribe callback function. * * @param subscriptionCb A function that runs on every update. * @param subscriptionOptions Additional information and notification condition. * @returns Unsubscribe callback function. */ subscribe(subscriptionCb: SubscriptionCb<T>, subscriptionOptions?: SubscriptionOptions<T>): UnsubscribeCb; /** Remove all unprotected subscribers */ unsubscribeAll(): void; /** * Returns count of all active subscribers. * @returns number. */ getActiveSubscribersCount(): number; /** * Flexible state update. * @param updateCb Callback for state updates. */ update(updateCb: UpdateCb<T>, options?: UpdateOptions<T>): boolean; /** * Unwrap a proxy object to a regular JavaScript object * @returns unwrapped state */ unwrap(): T; /** * Dispatch an async action * @param action An async action. It accepts a stateManager object, * which is used to access the current state. * @returns Promise. */ asyncAction(action: (stateManager: StatemanjsAPI<T>) => Promise<void>): Promise<void>; /** * Create a computed state for a state property. * @param selectorFn A function that returns a value of a state property. * @returns A computed state. */ createSelector<E>(selectorFn: (state: T) => E, subscriptionOptions?: SubscriptionOptions<unknown>): StatemanjsComputedAPI<E>; /** * Debug API. Allows you to use additional debugging functionality such as transactions. * Parameters are set when creating the state. * @see {DebugAPI} */ DEBUG?: DebugAPI<T>; } type StatemanjsOptions<T> = { transactionsLen?: number; customComparator?: CustomComparator<T>; defaultComparator?: DefaultComparator; }; declare function createState<T>(element: T, options?: StatemanjsOptions<T>): StatemanjsAPI<T>; declare function createComputedState<T>(callback: () => T, deps: StatemanjsAPI<any>[], options?: StatemanjsOptions<T>): StatemanjsComputedAPI<T>; export { StatemanjsAPI, StatemanjsComputedAPI, StatemanjsOptions, SubscriptionOptions, createComputedState, createState };