diff --git a/README.md b/README.md index 2bfc5ff3..fd42c734 100644 --- a/README.md +++ b/README.md @@ -73,9 +73,9 @@ By default, all actions are broadcast to all registered stores. However, some st To stop an action from propagating from renderer to main store, simply set the scope to local by decorating your action with `stopForwarding` function. Read more about it in the [docs](#todo) -### Blacklisted actions +### Blocked actions -By default, some of the actions are blacklisted from broadcasting / propagating, those include actions starting with `@@` and `redux-form`. The list of ignored actions can be modified with [options](#todo). +By default, some of the actions are blocked from broadcasting / propagating, those include actions starting with `@@` and `redux-form`. The list of ignored actions can be modified with [options](#todo). ## Changelog diff --git a/src/mainStateSyncEnhancer.ts b/src/mainStateSyncEnhancer.ts index 19a97935..08aeb6e8 100644 --- a/src/mainStateSyncEnhancer.ts +++ b/src/mainStateSyncEnhancer.ts @@ -36,7 +36,7 @@ function createMiddleware(options: MainStateSyncEnhancerOptions) { }) return (next) => (action) => { - if (validateAction(action)) { + if (validateAction(action, options.denyList)) { webContents.getAllWebContents().forEach((contents) => { // Ignore chromium devtools if (contents.getURL().startsWith('devtools://')) return diff --git a/src/options/MainStateSyncEnhancerOptions.ts b/src/options/MainStateSyncEnhancerOptions.ts index cfc74b09..971bcfce 100644 --- a/src/options/MainStateSyncEnhancerOptions.ts +++ b/src/options/MainStateSyncEnhancerOptions.ts @@ -1,10 +1,15 @@ export type MainStateSyncEnhancerOptions = { /** - * Custom store serialization function. This function is called for each member of the object. - * If a member contains nested objects, + * Custom store serialization function. + * This function is called for each member of the object. If a member contains nested objects, * the nested objects are transformed before the parent object is. */ serializer?: (this: unknown, key: string, value: unknown) => unknown + + /** + * Custom list for actions that should never replay across stores + */ + denyList?: RegExp[] } export const defaultMainOptions: MainStateSyncEnhancerOptions = {} diff --git a/src/options/RendererStateSyncEnhancerOptions.ts b/src/options/RendererStateSyncEnhancerOptions.ts index 593f4ea9..270d49c1 100644 --- a/src/options/RendererStateSyncEnhancerOptions.ts +++ b/src/options/RendererStateSyncEnhancerOptions.ts @@ -6,6 +6,11 @@ export type RendererStateSyncEnhancerOptions = { */ deserializer?: (this: unknown, key: string, value: unknown) => unknown + /** + * Custom list for actions that should never replay across stores + */ + denyList?: RegExp[] + /** * By default, the renderer store is initialized from the main store synchronously. * Since the synchronous fetching of the state is blocking the renderer process until it gets the state diff --git a/src/rendererStateSyncEnhancer.ts b/src/rendererStateSyncEnhancer.ts index dfb6c584..ca49331e 100644 --- a/src/rendererStateSyncEnhancer.ts +++ b/src/rendererStateSyncEnhancer.ts @@ -3,18 +3,18 @@ import { Action, applyMiddleware, Middleware, StoreCreator, StoreEnhancer } from import { IPCEvents } from './constants' import { fetchInitialState, fetchInitialStateAsync } from './fetchState' import { replaceState, withStoreReplacer } from './fetchState/replaceState' -import { defaultRendererOptions } from './options/RendererStateSyncEnhancerOptions' +import { defaultRendererOptions, RendererStateSyncEnhancerOptions } from './options/RendererStateSyncEnhancerOptions' import { preventDoubleInitialization, stopForwarding, validateAction } from './utils' -const middleware: Middleware = (store) => { +const createMiddleware = (options: RendererStateSyncEnhancerOptions): Middleware => (store) => { // When receiving an action from main ipcRenderer.on(IPCEvents.ACTION, (_, action: Action) => { store.dispatch(stopForwarding(action)) }) return (next) => (action) => { - if (validateAction(action)) { + if (validateAction(action, options.denyList)) { ipcRenderer.send(IPCEvents.ACTION, action) } @@ -39,7 +39,7 @@ export const rendererStateSyncEnhancer = (options = defaultRendererOptions): Sto const store = createStore( options.lazyInit ? withStoreReplacer(reducer) : reducer, initialState, - applyMiddleware(middleware) + applyMiddleware(createMiddleware(options)) ) if (options.lazyInit) { diff --git a/src/utils/actions.ts b/src/utils/actions.ts index e9344f7e..fcbe2615 100644 --- a/src/utils/actions.ts +++ b/src/utils/actions.ts @@ -1,8 +1,5 @@ import { isFSA, FluxStandardAction } from './isFSA' -// Certain actions that we should never replay across stores -const blacklist = [/^@@/, /^redux-form/] - // Gives us just enough action type info to work for the functions below export type ActionMeta = { scope?: 'local' | string @@ -23,10 +20,14 @@ export const stopForwarding = (action: FluxStandardAction) => ({ /** * validateAction ensures that the action meets the right format and isn't scoped locally */ -export const validateAction = (action: any): action is FluxStandardAction => { +export const validateAction = ( + action: any, + // Actions that we should never replay across stores + denyList: RegExp[] = [/^@@/, /^redux-form/] +): action is FluxStandardAction => { return ( isFSA(action) && action.meta?.scope !== 'local' && - blacklist.every((rule) => !rule.test(action.type)) + denyList.every((rule) => !rule.test(action.type)) ) }