UNPKG

@daimo/pay

Version:

Seamless crypto payments. Onboard users from any chain, any coin into your app with one click.

83 lines (81 loc) 2.96 kB
/** * Creates a store that manages state and dispatches events to a list of * subscribers. * * @param reducer The reducer function that takes the current state and an event * and deterministically returns a new state. * @param init The initial state of the store. * @returns An object with three methods: * - getState: Returns the current state of the store. * - dispatch: Transition to a new state by applying the reducer function to * the current state and the event. * - subscribe: Takes a function as an argument and adds it to the list of * subscribers. When the state changes, all subscribers will be called. The * function returns a function that can be used to unsubscribe from the store. */ function createStore(reducer, init) { let state = init; const listeners = new Set(); return { getState: () => state, dispatch: (e) => { const prev = state; state = reducer(state, e); listeners.forEach((l) => l({ prev, next: state, event: e })); }, subscribe: (l) => { listeners.add(l); // Return an unsubscribe function. return () => listeners.delete(l); }, }; } /** * Wait until the store enters any state that satisfies the given predicate(s), * or reject on error. * * @returns * `Promise<T>` resolving with the first state where `predicate` is true, * or rejecting if `isError` ever returns true. * * @example After hydrating an order, wait for the payment FSM to transition to * the new state before returning the updated order. * * // 1. Kick off the preview transition * store.dispatch({ type: "hydrate_order" }); * * // 2. Pause until the order is successfully hydrated or errors * const newState = await waitForState( * store, * (s): s is NewState => s.type === "payment_unpaid", * s => s.type === "error", * s => (s as ErrorState).message * ); * * // 3. Now newState.order is updated with the hydrated order * return newState.order; * ``` */ function waitForState(store, predicates, isError, getErrorMessage) { // Normalise to an array and build a helper that succeeds if *any* guard passes const guards = typeof predicates === "function" ? [predicates] : predicates; const matches = (s) => guards.some((g) => g(s)); return new Promise((resolve, reject) => { // Fast path – we might already be in a valid state const first = store.getState(); if (matches(first)) return resolve(first); const unsubscribe = store.subscribe(({ next }) => { if (matches(next)) { unsubscribe(); resolve(next); } else if (isError?.(next)) { unsubscribe(); reject(new Error(getErrorMessage?.(next) ?? "error")); } }); }); } export { createStore, waitForState }; //# sourceMappingURL=stateStore.js.map