Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

electron-redux

Package Overview
Dependencies
Maintainers
2
Versions
37
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

electron-redux - npm Package Compare versions

Comparing version 2.0.0-alpha.7 to 2.0.0-alpha.8

types/composeWithStateSync.d.ts

178

es/electron-redux.js

@@ -1,6 +0,13 @@

import { webContents, ipcMain, ipcRenderer } from 'electron';
import { compose } from 'redux';
import { webContents, ipcRenderer, ipcMain } from 'electron';
import isPlainObject from 'lodash.isplainobject';
import isString from 'lodash.isstring';
var IPCEvents;
(function (IPCEvents) {
IPCEvents["INIT_STATE"] = "electron-redux.INIT_STATE";
IPCEvents["INIT_STATE_ASYNC"] = "electron-redux.INIT_STATE_ASYNC";
IPCEvents["ACTION"] = "electron-redux.ACTION";
})(IPCEvents || (IPCEvents = {}));
function _defineProperty(obj, key, value) {

@@ -55,12 +62,2 @@ if (key in obj) {

var IPCEvents;
(function (IPCEvents) {
IPCEvents["INIT_STATE"] = "electron-redux.INIT_STATE";
IPCEvents["INIT_STATE_ASYNC"] = "electron-redux.INIT_STATE_ASYNC";
IPCEvents["ACTION"] = "electron-redux.ACTION";
})(IPCEvents || (IPCEvents = {}));
const defaultMainOptions = {};
const isFSA = action => isPlainObject(action) && isString(action.type) && Object.keys(action).every(isValidKey);

@@ -106,5 +103,46 @@

};
const isRenderer = process.type === 'renderer';
const isMain = process.type === 'browser';
function createMiddleware(options) {
const middleware = store => {
const processActionMain = (action, options = {}) => {
if (validateAction(action, options.denyList)) {
webContents.getAllWebContents().forEach(contents => {
// Ignore chromium devtools
if (contents.getURL().startsWith('devtools://')) return;
contents.send(IPCEvents.ACTION, action);
});
}
};
const processActionRenderer = (action, options = {}) => {
if (validateAction(action, options.denyList)) {
ipcRenderer.send(IPCEvents.ACTION, action);
}
};
const forwardAction = (store, options) => {
return _objectSpread2(_objectSpread2({}, store), {}, {
dispatch: action => {
const value = store.dispatch(action);
if (!(options === null || options === void 0 ? void 0 : options.preventActionReplay)) {
if (isMain) {
processActionMain(action, options);
} else if (isRenderer) {
processActionRenderer(action, options);
}
}
return value;
}
});
};
/**
* Creates new instance of main process redux enhancer.
* @param {MainStateSyncEnhancerOptions} options Additional enhancer options
* @returns StoreEnhancer
*/
const mainStateSyncEnhancer = (options = {}) => createStore => {
return (reducer, preloadedState) => {
const store = createStore(reducer, preloadedState);
ipcMain.handle(IPCEvents.INIT_STATE_ASYNC, async () => {

@@ -128,39 +166,4 @@ return JSON.stringify(store.getState(), options.serializer);

});
return next => action => {
if (validateAction(action, options.denyList)) {
webContents.getAllWebContents().forEach(contents => {
// Ignore chromium devtools
if (contents.getURL().startsWith('devtools://')) return;
contents.send(IPCEvents.ACTION, action);
});
}
return next(action);
};
return forwardAction(store, options);
};
return middleware;
}
/**
* Creates new instance of main process redux enhancer.
* @param {MainStateSyncEnhancerOptions} options Additional enhancer options
* @returns StoreEnhancer
*/
const mainStateSyncEnhancer = (options = defaultMainOptions) => createStore => {
preventDoubleInitialization();
const middleware = createMiddleware(options);
return (reducer, preloadedState) => {
const store = createStore(reducer, preloadedState);
let dispatch = store.dispatch;
const middlewareAPI = {
getState: store.getState,
dispatch
};
dispatch = compose(middleware(middlewareAPI))(dispatch);
return _objectSpread2(_objectSpread2({}, store), {}, {
dispatch
});
};
};

@@ -209,17 +212,2 @@

const defaultRendererOptions = {};
const createMiddleware$1 = options => store => {
// When receiving an action from main
ipcRenderer.on(IPCEvents.ACTION, (_, action) => {
store.dispatch(stopForwarding(action));
});
return next => action => {
if (validateAction(action, options.denyList)) {
ipcRenderer.send(IPCEvents.ACTION, action);
}
return next(action);
};
};
/**

@@ -233,7 +221,4 @@ * Creates new instance of renderer process redux enhancer.

const rendererStateSyncEnhancer = (options = defaultRendererOptions) => createStore => {
preventDoubleInitialization();
const rendererStateSyncEnhancer = (options = {}) => createStore => {
return (reducer, state) => {
const middleware = createMiddleware$1(options);
const initialState = options.lazyInit ? state : fetchInitialState(options);

@@ -246,16 +231,51 @@ const store = createStore(options.lazyInit ? withStoreReplacer(reducer) : reducer, initialState);

});
}
} // When receiving an action from main
let dispatch = store.dispatch;
const middlewareAPI = {
getState: store.getState,
dispatch
};
dispatch = compose(middleware(middlewareAPI))(dispatch);
return _objectSpread2(_objectSpread2({}, store), {}, {
dispatch
ipcRenderer.on(IPCEvents.ACTION, (_, action) => {
store.dispatch(stopForwarding(action));
});
return forwardAction(store, options);
};
};
export { mainStateSyncEnhancer, rendererStateSyncEnhancer, stopForwarding };
const stateSyncEnhancer = (config = {}) => {
var _process;
preventDoubleInitialization();
if (isRenderer) {
return rendererStateSyncEnhancer(config);
} else if (isMain) {
return mainStateSyncEnhancer(config);
}
throw new Error(`Unsupported process: process.type = ${(_process = process) === null || _process === void 0 ? void 0 : _process.type}`);
};
const forwardActionEnhancer = options => createStore => (reducer, preloadedState) => {
const store = createStore(reducer, preloadedState);
return forwardAction(store, options);
};
const extensionCompose = options => (...funcs) => {
return createStore => {
return [stateSyncEnhancer(_objectSpread2(_objectSpread2({}, options), {}, {
preventActionReplay: true
})), ...funcs, forwardActionEnhancer(options)].reduceRight((composed, f) => f(composed), createStore);
};
};
function composeWithStateSync(firstFuncOrOpts, ...funcs) {
if (arguments.length === 0) {
return stateSyncEnhancer();
}
if (arguments.length === 1 && typeof firstFuncOrOpts === 'object') {
return extensionCompose(firstFuncOrOpts);
}
return extensionCompose({})(firstFuncOrOpts, ...funcs);
}
export { composeWithStateSync, mainStateSyncEnhancer, rendererStateSyncEnhancer, stateSyncEnhancer, stopForwarding };

@@ -6,3 +6,2 @@ 'use strict';

var electron = require('electron');
var redux = require('redux');
var isPlainObject = require('lodash.isplainobject');

@@ -16,2 +15,10 @@ var isString = require('lodash.isstring');

var IPCEvents;
(function (IPCEvents) {
IPCEvents["INIT_STATE"] = "electron-redux.INIT_STATE";
IPCEvents["INIT_STATE_ASYNC"] = "electron-redux.INIT_STATE_ASYNC";
IPCEvents["ACTION"] = "electron-redux.ACTION";
})(IPCEvents || (IPCEvents = {}));
function _defineProperty(obj, key, value) {

@@ -66,12 +73,2 @@ if (key in obj) {

var IPCEvents;
(function (IPCEvents) {
IPCEvents["INIT_STATE"] = "electron-redux.INIT_STATE";
IPCEvents["INIT_STATE_ASYNC"] = "electron-redux.INIT_STATE_ASYNC";
IPCEvents["ACTION"] = "electron-redux.ACTION";
})(IPCEvents || (IPCEvents = {}));
const defaultMainOptions = {};
const isFSA = action => isPlainObject__default['default'](action) && isString__default['default'](action.type) && Object.keys(action).every(isValidKey);

@@ -117,5 +114,46 @@

};
const isRenderer = process.type === 'renderer';
const isMain = process.type === 'browser';
function createMiddleware(options) {
const middleware = store => {
const processActionMain = (action, options = {}) => {
if (validateAction(action, options.denyList)) {
electron.webContents.getAllWebContents().forEach(contents => {
// Ignore chromium devtools
if (contents.getURL().startsWith('devtools://')) return;
contents.send(IPCEvents.ACTION, action);
});
}
};
const processActionRenderer = (action, options = {}) => {
if (validateAction(action, options.denyList)) {
electron.ipcRenderer.send(IPCEvents.ACTION, action);
}
};
const forwardAction = (store, options) => {
return _objectSpread2(_objectSpread2({}, store), {}, {
dispatch: action => {
const value = store.dispatch(action);
if (!(options === null || options === void 0 ? void 0 : options.preventActionReplay)) {
if (isMain) {
processActionMain(action, options);
} else if (isRenderer) {
processActionRenderer(action, options);
}
}
return value;
}
});
};
/**
* Creates new instance of main process redux enhancer.
* @param {MainStateSyncEnhancerOptions} options Additional enhancer options
* @returns StoreEnhancer
*/
const mainStateSyncEnhancer = (options = {}) => createStore => {
return (reducer, preloadedState) => {
const store = createStore(reducer, preloadedState);
electron.ipcMain.handle(IPCEvents.INIT_STATE_ASYNC, async () => {

@@ -139,39 +177,4 @@ return JSON.stringify(store.getState(), options.serializer);

});
return next => action => {
if (validateAction(action, options.denyList)) {
electron.webContents.getAllWebContents().forEach(contents => {
// Ignore chromium devtools
if (contents.getURL().startsWith('devtools://')) return;
contents.send(IPCEvents.ACTION, action);
});
}
return next(action);
};
return forwardAction(store, options);
};
return middleware;
}
/**
* Creates new instance of main process redux enhancer.
* @param {MainStateSyncEnhancerOptions} options Additional enhancer options
* @returns StoreEnhancer
*/
const mainStateSyncEnhancer = (options = defaultMainOptions) => createStore => {
preventDoubleInitialization();
const middleware = createMiddleware(options);
return (reducer, preloadedState) => {
const store = createStore(reducer, preloadedState);
let dispatch = store.dispatch;
const middlewareAPI = {
getState: store.getState,
dispatch
};
dispatch = redux.compose(middleware(middlewareAPI))(dispatch);
return _objectSpread2(_objectSpread2({}, store), {}, {
dispatch
});
};
};

@@ -220,17 +223,2 @@

const defaultRendererOptions = {};
const createMiddleware$1 = options => store => {
// When receiving an action from main
electron.ipcRenderer.on(IPCEvents.ACTION, (_, action) => {
store.dispatch(stopForwarding(action));
});
return next => action => {
if (validateAction(action, options.denyList)) {
electron.ipcRenderer.send(IPCEvents.ACTION, action);
}
return next(action);
};
};
/**

@@ -244,7 +232,4 @@ * Creates new instance of renderer process redux enhancer.

const rendererStateSyncEnhancer = (options = defaultRendererOptions) => createStore => {
preventDoubleInitialization();
const rendererStateSyncEnhancer = (options = {}) => createStore => {
return (reducer, state) => {
const middleware = createMiddleware$1(options);
const initialState = options.lazyInit ? state : fetchInitialState(options);

@@ -257,18 +242,55 @@ const store = createStore(options.lazyInit ? withStoreReplacer(reducer) : reducer, initialState);

});
}
} // When receiving an action from main
let dispatch = store.dispatch;
const middlewareAPI = {
getState: store.getState,
dispatch
};
dispatch = redux.compose(middleware(middlewareAPI))(dispatch);
return _objectSpread2(_objectSpread2({}, store), {}, {
dispatch
electron.ipcRenderer.on(IPCEvents.ACTION, (_, action) => {
store.dispatch(stopForwarding(action));
});
return forwardAction(store, options);
};
};
const stateSyncEnhancer = (config = {}) => {
var _process;
preventDoubleInitialization();
if (isRenderer) {
return rendererStateSyncEnhancer(config);
} else if (isMain) {
return mainStateSyncEnhancer(config);
}
throw new Error(`Unsupported process: process.type = ${(_process = process) === null || _process === void 0 ? void 0 : _process.type}`);
};
const forwardActionEnhancer = options => createStore => (reducer, preloadedState) => {
const store = createStore(reducer, preloadedState);
return forwardAction(store, options);
};
const extensionCompose = options => (...funcs) => {
return createStore => {
return [stateSyncEnhancer(_objectSpread2(_objectSpread2({}, options), {}, {
preventActionReplay: true
})), ...funcs, forwardActionEnhancer(options)].reduceRight((composed, f) => f(composed), createStore);
};
};
function composeWithStateSync(firstFuncOrOpts, ...funcs) {
if (arguments.length === 0) {
return stateSyncEnhancer();
}
if (arguments.length === 1 && typeof firstFuncOrOpts === 'object') {
return extensionCompose(firstFuncOrOpts);
}
return extensionCompose({})(firstFuncOrOpts, ...funcs);
}
exports.composeWithStateSync = composeWithStateSync;
exports.mainStateSyncEnhancer = mainStateSyncEnhancer;
exports.rendererStateSyncEnhancer = rendererStateSyncEnhancer;
exports.stateSyncEnhancer = stateSyncEnhancer;
exports.stopForwarding = stopForwarding;
{
"name": "electron-redux",
"version": "2.0.0-alpha.7",
"version": "2.0.0-alpha.8",
"description": "Redux & Electron: Make sure all your stores are on the same page",

@@ -5,0 +5,0 @@ "repository": "https://github.com/klarna/electron-redux.git",

@@ -38,9 +38,11 @@ 🚧 THIS IS **ALPHA** version of the library - the API still might change 🚧

electron-redux comes as a [Redux StoreEnhancer](https://redux.js.org/understanding/thinking-in-redux/glossary#store-enhancer). To initialize your stores, you just need to decorate them in the `main` and `renderer` processes of electron with their respective enhancers:
### Basic setup
If you have a setup without any enhancers, also including middleware, you can use the basic setup. For the basic setup, electron redux exposes a [Redux StoreEnhancer](https://redux.js.org/understanding/thinking-in-redux/glossary#store-enhancer). You simply add the enhancer to your createStore function to set it up.
```ts
// main.ts
import { mainStateSyncEnhancer } from 'electron-redux'
import { stateSyncEnhancer } from 'electron-redux'
const store = createStore(reducer, mainStateSyncEnhancer())
const store = createStore(reducer, stateSyncEnhancer())
```

@@ -50,7 +52,25 @@

// renderer.ts
import { rendererStateSyncEnhancer } from 'electron-redux'
import { stateSyncEnhancer } from 'electron-redux'
const store = createStore(reducer, rendererStateSyncEnhancer())
const store = createStore(reducer, stateSyncEnhancer())
```
### Multi-enhancer setup
> This setup is required when you have other enhancers/middleware. This is especially the case for enhancers or middleware which dispatch actions, such as **redux-saga** and **redux-observable**
For this setup we will use the `composeWithStateSync` function. This function is created to wrap around your enhancers, just like the [compose](https://redux.js.org/api/compose) function from redux. When using this, you will not need `stateSyncEnhancer` as this does the same thing under the hood. If you do, it will throw an error.
```ts
import { createStore, applyMiddleware, compose } from 'redux'
import { composeWithStateSync } from 'electron-redux'
const middleware = applyMiddleware(...middleware)
// add other enhances here if you have any, works like `compose` from redux
const enhancer: StoreEnhancer = composeWithStateSync(middleware /* ... other enhancers ... */)
const store = createStore(reducer, enhancer)
```
That's it!

@@ -57,0 +77,0 @@

import { mainStateSyncEnhancer } from './mainStateSyncEnhancer';
import { stopForwarding } from './utils';
import { rendererStateSyncEnhancer } from './rendererStateSyncEnhancer';
export { mainStateSyncEnhancer, rendererStateSyncEnhancer, stopForwarding };
import { stateSyncEnhancer } from './stateSyncEnhancer';
import { composeWithStateSync } from './composeWithStateSync';
export { mainStateSyncEnhancer, rendererStateSyncEnhancer, stopForwarding, stateSyncEnhancer, composeWithStateSync, };

@@ -1,2 +0,3 @@

export declare type MainStateSyncEnhancerOptions = {
import { StateSyncOptions } from './StateSyncOptions';
export interface MainStateSyncEnhancerOptions extends StateSyncOptions {
/**

@@ -8,7 +9,2 @@ * Custom store serialization function.

serializer?: (this: unknown, key: string, value: unknown) => unknown;
/**
* Custom list for actions that should never replay across stores
*/
denyList?: RegExp[];
};
export declare const defaultMainOptions: MainStateSyncEnhancerOptions;
}

@@ -1,2 +0,3 @@

export declare type RendererStateSyncEnhancerOptions = {
import { StateSyncOptions } from './StateSyncOptions';
export interface RendererStateSyncEnhancerOptions extends StateSyncOptions {
/**

@@ -9,6 +10,2 @@ * Custom function used during de-serialization of the redux store to transform the object.

/**
* Custom list for actions that should never replay across stores
*/
denyList?: RegExp[];
/**
* By default, the renderer store is initialized from the main store synchronously.

@@ -20,3 +17,2 @@ * Since the synchronous fetching of the state is blocking the renderer process until it gets the state

lazyInit?: boolean;
};
export declare const defaultRendererOptions: RendererStateSyncEnhancerOptions;
}

@@ -9,9 +9,3 @@ import { FluxStandardAction } from './isFSA';

*/
export declare const stopForwarding: (action: FluxStandardAction<ActionMeta>) => {
meta: {
scope: string;
};
type: string;
payload?: unknown;
};
export declare const stopForwarding: (action: FluxStandardAction<ActionMeta>) => any;
/**

@@ -18,0 +12,0 @@ * validateAction ensures that the action meets the right format and isn't scoped locally

@@ -11,1 +11,3 @@ export declare const preventDoubleInitialization: () => void;

export declare const trimProperties: <T extends keyof X, X>(props: T[], obj: X) => Pick<X, Exclude<keyof X, T>>;
export declare const isRenderer: boolean;
export declare const isMain: boolean;
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc