Update Redux packages (#1583)

* Update Redux packages

* Fix instrument build

* Fix some test type errors

* Fix redux-devtools build

* Fix rtk-query-monitor build

* Fix redux-devtools-app build

* Fix redux-devtools-extension build

* Fix redux-devtools-remote build

* Fix extension build

* slider-monitor-example

* test-tab-demo

* inspector-monitor-demo

* rtk-query-monitor-demo

* counter-example

* todomvc-example

* Fix lint

* Fix instrument test types

* Fix core tests

* Fix rtk-query-monitor tests

* Updates
This commit is contained in:
Nathan Bierema 2024-08-05 23:11:13 -04:00 committed by GitHub
parent bd463b19ec
commit 8682d05b0b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
71 changed files with 591 additions and 548 deletions

View File

@ -31,7 +31,7 @@
"@redux-devtools/slider-monitor": "^5.0.1",
"@redux-devtools/ui": "^1.3.2",
"@redux-devtools/utils": "^3.0.0",
"@reduxjs/toolkit": "^1.9.7",
"@reduxjs/toolkit": "^2.2.7",
"@types/jsan": "^3.1.5",
"jsan": "^3.1.14",
"localforage": "^1.10.0",
@ -41,8 +41,8 @@
"react-icons": "^5.2.1",
"react-is": "^18.3.1",
"react-json-tree": "^0.19.0",
"react-redux": "^8.1.3",
"redux": "^4.2.1",
"react-redux": "^9.1.2",
"redux": "^5.0.1",
"redux-persist": "^6.0.0",
"styled-components": "^5.3.11"
},

View File

@ -18,7 +18,7 @@ import syncOptions, {
} from '../../options/syncOptions';
import openDevToolsWindow, { DevToolsPosition } from '../openWindow';
import { getReport } from '../logging';
import { Action, Dispatch, MiddlewareAPI } from 'redux';
import { Action, Dispatch, Middleware } from 'redux';
import type {
ContentScriptToBackgroundMessage,
SplitMessage,
@ -670,10 +670,10 @@ declare global {
window.syncOptions = syncOptions(toAllTabs); // Expose to the options page
export default function api(
store: MiddlewareAPI<Dispatch<BackgroundAction>, BackgroundState>,
) {
return (next: Dispatch<BackgroundAction>) => (action: BackgroundAction) => {
const api: Middleware<{}, BackgroundState, Dispatch<BackgroundAction>> =
(store) => (next) => (untypedAction) => {
const action = untypedAction as BackgroundAction;
if (action.type === LIFTED_ACTION) toContentScript(action);
else if (action.type === TOGGLE_PERSIST) {
togglePersist();
@ -684,4 +684,5 @@ export default function api(
}
return next(action);
};
}
export default api;

View File

@ -1,14 +1,17 @@
import { combineReducers, Reducer } from 'redux';
import { instances, InstancesState } from '@redux-devtools/app';
import type { BackgroundAction } from './backgroundStore';
import { BackgroundAction } from './backgroundStore';
export interface BackgroundState {
readonly instances: InstancesState;
}
const rootReducer: Reducer<BackgroundState, BackgroundAction> =
combineReducers<BackgroundState>({
instances,
});
const rootReducer: Reducer<
BackgroundState,
BackgroundAction,
Partial<BackgroundState>
> = combineReducers({
instances,
}) as any;
export default rootReducer;

View File

@ -1,4 +1,4 @@
import { createStore, applyMiddleware, PreloadedState } from 'redux';
import { createStore, applyMiddleware } from 'redux';
import {
CustomAction,
DispatchAction,
@ -60,7 +60,7 @@ export type BackgroundAction =
| DisconnectedAction;
export default function configureStore(
preloadedState?: PreloadedState<BackgroundState>,
preloadedState?: Partial<BackgroundState>,
) {
return createStore(rootReducer, preloadedState, applyMiddleware(api));
/*

View File

@ -30,16 +30,19 @@ export interface StoreStateWithoutSocket {
readonly stateTreeSettings: StateTreeSettings;
}
const rootReducer: Reducer<StoreStateWithoutSocket, StoreAction> =
combineReducers<StoreStateWithoutSocket>({
instances,
monitor,
reports,
notification,
section,
theme,
connection,
stateTreeSettings,
});
const rootReducer: Reducer<
StoreStateWithoutSocket,
StoreAction,
Partial<StoreStateWithoutSocket>
> = combineReducers({
instances,
monitor,
reports,
notification,
section,
theme,
connection,
stateTreeSettings,
}) as any;
export default rootReducer;

View File

@ -1,4 +1,4 @@
import { createStore, applyMiddleware, Reducer } from 'redux';
import { createStore, applyMiddleware, Reducer, Store } from 'redux';
import localForage from 'localforage';
import { persistReducer, persistStore } from 'redux-persist';
import { exportStateMiddleware, StoreAction } from '@redux-devtools/app';
@ -23,6 +23,6 @@ export default function configureStore(
panelDispatcher(bgConnection),
);
const store = createStore(persistedReducer, enhancer);
const persistor = persistStore(store);
const persistor = persistStore(store as Store);
return { store, persistor };
}

View File

@ -7,31 +7,33 @@ import {
TOGGLE_PERSIST,
UPDATE_STATE,
} from '@redux-devtools/app';
import { Dispatch, MiddlewareAPI } from 'redux';
import { Dispatch, Middleware } from 'redux';
function panelDispatcher(bgConnection: chrome.runtime.Port) {
function panelDispatcher(
bgConnection: chrome.runtime.Port,
): Middleware<{}, StoreState, Dispatch<StoreAction>> {
let autoselected = false;
const tabId = chrome.devtools.inspectedWindow.tabId;
return (store: MiddlewareAPI<Dispatch<StoreAction>, StoreState>) =>
(next: Dispatch<StoreAction>) =>
(action: StoreAction) => {
const result = next(action);
if (!autoselected && action.type === UPDATE_STATE && tabId) {
autoselected = true;
const connections = store.getState().instances.connections[tabId];
if (connections && connections.length === 1) {
next({ type: SELECT_INSTANCE, selected: connections[0] });
}
return (store) => (next) => (untypedAction) => {
const action = untypedAction as StoreAction;
const result = next(action);
if (!autoselected && action.type === UPDATE_STATE && tabId) {
autoselected = true;
const connections = store.getState().instances.connections[tabId];
if (connections && connections.length === 1) {
next({ type: SELECT_INSTANCE, selected: connections[0] });
}
if (action.type === LIFTED_ACTION || action.type === TOGGLE_PERSIST) {
const instances = store.getState().instances;
const instanceId = getActiveInstance(instances);
const id = instances.options[instanceId].connectionId;
bgConnection.postMessage({ ...action, instanceId, id });
}
return result;
};
}
if (action.type === LIFTED_ACTION || action.type === TOGGLE_PERSIST) {
const instances = store.getState().instances;
const instanceId = getActiveInstance(instances);
const id = instances.options[instanceId].connectionId;
bgConnection.postMessage({ ...action, instanceId, id });
}
return result;
};
}
export default panelDispatcher;

View File

@ -9,7 +9,6 @@ import {
Action,
ActionCreator,
Dispatch,
PreloadedState,
Reducer,
StoreEnhancer,
StoreEnhancerStoreCreator,
@ -526,34 +525,28 @@ function __REDUX_DEVTOOLS_EXTENSION__<S, A extends Action<string>>(
relayState(liftedState);
}
const enhance =
(): StoreEnhancer =>
<NextExt, NextStateExt>(
next: StoreEnhancerStoreCreator<NextExt, NextStateExt>,
): any => {
return <S2 extends S, A2 extends A>(
reducer_: Reducer<S2, A2>,
initialState_?: PreloadedState<S2>,
) => {
if (!isAllowed(window.devToolsOptions)) {
return next(reducer_, initialState_);
}
const enhance = (): StoreEnhancer => (next) => {
return <S2, A2 extends Action<string>, PreloadedState>(
reducer_: Reducer<S2, A2, PreloadedState>,
initialState_?: PreloadedState | undefined,
) => {
if (!isAllowed(window.devToolsOptions)) {
return next(reducer_, initialState_);
}
store = stores[instanceId] = configureStore(
next as StoreEnhancerStoreCreator,
monitor.reducer,
{
...config,
maxAge: getMaxAge as any,
},
)(reducer_, initialState_) as any;
store = stores[instanceId] = (
configureStore(next, monitor.reducer, {
...config,
maxAge: getMaxAge as any,
}) as any
)(reducer_, initialState_) as any;
if (isInIframe()) setTimeout(init, 3000);
else init();
if (isInIframe()) setTimeout(init, 3000);
else init();
return store;
};
return store as any;
};
};
return enhance();
}
@ -598,11 +591,11 @@ export type InferComposedStoreExt<StoreEnhancers> = StoreEnhancers extends [
? HeadStoreEnhancer extends StoreEnhancer<infer StoreExt>
? StoreExt & InferComposedStoreExt<RestStoreEnhancers>
: never
: unknown;
: {};
const extensionCompose =
(config: Config) =>
<StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
<StoreEnhancers extends readonly StoreEnhancer[]>(
...funcs: StoreEnhancers
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>> => {
// @ts-ignore FIXME
@ -619,10 +612,10 @@ const extensionCompose =
interface ReduxDevtoolsExtensionCompose {
(
config: Config,
): <StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
): <StoreEnhancers extends readonly StoreEnhancer[]>(
...funcs: StoreEnhancers
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
<StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
<StoreEnhancers extends readonly StoreEnhancer[]>(
...funcs: StoreEnhancers
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
}
@ -635,24 +628,22 @@ declare global {
function reduxDevtoolsExtensionCompose(
config: Config,
): <StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
): <StoreEnhancers extends readonly StoreEnhancer[]>(
...funcs: StoreEnhancers
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
function reduxDevtoolsExtensionCompose<
StoreEnhancers extends readonly StoreEnhancer<unknown>[],
StoreEnhancers extends readonly StoreEnhancer[],
>(
...funcs: StoreEnhancers
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
function reduxDevtoolsExtensionCompose(
...funcs: [Config] | StoreEnhancer<unknown>[]
) {
function reduxDevtoolsExtensionCompose(...funcs: [Config] | StoreEnhancer[]) {
if (funcs.length === 0) {
return __REDUX_DEVTOOLS_EXTENSION__();
}
if (funcs.length === 1 && typeof funcs[0] === 'object') {
return extensionCompose(funcs[0]);
}
return extensionCompose({})(...(funcs as StoreEnhancer<unknown>[]));
return extensionCompose({})(...(funcs as StoreEnhancer[]));
}
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ = reduxDevtoolsExtensionCompose;

View File

@ -1,4 +1,4 @@
import { Dispatch, MiddlewareAPI } from 'redux';
import { Dispatch, Middleware, MiddlewareAPI } from 'redux';
import {
SELECT_INSTANCE,
StoreAction,
@ -9,7 +9,7 @@ import {
function selectInstance(
tabId: number,
store: MiddlewareAPI<Dispatch<StoreAction>, StoreState>,
next: Dispatch<StoreAction>,
next: (action: unknown) => unknown,
) {
const instances = store.getState().instances;
if (instances.current === 'default') return;
@ -33,10 +33,10 @@ function getCurrentTabId(next: (tabId: number) => void) {
);
}
export default function popupSelector(
store: MiddlewareAPI<Dispatch<StoreAction>, StoreState>,
) {
return (next: Dispatch<StoreAction>) => (action: StoreAction) => {
const popupSelector: Middleware<{}, StoreState, Dispatch<StoreAction>> =
(store) => (next) => (untypedAction) => {
const action = untypedAction as StoreAction;
const result = next(action);
if (action.type === UPDATE_STATE) {
if (chrome.devtools && chrome.devtools.inspectedWindow) {
@ -47,4 +47,5 @@ export default function popupSelector(
}
return result;
};
}
export default popupSelector;

View File

@ -13,17 +13,20 @@ import {
import instances from './instancesReducer';
import type { WindowStoreAction } from './windowStore';
const rootReducer: Reducer<StoreState, WindowStoreAction> =
combineReducers<StoreState>({
instances,
monitor,
socket,
reports,
notification,
section,
theme,
connection,
stateTreeSettings,
});
const rootReducer: Reducer<
StoreState,
WindowStoreAction,
Partial<StoreState>
> = combineReducers({
instances,
monitor,
socket,
reports,
notification,
section,
theme,
connection,
stateTreeSettings,
}) as any;
export default rootReducer;

View File

@ -69,7 +69,7 @@ export default function configureStore(
);
}
const store = createStore(persistedReducer, enhancer);
const persistor = persistStore(store, null, () => {
const persistor = persistStore(store as Store, null, () => {
if (store.getState().connection.type !== 'disabled') {
store.dispatch({
type: CONNECT_REQUEST,

View File

@ -6,16 +6,19 @@ import {
TOGGLE_PERSIST,
UPDATE_STATE,
} from '@redux-devtools/app';
import { Dispatch, MiddlewareAPI, Store } from 'redux';
import { Dispatch, Middleware, Store } from 'redux';
import type { BackgroundState } from '../../background/store/backgroundReducer';
import type { WindowStoreAction } from './windowStore';
import type { BackgroundAction } from '../../background/store/backgroundStore';
const syncStores =
(baseStore: Store<BackgroundState, BackgroundAction>) =>
(store: MiddlewareAPI<Dispatch<StoreAction>, StoreState>) =>
(next: Dispatch<WindowStoreAction>) =>
(action: StoreAction) => {
(
baseStore: Store<BackgroundState, BackgroundAction>,
): Middleware<{}, StoreState, Dispatch<StoreAction>> =>
(store) =>
(next) =>
(untypedAction) => {
const action = untypedAction as StoreAction;
if (action.type === UPDATE_STATE) {
return next({
...action,

View File

@ -61,6 +61,7 @@
"@babel/preset-react": "^7.24.7",
"@babel/preset-typescript": "^7.24.7",
"@emotion/react": "^11.13.0",
"@reduxjs/toolkit": "^2.2.7",
"@rjsf/core": "^4.2.3",
"@testing-library/dom": "^10.3.2",
"@testing-library/jest-dom": "^6.4.6",
@ -85,8 +86,8 @@
"jest-environment-jsdom": "^29.7.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-redux": "^8.1.3",
"redux": "^4.2.1",
"react-redux": "^9.1.2",
"redux": "^5.0.1",
"redux-persist": "^6.0.0",
"rimraf": "^6.0.1",
"styled-components": "^5.3.11",

View File

@ -1,7 +1,7 @@
import { stringifyJSON } from '../utils/stringifyJSON';
import { UPDATE_STATE, LIFTED_ACTION, EXPORT } from '../constants/actionTypes';
import { getActiveInstance } from '../reducers/instances';
import { Dispatch, MiddlewareAPI } from 'redux';
import { Dispatch, Middleware } from 'redux';
import { CoreStoreAction } from '../actions';
import { CoreStoreState } from '../reducers';
@ -22,44 +22,45 @@ function download(state: string) {
}, 0);
}
export const exportStateMiddleware =
(store: MiddlewareAPI<Dispatch<CoreStoreAction>, CoreStoreState>) =>
(next: Dispatch<CoreStoreAction>) =>
(action: CoreStoreAction) => {
const result = next(action);
export const exportStateMiddleware: Middleware<
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
{},
CoreStoreState,
Dispatch<CoreStoreAction>
> = (store) => (next) => (untypedAction) => {
const result = next(untypedAction);
if (
toExport &&
action.type === UPDATE_STATE &&
action.request!.type === 'EXPORT'
) {
const request = action.request!;
const id = request.instanceId || request.id;
if (id === toExport) {
toExport = undefined;
download(
JSON.stringify(
{
payload: request.payload,
preloadedState: request.committedState,
},
null,
'\t',
),
);
}
} else if (action.type === EXPORT) {
const instances = store.getState().instances;
const instanceId = getActiveInstance(instances);
const options = instances.options[instanceId];
if (options.features.export === true) {
download(
stringifyJSON(instances.states[instanceId], options.serialize),
);
} else {
toExport = instanceId;
next({ type: LIFTED_ACTION, message: 'EXPORT', toExport: true });
}
const action = untypedAction as CoreStoreAction;
if (
toExport &&
action.type === UPDATE_STATE &&
action.request!.type === 'EXPORT'
) {
const request = action.request!;
const id = request.instanceId || request.id;
if (id === toExport) {
toExport = undefined;
download(
JSON.stringify(
{
payload: request.payload,
preloadedState: request.committedState,
},
null,
'\t',
),
);
}
return result;
};
} else if (action.type === EXPORT) {
const instances = store.getState().instances;
const instanceId = getActiveInstance(instances);
const options = instances.options[instanceId];
if (options.features.export === true) {
download(stringifyJSON(instances.states[instanceId], options.serialize));
} else {
toExport = instanceId;
next({ type: LIFTED_ACTION, message: 'EXPORT', toExport: true });
}
}
return result;
};

View File

@ -1,6 +1,6 @@
import React from 'react';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { createStore, applyMiddleware, Reducer } from 'redux';
import { render, screen, within } from '@testing-library/react';
import App from '../src/containers/App';
import { exportStateMiddleware } from '../src/middlewares/exportState';
@ -8,6 +8,7 @@ import { coreReducers } from '../src/reducers';
import { DATA_TYPE_KEY } from '../src/constants/dataTypes';
import { stringifyJSON } from '../src/utils/stringifyJSON';
import { combineReducers } from 'redux';
import { CoreStoreAction, CoreStoreState } from '../lib/types';
Object.defineProperty(window, 'matchMedia', {
writable: true,
@ -24,7 +25,11 @@ Object.defineProperty(window, 'matchMedia', {
});
const store = createStore(
combineReducers(coreReducers),
combineReducers(coreReducers) as Reducer<
CoreStoreState,
CoreStoreAction,
Partial<CoreStoreState>
>,
applyMiddleware(exportStateMiddleware),
);

View File

@ -44,8 +44,8 @@
"localforage": "^1.10.0",
"jsan": "^3.1.14",
"lodash": "^4.17.21",
"react-redux": "^8.1.3",
"redux": "^4.2.1",
"react-redux": "^9.1.2",
"redux": "^5.0.1",
"redux-persist": "^6.0.0",
"socketcluster-client": "^19.2.1"
},
@ -58,6 +58,7 @@
"@babel/preset-react": "^7.24.7",
"@babel/preset-typescript": "^7.24.7",
"@emotion/react": "^11.13.0",
"@reduxjs/toolkit": "^2.2.7",
"@rjsf/core": "^4.2.3",
"@types/jsan": "^3.1.5",
"@types/json-schema": "^7.0.15",

View File

@ -17,7 +17,7 @@ import {
} from '@redux-devtools/app-core';
import socketClusterClient, { AGClientSocket } from 'socketcluster-client';
import { stringify } from 'jsan';
import { Dispatch, MiddlewareAPI } from 'redux';
import { Dispatch, Middleware, MiddlewareAPI } from 'redux';
import * as actions from '../constants/socketActionTypes';
import { nonReduxDispatch } from '../utils/monitorActions';
import { EmitAction, StoreAction } from '../actions';
@ -266,10 +266,15 @@ function getReport(reportId: unknown) {
})();
}
export function api(inStore: MiddlewareAPI<Dispatch<StoreAction>, StoreState>) {
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export const api: Middleware<{}, StoreState, Dispatch<StoreAction>> = (
inStore,
) => {
store = inStore;
return (next: Dispatch<StoreAction>) => (action: StoreAction) => {
const result = next(action);
return (next) => (untypedAction) => {
const result = next(untypedAction);
const action = untypedAction as StoreAction;
switch (action.type) {
case actions.CONNECT_REQUEST:
connect();
@ -299,4 +304,4 @@ export function api(inStore: MiddlewareAPI<Dispatch<StoreAction>, StoreState>) {
}
return result;
};
}
};

View File

@ -2,15 +2,13 @@ import { CoreStoreState, coreReducers } from '@redux-devtools/app-core';
import { combineReducers } from 'redux';
import { connection, ConnectionState } from './connection';
import { socket, SocketState } from './socket';
import { StoreAction } from '../actions';
export interface StoreState extends CoreStoreState {
readonly connection: ConnectionState;
readonly socket: SocketState;
}
/// @ts-expect-error An error happens due to TypeScript not being able to reconcile a clash between CoreStoreAction and StoreAction in the core reducers, but this is correct as they're a superset
export const rootReducer = combineReducers<StoreState, StoreAction>({
export const rootReducer = combineReducers({
...coreReducers,
connection,
socket,

View File

@ -14,7 +14,7 @@ const persistConfig = {
const persistedReducer: Reducer<StoreState, StoreAction> = persistReducer(
persistConfig,
rootReducer,
rootReducer as unknown as Reducer<StoreState, StoreAction>,
) as any;
export default function configureStore(
@ -41,7 +41,7 @@ export default function configureStore(
persistedReducer,
composeEnhancers(applyMiddleware(...middlewares, api)),
);
const persistor = persistStore(store, null, () => {
const persistor = persistStore(store as Store, null, () => {
callback(store);
});
return { store, persistor };

View File

@ -61,7 +61,7 @@
"eslint-plugin-react": "^7.35.0",
"eslint-plugin-react-hooks": "^4.6.2",
"react": "^18.3.1",
"redux": "^4.2.1",
"redux": "^5.0.1",
"rimraf": "^6.0.1",
"typescript": "~5.5.3"
},

View File

@ -44,7 +44,7 @@
"@apollo/server": "^4.10.4",
"@emotion/react": "^11.13.0",
"@redux-devtools/app": "^6.0.0",
"@reduxjs/toolkit": "^1.9.7",
"@reduxjs/toolkit": "^2.2.7",
"@types/react": "^18.3.3",
"body-parser": "^1.20.2",
"chalk": "^5.3.0",

View File

@ -63,7 +63,7 @@
"eslint-plugin-react": "^7.35.0",
"eslint-plugin-react-hooks": "^4.6.2",
"react": "^18.3.1",
"redux": "^4.2.1",
"redux": "^5.0.1",
"rimraf": "^6.0.1",
"typescript": "~5.5.3"
},

View File

@ -43,7 +43,7 @@
"@typescript-eslint/parser": "^8.0.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"redux": "^4.2.1",
"redux": "^5.0.1",
"rimraf": "^6.0.1",
"typescript": "~5.5.3"
},

View File

@ -15,18 +15,16 @@ declare const process: {
function extensionComposeStub(
config: Config,
): <StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
): <StoreEnhancers extends readonly StoreEnhancer[]>(
...funcs: StoreEnhancers
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
function extensionComposeStub<
StoreEnhancers extends readonly StoreEnhancer<unknown>[],
>(
function extensionComposeStub<StoreEnhancers extends readonly StoreEnhancer[]>(
...funcs: StoreEnhancers
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
function extensionComposeStub(...funcs: [Config] | StoreEnhancer<unknown>[]) {
function extensionComposeStub(...funcs: [Config] | StoreEnhancer[]) {
if (funcs.length === 0) return undefined;
if (typeof funcs[0] === 'object') return compose;
return compose(...(funcs as StoreEnhancer<unknown>[]));
return compose(...(funcs as StoreEnhancer[]));
}
export const composeWithDevTools: ReduxDevtoolsExtensionCompose =

View File

@ -235,15 +235,16 @@ export type InferComposedStoreExt<StoreEnhancers> = StoreEnhancers extends [
? HeadStoreEnhancer extends StoreEnhancer<infer StoreExt>
? StoreExt & InferComposedStoreExt<RestStoreEnhancers>
: never
: unknown;
: // eslint-disable-next-line @typescript-eslint/no-empty-object-type
{};
export interface ReduxDevtoolsExtensionCompose {
(
config: Config,
): <StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
): <StoreEnhancers extends readonly StoreEnhancer[]>(
...funcs: StoreEnhancers
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
<StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
<StoreEnhancers extends readonly StoreEnhancer[]>(
...funcs: StoreEnhancers
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
}
@ -257,18 +258,16 @@ declare global {
function extensionComposeStub(
config: Config,
): <StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
): <StoreEnhancers extends readonly StoreEnhancer[]>(
...funcs: StoreEnhancers
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
function extensionComposeStub<
StoreEnhancers extends readonly StoreEnhancer<unknown>[],
>(
function extensionComposeStub<StoreEnhancers extends readonly StoreEnhancer[]>(
...funcs: StoreEnhancers
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
function extensionComposeStub(...funcs: [Config] | StoreEnhancer<unknown>[]) {
function extensionComposeStub(...funcs: [Config] | StoreEnhancer[]) {
if (funcs.length === 0) return undefined;
if (typeof funcs[0] === 'object') return compose;
return compose(...(funcs as StoreEnhancer<unknown>[]));
return compose(...(funcs as StoreEnhancer[]));
}
export const composeWithDevTools: ReduxDevtoolsExtensionCompose =

View File

@ -1,12 +1,5 @@
import assign from './utils/assign';
import { compose } from 'redux';
import type {
Action,
Dispatch,
PreloadedState,
Reducer,
StoreEnhancer,
} from 'redux';
import type { Action, Dispatch, Reducer, StoreEnhancer } from 'redux';
import type { Config, EnhancerOptions, InferComposedStoreExt } from './index';
function enhancer(options?: EnhancerOptions): StoreEnhancer {
@ -17,9 +10,9 @@ function enhancer(options?: EnhancerOptions): StoreEnhancer {
if (config.latency === undefined) config.latency = 500;
return function (createStore) {
return function <S, A extends Action<string>>(
reducer: Reducer<S, A>,
preloadedState: PreloadedState<S> | undefined,
return function <S, A extends Action<string>, PreloadedState>(
reducer: Reducer<S, A, PreloadedState>,
preloadedState?: PreloadedState | undefined,
) {
const store = createStore(reducer, preloadedState);
const origDispatch = store.dispatch;
@ -33,35 +26,32 @@ function enhancer(options?: EnhancerOptions): StoreEnhancer {
return r;
};
if (Object.assign) return Object.assign(store, { dispatch: dispatch });
return assign(store, 'dispatch', dispatch);
return Object.assign(store, { dispatch: dispatch });
};
};
}
function composeWithEnhancer(config?: EnhancerOptions) {
return function (...funcs: StoreEnhancer<unknown>[]) {
return function (...funcs: StoreEnhancer[]) {
return compose(compose(...funcs), enhancer(config));
};
}
export function composeWithDevTools(
config: Config,
): <StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
): <StoreEnhancers extends readonly StoreEnhancer[]>(
...funcs: StoreEnhancers
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
export function composeWithDevTools<
StoreEnhancers extends readonly StoreEnhancer<unknown>[],
StoreEnhancers extends readonly StoreEnhancer[],
>(
...funcs: StoreEnhancers
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
export function composeWithDevTools(
...funcs: [Config] | StoreEnhancer<unknown>[]
) {
export function composeWithDevTools(...funcs: [Config] | StoreEnhancer[]) {
if (typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__) {
if (funcs.length === 0) return enhancer();
if (typeof funcs[0] === 'object') return composeWithEnhancer(funcs[0]);
return composeWithEnhancer()(...(funcs as StoreEnhancer<unknown>[]));
return composeWithEnhancer()(...(funcs as StoreEnhancer[]));
}
if (funcs.length === 0) return undefined;

View File

@ -16,18 +16,16 @@ declare const process: {
function extensionComposeStub(
config: Config,
): <StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
): <StoreEnhancers extends readonly StoreEnhancer[]>(
...funcs: StoreEnhancers
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
function extensionComposeStub<
StoreEnhancers extends readonly StoreEnhancer<unknown>[],
>(
function extensionComposeStub<StoreEnhancers extends readonly StoreEnhancer[]>(
...funcs: StoreEnhancers
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
function extensionComposeStub(...funcs: [Config] | StoreEnhancer<unknown>[]) {
function extensionComposeStub(...funcs: [Config] | StoreEnhancer[]) {
if (funcs.length === 0) return undefined;
if (typeof funcs[0] === 'object') return compose;
return compose(...(funcs as StoreEnhancer<unknown>[]));
return compose(...(funcs as StoreEnhancer[]));
}
export const composeWithDevTools: ReduxDevtoolsExtensionCompose =

View File

@ -1,26 +0,0 @@
const objectKeys =
Object.keys ||
function (obj) {
const keys = [];
for (const key in obj) {
if ({}.hasOwnProperty.call(obj, key)) keys.push(key);
}
return keys;
};
export default function assign<T extends object, K extends keyof T>(
obj: T,
newKey: K,
newValue: T[K],
): T {
const keys = objectKeys(obj);
const copy: T = {} as T;
for (let i = 0, l = keys.length; i < l; i++) {
const key = keys[i];
copy[key as keyof T] = obj[key as keyof T];
}
copy[newKey] = newValue;
return copy;
}

View File

@ -21,9 +21,9 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-is": "^18.3.1",
"react-redux": "^8.1.3",
"react-redux": "^9.1.2",
"react-router-dom": "^6.25.1",
"redux": "^4.2.1",
"redux": "^5.0.1",
"redux-logger": "^3.0.6",
"styled-components": "^5.3.11"
},
@ -36,7 +36,7 @@
"@types/node": "^20.14.11",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/redux-logger": "3.0.12",
"@types/redux-logger": "^3.0.13",
"@types/styled-components": "^5.1.34",
"@types/webpack-env": "^1.18.5",
"@typescript-eslint/eslint-plugin": "^8.0.0",

View File

@ -33,9 +33,9 @@ const useDevtoolsExtension =
!!(window as unknown as { __REDUX_DEVTOOLS_EXTENSION__: unknown }) &&
getOptions(window.location).useExtension;
const enhancer = compose(
const enhancer: StoreEnhancer = compose(
applyMiddleware(logger),
(next: StoreEnhancerStoreCreator) => {
((next) => {
const instrument = useDevtoolsExtension
? (
window as unknown as {
@ -44,9 +44,9 @@ const enhancer = compose(
).__REDUX_DEVTOOLS_EXTENSION__()
: DevTools.instrument();
return instrument(next);
},
}) as StoreEnhancer,
persistState(getDebugSessionKey()),
);
) as any;
const store = createStore(rootReducer, enhancer);

View File

@ -155,12 +155,12 @@ export interface DemoAppState {
}
export const rootReducer: Reducer<DemoAppState, DemoAppAction> =
combineReducers<DemoAppState, DemoAppAction>({
timeoutUpdateEnabled: (state = false, action) =>
combineReducers({
timeoutUpdateEnabled: (state = false, action: DemoAppAction) =>
action.type === 'TOGGLE_TIMEOUT_UPDATE'
? action.timeoutUpdateEnabled
: state,
store: (state = 0, action) =>
store: (state = 0, action: DemoAppAction) =>
action.type === 'INCREMENT' ? state + 1 : state,
undefined: (state = { val: undefined }) => state,
null: (state = null) => state,
@ -169,7 +169,7 @@ export const rootReducer: Reducer<DemoAppState, DemoAppAction> =
// noop
},
) => state,
array: (state = [], action) =>
array: (state = [], action: DemoAppAction) =>
action.type === 'PUSH'
? [...state, Math.random()]
: action.type === 'POP'
@ -177,13 +177,13 @@ export const rootReducer: Reducer<DemoAppState, DemoAppAction> =
: action.type === 'REPLACE'
? [Math.random(), ...state.slice(1)]
: state,
hugeArrays: (state = [], action) =>
hugeArrays: (state = [], action: DemoAppAction) =>
action.type === 'PUSH_HUGE_ARRAY' ? [...state, ...HUGE_ARRAY] : state,
hugeObjects: (state = [], action) =>
hugeObjects: (state = [], action: DemoAppAction) =>
action.type === 'ADD_HUGE_OBJECT' ? [...state, HUGE_OBJECT] : state,
iterators: (state = [], action) =>
iterators: (state = [], action: DemoAppAction) =>
action.type === 'ADD_ITERATOR' ? [...state, createIterator()] : state,
nested: (state = NESTED, action) =>
nested: (state = NESTED, action: DemoAppAction) =>
action.type === 'CHANGE_NESTED'
? {
...state,
@ -200,23 +200,23 @@ export const rootReducer: Reducer<DemoAppState, DemoAppAction> =
},
}
: state,
recursive: (state = [], action) =>
recursive: (state = [], action: DemoAppAction) =>
action.type === 'ADD_RECURSIVE' ? [...state, { ...RECURSIVE }] : state,
immutables: (state = [], action) =>
immutables: (state = [], action: DemoAppAction) =>
action.type === 'ADD_IMMUTABLE_MAP' ? [...state, IMMUTABLE_MAP] : state,
immutableNested: (state = IMMUTABLE_NESTED, action) =>
immutableNested: (state = IMMUTABLE_NESTED, action: DemoAppAction) =>
action.type === 'CHANGE_IMMUTABLE_NESTED'
? state.updateIn(
['long', 'nested', 0, 'path', 'to', 'a'],
(str: unknown) => (str as string) + '!',
)
: state,
addFunction: (state = null, action) =>
addFunction: (state = null, action: DemoAppAction) =>
action.type === 'ADD_FUNCTION' ? { f: FUNC } : state,
addSymbol: (state = null, action) =>
addSymbol: (state = null, action: DemoAppAction) =>
action.type === 'ADD_SYMBOL'
? { s: window.Symbol('symbol'), error: new Error('TEST') }
: state,
shuffleArray: (state = DEFAULT_SHUFFLE_ARRAY, action) =>
shuffleArray: (state = DEFAULT_SHUFFLE_ARRAY, action: DemoAppAction) =>
action.type === 'SHUFFLE_ARRAY' ? shuffle(state) : state,
});
}) as any;

View File

@ -81,7 +81,7 @@
"jest-environment-jsdom": "^29.7.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"redux": "^4.2.1",
"redux": "^5.0.1",
"rimraf": "^6.0.1",
"ts-jest": "^29.2.3",
"typescript": "~5.5.3"

View File

@ -70,7 +70,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-test-renderer": "^18.3.1",
"redux": "^4.2.1",
"redux": "^5.0.1",
"rimraf": "^6.0.1",
"ts-jest": "^29.2.3",
"typescript": "~5.5.3"

View File

@ -20,9 +20,9 @@
"react-base16-styling": "^0.10.0",
"react-bootstrap": "^2.10.4",
"react-dom": "^18.3.1",
"react-redux": "^8.1.3",
"react-redux": "^9.1.2",
"react-router-dom": "^6.25.1",
"redux": "^4.2.1",
"redux": "^5.0.1",
"redux-logger": "^3.0.6"
},
"devDependencies": {
@ -34,7 +34,7 @@
"@types/node": "^20.14.11",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/redux-logger": "3.0.12",
"@types/redux-logger": "^3.0.13",
"@types/webpack-env": "^1.18.5",
"@typescript-eslint/eslint-plugin": "^8.0.0",
"@typescript-eslint/parser": "^8.0.0",

View File

@ -32,7 +32,7 @@ const useDevtoolsExtension =
!!(window as unknown as { __REDUX_DEVTOOLS_EXTENSION__: unknown })
.__REDUX_DEVTOOLS_EXTENSION__ && getOptions(window.location).useExtension;
const enhancer = compose(
const enhancer: StoreEnhancer = compose(
applyMiddleware(logger),
(next: StoreEnhancerStoreCreator) => {
const instrument = useDevtoolsExtension
@ -45,7 +45,7 @@ const enhancer = compose(
return instrument(next);
},
persistState(getDebugSessionKey()),
);
) as any;
const store = createStore(rootReducer, enhancer);

View File

@ -185,12 +185,12 @@ export interface DemoAppState {
}
export const rootReducer: Reducer<DemoAppState, DemoAppAction> =
combineReducers<DemoAppState, DemoAppAction>({
timeoutUpdateEnabled: (state = false, action) =>
combineReducers({
timeoutUpdateEnabled: (state = false, action: DemoAppAction) =>
action.type === 'TOGGLE_TIMEOUT_UPDATE'
? action.timeoutUpdateEnabled
: state,
store: (state = 0, action) =>
store: (state = 0, action: DemoAppAction) =>
action.type === 'INCREMENT' ? state + 1 : state,
undefined: (state = { val: undefined }) => state,
null: (state = null) => state,
@ -199,7 +199,7 @@ export const rootReducer: Reducer<DemoAppState, DemoAppAction> =
// noop
},
) => state,
array: (state = [], action) =>
array: (state = [], action: DemoAppAction) =>
action.type === 'PUSH'
? [...state, Math.random()]
: action.type === 'POP'
@ -207,13 +207,13 @@ export const rootReducer: Reducer<DemoAppState, DemoAppAction> =
: action.type === 'REPLACE'
? [Math.random(), ...state.slice(1)]
: state,
hugeArrays: (state = [], action) =>
hugeArrays: (state = [], action: DemoAppAction) =>
action.type === 'PUSH_HUGE_ARRAY' ? [...state, ...HUGE_ARRAY] : state,
hugeObjects: (state = [], action) =>
hugeObjects: (state = [], action: DemoAppAction) =>
action.type === 'ADD_HUGE_OBJECT' ? [...state, HUGE_OBJECT] : state,
iterators: (state = [], action) =>
iterators: (state = [], action: DemoAppAction) =>
action.type === 'ADD_ITERATOR' ? [...state, createIterator()] : state,
nested: (state = NESTED, action) =>
nested: (state = NESTED, action: DemoAppAction) =>
action.type === 'CHANGE_NESTED'
? {
...state,
@ -230,25 +230,28 @@ export const rootReducer: Reducer<DemoAppState, DemoAppAction> =
},
}
: state,
recursive: (state: { obj?: unknown }[] = [], action) =>
recursive: (state: { obj?: unknown }[] = [], action: DemoAppAction) =>
action.type === 'ADD_RECURSIVE' ? [...state, { ...RECURSIVE }] : state,
immutables: (state: Immutable.Map<string, unknown>[] = [], action) =>
immutables: (
state: Immutable.Map<string, unknown>[] = [],
action: DemoAppAction,
) =>
action.type === 'ADD_IMMUTABLE_MAP' ? [...state, IMMUTABLE_MAP] : state,
maps: (state: Map<string, MapValue>[] = [], action) =>
maps: (state: Map<string, MapValue>[] = [], action: DemoAppAction) =>
action.type === 'ADD_NATIVE_MAP' ? [...state, NATIVE_MAP] : state,
immutableNested: (state = IMMUTABLE_NESTED, action) =>
immutableNested: (state = IMMUTABLE_NESTED, action: DemoAppAction) =>
action.type === 'CHANGE_IMMUTABLE_NESTED'
? state.updateIn(
['long', 'nested', 0, 'path', 'to', 'a'],
(str: unknown) => (str as string) + '!',
)
: state,
addFunction: (state = null, action) =>
addFunction: (state = null, action: DemoAppAction) =>
action.type === 'ADD_FUNCTION' ? { f: FUNC } : state,
addSymbol: (state = null, action) =>
addSymbol: (state = null, action: DemoAppAction) =>
action.type === 'ADD_SYMBOL'
? { s: window.Symbol('symbol'), error: new Error('TEST') }
: state,
shuffleArray: (state = DEFAULT_SHUFFLE_ARRAY, action) =>
shuffleArray: (state = DEFAULT_SHUFFLE_ARRAY, action: DemoAppAction) =>
action.type === 'SHUFFLE_ARRAY' ? shuffle(state) : state,
});
}) as any;

View File

@ -72,7 +72,7 @@
"eslint-plugin-react": "^7.35.0",
"eslint-plugin-react-hooks": "^4.6.2",
"react": "^18.3.1",
"redux": "^4.2.1",
"redux": "^5.0.1",
"rimraf": "^6.0.1",
"typescript": "~5.5.3"
},

View File

@ -60,7 +60,7 @@
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-jest": "^28.6.0",
"jest": "^29.7.0",
"redux": "^4.2.1",
"redux": "^5.0.1",
"rimraf": "^6.0.1",
"rxjs": "^7.8.1",
"ts-jest": "^29.2.3",

View File

@ -4,7 +4,6 @@ import isPlainObject from 'lodash/isPlainObject';
import {
Action,
Observer,
PreloadedState,
Reducer,
Store,
StoreEnhancer,
@ -271,8 +270,8 @@ export const INIT_ACTION = { type: '@@INIT' };
/**
* Computes the next entry with exceptions catching.
*/
function computeWithTryCatch<S, A extends Action<string>>(
reducer: Reducer<S, A>,
function computeWithTryCatch<S, A extends Action<string>, PreloadedState>(
reducer: Reducer<S, A, PreloadedState>,
action: A,
state: S,
) {
@ -301,8 +300,8 @@ function computeWithTryCatch<S, A extends Action<string>>(
/**
* Computes the next entry in the log by applying an action.
*/
function computeNextEntry<S, A extends Action<string>>(
reducer: Reducer<S, A>,
function computeNextEntry<S, A extends Action<string>, PreloadedState>(
reducer: Reducer<S, A, PreloadedState>,
action: A,
state: S,
shouldCatchErrors: boolean | undefined,
@ -316,10 +315,10 @@ function computeNextEntry<S, A extends Action<string>>(
/**
* Runs the reducer on invalidated actions to get a fresh computation log.
*/
function recomputeStates<S, A extends Action<string>>(
function recomputeStates<S, A extends Action<string>, PreloadedState>(
computedStates: { state: S; error?: string }[],
minInvalidatedStateIndex: number,
reducer: Reducer<S, A>,
reducer: Reducer<S, A, PreloadedState>,
committedState: S,
actionsById: { [actionId: number]: PerformAction<A> },
stagedActionIds: number[],
@ -413,11 +412,12 @@ export interface LiftedState<S, A extends Action<string>, MonitorState> {
function liftReducerWith<
S,
A extends Action<string>,
PreloadedState,
MonitorState,
MonitorAction extends Action<string>,
>(
reducer: Reducer<S, A>,
initialCommittedState: PreloadedState<S> | undefined,
reducer: Reducer<S, A, PreloadedState>,
initialCommittedState: S | PreloadedState | undefined,
monitorReducer: Reducer<MonitorState, MonitorAction>,
options: Options<S, A, MonitorState, MonitorAction>,
): Reducer<LiftedState<S, A, MonitorState>, LiftedAction<S, A, MonitorState>> {
@ -575,7 +575,7 @@ function liftReducerWith<
if (maxAge && stagedActionIds.length > maxAge) {
// States must be recomputed before committing excess.
computedStates = recomputeStates<S, A>(
computedStates = recomputeStates<S, A, PreloadedState>(
computedStates,
minInvalidatedStateIndex,
reducer,
@ -872,6 +872,7 @@ export type EnhancedStore<S, A extends Action<string>, MonitorState> = Store<
function unliftStore<
S,
A extends Action<string>,
PreloadedState,
MonitorState,
MonitorAction extends Action<string>,
NextExt,
@ -882,7 +883,9 @@ function unliftStore<
LiftedAction<S, A, MonitorState>
> &
NextExt,
liftReducer: (r: Reducer<S, A>) => LiftedReducer<S, A, MonitorState>,
liftReducer: (
r: Reducer<S, A, PreloadedState>,
) => LiftedReducer<S, A, MonitorState>,
options: Options<S, A, MonitorState, MonitorAction>,
) {
let lastDefinedState: S & NextStateExt;
@ -924,7 +927,7 @@ function unliftStore<
replaceReducer(nextReducer: Reducer<S & NextStateExt, A>) {
liftedStore.replaceReducer(
liftReducer(
nextReducer as unknown as Reducer<S, A>,
nextReducer as unknown as Reducer<S, A, PreloadedState>,
) as unknown as Reducer<
LiftedState<S, A, MonitorState> & NextStateExt,
LiftedAction<S, A, MonitorState>
@ -1006,14 +1009,17 @@ export function instrument<
);
}
return <NextExt, NextStateExt>(
return <
NextExt extends NonNullable<unknown>,
NextStateExt extends NonNullable<unknown>,
>(
createStore: StoreEnhancerStoreCreator<NextExt, NextStateExt>,
) =>
<S, A extends Action<string>>(
reducer: Reducer<S, A>,
initialState?: PreloadedState<S>,
<S, A extends Action<string>, PreloadedState>(
reducer: Reducer<S, A, PreloadedState>,
initialState?: PreloadedState | undefined,
) => {
function liftReducer(r: Reducer<S, A>) {
function liftReducer(r: Reducer<S, A, PreloadedState>) {
if (typeof r !== 'function') {
if (r && typeof (r as { default: unknown }).default === 'function') {
throw new Error(
@ -1025,7 +1031,13 @@ export function instrument<
}
throw new Error('Expected the reducer to be a function.');
}
return liftReducerWith<S, A, MonitorState, MonitorAction>(
return liftReducerWith<
S,
A,
PreloadedState,
MonitorState,
MonitorAction
>(
r,
initialState,
monitorReducer,
@ -1057,12 +1069,17 @@ export function instrument<
return unliftStore<
S,
A,
PreloadedState,
MonitorState,
MonitorAction,
NextExt,
NextStateExt
>(
liftedStore,
liftedStore as Store<
LiftedState<S, A, MonitorState> & NextStateExt,
LiftedAction<S, A, MonitorState>
> &
NextExt,
liftReducer,
options as unknown as Options<S, A, MonitorState, MonitorAction>,
);

View File

@ -1,8 +1,16 @@
import { createStore, compose, Reducer, Store, Action } from 'redux';
import {
createStore,
compose,
Reducer,
Store,
Action,
StoreEnhancer,
} from 'redux';
import {
ActionCreators,
EnhancedStore,
instrument,
LiftedAction,
LiftedStore,
LiftedState,
} from '../src/instrument';
@ -487,10 +495,18 @@ describe('instrument', () => {
const savedComputedStates = monitoredLiftedStore.getState().computedStates;
monitoredLiftedStore.dispatch({ type: 'lol' } as Action);
monitoredLiftedStore.dispatch({ type: 'lol' } as unknown as LiftedAction<
number,
Action,
null
>);
expect(reducerCalls).toBe(4);
monitoredLiftedStore.dispatch({ type: 'wat' } as Action);
monitoredLiftedStore.dispatch({ type: 'wat' } as unknown as LiftedAction<
number,
Action,
null
>);
expect(reducerCalls).toBe(4);
expect(monitoredLiftedStore.getState().computedStates).toBe(
@ -1366,7 +1382,9 @@ describe('instrument', () => {
it('throws if reducer is not a function', () => {
expect(() =>
createStore(undefined as unknown as Reducer, instrument()),
).toThrow('Expected the reducer to be a function.');
).toThrow(
"Expected the root reducer to be a function. Instead, received: 'undefined'",
);
});
it('warns if the reducer is not a function but has a default field that is', () => {
@ -1380,16 +1398,16 @@ describe('instrument', () => {
instrument(),
),
).toThrow(
'Expected the reducer to be a function. ' +
'Instead got an object with a "default" field. ' +
'Did you pass a module instead of the default export? ' +
'Try passing require(...).default instead.',
"Expected the root reducer to be a function. Instead, received: 'object'",
);
});
it('throws if there are more than one instrument enhancer included', () => {
expect(() => {
createStore(counter, compose(instrument(), instrument()));
createStore(
counter,
compose(instrument(), instrument()) as StoreEnhancer,
);
}).toThrow(
'DevTools instrumentation should not be applied more than once. ' +
'Check your store configuration.',

View File

@ -64,7 +64,7 @@
"eslint-plugin-react": "^7.35.0",
"eslint-plugin-react-hooks": "^4.6.2",
"react": "^18.3.1",
"redux": "^4.2.1",
"redux": "^5.0.1",
"rimraf": "^6.0.1",
"typescript": "~5.5.3"
},

View File

@ -63,7 +63,7 @@
"@typescript-eslint/parser": "^8.0.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"redux": "^4.2.1",
"redux": "^5.0.1",
"rimraf": "^6.0.1",
"typescript": "~5.5.3"
},

View File

@ -7,8 +7,7 @@ export default function configureStore<
MonitorState,
MonitorAction extends Action<string>,
>(
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
next: StoreEnhancerStoreCreator<{}, unknown>,
next: StoreEnhancerStoreCreator,
subscriber: Reducer<MonitorState, MonitorAction>,
options: Options<S, A, MonitorState, MonitorAction>,
) {

View File

@ -6,7 +6,6 @@ import getHostForRN from 'rn-host-detect';
import {
Action,
ActionCreator,
PreloadedState,
Reducer,
StoreEnhancer,
StoreEnhancerStoreCreator,
@ -174,7 +173,7 @@ type Message<S, A extends Action<string>> =
| ActionMessage
| DispatchMessage<S, A>;
class DevToolsEnhancer<S, A extends Action<string>> {
class DevToolsEnhancer<S, A extends Action<string>, PreloadedState> {
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
store!: EnhancedStore<S, A, {}>;
filters: LocalFilter | undefined;
@ -547,11 +546,14 @@ class DevToolsEnhancer<S, A extends Action<string>> {
? process.env.NODE_ENV === 'development'
: options.realtime;
if (!realtime && !(this.startOn || this.sendOn || this.sendOnError))
return (f: StoreEnhancerStoreCreator) => f;
return (f) => f;
const maxAge = options.maxAge || 30;
return ((next: StoreEnhancerStoreCreator) => {
return (reducer: Reducer<S, A>, initialState: PreloadedState<S>) => {
return (
reducer: Reducer<S, A, PreloadedState>,
initialState?: PreloadedState | undefined,
) => {
this.store = configureStore(next, this.monitorReducer, {
maxAge,
trace: options.trace,
@ -578,8 +580,9 @@ class DevToolsEnhancer<S, A extends Action<string>> {
};
}
export default <S, A extends Action<string>>(options?: Options<S, A>) =>
new DevToolsEnhancer<S, A>().enhance(options);
export default <S, A extends Action<string>, PreloadedState>(
options?: Options<S, A>,
) => new DevToolsEnhancer<S, A, PreloadedState>().enhance(options);
const compose =
(options: Options<unknown, Action<string>>) =>
@ -588,9 +591,9 @@ const compose =
const devToolsEnhancer = new DevToolsEnhancer();
function preEnhancer(createStore: StoreEnhancerStoreCreator) {
return <S, A extends Action<string>>(
reducer: Reducer<S, A>,
preloadedState: PreloadedState<S>,
return <S, A extends Action<string>, PreloadedState>(
reducer: Reducer<S, A, PreloadedState>,
preloadedState?: PreloadedState | undefined,
) => {
devToolsEnhancer.store = createStore(reducer, preloadedState) as any;
return {

View File

@ -18,14 +18,14 @@
"@redux-devtools/core": "^4.0.0",
"@redux-devtools/dock-monitor": "^4.0.0",
"@redux-devtools/rtk-query-monitor": "^5.0.0",
"@reduxjs/toolkit": "^1.9.7",
"@reduxjs/toolkit": "^2.2.7",
"framer-motion": "^11.3.8",
"msw": "^2.3.5",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-icons": "^5.2.1",
"react-is": "^18.3.1",
"react-redux": "^8.1.3",
"react-redux": "^9.1.2",
"react-router-dom": "^6.25.1",
"styled-components": "^5.3.11"
},

View File

@ -1,6 +1,5 @@
import {
configureStore,
Middleware,
combineReducers,
EnhancedStore,
} from '@reduxjs/toolkit';
@ -21,9 +20,6 @@ export const store: EnhancedStore<ReturnType<typeof reducer>> = configureStore({
devTools,
// adding the api middleware enables caching, invalidation, polling and other features of `rtk-query`
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat([
pokemonApi.middleware,
postsApi.middleware,
]) as Middleware[],
getDefaultMiddleware().concat([pokemonApi.middleware, postsApi.middleware]),
enhancers: (devTools ? [] : [DevTools.instrument()]) as any,
});

View File

@ -64,7 +64,7 @@
"@emotion/babel-preset-css-prop": "^11.12.0",
"@emotion/react": "^11.13.0",
"@redux-devtools/core": "^4.0.0",
"@reduxjs/toolkit": "^1.9.7",
"@reduxjs/toolkit": "^2.2.7",
"@testing-library/dom": "^10.3.2",
"@testing-library/jest-dom": "^6.4.6",
"@testing-library/react": "^16.0.0",
@ -83,8 +83,8 @@
"jest-environment-jsdom": "^29.7.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-redux": "^8.1.3",
"redux": "^4.2.1",
"react-redux": "^9.1.2",
"redux": "^5.0.1",
"rimraf": "^6.0.1",
"ts-jest": "^29.2.3",
"typescript": "~5.5.3"

View File

@ -1,5 +1,5 @@
import { createSelector, Selector } from '@reduxjs/toolkit';
import { QueryStatus } from '@reduxjs/toolkit/dist/query';
import { QueryStatus } from '@reduxjs/toolkit/query';
import React, { ReactNode, PureComponent } from 'react';
import type { ShouldExpandNodeInitially } from 'react-json-tree';
import { QueryPreviewTabs, RtkResourceInfo, RTKStatusFlags } from '../types';

View File

@ -1,5 +1,5 @@
import React, { PureComponent, createRef, ReactNode } from 'react';
import type { AnyAction, Dispatch, Action } from '@reduxjs/toolkit';
import type { Dispatch, Action } from '@reduxjs/toolkit';
import type { LiftedAction, LiftedState } from '@redux-devtools/core';
import {
QueryFormValues,
@ -96,15 +96,33 @@ class RtkQueryInspector<S, A extends Action<string>> extends PureComponent<
}
handleQueryFormValuesChange = (values: Partial<QueryFormValues>): void => {
this.props.dispatch(changeQueryFormValues(values) as AnyAction);
this.props.dispatch(
changeQueryFormValues(values) as unknown as LiftedAction<
S,
A,
RtkQueryMonitorState
>,
);
};
handleSelectQuery = (queryInfo: RtkResourceInfo): void => {
this.props.dispatch(selectQueryKey(queryInfo) as AnyAction);
this.props.dispatch(
selectQueryKey(queryInfo) as unknown as LiftedAction<
S,
A,
RtkQueryMonitorState
>,
);
};
handleTabChange = (tab: QueryPreviewTabs): void => {
this.props.dispatch(selectedPreviewTab(tab) as AnyAction);
this.props.dispatch(
selectedPreviewTab(tab) as unknown as LiftedAction<
S,
A,
RtkQueryMonitorState
>,
);
};
render(): ReactNode {

View File

@ -3,6 +3,7 @@ import {
configureStore,
EnhancedStore,
Middleware,
Tuple,
} from '@reduxjs/toolkit';
import { createApi } from '@reduxjs/toolkit/query/react';
import type { BaseQueryFn, FetchArgs } from '@reduxjs/toolkit/query';
@ -70,8 +71,9 @@ export function setupStore(
devTools: false,
// adding the api middleware enables caching, invalidation, polling and other features of `rtk-query`
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat([pokemonApi.middleware]) as Middleware[],
enhancers: [devTools.instrument()],
getDefaultMiddleware().concat(pokemonApi.middleware),
enhancers: (getDefaultEnhancers) =>
getDefaultEnhancers().concat(devTools.instrument()),
});
return {

View File

@ -23,8 +23,8 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-is": "^18.3.1",
"react-redux": "^8.1.3",
"redux": "^4.2.1",
"react-redux": "^9.1.2",
"redux": "^5.0.1",
"styled-components": "^5.3.11",
"todomvc-app-css": "^2.4.3"
},

View File

@ -1,12 +1,17 @@
import { combineReducers } from 'redux';
import { combineReducers, Reducer } from 'redux';
import todos, { Todo } from './todos';
import { TodoAction } from '../actions/TodoActions';
export interface TodoState {
todos: Todo[];
}
const rootReducer = combineReducers({
const rootReducer: Reducer<
TodoState,
TodoAction,
Partial<TodoState>
> = combineReducers({
todos,
});
}) as any;
export default rootReducer;

View File

@ -1,4 +1,4 @@
import { createStore, compose, PreloadedState } from 'redux';
import { createStore, compose, StoreEnhancer } from 'redux';
import { persistState } from '@redux-devtools/core';
import rootReducer, { TodoState } from '../reducers';
import DevTools from '../containers/DevTools';
@ -8,13 +8,11 @@ function getDebugSessionKey() {
return matches && matches.length > 0 ? matches[1] : null;
}
const enhancer = compose(
const enhancer: StoreEnhancer = compose(
DevTools.instrument(),
persistState(getDebugSessionKey()),
);
export default function configureStore(
initialState?: PreloadedState<TodoState>,
) {
export default function configureStore(initialState?: Partial<TodoState>) {
return createStore(rootReducer, initialState, enhancer);
}

View File

@ -1,8 +1,6 @@
import { createStore, PreloadedState } from 'redux';
import { createStore } from 'redux';
import rootReducer, { TodoState } from '../reducers';
export default function configureStore(
initialState?: PreloadedState<TodoState>,
) {
export default function configureStore(initialState?: Partial<TodoState>) {
return createStore(rootReducer, initialState);
}

View File

@ -1,9 +1,9 @@
import { PreloadedState, Store } from 'redux';
import { Store } from 'redux';
import { TodoState } from '../reducers';
import { TodoAction } from '../actions/TodoActions';
const configureStore: (
initialState?: PreloadedState<TodoState>,
initialState?: Partial<TodoState>,
) => Store<TodoState, TodoAction> =
process.env.NODE_ENV === 'production'
? // eslint-disable-next-line @typescript-eslint/no-require-imports

View File

@ -53,7 +53,7 @@
"eslint-plugin-react": "^7.35.0",
"eslint-plugin-react-hooks": "^4.6.2",
"react": "^18.3.1",
"redux": "^4.2.1",
"redux": "^5.0.1",
"rimraf": "^6.0.1",
"typescript": "~5.5.3"
},

View File

@ -41,7 +41,7 @@
"jsan": "^3.1.14",
"lodash": "^4.17.21",
"nanoid": "^5.0.7",
"redux": "^4.2.1"
"redux": "^5.0.1"
},
"devDependencies": {
"@babel/cli": "^7.24.8",

View File

@ -24,9 +24,9 @@
"@redux-devtools/log-monitor": "^5.0.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-redux": "^8.1.3",
"redux": "^4.2.1",
"redux-thunk": "^2.4.2"
"react-redux": "^9.1.2",
"redux": "^5.0.1",
"redux-thunk": "^3.1.0"
},
"devDependencies": {
"@babel/core": "^7.24.9",

View File

@ -1,9 +1,14 @@
import { combineReducers } from 'redux';
import { combineReducers, Reducer } from 'redux';
import counter from './counter';
import { CounterAction } from '../actions/CounterActions';
const rootReducer = combineReducers({
const rootReducer: Reducer<
CounterState,
CounterAction,
Partial<CounterState>
> = combineReducers({
counter,
});
}) as any;
export interface CounterState {
counter: number;

View File

@ -2,34 +2,40 @@ import {
createStore,
applyMiddleware,
compose,
PreloadedState,
Reducer,
StoreEnhancer,
Middleware,
} from 'redux';
import { persistState } from '@redux-devtools/core';
import thunk from 'redux-thunk';
import rootReducer, { CounterState } from '../reducers';
import DevTools from '../containers/DevTools';
import { CounterAction } from '../actions/CounterActions';
function getDebugSessionKey() {
const matches = /[?&]debug_session=([^&#]+)\b/.exec(window.location.href);
return matches && matches.length > 0 ? matches[1] : null;
}
const enhancer = compose(
applyMiddleware(thunk),
const enhancer: StoreEnhancer = compose(
applyMiddleware(thunk as unknown as Middleware),
DevTools.instrument(),
persistState(getDebugSessionKey()),
);
export default function configureStore(
initialState?: PreloadedState<CounterState>,
) {
export default function configureStore(initialState?: Partial<CounterState>) {
const store = createStore(rootReducer, initialState, enhancer);
if (module.hot) {
module.hot.accept('../reducers', () =>
// eslint-disable-next-line @typescript-eslint/no-require-imports
store.replaceReducer(require('../reducers').default as Reducer),
store.replaceReducer(
// eslint-disable-next-line @typescript-eslint/no-require-imports
require('../reducers').default as Reducer<
CounterState,
CounterAction,
Partial<CounterState>
>,
),
);
}

View File

@ -1,11 +1,9 @@
import { createStore, applyMiddleware, PreloadedState } from 'redux';
import { createStore, applyMiddleware, Middleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer, { CounterState } from '../reducers';
const enhancer = applyMiddleware(thunk);
const enhancer = applyMiddleware(thunk as unknown as Middleware);
export default function configureStore(
initialState?: PreloadedState<CounterState>,
) {
export default function configureStore(initialState?: Partial<CounterState>) {
return createStore(rootReducer, initialState, enhancer);
}

View File

@ -1,9 +1,9 @@
import { PreloadedState, Store } from 'redux';
import { Store } from 'redux';
import { CounterState } from '../reducers';
import { CounterAction } from '../actions/CounterActions';
const configureStore: (
initialState?: PreloadedState<CounterState>,
initialState?: Partial<CounterState>,
) => Store<CounterState, CounterAction> =
process.env.NODE_ENV === 'production'
? // eslint-disable-next-line @typescript-eslint/no-require-imports

View File

@ -37,8 +37,8 @@
"classnames": "^2.5.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-redux": "^8.1.3",
"redux": "^4.2.1",
"react-redux": "^9.1.2",
"redux": "^5.0.1",
"todomvc-app-css": "^2.4.3"
},
"devDependencies": {

View File

@ -1,12 +1,17 @@
import { combineReducers } from 'redux';
import { combineReducers, Reducer } from 'redux';
import todos, { Todo } from './todos';
import { TodoAction } from '../actions/TodoActions';
export interface TodoState {
todos: Todo[];
}
const rootReducer = combineReducers({
const rootReducer: Reducer<
TodoState,
TodoAction,
Partial<TodoState>
> = combineReducers({
todos,
});
}) as any;
export default rootReducer;

View File

@ -1,4 +1,4 @@
import { createStore, compose, PreloadedState } from 'redux';
import { createStore, compose, StoreEnhancer } from 'redux';
import { persistState } from '@redux-devtools/core';
import rootReducer, { TodoState } from '../reducers';
import DevTools from '../containers/DevTools';
@ -8,13 +8,11 @@ function getDebugSessionKey() {
return matches && matches.length > 0 ? matches[1] : null;
}
const enhancer = compose(
const enhancer: StoreEnhancer = compose(
DevTools.instrument(),
persistState(getDebugSessionKey()),
);
export default function configureStore(
initialState?: PreloadedState<TodoState>,
) {
export default function configureStore(initialState?: Partial<TodoState>) {
return createStore(rootReducer, initialState, enhancer);
}

View File

@ -1,8 +1,6 @@
import { createStore, PreloadedState } from 'redux';
import { createStore } from 'redux';
import rootReducer, { TodoState } from '../reducers';
export default function configureStore(
initialState?: PreloadedState<TodoState>,
) {
export default function configureStore(initialState?: Partial<TodoState>) {
return createStore(rootReducer, initialState);
}

View File

@ -1,9 +1,9 @@
import { PreloadedState, Store } from 'redux';
import { Store } from 'redux';
import { TodoState } from '../reducers';
import { TodoAction } from '../actions/TodoActions';
const configureStore: (
initialState?: PreloadedState<TodoState>,
initialState?: Partial<TodoState>,
) => Store<TodoState, TodoAction> =
process.env.NODE_ENV === 'production'
? // eslint-disable-next-line @typescript-eslint/no-require-imports

View File

@ -67,8 +67,8 @@
"jest": "^29.7.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-redux": "^8.1.3",
"redux": "^4.2.1",
"react-redux": "^9.1.2",
"redux": "^5.0.1",
"rimraf": "^6.0.1",
"ts-jest": "^29.2.3",
"typescript": "~5.5.3"

View File

@ -1,6 +1,6 @@
import mapValues from 'lodash/mapValues';
import identity from 'lodash/identity';
import { Action, PreloadedState, Reducer, StoreEnhancer } from 'redux';
import { Action, Reducer, StoreEnhancer } from 'redux';
import { LiftedState } from '@redux-devtools/instrument';
export default function persistState<S, A extends Action<string>, MonitorState>(
@ -32,9 +32,9 @@ export default function persistState<S, A extends Action<string>, MonitorState>(
}
return (next) =>
<S2, A2 extends Action<string>>(
reducer: Reducer<S2, A2>,
initialState?: PreloadedState<S2>,
<S2, A2 extends Action<string>, PreloadedState>(
reducer: Reducer<S2, A2, PreloadedState>,
initialState?: PreloadedState | undefined,
) => {
const key = `redux-dev-session-${sessionId}`;
@ -58,7 +58,7 @@ export default function persistState<S, A extends Action<string>, MonitorState>(
const store = next(
reducer,
finalInitialState as PreloadedState<S2> | undefined,
finalInitialState as PreloadedState | undefined,
);
return {

View File

@ -1,5 +1,5 @@
import { instrument, persistState } from '../src';
import { compose, createStore } from 'redux';
import { compose, createStore, StoreEnhancer } from 'redux';
describe('persistState', () => {
const savedLocalStorage = global.localStorage;
@ -50,7 +50,7 @@ describe('persistState', () => {
it('should persist state', () => {
const store = createStore(
reducer,
compose(instrument(), persistState('id')),
compose(instrument(), persistState('id')) as StoreEnhancer,
);
expect(store.getState()).toBe(0);
@ -60,20 +60,26 @@ describe('persistState', () => {
const store2 = createStore(
reducer,
compose(instrument(), persistState('id')),
compose(instrument(), persistState('id')) as StoreEnhancer,
);
expect(store2.getState()).toBe(2);
});
it('should not persist state if no session id', () => {
const store = createStore(reducer, compose(instrument(), persistState()));
const store = createStore(
reducer,
compose(instrument(), persistState()) as StoreEnhancer,
);
expect(store.getState()).toBe(0);
store.dispatch({ type: 'INCREMENT' });
store.dispatch({ type: 'INCREMENT' });
expect(store.getState()).toBe(2);
const store2 = createStore(reducer, compose(instrument(), persistState()));
const store2 = createStore(
reducer,
compose(instrument(), persistState()) as StoreEnhancer,
);
expect(store2.getState()).toBe(0);
});
@ -82,7 +88,7 @@ describe('persistState', () => {
state === undefined ? -1 : state - 1;
const store = createStore(
reducer,
compose(instrument(), persistState('id', oneLess)),
compose(instrument(), persistState('id', oneLess)) as StoreEnhancer,
);
expect(store.getState()).toBe(0);
@ -92,7 +98,7 @@ describe('persistState', () => {
const store2 = createStore(
reducer,
compose(instrument(), persistState('id', oneLess)),
compose(instrument(), persistState('id', oneLess)) as StoreEnhancer,
);
expect(store2.getState()).toBe(1);
});
@ -102,7 +108,10 @@ describe('persistState', () => {
action.type === 'INCREMENT' ? ({ type: 'DECREMENT' } as const) : action;
const store = createStore(
reducer,
compose(instrument(), persistState('id', undefined, incToDec)),
compose(
instrument(),
persistState('id', undefined, incToDec),
) as StoreEnhancer,
);
expect(store.getState()).toBe(0);
@ -112,7 +121,10 @@ describe('persistState', () => {
const store2 = createStore(
reducer,
compose(instrument(), persistState('id', undefined, incToDec)),
compose(
instrument(),
persistState('id', undefined, incToDec),
) as StoreEnhancer,
);
expect(store2.getState()).toBe(-2);
});
@ -124,7 +136,10 @@ describe('persistState', () => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
delete global.localStorage.getItem;
createStore(reducer, compose(instrument(), persistState('id')));
createStore(
reducer,
compose(instrument(), persistState('id')) as StoreEnhancer,
);
expect(spy.mock.calls[0]).toContain(
'Could not read debug session from localStorage:',
@ -142,7 +157,7 @@ describe('persistState', () => {
delete global.localStorage.setItem;
const store = createStore(
reducer,
compose(instrument(), persistState('id')),
compose(instrument(), persistState('id')) as StoreEnhancer,
);
store.dispatch({ type: 'INCREMENT' });

View File

@ -81,8 +81,8 @@ importers:
specifier: ^3.0.0
version: link:../packages/redux-devtools-utils
'@reduxjs/toolkit':
specifier: ^1.9.7
version: 1.9.7(react-redux@8.1.3)(react@18.3.1)
specifier: ^2.2.7
version: 2.2.7(react-redux@9.1.2)(react@18.3.1)
'@types/jsan':
specifier: ^3.1.5
version: 3.1.5
@ -111,14 +111,14 @@ importers:
specifier: ^0.19.0
version: link:../packages/react-json-tree
react-redux:
specifier: ^8.1.3
version: 8.1.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)(redux@4.2.1)
specifier: ^9.1.2
version: 9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1)
redux:
specifier: ^4.2.1
version: 4.2.1
specifier: ^5.0.1
version: 5.0.1
redux-persist:
specifier: ^6.0.0
version: 6.0.0(react@18.3.1)(redux@4.2.1)
version: 6.0.0(react@18.3.1)(redux@5.0.1)
styled-components:
specifier: ^5.3.11
version: 5.3.11(@babel/core@7.24.9)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1)
@ -829,11 +829,11 @@ importers:
specifier: ^18.3.1
version: 18.3.1(react@18.3.1)
react-redux:
specifier: ^8.1.3
version: 8.1.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)(redux@4.2.1)
specifier: ^9.1.2
version: 9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1)
redux:
specifier: ^4.2.1
version: 4.2.1
specifier: ^5.0.1
version: 5.0.1
rimraf:
specifier: ^6.0.1
version: 6.0.1
@ -852,9 +852,6 @@ importers:
'@redux-devtools/ui':
specifier: ^1.3.2
version: link:../redux-devtools-ui
'@reduxjs/toolkit':
specifier: ^1.0.0 || ^2.0.0
version: 1.9.7(react-redux@8.1.3)(react@18.3.1)
jsan:
specifier: ^3.1.14
version: 3.1.14
@ -865,14 +862,14 @@ importers:
specifier: ^4.17.21
version: 4.17.21
react-redux:
specifier: ^8.1.3
version: 8.1.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)(redux@4.2.1)
specifier: ^9.1.2
version: 9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1)
redux:
specifier: ^4.2.1
version: 4.2.1
specifier: ^5.0.1
version: 5.0.1
redux-persist:
specifier: ^6.0.0
version: 6.0.0(react@18.3.1)(redux@4.2.1)
version: 6.0.0(react@18.3.1)(redux@5.0.1)
socketcluster-client:
specifier: ^19.2.1
version: 19.2.1
@ -901,6 +898,9 @@ importers:
'@emotion/react':
specifier: ^11.13.0
version: 11.13.0(@types/react@18.3.3)(react@18.3.1)
'@reduxjs/toolkit':
specifier: ^2.2.7
version: 2.2.7(react-redux@9.1.2)(react@18.3.1)
'@rjsf/core':
specifier: ^4.2.3
version: 4.2.3(react@18.3.1)
@ -1036,9 +1036,6 @@ importers:
'@redux-devtools/ui':
specifier: ^1.3.1
version: link:../redux-devtools-ui
'@reduxjs/toolkit':
specifier: ^1.0.0 || ^2.0.0
version: 1.9.7(react-redux@8.1.3)(react@18.3.1)
d3-state-visualizer:
specifier: ^3.0.0
version: link:../d3-state-visualizer
@ -1082,6 +1079,9 @@ importers:
'@emotion/react':
specifier: ^11.13.0
version: 11.13.0(@types/react@18.3.3)(react@18.3.1)
'@reduxjs/toolkit':
specifier: ^2.2.7
version: 2.2.7(react-redux@9.1.2)(react@18.3.1)
'@rjsf/core':
specifier: ^4.2.3
version: 4.2.3(react@18.3.1)
@ -1155,14 +1155,14 @@ importers:
specifier: ^18.3.1
version: 18.3.1(react@18.3.1)
react-redux:
specifier: ^8.1.3
version: 8.1.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)(redux@4.2.1)
specifier: ^9.1.2
version: 9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1)
redux:
specifier: ^4.2.1
version: 4.2.1
specifier: ^5.0.1
version: 5.0.1
redux-persist:
specifier: ^6.0.0
version: 6.0.0(react@18.3.1)(redux@4.2.1)
version: 6.0.0(react@18.3.1)(redux@5.0.1)
rimraf:
specifier: ^6.0.1
version: 6.0.1
@ -1243,8 +1243,8 @@ importers:
specifier: ^18.3.1
version: 18.3.1
redux:
specifier: ^4.2.1
version: 4.2.1
specifier: ^5.0.1
version: 5.0.1
rimraf:
specifier: ^6.0.1
version: 6.0.1
@ -1264,8 +1264,8 @@ importers:
specifier: ^6.0.0
version: link:../redux-devtools-app
'@reduxjs/toolkit':
specifier: ^1.9.7
version: 1.9.7(react-redux@8.1.3)(react@18.3.1)
specifier: ^2.2.7
version: 2.2.7(react-redux@9.1.2)(react@18.3.1)
'@types/react':
specifier: ^18.3.3
version: 18.3.3
@ -1479,8 +1479,8 @@ importers:
specifier: ^18.3.1
version: 18.3.1
redux:
specifier: ^4.2.1
version: 4.2.1
specifier: ^5.0.1
version: 5.0.1
rimraf:
specifier: ^6.0.1
version: 6.0.1
@ -1528,8 +1528,8 @@ importers:
specifier: ^9.1.0
version: 9.1.0(eslint@8.57.0)
redux:
specifier: ^4.2.1
version: 4.2.1
specifier: ^5.0.1
version: 5.0.1
rimraf:
specifier: ^6.0.1
version: 6.0.1
@ -1649,8 +1649,8 @@ importers:
specifier: ^18.3.1
version: 18.3.1
redux:
specifier: ^4.2.1
version: 4.2.1
specifier: ^5.0.1
version: 5.0.1
rimraf:
specifier: ^6.0.1
version: 6.0.1
@ -1776,8 +1776,8 @@ importers:
specifier: ^18.3.1
version: 18.3.1(react@18.3.1)
redux:
specifier: ^4.2.1
version: 4.2.1
specifier: ^5.0.1
version: 5.0.1
rimraf:
specifier: ^6.0.1
version: 6.0.1
@ -1824,14 +1824,14 @@ importers:
specifier: ^18.3.1
version: 18.3.1
react-redux:
specifier: ^8.1.3
version: 8.1.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)(redux@4.2.1)
specifier: ^9.1.2
version: 9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1)
react-router-dom:
specifier: ^6.25.1
version: 6.25.1(react-dom@18.3.1)(react@18.3.1)
redux:
specifier: ^4.2.1
version: 4.2.1
specifier: ^5.0.1
version: 5.0.1
redux-logger:
specifier: ^3.0.6
version: 3.0.6
@ -1864,8 +1864,8 @@ importers:
specifier: ^18.3.0
version: 18.3.0
'@types/redux-logger':
specifier: 3.0.12
version: 3.0.12
specifier: ^3.0.13
version: 3.0.13
'@types/styled-components':
specifier: ^5.1.34
version: 5.1.34
@ -2042,8 +2042,8 @@ importers:
specifier: ^18.3.1
version: 18.3.1(react@18.3.1)
redux:
specifier: ^4.2.1
version: 4.2.1
specifier: ^5.0.1
version: 5.0.1
rimraf:
specifier: ^6.0.1
version: 6.0.1
@ -2087,14 +2087,14 @@ importers:
specifier: ^18.3.1
version: 18.3.1(react@18.3.1)
react-redux:
specifier: ^8.1.3
version: 8.1.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)(redux@4.2.1)
specifier: ^9.1.2
version: 9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1)
react-router-dom:
specifier: ^6.25.1
version: 6.25.1(react-dom@18.3.1)(react@18.3.1)
redux:
specifier: ^4.2.1
version: 4.2.1
specifier: ^5.0.1
version: 5.0.1
redux-logger:
specifier: ^3.0.6
version: 3.0.6
@ -2124,8 +2124,8 @@ importers:
specifier: ^18.3.0
version: 18.3.0
'@types/redux-logger':
specifier: 3.0.12
version: 3.0.12
specifier: ^3.0.13
version: 3.0.13
'@types/webpack-env':
specifier: ^1.18.5
version: 1.18.5
@ -2230,8 +2230,8 @@ importers:
specifier: ^29.7.0
version: 29.7.0(@types/node@20.14.11)(ts-node@10.9.2)
redux:
specifier: ^4.2.1
version: 4.2.1
specifier: ^5.0.1
version: 5.0.1
rimraf:
specifier: ^6.0.1
version: 6.0.1
@ -2312,8 +2312,8 @@ importers:
specifier: ^18.3.1
version: 18.3.1
redux:
specifier: ^4.2.1
version: 4.2.1
specifier: ^5.0.1
version: 5.0.1
rimraf:
specifier: ^6.0.1
version: 6.0.1
@ -2385,8 +2385,8 @@ importers:
specifier: ^9.1.0
version: 9.1.0(eslint@8.57.0)
redux:
specifier: ^4.2.1
version: 4.2.1
specifier: ^5.0.1
version: 5.0.1
rimraf:
specifier: ^6.0.1
version: 6.0.1
@ -2458,8 +2458,8 @@ importers:
specifier: ^4.0.0
version: link:../redux-devtools
'@reduxjs/toolkit':
specifier: ^1.9.7
version: 1.9.7(react-redux@8.1.3)(react@18.3.1)
specifier: ^2.2.7
version: 2.2.7(react-redux@9.1.2)(react@18.3.1)
'@testing-library/dom':
specifier: ^10.3.2
version: 10.3.2
@ -2515,11 +2515,11 @@ importers:
specifier: ^18.3.1
version: 18.3.1(react@18.3.1)
react-redux:
specifier: ^8.1.3
version: 8.1.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)(redux@4.2.1)
specifier: ^9.1.2
version: 9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1)
redux:
specifier: ^4.2.1
version: 4.2.1
specifier: ^5.0.1
version: 5.0.1
rimraf:
specifier: ^6.0.1
version: 6.0.1
@ -2557,8 +2557,8 @@ importers:
specifier: ^5.0.0
version: link:..
'@reduxjs/toolkit':
specifier: ^1.9.7
version: 1.9.7(react-redux@8.1.3)(react@18.3.1)
specifier: ^2.2.7
version: 2.2.7(react-redux@9.1.2)(react@18.3.1)
framer-motion:
specifier: ^11.3.8
version: 11.3.8(react-dom@18.3.1)(react@18.3.1)
@ -2578,8 +2578,8 @@ importers:
specifier: ^18.3.1
version: 18.3.1
react-redux:
specifier: ^8.1.3
version: 8.1.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)(redux@4.2.1)
specifier: ^9.1.2
version: 9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1)
react-router-dom:
specifier: ^6.25.1
version: 6.25.1(react-dom@18.3.1)(react@18.3.1)
@ -2800,8 +2800,8 @@ importers:
specifier: ^18.3.1
version: 18.3.1
redux:
specifier: ^4.2.1
version: 4.2.1
specifier: ^5.0.1
version: 5.0.1
rimraf:
specifier: ^6.0.1
version: 6.0.1
@ -2836,11 +2836,11 @@ importers:
specifier: ^18.3.1
version: 18.3.1
react-redux:
specifier: ^8.1.3
version: 8.1.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)(redux@4.2.1)
specifier: ^9.1.2
version: 9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1)
redux:
specifier: ^4.2.1
version: 4.2.1
specifier: ^5.0.1
version: 5.0.1
styled-components:
specifier: ^5.3.11
version: 5.3.11(@babel/core@7.24.9)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1)
@ -3144,8 +3144,8 @@ importers:
specifier: ^5.0.7
version: 5.0.7
redux:
specifier: ^4.2.1
version: 4.2.1
specifier: ^5.0.1
version: 5.0.1
devDependencies:
'@babel/cli':
specifier: ^7.24.8
@ -3211,14 +3211,14 @@ importers:
specifier: ^18.3.1
version: 18.3.1(react@18.3.1)
react-redux:
specifier: ^8.1.3
version: 8.1.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)(redux@4.2.1)
specifier: ^9.1.2
version: 9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1)
redux:
specifier: ^4.2.1
version: 4.2.1
specifier: ^5.0.1
version: 5.0.1
redux-thunk:
specifier: ^2.4.2
version: 2.4.2(redux@4.2.1)
specifier: ^3.1.0
version: 3.1.0(redux@5.0.1)
devDependencies:
'@babel/core':
specifier: ^7.24.9
@ -3311,11 +3311,11 @@ importers:
specifier: ^18.3.1
version: 18.3.1(react@18.3.1)
react-redux:
specifier: ^8.1.3
version: 8.1.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)(redux@4.2.1)
specifier: ^9.1.2
version: 9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1)
redux:
specifier: ^4.2.1
version: 4.2.1
specifier: ^5.0.1
version: 5.0.1
todomvc-app-css:
specifier: ^2.4.3
version: 2.4.3
@ -7870,23 +7870,23 @@ packages:
react: 18.3.1
dev: false
/@reduxjs/toolkit@1.9.7(react-redux@8.1.3)(react@18.3.1):
resolution: {integrity: sha512-t7v8ZPxhhKgOKtU+uyJT13lu4vL7az5aFi4IdoDs/eS548edn2M8Ik9h8fxgvMjGoAUVFSt6ZC1P5cWmQ014QQ==}
/@reduxjs/toolkit@2.2.7(react-redux@9.1.2)(react@18.3.1):
resolution: {integrity: sha512-faI3cZbSdFb8yv9dhDTmGwclW0vk0z5o1cia+kf7gCbaCwHI5e+7tP57mJUv22pNcNbeA62GSrPpfrUfdXcQ6g==}
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:
optional: true
react-redux:
optional: true
dependencies:
immer: 9.0.21
immer: 10.1.1
react: 18.3.1
react-redux: 8.1.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)(redux@4.2.1)
redux: 4.2.1
redux-thunk: 2.4.2(redux@4.2.1)
reselect: 4.1.8
react-redux: 9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1)
redux: 5.0.1
redux-thunk: 3.1.0(redux@5.0.1)
reselect: 5.1.1
/@remix-run/router@1.18.0:
resolution: {integrity: sha512-L3jkqmqoSVBVKHfpGZmLrex0lxR5SucGA0sUfFzGctehw+S/ggL9L/0NnC5mw6P8HUWpFZ3nQw3cRApjjWx9Sw==}
@ -9452,6 +9452,7 @@ packages:
resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==}
dependencies:
'@types/react': 18.3.3
dev: true
/@types/react-test-renderer@18.3.0:
resolution: {integrity: sha512-HW4MuEYxfDbOHQsVlY/XtOvNHftCVEPhJF2pQXXwcUiUF+Oyb0usgp48HSgpK5rt8m9KZb22yqOeZm+rrVG8gw==}
@ -9471,10 +9472,10 @@ packages:
'@types/prop-types': 15.7.12
csstype: 3.1.3
/@types/redux-logger@3.0.12:
resolution: {integrity: sha512-5vAlwokZi/Unb1eGoZfVVzIBTPNDflwXiDzPLT1SynP6hdJfsOEf+w6ZOySOyboLWciCRYeE5DGYUnwVCq+Uyg==}
/@types/redux-logger@3.0.13:
resolution: {integrity: sha512-jylqZXQfMxahkuPcO8J12AKSSCQngdEWQrw7UiLUJzMBcv1r4Qg77P6mjGLjM27e5gFQDPD8vwUMJ9AyVxFSsg==}
dependencies:
redux: 4.2.1
redux: 5.0.1
dev: true
/@types/resolve@1.20.6:
@ -14355,8 +14356,8 @@ packages:
/immediate@3.0.6:
resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
/immer@9.0.21:
resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==}
/immer@10.1.1:
resolution: {integrity: sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==}
/immutable@4.3.6:
resolution: {integrity: sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==}
@ -17693,37 +17694,22 @@ packages:
resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==}
dev: false
/react-redux@8.1.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)(redux@4.2.1):
resolution: {integrity: sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw==}
/react-redux@9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1):
resolution: {integrity: sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==}
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
redux: ^5.0.0
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
react-dom:
optional: true
react-native:
optional: true
redux:
optional: true
dependencies:
'@babel/runtime': 7.24.8
'@types/hoist-non-react-statics': 3.3.5
'@types/react': 18.3.3
'@types/react-dom': 18.3.0
'@types/use-sync-external-store': 0.0.3
hoist-non-react-statics: 3.3.2
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react-is: 18.3.1
redux: 4.2.1
redux: 5.0.1
use-sync-external-store: 1.2.2(react@18.3.1)
/react-remove-scroll-bar@2.3.6(@types/react@18.3.3)(react@18.3.1):
@ -17931,7 +17917,7 @@ packages:
deep-diff: 0.3.8
dev: false
/redux-persist@6.0.0(react@18.3.1)(redux@4.2.1):
/redux-persist@6.0.0(react@18.3.1)(redux@5.0.1):
resolution: {integrity: sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==}
peerDependencies:
react: '>=16'
@ -17941,19 +17927,17 @@ packages:
optional: true
dependencies:
react: 18.3.1
redux: 4.2.1
redux: 5.0.1
/redux-thunk@2.4.2(redux@4.2.1):
resolution: {integrity: sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==}
/redux-thunk@3.1.0(redux@5.0.1):
resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==}
peerDependencies:
redux: ^4
redux: ^5.0.0
dependencies:
redux: 4.2.1
redux: 5.0.1
/redux@4.2.1:
resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==}
dependencies:
'@babel/runtime': 7.24.8
/redux@5.0.1:
resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==}
/reflect.getprototypeof@1.0.6:
resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==}
@ -18070,8 +18054,8 @@ packages:
/requires-port@1.0.0:
resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
/reselect@4.1.8:
resolution: {integrity: sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==}
/reselect@5.1.1:
resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==}
/resolve-alpn@1.2.1:
resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==}