diff --git a/package-lock.json b/package-lock.json index 1199b803..e209df91 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "@electron-forge/plugin-base": "^7.2.0", "@electron-forge/plugin-webpack": "^7.2.0", "@electron-forge/shared-types": "^7.2.0", - "@reduxjs/toolkit": "^1.9.7", + "@reduxjs/toolkit": "^2.0.1", "@testing-library/jest-dom": "^6.1.5", "@testing-library/react": "^14.1.2", "@timfish/forge-externals-plugin": "^0.2.1", @@ -43,7 +43,7 @@ "cross-env": "^7.0.3", "css-loader": "^6.8.1", "cssnano": "^6.0.2", - "electron": "^27.1.0", + "electron": "^28.0.0", "electron-log": "^5.0.1", "eslint": "^8.56.0", "fast-deep-equal": "^3.1.3", @@ -59,14 +59,14 @@ "node-loader": "^2.0.0", "picocolors": "^1.0.0", "postcss": "^8.4.32", - "postcss-cli": "^10.1.0", + "postcss-cli": "^11.0.0", "postcss-import": "^15.1.0", "postcss-loader": "^7.3.3", "prettier": "^3.1.1", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-redux": "^8.1.3", - "redux": "^4.2.1", + "react-redux": "^9.0.4", + "redux": "^5.0.0", "rimraf": "^5.0.5", "style-loader": "^3.3.3", "tailwindcss": "^3.3.6", @@ -2843,19 +2843,19 @@ } }, "node_modules/@reduxjs/toolkit": { - "version": "1.9.7", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.7.tgz", - "integrity": "sha512-t7v8ZPxhhKgOKtU+uyJT13lu4vL7az5aFi4IdoDs/eS548edn2M8Ik9h8fxgvMjGoAUVFSt6ZC1P5cWmQ014QQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.0.1.tgz", + "integrity": "sha512-fxIjrR9934cmS8YXIGd9e7s1XRsEU++aFc9DVNMFMRTM5Vtsg2DCRMj21eslGtDt43IUf9bJL3h5bwUlZleibA==", "dev": true, "dependencies": { - "immer": "^9.0.21", - "redux": "^4.2.1", - "redux-thunk": "^2.4.2", - "reselect": "^4.1.8" + "immer": "^10.0.3", + "redux": "^5.0.0", + "redux-thunk": "^3.1.0", + "reselect": "^5.0.1" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18", - "react-redux": "^7.2.1 || ^8.0.2" + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "peerDependenciesMeta": { "react": { @@ -2866,16 +2866,6 @@ } } }, - "node_modules/@reduxjs/toolkit/node_modules/immer": { - "version": "9.0.21", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", - "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -3439,6 +3429,15 @@ "redux": "^4.0.0" } }, + "node_modules/@types/react-redux/node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, "node_modules/@types/responselike": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", @@ -7228,9 +7227,9 @@ "dev": true }, "node_modules/electron": { - "version": "27.1.0", - "resolved": "https://registry.npmjs.org/electron/-/electron-27.1.0.tgz", - "integrity": "sha512-XPdJiO475QJ8cx59/goWNNWnlV0vab+Ut3occymos7VDxkHV5mFrlW6tcGi+M3bW6gBfwpJocWMng8tw542vww==", + "version": "28.0.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-28.0.0.tgz", + "integrity": "sha512-eDhnCFBvG0PGFVEpNIEdBvyuGUBsFdlokd+CtuCe2ER3P+17qxaRfWRxMmksCOKgDHb5Wif5UxqOkZSlA4snlw==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -14764,18 +14763,18 @@ } }, "node_modules/postcss-cli": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-10.1.0.tgz", - "integrity": "sha512-Zu7PLORkE9YwNdvOeOVKPmWghprOtjFQU3srMUGbdz3pHJiFh7yZ4geiZFMkjMfB0mtTFR3h8RemR62rPkbOPA==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-11.0.0.tgz", + "integrity": "sha512-xMITAI7M0u1yolVcXJ9XTZiO9aO49mcoKQy6pCDFdMh9kGqhzLVpWxeD/32M/QBmkhcGypZFFOLNLmIW4Pg4RA==", "dev": true, "dependencies": { "chokidar": "^3.3.0", "dependency-graph": "^0.11.0", "fs-extra": "^11.0.0", "get-stdin": "^9.0.0", - "globby": "^13.0.0", + "globby": "^14.0.0", "picocolors": "^1.0.0", - "postcss-load-config": "^4.0.0", + "postcss-load-config": "^5.0.0", "postcss-reporter": "^7.0.0", "pretty-hrtime": "^1.0.3", "read-cache": "^1.0.0", @@ -14786,7 +14785,7 @@ "postcss": "index.js" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "postcss": "^8.0.0" @@ -14807,28 +14806,38 @@ } }, "node_modules/postcss-cli/node_modules/globby": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz", - "integrity": "sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.0.tgz", + "integrity": "sha512-/1WM/LNHRAOH9lZta77uGbq0dAEQM+XjNesWwhlERDVenqothRbnzTrL3/LrIoEPPjeUHC3vrS6TwoyxeHs7MQ==", "dev": true, "dependencies": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^4.0.0" + "@sindresorhus/merge-streams": "^1.0.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-cli/node_modules/globby/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "node_modules/postcss-cli/node_modules/lilconfig": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", + "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/postcss-cli/node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", "dev": true, "engines": { "node": ">=12" @@ -14837,10 +14846,45 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/postcss-cli/node_modules/postcss-load-config": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-5.0.2.tgz", + "integrity": "sha512-Q8QR3FYbqOKa0bnC1UQ2bFq9/ulHX5Bi34muzitMr8aDtUelO5xKeJEYC/5smE0jNE9zdB/NBnOwXKexELbRlw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + } + } + }, "node_modules/postcss-cli/node_modules/slash": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-5.0.0.tgz", - "integrity": "sha512-n6KkmvKS0623igEVj3FF0OZs1gYYJ0o0Hj939yc1fyxl2xt+xYpLnzJB6xBSqOfV9ZFLEWodBBN/heZJahuIJQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", "dev": true, "engines": { "node": ">=14.16" @@ -15797,36 +15841,24 @@ "dev": true }, "node_modules/react-redux": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.3.tgz", - "integrity": "sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.0.4.tgz", + "integrity": "sha512-9J1xh8sWO0vYq2sCxK2My/QO7MzUMRi3rpiILP/+tDr8krBHixC6JMM17fMK88+Oh3e4Ae6/sHIhNBgkUivwFA==", "dev": true, "dependencies": { - "@babel/runtime": "^7.12.1", - "@types/hoist-non-react-statics": "^3.3.1", "@types/use-sync-external-store": "^0.0.3", - "hoist-non-react-statics": "^3.3.2", - "react-is": "^18.0.0", "use-sync-external-store": "^1.0.0" }, "peerDependencies": { - "@types/react": "^16.8 || ^17.0 || ^18.0", - "@types/react-dom": "^16.8 || ^17.0 || ^18.0", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0", - "react-native": ">=0.59", - "redux": "^4 || ^5.0.0-beta.0" + "@types/react": "^18.2.25", + "react": "^18.0", + "react-native": ">=0.69", + "redux": "^5.0.0" }, "peerDependenciesMeta": { "@types/react": { "optional": true }, - "@types/react-dom": { - "optional": true - }, - "react-dom": { - "optional": true - }, "react-native": { "optional": true }, @@ -15835,12 +15867,6 @@ } } }, - "node_modules/react-redux/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, "node_modules/read-binary-file-arch": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/read-binary-file-arch/-/read-binary-file-arch-1.0.6.tgz", @@ -16016,21 +16042,18 @@ } }, "node_modules/redux": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", - "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.9.2" - } + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.0.tgz", + "integrity": "sha512-blLIYmYetpZMET6Q6uCY7Jtl/Im5OBldy+vNPauA8vvsdqyt66oep4EUpAMWNHauTC6xa9JuRPhRB72rY82QGA==", + "dev": true }, "node_modules/redux-thunk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", - "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", "dev": true, "peerDependencies": { - "redux": "^4" + "redux": "^5.0.0" } }, "node_modules/reflect.getprototypeof": { @@ -16153,9 +16176,9 @@ "dev": true }, "node_modules/reselect": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", - "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.0.1.tgz", + "integrity": "sha512-D72j2ubjgHpvuCiORWkOUxndHJrxDaSolheiz5CO+roz8ka97/4msh2E8F5qay4GawR5vzBt5MkbDHT+Rdy/Wg==", "dev": true }, "node_modules/resolve": { diff --git a/package.json b/package.json index 9539d068..0cbde097 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "@electron-forge/plugin-base": "^7.2.0", "@electron-forge/plugin-webpack": "^7.2.0", "@electron-forge/shared-types": "^7.2.0", - "@reduxjs/toolkit": "^1.9.7", + "@reduxjs/toolkit": "^2.0.1", "@testing-library/jest-dom": "^6.1.5", "@testing-library/react": "^14.1.2", "@timfish/forge-externals-plugin": "^0.2.1", @@ -70,7 +70,7 @@ "cross-env": "^7.0.3", "css-loader": "^6.8.1", "cssnano": "^6.0.2", - "electron": "^27.1.0", + "electron": "^28.0.0", "electron-log": "^5.0.1", "eslint": "^8.56.0", "fast-deep-equal": "^3.1.3", @@ -86,14 +86,14 @@ "node-loader": "^2.0.0", "picocolors": "^1.0.0", "postcss": "^8.4.32", - "postcss-cli": "^10.1.0", + "postcss-cli": "^11.0.0", "postcss-import": "^15.1.0", "postcss-loader": "^7.3.3", "prettier": "^3.1.1", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-redux": "^8.1.3", - "redux": "^4.2.1", + "react-redux": "^9.0.4", + "redux": "^5.0.0", "rimraf": "^5.0.5", "style-loader": "^3.3.3", "tailwindcss": "^3.3.6", diff --git a/src/main/state/actions.ts b/src/main/state/actions.ts index dde254c1..d808b71e 100644 --- a/src/main/state/actions.ts +++ b/src/main/state/actions.ts @@ -1,5 +1,4 @@ import type { Rectangle } from 'electron/main' -import type { CombinedState } from 'redux' import type { AppName } from '../../config/apps' import type { Data } from '../../shared/state/reducer.data' @@ -20,8 +19,9 @@ const startedScanning = main('installed-apps/scanning') const retrievedInstalledApps = main('installed-apps/retrieved') -const receivedRendererStartupSignal = - main>('sync-reducers') +const receivedRendererStartupSignal = main<{ data: Data; storage: Storage }>( + 'sync-reducers', +) const gotDefaultBrowserStatus = main('default-browser-status/got') diff --git a/src/main/state/middleware.bus.ts b/src/main/state/middleware.bus.ts index 5edb55d6..7f40a37d 100644 --- a/src/main/state/middleware.bus.ts +++ b/src/main/state/middleware.bus.ts @@ -1,14 +1,14 @@ import { Channel } from '../../shared/state/channels' import type { Middleware } from '../../shared/state/model' +import { isFSA } from '../../shared/state/model' import { pickerWindow, prefsWindow } from '../windows' /** * Pass actions between main and renderers */ export const busMiddleware = (): Middleware => () => (next) => (action) => { - /** - * Move to next middleware - */ + if (!isFSA(action)) return next(action) + // eslint-disable-next-line n/callback-return -- must flush to get nextState const result = next(action) diff --git a/src/main/state/store.ts b/src/main/state/store.ts index 845ad47c..526e998f 100644 --- a/src/main/state/store.ts +++ b/src/main/state/store.ts @@ -1,15 +1,19 @@ +/* eslint-disable unicorn/prefer-spread -- see https://redux-toolkit.js.org/api/getDefaultMiddleware#intended-usage */ + +import { configureStore } from '@reduxjs/toolkit' import { app } from 'electron' import { Channel } from '../../shared/state/channels' -import createStore from '../../shared/state/create-store' +import { channelInjectorMiddleware } from '../../shared/state/middleware.channel-injector' +import { logMiddleware } from '../../shared/state/middleware.log' import { defaultData } from '../../shared/state/reducer.data' import type { RootState } from '../../shared/state/reducer.root' +import { rootReducer } from '../../shared/state/reducer.root' import { database } from '../database' import { actionHubMiddleware } from './middleware.action-hub' import { busMiddleware } from './middleware.bus' const channel = Channel.MAIN -const middleware = [busMiddleware(), actionHubMiddleware()] const preloadedState: RootState = { data: { @@ -20,6 +24,15 @@ const preloadedState: RootState = { storage: database.getAll(), } -const { dispatch, getState } = createStore(channel, middleware, preloadedState) +const { dispatch, getState } = configureStore({ + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ thunk: false }) + .prepend(channelInjectorMiddleware(channel)) + .concat(busMiddleware()) + .concat(actionHubMiddleware()) + .concat(logMiddleware()), + preloadedState, + reducer: rootReducer, +}) export { dispatch, getState } diff --git a/src/renderers/picker/state/middleware.ts b/src/renderers/picker/state/middleware.ts index a3b28167..e33b00e8 100644 --- a/src/renderers/picker/state/middleware.ts +++ b/src/renderers/picker/state/middleware.ts @@ -1,10 +1,11 @@ /* eslint-disable unicorn/prefer-regexp-test */ +import type { Middleware } from 'redux' + import { clickedRestorePicker, openedUrl, retrievedInstalledApps, } from '../../../main/state/actions' -import type { Middleware } from '../../../shared/state/model' import { getKeyLayout } from '../../shared/utils/get-key-layout-map' import { appsRef, appsScrollerRef } from '../refs' import { clickedDonate, clickedMaybeLater } from './actions' diff --git a/src/renderers/picker/state/store.ts b/src/renderers/picker/state/store.ts index 128c8217..96bd2749 100644 --- a/src/renderers/picker/state/store.ts +++ b/src/renderers/picker/state/store.ts @@ -1,18 +1,29 @@ -import type { AnyAction } from '@reduxjs/toolkit' +/* eslint-disable unicorn/prefer-spread -- see https://redux-toolkit.js.org/api/getDefaultMiddleware#intended-usage */ + +import type { Action } from '@reduxjs/toolkit' +import { configureStore } from '@reduxjs/toolkit' import { Channel } from '../../../shared/state/channels' -import createStore from '../../../shared/state/create-store' +import { channelInjectorMiddleware } from '../../../shared/state/middleware.channel-injector' +import { logMiddleware } from '../../../shared/state/middleware.log' +import { rootReducer } from '../../../shared/state/reducer.root' import { busMiddleware } from '../../shared/state/middleware.bus' import { pickerMiddleware } from './middleware' -const middleware = [busMiddleware(Channel.PICKER), pickerMiddleware()] - -const store = createStore(Channel.PICKER, middleware) +const store = configureStore({ + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ thunk: false }) + .prepend(channelInjectorMiddleware(Channel.PICKER)) + .concat(busMiddleware(Channel.PICKER)) + .concat(pickerMiddleware()) + .concat(logMiddleware()), + reducer: rootReducer, +}) /** * Listen for all actions from main */ -window.electron.receive(Channel.MAIN, (action: AnyAction) => { +window.electron.receive(Channel.MAIN, (action: Action) => { store.dispatch(action) }) diff --git a/src/renderers/prefs/state/middleware.ts b/src/renderers/prefs/state/middleware.ts index 726fc745..4277f191 100644 --- a/src/renderers/prefs/state/middleware.ts +++ b/src/renderers/prefs/state/middleware.ts @@ -1,6 +1,7 @@ /* eslint-disable unicorn/prefer-regexp-test */ +import type { Middleware } from 'redux' + import { clickedOpenPrefs } from '../../../main/state/actions' -import type { Middleware } from '../../../shared/state/model' import { getKeyLayout } from '../../shared/utils/get-key-layout-map' /** diff --git a/src/renderers/prefs/state/store.ts b/src/renderers/prefs/state/store.ts index 48d66ef4..ca890b1b 100644 --- a/src/renderers/prefs/state/store.ts +++ b/src/renderers/prefs/state/store.ts @@ -1,18 +1,29 @@ -import type { AnyAction } from '@reduxjs/toolkit' +/* eslint-disable unicorn/prefer-spread -- see https://redux-toolkit.js.org/api/getDefaultMiddleware#intended-usage */ + +import type { UnknownAction } from '@reduxjs/toolkit' +import { configureStore } from '@reduxjs/toolkit' import { Channel } from '../../../shared/state/channels' -import createStore from '../../../shared/state/create-store' +import { channelInjectorMiddleware } from '../../../shared/state/middleware.channel-injector' +import { logMiddleware } from '../../../shared/state/middleware.log' +import { rootReducer } from '../../../shared/state/reducer.root' import { busMiddleware } from '../../shared/state/middleware.bus' import { prefsMiddleware } from './middleware' -const middleware = [busMiddleware(Channel.PREFS), prefsMiddleware()] - -const store = createStore(Channel.PREFS, middleware) +const store = configureStore({ + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ thunk: false }) + .prepend(channelInjectorMiddleware(Channel.PREFS)) + .concat(busMiddleware(Channel.PREFS)) + .concat(prefsMiddleware()) + .concat(logMiddleware()), + reducer: rootReducer, +}) /** * Listen for all actions */ -window.electron.receive(Channel.MAIN, (action: AnyAction) => { +window.electron.receive(Channel.MAIN, (action: UnknownAction) => { store.dispatch(action) }) diff --git a/src/renderers/shared/state/middleware.bus.ts b/src/renderers/shared/state/middleware.bus.ts index 38199137..4d662b48 100644 --- a/src/renderers/shared/state/middleware.bus.ts +++ b/src/renderers/shared/state/middleware.bus.ts @@ -1,5 +1,7 @@ +import type { Middleware } from 'redux' + import type { Channel } from '../../../shared/state/channels' -import type { Middleware } from '../../../shared/state/model' +import { isFSA } from '../../../shared/state/model' /** * Pass actions between main and renderers @@ -9,6 +11,8 @@ export const busMiddleware = () => (next) => (action) => { + if (!isFSA(action)) return next(action) + /** * Move to next middleware */ diff --git a/src/shared/state/create-store.ts b/src/shared/state/create-store.ts deleted file mode 100644 index 6d4773e1..00000000 --- a/src/shared/state/create-store.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { - CombinedState, - EnhancedStore, - PreloadedState, -} from '@reduxjs/toolkit' -import { configureStore } from '@reduxjs/toolkit' -import type { NoInfer } from '@reduxjs/toolkit/dist/tsHelpers' - -import type { Channel } from './channels' -import { channelInjectorMiddleware } from './middleware.channel-injector' -import { logMiddleware } from './middleware.log' -import type { FSA, Middleware } from './model' -import type { RootState } from './reducer.root' -import { rootReducer } from './reducer.root' - -type BoundaryType = EnhancedStore, FSA, Middleware[]> - -const createStore = ( - channel: Channel, - middleware: Middleware[], - preloadedState?: PreloadedState>>, -): BoundaryType => - configureStore({ - middleware: (getDefaultMiddleware) => [ - channelInjectorMiddleware(channel), - ...getDefaultMiddleware({ thunk: false }), - ...middleware, - logMiddleware(), - ], - preloadedState, - reducer: rootReducer, - }) - -export default createStore diff --git a/src/shared/state/middleware.channel-injector.ts b/src/shared/state/middleware.channel-injector.ts index 70056579..73524c6e 100644 --- a/src/shared/state/middleware.channel-injector.ts +++ b/src/shared/state/middleware.channel-injector.ts @@ -1,6 +1,7 @@ import { addChannelToAction } from '../utils/add-channel-to-action' import type { Channel } from './channels' import type { Middleware } from './model' +import { isFSA } from './model' /** * Adds the current channel to actions if it is not present. @@ -12,10 +13,11 @@ export const channelInjectorMiddleware = () => (next) => (action) => { + if (!isFSA(action)) return next(action) + const actionWithChannel = action.meta?.channel ? action : addChannelToAction(action, channel) - // Move to next middleware return next(actionWithChannel) } diff --git a/src/shared/state/middleware.log.ts b/src/shared/state/middleware.log.ts index 71070e6d..6b4b6517 100644 --- a/src/shared/state/middleware.log.ts +++ b/src/shared/state/middleware.log.ts @@ -1,12 +1,13 @@ import { actionLogger } from '../utils/action-logger' import type { Middleware } from './model' +import { isFSA } from './model' /** * Log all actions to console */ export const logMiddleware = (): Middleware => () => (next) => (action) => { // TODO figure out how to use `app.isPackaged` in an isomorphic way. - if (process.env.NODE_ENV === 'development') { + if (process.env.NODE_ENV === 'development' && isFSA(action)) { actionLogger(action) } diff --git a/src/shared/state/model.ts b/src/shared/state/model.ts index e715a9a5..ee1af06e 100644 --- a/src/shared/state/model.ts +++ b/src/shared/state/model.ts @@ -1,4 +1,5 @@ -import type { Dispatch } from '@reduxjs/toolkit' +import type { Dispatch, Middleware as ReduxMiddleware } from '@reduxjs/toolkit' +import { isFluxStandardAction } from '@reduxjs/toolkit' import type { RootState } from './reducer.root' @@ -9,9 +10,11 @@ type FSA = { meta?: Record } -type Middleware = (api: { - dispatch: Dispatch - getState: () => RootState -}) => (next: Dispatch) => (event: FSA) => ReturnType> +const isFSA = (action: unknown): action is FSA => { + // TODO tighten this to ensure `error` and `meta` are correct shape + return isFluxStandardAction(action) +} + +type Middleware = ReduxMiddleware, RootState, Dispatch> -export { FSA, Middleware } +export { FSA, isFSA, Middleware }