UNPKG

@zubridge/electron

Version:

A streamlined state management library for Electron applications using Zustand.

245 lines (233 loc) 10.4 kB
import { Action, AnyState, Handler, RootReducer, BackendBridge, StateManager, Dispatch, WrapperOrWebContents } from '@zubridge/types'; import { Store } from 'redux'; import { StoreApi as StoreApi$1 } from 'zustand/vanilla'; import { StoreApi } from 'zustand'; interface NapiAction { type: string; payload?: string; } /** * Interface for the middleware provided by @zubridge/middleware */ interface ZubridgeMiddleware { /** * Process an action before it's sent to the store */ processAction: (action: NapiAction) => Promise<void>; /** * Update the middleware's state after a state change */ setState: (state: string) => Promise<void>; /** * Clean up resources when the bridge is destroyed */ destroy?: () => Promise<void>; trackActionDispatch?: (action: Action) => Promise<void>; trackActionReceived?: (action: Action) => Promise<void>; trackStateUpdate?: (action: Action, state: string) => Promise<void>; trackActionAcknowledged?: (actionId: string) => Promise<void>; } /** * Helper to create bridge middleware options for Electron bridges * * This function integrates Rust-based middleware (@zubridge/middleware) with the Electron bridge. * * Note: You typically don't need to use this function directly. You can just pass the middleware * instance directly to the bridge creation functions. * * @example * ```typescript * import { createZustandBridge } from '@zubridge/electron'; * import { initZubridgeMiddleware } from '@zubridge/middleware'; * * // Initialize middleware from @zubridge/middleware (Rust implementation) * const middleware = initZubridgeMiddleware({ * logging: { enabled: true } * }); * * // Create bridge with Rust middleware - just pass middleware directly * const bridge = createZustandBridge(store, windows, { * // Your other options * middleware: middleware * }); * ``` * * @internal This function is used internally by bridge creation functions */ declare function createMiddlewareOptions(middleware: ZubridgeMiddleware): { beforeProcessAction: (action: Action) => Promise<Action>; afterStateChange: (state: AnyState) => Promise<void>; onBridgeDestroy: () => Promise<void>; }; /** * Options for the Redux adapter */ interface ReduxOptions<_S extends AnyState> { handlers?: Record<string, Handler | Record<string, unknown>>; middleware?: ZubridgeMiddleware; } /** * Options for the Zustand bridge and adapter */ interface ZustandOptions<S extends AnyState> { handlers?: Record<string, Handler>; reducer?: RootReducer<S>; middleware?: ZubridgeMiddleware; } interface CoreBridgeOptions { middleware?: ZubridgeMiddleware; beforeProcessAction?: (action: Action, windowId?: number) => Promise<Action> | Action; afterProcessAction?: (action: Action, processingTime: number, windowId?: number) => Promise<void> | void; beforeStateChange?: (state: AnyState, windowId?: number) => Promise<void> | void; afterStateChange?: (state: AnyState, windowId?: number) => Promise<void> | void; onBridgeDestroy?: () => Promise<void> | void; resourceManagement?: { /** Enable periodic cleanup of destroyed window subscription managers (default: true) */ enablePeriodicCleanup?: boolean; /** Cleanup interval in milliseconds (default: 10 minutes) */ cleanupIntervalMs?: number; /** Maximum number of subscription managers before forcing cleanup (default: 1000) */ maxSubscriptionManagers?: number; }; serialization?: { /** Maximum depth to traverse when sanitizing state (default: 10) */ maxDepth?: number; }; } /** * Creates a core bridge between the main process and renderer processes * This implements the Zubridge Electron backend contract without requiring a specific state management library */ declare function createCoreBridge<State extends AnyState>(stateManager: StateManager<State>, options?: CoreBridgeOptions): BackendBridge; /** * Creates a bridge from a store (either Zustand or Redux) */ declare function createBridgeFromStore<S extends AnyState = AnyState>(store: StoreApi<S> | Store<S>, options?: ZustandOptions<S> | ReduxOptions<S> | CoreBridgeOptions): BackendBridge; /** * Creates a dispatch function for the given store * This automatically gets or creates an appropriate state manager based on the store type */ declare function createDispatch<S extends AnyState>(store: StoreApi$1<S> | Store<S>, options?: ZustandOptions<S> | ReduxOptions<S>): Dispatch<S>; /** * Creates a dispatch function using a pre-created state manager * @internal This overload is intended for internal use by bridge creators */ declare function createDispatch<S extends AnyState>(stateManager: StateManager<S>): Dispatch<S>; /** * Register an action type with the state keys it affects * @param actionType The action type string * @param stateKeys Array of state keys this action affects */ declare function registerActionMapping(actionType: string, stateKeys: string[]): void; /** * Register multiple action mappings at once * @param mappings Object mapping action types to arrays of state keys */ declare function registerActionMappings(mappings: Record<string, string[]>): void; /** * Get the state keys affected by an action * @param actionType The action type string * @returns Array of state keys this action affects, or empty array if unknown */ declare function getAffectedStateKeys(actionType: string): string[]; /** * Check if a window can dispatch an action based on its subscriptions * @param action The action to validate * @returns Promise resolving to boolean indicating if dispatch is allowed */ declare function canDispatchAction(action: Action): Promise<boolean>; /** * Validate that a window can dispatch an action, throwing if not allowed * @param action The action to validate * @throws Error if the window cannot dispatch this action */ declare function validateActionDispatch(action: Action): Promise<void>; /** * Gets the current window's subscriptions from the main process * @returns Array of state keys this window is subscribed to, or empty array if none */ declare function getWindowSubscriptions(): Promise<string[]>; /** * Determines if the window is subscribed to a particular state key * @param key The state key to check * @returns True if subscribed, false otherwise */ declare function isSubscribedToKey(key: string): Promise<boolean>; /** * Validates that the window has access to the specified state key * Throws an error if the window is not subscribed to the key * @param key The state key to validate * @param action Optional action to check for bypass flags * @throws Error if window is not subscribed to the key and not bypassing */ declare function validateStateAccess(key: string, action?: Action): Promise<void>; /** * Validates that the window can access all of the specified state keys * @param keys Array of state keys to validate * @param action Optional action to check for bypass flags * @throws Error if window is not subscribed to any of the keys and not bypassing */ declare function validateStateAccessBatch(keys: string[], action?: Action): Promise<void>; /** * Checks if a state key exists in the provided state object * @param state The state object to check * @param key The key to look for (can use dot notation) * @returns True if the key exists, false otherwise */ declare function stateKeyExists(state: Record<string, unknown>, key: string): boolean; /** * Validates state access with additional check for key existence * @param state The state object * @param key The key to validate * @param action Optional action to check for bypass flags * @throws Error if the key doesn't exist or the window isn't subscribed */ declare function validateStateAccessWithExistence(state: Record<string, unknown>, key: string, action?: Action): Promise<void>; /** * Determines if the application is running in development mode * * Uses a combination of checks to ensure consistent behavior: * 1. Checks if app is packaged (production builds are packaged) * 2. Checks NODE_ENV environment variable * 3. Checks ELECTRON_IS_DEV environment variable (set by electron-is-dev or similar utilities) * * @returns {boolean} True if running in development mode, false otherwise */ declare const isDev: () => Promise<boolean>; /** * Interface for a bridge that connects a Zustand store to the main process */ interface ZustandBridge<S extends AnyState = AnyState> extends BackendBridge { subscribe: (windows: WrapperOrWebContents[], keys?: string[]) => { unsubscribe: () => void; }; unsubscribe: (...args: unknown[]) => void; dispatch: Dispatch<S>; destroy: () => void; } /** * Interface for a bridge that connects a Redux store to the main process */ interface ReduxBridge<S extends AnyState = AnyState> extends BackendBridge { subscribe: (windows: WrapperOrWebContents[], keys?: string[]) => { unsubscribe: () => void; }; unsubscribe: (...args: unknown[]) => void; dispatch: Dispatch<S>; destroy: () => void; } /** * Creates a bridge between a Zustand store and the renderer process */ declare function createZustandBridge<S extends AnyState>(store: StoreApi$1<S>, options?: ZustandOptions<S> & CoreBridgeOptions): ZustandBridge<S>; /** * Creates a bridge between a Redux store and the renderer process */ declare function createReduxBridge<S extends AnyState>(store: Store<S>, options?: ReduxOptions<S> & CoreBridgeOptions): ReduxBridge<S>; /** * Legacy bridge alias for backward compatibility * @deprecated This is now an alias for createZustandBridge and uses the new IPC channels. * Please update your code to use createZustandBridge directly in the future. */ declare const mainZustandBridge: typeof createZustandBridge; export { type CoreBridgeOptions, type ReduxBridge, type ReduxOptions, type ZubridgeMiddleware, type ZustandBridge, type ZustandOptions, canDispatchAction, createBridgeFromStore, createCoreBridge, createDispatch, createMiddlewareOptions, createReduxBridge, createZustandBridge, getAffectedStateKeys, getWindowSubscriptions, isDev, isSubscribedToKey, mainZustandBridge, registerActionMapping, registerActionMappings, stateKeyExists, validateActionDispatch, validateStateAccess, validateStateAccessBatch, validateStateAccessWithExistence };