UNPKG

@medamajs/compose

Version:

Composable state management extension for medama with support for hierarchical state layers, dynamic composition, and parallel state synchronization

249 lines (206 loc) 7.02 kB
import { createMedama } from 'medama'; /** * Function to execute job with read mode enabled. Sets read work state to true * before execution, resets both read work and subscription means states after * completion. * * @param job Function to execute in read mode */ type RunWithReadModeOn = (job: () => void) => void; type ReadWorkModeMethods = { /** * Returns current read work state. True indicates that reading process is in * progress and any nested reads should be treated as derivative calls rather * than initiator calls. */ getReadWorkState: () => boolean; /** * Function to execute job with read mode enabled. Sets read work state to * true before execution, resets both read work and subscription means states * after completion. */ runWithReadModeOn: RunWithReadModeOn; /** * Sets subscription means requested state to true. Indicates that nested * composite states should collect and relay subscription means up the chain. */ setSubscriptionMeansRequested: () => void; /** * Returns current subscription means requested state. True indicates that * nested composite states should collect and relay subscription means up the * chain. */ getRequestSubscriptionMeansState: () => boolean; /** * Resets both read work state and subscription means requested state to * false. Used during initialization and error handling to ensure clean state. */ resetReadWorkMode: () => void; }; /** * Creates a manager to control read work mode and subscription collection * state. Manages two key states: * - Read work state: Tracks if reading process is active * - Subscription means state: Controls if nested states should collect * subscriptions * * Provides methods to: * - Start/finish reading operations * - Control subscription means collection * - Reset states during initialization or error handling * * @returns Object containing methods to manage read work mode */ export const createReadWorkModeManager = (): ReadWorkModeMethods => { let readWorkState = false; let requestSubscriptionMeansState = false; const getReadWorkState = (): boolean => readWorkState; const runWithReadModeOn = (job: () => void): void => { readWorkState = true; job(); readWorkState = false; requestSubscriptionMeansState = false; }; const setSubscriptionMeansRequested = (): void => { requestSubscriptionMeansState = true; }; const getRequestSubscriptionMeansState = (): boolean => requestSubscriptionMeansState; const resetReadWorkMode = (): void => { readWorkState = false; requestSubscriptionMeansState = false; }; return { getReadWorkState, runWithReadModeOn, setSubscriptionMeansRequested, getRequestSubscriptionMeansState, resetReadWorkMode, }; }; export type DeferOrRun = (job: () => void) => void; type Reset = () => void; type ConditionalDeferrerMethods = { /** * Either runs job immediately or defers it based on update work state: * - If not in update mode: runs job immediately * - If in update mode: defers job and subscribes to resolution signal (if not * already subscribed) */ deferOrRun: DeferOrRun; /** * Resets subscription state to false. Used during initialization and error * handling to ensure clean state. */ reset: Reset; }; type CreateConditionalDeferrer = ( deferJob: (job: () => void) => void, resolveDeferred: () => void ) => ConditionalDeferrerMethods; type UpdateWorkModeMethods = { /** * Returns current update work state. True indicates that update process is in * progress and new jobs should be deferred rather than executed immediately. */ getUpdateWorkState: () => boolean; /** * Sets update work state to true, indicating start of update process. Used to * mark that any new jobs should be deferred rather than executed immediately. */ startUpdating: () => void; /** * Signals resolution of deferred jobs and sets update work state to false. * Triggers execution of all deferred jobs in the queue. */ signalDeferredJobsToResolve: () => void; /** * Creates a handler that either runs jobs immediately or defers them based on * current state. Provides subscription mechanism to resolve deferred jobs * when signaled. * * @param deferJob Function to add job to deferred queue * @param resolveDeferred Function to process deferred queue */ createConditionalDeferrer: CreateConditionalDeferrer; /** * Resets signal state and update work state to false. Used during * initialization and error handling to ensure clean state. */ resetUpdateWorkMode: () => void; }; type SignalToResolveDeferredJobsState = { signal: object; }; /** * Creates a manager to control update work mode and deferred job handling. * Manages update state and provides mechanisms for: * - Controlling when jobs should be deferred vs executed immediately * - Signaling when deferred jobs should be processed * - Creating conditional deferrer instances that handle job execution timing * * Uses medama state to manage signaling system for deferred job resolution. * * @returns Object containing methods to manage update work mode and job * deferral */ export const createUpdateWorkModeManager = (): UpdateWorkModeMethods => { let updateWorkState = false; const getUpdateWorkState = (): boolean => updateWorkState; const startUpdating = (): void => { updateWorkState = true; }; const { subscribeToState: subscribeToSignalState, setState: setSignalState, resetState: resetSignalState, } = createMedama<SignalToResolveDeferredJobsState>(); const signalToResolveSelector = ({ signal }: SignalToResolveDeferredJobsState): object => signal; const signalDeferredJobsToResolve = (): void => { setSignalState({ signal: {} }); updateWorkState = false; }; const subscribeForResolvingWhenSignalled = (callback: () => void): void => { const { unsubscribe } = subscribeToSignalState( signalToResolveSelector, (): (() => void) => () => { callback(); unsubscribe(); } ); }; const createConditionalDeferrer = ( deferJob: (job: () => void) => void, resolveDeferred: () => void ): ConditionalDeferrerMethods => { let subscribed = false; return { deferOrRun: (job): void => { if (updateWorkState === false) { job(); return; } deferJob(job); if (subscribed) return; subscribeForResolvingWhenSignalled((): void => { resolveDeferred(); subscribed = false; }); subscribed = true; }, reset: (): void => { subscribed = false; }, }; }; const resetUpdateWorkMode = (): void => { resetSignalState(); updateWorkState = false; }; return { getUpdateWorkState, startUpdating, signalDeferredJobsToResolve, createConditionalDeferrer, resetUpdateWorkMode, }; };